import { ax as isIOS, ay as css$h, az as I18nMixin, aA as FocusTrapController, aB as isKeyboardActive, aC as Debouncer, aD as animationFrame, aE as ElementMixin, aF as ThemableMixin, aG as PolylitMixin, aH as LumoInjectionMixin, aI as LitElement, aJ as html, aK as defineCustomElement, aL as addGlobalStyles, aM as DirMixin, aN as overlayStyles, aO as PositionMixin, aP as OverlayMixin, aQ as timeOut, aR as announce, aS as detailsSummary, aT as ActiveMixin, aU as CollapsibleMixin, aV as DelegateFocusMixin, aW as DelegateStateMixin, aX as SummaryController, aY as TooltipController, aZ as KeyboardDirectionMixin, a_ as isElementFocused, a$ as SlotObserver, b0 as ButtonMixin, b1 as buttonStyles, b2 as isEmptyTextNode, b3 as FocusMixin, b4 as ifDefined, b5 as ListMixin, b6 as itemStyles, b7 as ItemMixin, b8 as ResizeMixin, b9 as SlotController, ba as render$1, bb as isElementHidden, bc as issueWarning, bd as generateUniqueId, be as unsafeCSS, bf as get$5, bg as field, bh as group, bi as FieldMixin, bj as DisabledMixin, bk as Directive, bl as isSingleExpression, bm as PartType, bn as directive, bo as noChange, bp as ComboBoxPlaceholder, bq as gestures, br as removeListener, bs as addListener, bt as dialogOverlayStyles, bu as DialogBaseMixin, bv as ThemePropertyMixin, bw as ColumnBaseMixin, bx as updateColumnOrders, by as ColumnObserver, bz as Button, bA as set, bB as GridColumn, bC as gridStyles, bD as Grid, bE as SlotStylesMixin, bF as FocusRestorationController, bG as MediaQueryController, bH as nothing, bI as setTouchAction, bJ as isFocusable, bK as KeyboardMixin, bL as getFlattenedElements, bM as isElementFocusable, bN as InputConstraintsMixin, bO as VirtualKeyboardController, bP as InputControlMixin, bQ as inputFieldShared, bR as InputController, bS as LabelledInputController, bT as ComboBoxItemMixin, bU as comboBoxItemStyles, bV as ComboBoxOverlayMixin, bW as ComboBoxScrollerMixin, bX as comboBoxScrollerStyles, bY as PatternMixin, bZ as ComboBoxBaseMixin, b_ as addValueToAttribute, b$ as removeValueFromAttribute, c0 as iterateRowCells, c1 as updatePart, c2 as Checkbox, c3 as Select, c4 as TextField, c5 as getDeepActiveElement, c6 as InputMixin, c7 as SlotChildObserveController, al as __vitePreload, c8 as isTemplateResult, c9 as Popover, ca as reactExports, cb as clientExports, cc as jsxDEV, cd as Outlet, ce as Tooltip$2, cf as screenReaderOnly, cg as InputFieldMixin, ch as setCommittedValue, ci as loaderStyles, cj as isTouch, ck as Virtualizer, cl as OverflowController, cm as isChrome, cn as isSafari$1, co as Iconset } from "./indexhtml-Kdz6Ae66.js";
import { renderMarkdownToElement } from "./markdown-helpers-CSzEQQ8a.js";
import "./commonjsHelpers-CUmg6egw.js";
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function _detectIosNavbar() {
  if (isIOS) {
    const innerHeight = window.innerHeight;
    const innerWidth = window.innerWidth;
    const landscape = innerWidth > innerHeight;
    const clientHeight = document.documentElement.clientHeight;
    if (landscape && clientHeight > innerHeight) {
      document.documentElement.style.setProperty("--vaadin-viewport-offset-bottom", `${clientHeight - innerHeight}px`);
    } else {
      document.documentElement.style.setProperty("--vaadin-viewport-offset-bottom", "");
    }
  }
}
_detectIosNavbar();
window.addEventListener("resize", _detectIosNavbar);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const appLayoutStyles = css$h`
  :host {
    display: block;
    box-sizing: border-box;
    height: 100%;
    --vaadin-app-layout-transition-duration: 0s;
    transition: padding var(--vaadin-app-layout-transition-duration);
    --_vaadin-app-layout-drawer-width: var(--vaadin-app-layout-drawer-width, auto);
    --vaadin-app-layout-touch-optimized: false;
    --vaadin-app-layout-navbar-offset-top: var(--_vaadin-app-layout-navbar-offset-size);
    --vaadin-app-layout-navbar-offset-bottom: var(--_vaadin-app-layout-navbar-offset-size-bottom);
    padding-top: max(var(--vaadin-app-layout-navbar-offset-top), var(--safe-area-inset-top));
    padding-bottom: max(var(--vaadin-app-layout-navbar-offset-bottom), var(--safe-area-inset-bottom));
  }

  :host(:dir(ltr)) [content] {
    padding-left: max(var(--vaadin-app-layout-drawer-offset-left), var(--safe-area-inset-left));
    padding-right: var(--safe-area-inset-right);
  }

  :host(:dir(rtl)) [content] {
    padding-left: var(--safe-area-inset-left);
    padding-right: max(var(--vaadin-app-layout-drawer-offset-left), var(--safe-area-inset-right));
  }

  :host([hidden]),
  [hidden] {
    display: none !important;
  }

  @media (prefers-reduced-motion: no-preference) {
    :host(:not([no-anim])) {
      --vaadin-app-layout-transition-duration: 200ms;
    }
  }

  :host([drawer-opened]) {
    --vaadin-app-layout-drawer-offset-left: var(--_vaadin-app-layout-drawer-offset-size);
  }

  :host([overlay]) {
    --vaadin-app-layout-drawer-offset-left: 0px;
  }

  :host(:not([no-scroll])) [content] {
    overflow: auto;
  }

  [content] {
    height: 100%;
    transition: inherit;
  }

  @media (pointer: coarse) and (max-width: 800px) and (min-height: 500px) {
    :host {
      --vaadin-app-layout-touch-optimized: true;
    }
  }

  [part~='navbar'] {
    position: fixed;
    display: flex;
    align-items: center;
    top: 0;
    inset-inline: 0;
    transition: inset-inline-start var(--vaadin-app-layout-transition-duration);
    padding-top: max(var(--vaadin-app-layout-navbar-padding-top, var(--vaadin-padding-s)), var(--safe-area-inset-top));
    padding-bottom: var(--vaadin-app-layout-navbar-padding-bottom, var(--vaadin-padding-s));
    padding-inline-start: max(
      var(--vaadin-app-layout-navbar-padding-inline-start, var(--vaadin-padding-s)),
      var(--safe-area-inset-left)
    );
    /* stylelint-disable-next-line declaration-block-no-redundant-longhand-properties */
    padding-inline-end: max(
      var(--vaadin-app-layout-navbar-padding-inline-end, var(--vaadin-padding-s)),
      var(--safe-area-inset-right)
    );
    z-index: 1;
    gap: var(--vaadin-app-layout-navbar-gap, var(--vaadin-gap-s));
    background: var(--vaadin-app-layout-navbar-background, var(--vaadin-background-container));
  }

  :host([primary-section='drawer'][drawer-opened]:not([overlay])) [part~='navbar'] {
    inset-inline-start: var(--vaadin-app-layout-drawer-offset-left, 0);
  }

  :host([primary-section='drawer']) [part='drawer'] {
    top: 0;
  }

  [part~='navbar-bottom'] {
    top: auto;
    bottom: 0;
    padding-top: var(--vaadin-app-layout-navbar-padding-top, var(--vaadin-padding-s));
    padding-bottom: max(
      var(--vaadin-app-layout-navbar-padding-bottom, var(--vaadin-padding-s)),
      var(--safe-area-inset-bottom)
    );
  }

  [part='drawer'] {
    overflow: auto;
    overscroll-behavior: contain;
    position: fixed;
    top: var(--vaadin-app-layout-navbar-offset-top, 0);
    bottom: var(--vaadin-app-layout-navbar-offset-bottom, var(--vaadin-viewport-offset-bottom, 0));
    inset-inline: var(--vaadin-app-layout-navbar-offset-left, 0) auto;
    transition:
      transform var(--vaadin-app-layout-transition-duration),
      visibility var(--vaadin-app-layout-transition-duration);
    transform: translateX(-100%);
    max-width: 90%;
    width: var(--_vaadin-app-layout-drawer-width);
    box-sizing: border-box;
    padding-block: var(--safe-area-inset-top) var(--safe-area-inset-bottom);
    outline: none;
    /* The drawer should be inaccessible by the tabbing navigation when it is closed. */
    visibility: hidden;
    display: flex;
    flex-direction: column;
    background: var(--vaadin-app-layout-drawer-background, transparent);
  }

  [part='drawer']:dir(ltr) {
    padding-left: var(--safe-area-inset-left);
  }

  [part='drawer']:dir(rtl) {
    padding-right: var(--safe-area-inset-right);
  }

  :host([has-navbar]:not([overlay])) [part='drawer'],
  :host([has-navbar]) [content] {
    --safe-area-inset-top: 0px;
  }

  :host([has-drawer]:not([overlay])[drawer-opened]) [content] {
    &:dir(ltr) {
      --safe-area-inset-left: 0px;
    }

    &:dir(rtl) {
      --safe-area-inset-right: 0px;
    }
  }

  :host([drawer-opened]) [part='drawer'] {
    /* The drawer should be accessible by the tabbing navigation when it is opened. */
    visibility: visible;
    transform: translateX(0%);
    touch-action: manipulation;
  }

  [part='backdrop'] {
    background: var(--vaadin-overlay-backdrop-background, rgba(0, 0, 0, 0.2));
    forced-color-adjust: none;
  }

  :host(:not([drawer-opened])) [part='backdrop'] {
    opacity: 0 !important;
  }

  :host([overlay]) [part='backdrop'] {
    position: fixed;
    inset: 0;
    pointer-events: none;
    transition: opacity var(--vaadin-app-layout-transition-duration);
    -webkit-tap-highlight-color: transparent;
  }

  :host([overlay]) [part='drawer'] {
    top: 0;
    bottom: 0;
    box-shadow: var(--vaadin-overlay-shadow, 0 8px 24px -4px rgba(0, 0, 0, 0.3));
    background: var(--vaadin-app-layout-drawer-background, var(--vaadin-background-color));
  }

  :host([overlay]) [part='drawer'],
  :host([overlay]) [part='backdrop'] {
    z-index: 2;
  }

  :host([drawer-opened][overlay]) [part='backdrop'] {
    pointer-events: auto;
    touch-action: manipulation;
  }

  :host([dir='rtl']) [part='drawer'] {
    transform: translateX(100%);
  }

  :host([dir='rtl'][drawer-opened]) [part='drawer'] {
    transform: translateX(0%);
  }

  @media (max-width: 800px), (max-height: 600px) {
    :host {
      --vaadin-app-layout-drawer-overlay: true;
      --_vaadin-app-layout-drawer-width: var(--vaadin-app-layout-drawer-width, 320px);
    }
  }

  /* If a vaadin-scroller is used in the drawer, allow it to take all remaining space and contain scrolling */
  [part='drawer'] ::slotted(vaadin-scroller) {
    flex: 1;
    overscroll-behavior: contain;
  }

  @media (forced-colors: active) {
    :host([overlay]) [part='drawer'] {
      border: 3px solid;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2017 Anton Korzunov
 * SPDX-License-Identifier: MIT
 */
let counterMap = /* @__PURE__ */ new WeakMap();
let uncontrolledNodes = /* @__PURE__ */ new WeakMap();
let markerMap = {};
let lockCount = 0;
const isElement = (node) => node && node.nodeType === Node.ELEMENT_NODE;
const logError = (...args) => {
  console.error(`Error: ${args.join(" ")}. Skip setting aria-hidden.`);
};
const correctTargets = (parent, targets) => {
  if (!isElement(parent)) {
    logError(parent, "is not a valid element");
    return [];
  }
  return targets.map((target) => {
    if (!isElement(target)) {
      logError(target, "is not a valid element");
      return null;
    }
    let node = target;
    while (node && node !== parent) {
      if (parent.contains(node)) {
        return target;
      }
      node = node.getRootNode().host;
    }
    logError(target, "is not contained inside", parent);
    return null;
  }).filter((x) => Boolean(x));
};
const applyAttributeToOthers = (originalTarget, parentNode, markerName, controlAttribute) => {
  const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
  if (!markerMap[markerName]) {
    markerMap[markerName] = /* @__PURE__ */ new WeakMap();
  }
  const markerCounter = markerMap[markerName];
  const hiddenNodes = [];
  const elementsToKeep = /* @__PURE__ */ new Set();
  const elementsToStop = new Set(targets);
  const keep = (el) => {
    if (!el || elementsToKeep.has(el)) {
      return;
    }
    elementsToKeep.add(el);
    const slot = el.assignedSlot;
    if (slot) {
      keep(slot);
    }
    keep(el.parentNode || el.host);
  };
  targets.forEach(keep);
  const deep = (parent) => {
    if (!parent || elementsToStop.has(parent)) {
      return;
    }
    const root = parent.shadowRoot;
    const children = root ? [...parent.children, ...root.children] : [...parent.children];
    children.forEach((node) => {
      if (["template", "script", "style"].includes(node.localName)) {
        return;
      }
      if (elementsToKeep.has(node)) {
        deep(node);
      } else {
        const attr2 = node.getAttribute(controlAttribute);
        const alreadyHidden = attr2 !== null && attr2 !== "false";
        const counterValue = (counterMap.get(node) || 0) + 1;
        const markerValue = (markerCounter.get(node) || 0) + 1;
        counterMap.set(node, counterValue);
        markerCounter.set(node, markerValue);
        hiddenNodes.push(node);
        if (counterValue === 1 && alreadyHidden) {
          uncontrolledNodes.set(node, true);
        }
        if (markerValue === 1) {
          node.setAttribute(markerName, "true");
        }
        if (!alreadyHidden) {
          node.setAttribute(controlAttribute, "true");
        }
      }
    });
  };
  deep(parentNode);
  elementsToKeep.clear();
  lockCount += 1;
  return () => {
    hiddenNodes.forEach((node) => {
      const counterValue = counterMap.get(node) - 1;
      const markerValue = markerCounter.get(node) - 1;
      counterMap.set(node, counterValue);
      markerCounter.set(node, markerValue);
      if (!counterValue) {
        if (uncontrolledNodes.has(node)) {
          uncontrolledNodes.delete(node);
        } else {
          node.removeAttribute(controlAttribute);
        }
      }
      if (!markerValue) {
        node.removeAttribute(markerName);
      }
    });
    lockCount -= 1;
    if (!lockCount) {
      counterMap = /* @__PURE__ */ new WeakMap();
      counterMap = /* @__PURE__ */ new WeakMap();
      uncontrolledNodes = /* @__PURE__ */ new WeakMap();
      markerMap = {};
    }
  };
};
const hideOthers = (originalTarget, parentNode = document.body, markerName = "data-aria-hidden") => {
  const targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
  if (parentNode) {
    targets.push(...Array.from(parentNode.querySelectorAll("[aria-live]")));
  }
  return applyAttributeToOthers(targets, parentNode, markerName, "aria-hidden");
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AriaModalController {
  /**
   * @param {HTMLElement} host
   */
  constructor(host, callback) {
    this.host = host;
    this.callback = typeof callback === "function" ? callback : () => host;
  }
  /**
   * Make the controller host modal by hiding other elements from screen readers
   * using `aria-hidden` attribute (can be replaced with `inert` in the future).
   *
   * The method name is chosen to align with the one provided by native `<dialog>`:
   * https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal
   */
  showModal() {
    const targets = this.callback();
    this.__showOthers = hideOthers(targets);
  }
  /**
   * Remove `aria-hidden` from other elements unless there are any other
   * controller hosts on the page activated by using `showModal()` call.
   */
  close() {
    if (this.__showOthers) {
      this.__showOthers();
      this.__showOthers = null;
    }
  }
}
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N$c = {
  drawer: "Drawer"
};
const AppLayoutMixin = (superclass) => class AppLayoutMixinClass extends I18nMixin(DEFAULT_I18N$c, superclass) {
  static get properties() {
    return {
      /**
       * Defines whether navbar or drawer will come first visually.
       * - By default (`primary-section="navbar"`), the navbar takes the full available width and moves the drawer down.
       * - If `primary-section="drawer"` is set, then the drawer will move the navbar, taking the full available height.
       * @attr {navbar|drawer} primary-section
       */
      primarySection: {
        type: String,
        value: "navbar",
        notify: true,
        reflectToAttribute: true,
        observer: "__primarySectionChanged",
        sync: true
      },
      /**
       * Controls whether the drawer is opened (visible) or not.
       * Its default value depends on the viewport:
       * - `true`, for desktop size views
       * - `false`, for mobile size views
       * @attr {boolean} drawer-opened
       */
      drawerOpened: {
        type: Boolean,
        notify: true,
        value: true,
        reflectToAttribute: true,
        observer: "__drawerOpenedChanged",
        sync: true
      },
      /**
       * Drawer is an overlay on top of the content
       * Controlled via CSS using `--vaadin-app-layout-drawer-overlay: true|false`;
       */
      overlay: {
        type: Boolean,
        notify: true,
        readOnly: true,
        value: false,
        reflectToAttribute: true,
        observer: "__overlayChanged",
        sync: true
      },
      /**
       * A global event that causes the drawer to close (be hidden) when it is in overlay mode.
       * - The default is `vaadin-router-location-changed` dispatched by Vaadin Router
       *
       * @attr {string} close-drawer-on
       */
      closeDrawerOn: {
        type: String,
        value: "vaadin-router-location-changed",
        observer: "_closeDrawerOnChanged"
      }
    };
  }
  static get observers() {
    return ["__i18nChanged(__effectiveI18n)"];
  }
  /**
   * Helper static method that dispatches a `close-overlay-drawer` event
   */
  static dispatchCloseOverlayDrawerEvent() {
    window.dispatchEvent(new CustomEvent("close-overlay-drawer"));
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following structure and default values:
   * ```js
   * {
   *   drawer: 'Drawer'
   * }
   * ```
   * @type {!AppLayoutI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  constructor() {
    super();
    this.__boundResizeListener = this._resize.bind(this);
    this.__drawerToggleClickListener = this._drawerToggleClick.bind(this);
    this.__onDrawerKeyDown = this.__onDrawerKeyDown.bind(this);
    this.__closeOverlayDrawerListener = this.__closeOverlayDrawer.bind(this);
    this.__trapFocusInDrawer = this.__trapFocusInDrawer.bind(this);
    this.__releaseFocusFromDrawer = this.__releaseFocusFromDrawer.bind(this);
    this.__ariaModalController = new AriaModalController(this, () => [
      ...this.querySelectorAll('vaadin-drawer-toggle, [slot="drawer"]')
    ]);
    this.__focusTrapController = new FocusTrapController(this);
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this._blockAnimationUntilAfterNextRender();
    window.addEventListener("resize", this.__boundResizeListener);
    this.addEventListener("drawer-toggle-click", this.__drawerToggleClickListener);
    requestAnimationFrame(() => {
      this._updateOffsetSize();
    });
    this._updateTouchOptimizedMode();
    this._updateDrawerSize();
    this._updateOverlayMode();
    this._navbarSizeObserver = new ResizeObserver(() => {
      requestAnimationFrame(() => {
        if (this.__isDrawerAnimating) {
          this.__updateOffsetSizePending = true;
        } else {
          this._updateOffsetSize();
        }
      });
    });
    this._navbarSizeObserver.observe(this.$.navbarTop);
    this._navbarSizeObserver.observe(this.$.navbarBottom);
    this._navbarSizeObserver.observe(this.$.drawer);
    window.addEventListener("close-overlay-drawer", this.__closeOverlayDrawerListener);
    window.addEventListener("keydown", this.__onDrawerKeyDown);
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(this.__focusTrapController);
    this.__setAriaExpanded();
    this.$.drawer.addEventListener("transitionstart", () => {
      this.__isDrawerAnimating = true;
    });
    this.$.drawer.addEventListener("transitionend", () => {
      if (this.__updateOffsetSizePending) {
        this.__updateOffsetSizePending = false;
        this._updateOffsetSize();
      }
      requestAnimationFrame(() => {
        this.__isDrawerAnimating = false;
      });
    });
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    window.removeEventListener("resize", this.__boundResizeListener);
    this.removeEventListener("drawer-toggle-click", this.__drawerToggleClickListener);
    window.removeEventListener("close-overlay-drawer", this.__drawerToggleClickListener);
    window.removeEventListener("keydown", this.__onDrawerKeyDown);
  }
  /** @private */
  __onNavbarSlotChange() {
    this._updateTouchOptimizedMode();
    this.toggleAttribute("has-navbar", !!this.querySelector('[slot="navbar"]'));
  }
  /** @private */
  __onDrawerSlotChange() {
    this._updateDrawerSize();
    this.toggleAttribute("has-drawer", !!this.querySelector('[slot="drawer"]'));
  }
  /**
   * A callback for the `primarySection` property observer.
   *
   * Ensures the property is set to its default value `navbar`
   * whenever the new value is not one of the valid values: `navbar`, `drawer`.
   *
   * @param {string} value
   * @private
   */
  __primarySectionChanged(value) {
    const isValid2 = ["navbar", "drawer"].includes(value);
    if (!isValid2) {
      this.primarySection = "navbar";
    }
  }
  /**
   * A callback for the `drawerOpened` property observer.
   *
   * When the drawer opens, the method ensures the drawer has a proper height and sets focus on it.
   * As long as the drawer is open, the focus is trapped within the drawer.
   *
   * When the drawer closes, the method releases focus from the drawer, setting focus on the drawer toggle.
   *
   * @param {boolean} drawerOpened
   * @param {boolean} oldDrawerOpened
   * @private
   */
  __drawerOpenedChanged(drawerOpened, oldDrawerOpened) {
    if (this.overlay) {
      if (drawerOpened) {
        this.__trapFocusInDrawer();
      } else if (oldDrawerOpened) {
        this.__releaseFocusFromDrawer();
      }
    }
    this.__setAriaExpanded();
  }
  /**
   * A callback for the `overlay` property observer.
   *
   * When layout resizes while in the overlay mode, drawer opened state
   * is not changed, but focus trap needs to be removed.
   *
   * @param {boolean} overlay
   * @param {boolean} oldOverlay
   * @private
   */
  __overlayChanged(_overlay, oldOverlay) {
    if (oldOverlay) {
      this.__restoreFocus();
    }
  }
  /**
   * A callback for the `i18n` property observer.
   *
   * The method ensures the drawer has ARIA attributes updated
   * once the `i18n` property changes.
   *
   * @private
   */
  __i18nChanged() {
    this.__updateDrawerAriaAttributes();
  }
  /** @private */
  _drawerToggleClick(e) {
    e.stopPropagation();
    this.drawerOpened = !this.drawerOpened;
  }
  /** @private */
  __closeOverlayDrawer() {
    if (this.overlay) {
      this.drawerOpened = false;
    }
  }
  /** @private */
  __setAriaExpanded() {
    const toggle = this.querySelector("vaadin-drawer-toggle");
    if (toggle) {
      toggle.setAttribute("aria-expanded", this.drawerOpened);
    }
  }
  /** @protected */
  _updateDrawerSize() {
    const childCount = this.querySelectorAll("[slot=drawer]").length;
    const drawer = this.$.drawer;
    if (childCount === 0) {
      drawer.setAttribute("hidden", "");
      this.style.setProperty("--_vaadin-app-layout-drawer-width", 0);
    } else {
      drawer.removeAttribute("hidden");
      this.style.removeProperty("--_vaadin-app-layout-drawer-width");
    }
    this._updateOffsetSize();
  }
  /** @private */
  _resize() {
    this._blockAnimationUntilAfterNextRender();
    this._updateTouchOptimizedMode();
    this._updateOverlayMode();
  }
  /** @protected */
  _updateOffsetSize() {
    const navbar = this.$.navbarTop;
    const navbarRect = navbar.getBoundingClientRect();
    const navbarBottom = this.$.navbarBottom;
    const navbarBottomRect = navbarBottom.getBoundingClientRect();
    const drawer = this.$.drawer;
    const drawerRect = drawer.getBoundingClientRect();
    this.style.setProperty("--_vaadin-app-layout-navbar-offset-size", `${navbarRect.height}px`);
    this.style.setProperty("--_vaadin-app-layout-navbar-offset-size-bottom", `${navbarBottomRect.height}px`);
    this.style.setProperty("--_vaadin-app-layout-drawer-offset-size", `${drawerRect.width}px`);
  }
  /** @protected */
  _updateOverlayMode() {
    const overlay = this._getCustomPropertyValue("--vaadin-app-layout-drawer-overlay") === "true";
    if (!this.overlay && overlay) {
      this._drawerStateSaved = this.drawerOpened;
      this.drawerOpened = false;
    }
    this._setOverlay(overlay);
    if (!this.overlay && this._drawerStateSaved) {
      this.drawerOpened = this._drawerStateSaved;
      this._drawerStateSaved = null;
    }
    this.__updateDrawerAriaAttributes();
  }
  /**
   * Updates ARIA attributes on the drawer depending on the drawer mode.
   *
   * - In the overlay mode, the method marks the drawer with ARIA attributes as a dialog
   * labelled with the `i18n.drawer` property.
   * - In the normal mode, the method removes the ARIA attributes that has been set for the overlay mode.
   *
   * @private
   */
  __updateDrawerAriaAttributes() {
    const drawer = this.$.drawer;
    if (this.overlay) {
      drawer.setAttribute("role", "dialog");
      drawer.setAttribute("aria-modal", "true");
      drawer.setAttribute("aria-label", this.__effectiveI18n.drawer);
    } else {
      drawer.removeAttribute("role");
      drawer.removeAttribute("aria-modal");
      drawer.removeAttribute("aria-label");
    }
  }
  /**
   * Returns a promise that resolves when the drawer opening/closing CSS transition ends.
   *
   * @return {Promise}
   * @private
   */
  __drawerTransitionComplete() {
    return Promise.all(this.$.drawer.getAnimations().map((animation) => animation.finished));
  }
  /** @private */
  async __trapFocusInDrawer() {
    await this.__drawerTransitionComplete();
    if (!this.drawerOpened) {
      return;
    }
    this.$.drawer.setAttribute("tabindex", "0");
    this.__ariaModalController.showModal();
    this.__focusTrapController.trapFocus(this.$.drawer);
  }
  /** @private */
  async __releaseFocusFromDrawer() {
    await this.__drawerTransitionComplete();
    if (this.drawerOpened) {
      return;
    }
    this.__restoreFocus();
    const toggle = this.querySelector("vaadin-drawer-toggle");
    if (toggle) {
      toggle.focus({ focusVisible: isKeyboardActive() });
    }
  }
  /** @private */
  __restoreFocus() {
    this.__ariaModalController.close();
    this.__focusTrapController.releaseFocus();
    this.$.drawer.removeAttribute("tabindex");
  }
  /**
   * Closes the drawer on Escape press if it has been opened in the overlay mode.
   *
   * @param {KeyboardEvent} event
   * @private
   */
  __onDrawerKeyDown(event) {
    if (event.key === "Escape" && this.overlay) {
      this.drawerOpened = false;
    }
  }
  /** @private */
  _closeDrawerOnChanged(closeDrawerOn, oldCloseDrawerOn) {
    if (oldCloseDrawerOn) {
      window.removeEventListener(oldCloseDrawerOn, this.__closeOverlayDrawerListener);
    }
    if (closeDrawerOn) {
      window.addEventListener(closeDrawerOn, this.__closeOverlayDrawerListener);
    }
  }
  /** @private */
  _onBackdropClick() {
    this._close();
  }
  /** @private */
  _onBackdropTouchend(event) {
    event.preventDefault();
    this._close();
  }
  /** @protected */
  _close() {
    this.drawerOpened = false;
  }
  /** @private */
  _getCustomPropertyValue(customProperty) {
    const customPropertyValue = getComputedStyle(this).getPropertyValue(customProperty);
    return (customPropertyValue || "").trim().toLowerCase();
  }
  /** @protected */
  _updateTouchOptimizedMode() {
    const touchOptimized = this._getCustomPropertyValue("--vaadin-app-layout-touch-optimized") === "true";
    const navbarItems = this.querySelectorAll('[slot*="navbar"]');
    if (navbarItems.length > 0) {
      Array.from(navbarItems).forEach((navbar) => {
        if (navbar.getAttribute("slot").indexOf("touch-optimized") > -1) {
          navbar.__touchOptimized = true;
        }
        if (touchOptimized && navbar.__touchOptimized) {
          navbar.setAttribute("slot", "navbar-bottom");
        } else {
          navbar.setAttribute("slot", "navbar");
        }
      });
    }
    if (this.$.navbarTop.querySelector("[name=navbar]").assignedNodes().length === 0) {
      this.$.navbarTop.setAttribute("hidden", "");
    } else {
      this.$.navbarTop.removeAttribute("hidden");
    }
    if (this.$.navbarBottom.querySelector("[name=navbar-bottom]").assignedNodes().length === 0) {
      this.$.navbarBottom.setAttribute("hidden", "");
    } else {
      this.$.navbarBottom.removeAttribute("hidden");
    }
    this._updateOffsetSize();
  }
  /** @protected */
  _blockAnimationUntilAfterNextRender() {
    this.setAttribute("no-anim", "");
    this.__debounceAnimation = Debouncer.debounce(this.__debounceAnimation, animationFrame, () => {
      setTimeout(() => {
        this.removeAttribute("no-anim");
      });
    });
  }
  /**
   * App Layout listens to `close-overlay-drawer` on the window level.
   * A custom event can be dispatched and the App Layout will close the drawer in overlay.
   *
   * That can be used, for instance, when a navigation occurs when user clicks in a menu item inside the drawer.
   *
   * See `dispatchCloseOverlayDrawerEvent()` helper method.
   *
   * @event close-overlay-drawer
   */
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AppLayout extends AppLayoutMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-app-layout";
  }
  static get styles() {
    return appLayoutStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="navbar navbar-top" id="navbarTop">
        <slot name="navbar" @slotchange="${this.__onNavbarSlotChange}"></slot>
      </div>
      <div part="backdrop" @click="${this._onBackdropClick}" @touchend="${this._onBackdropTouchend}"></div>
      <div part="drawer" id="drawer">
        <slot name="drawer" id="drawerSlot" @slotchange="${this.__onDrawerSlotChange}"></slot>
      </div>
      <div content>
        <slot></slot>
      </div>
      <div part="navbar navbar-bottom" id="navbarBottom" hidden>
        <slot name="navbar-bottom"></slot>
      </div>
      <div hidden>
        <slot id="touchSlot" name="navbar touch-optimized" @slotchange="${this.__onNavbarSlotChange}"></slot>
      </div>
    `;
  }
}
defineCustomElement(AppLayout);
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
addGlobalStyles(
  "vaadin-base-user-colors",
  css$h`
    @layer vaadin.base {
      html {
        --_color-count: 10;
        --_hue-step: round(360 / var(--_color-count), 1);
        --vaadin-user-color-0: var(--vaadin-user-color, oklch(0.52 0.2 240));
        --vaadin-user-color-1: oklch(
          from var(--vaadin-user-color-0) calc(0.62 + clamp(-0.15, (0.6201 - l) * 10000, 0.15)) c
            calc(h - var(--_hue-step) * 2 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-2: oklch(
          from var(--vaadin-user-color-0) l c calc(h - var(--_hue-step) * -2 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-3: oklch(
          from var(--vaadin-user-color-0) calc(0.62 + clamp(-0.15, (0.6201 - l) * 10000, 0.15)) c
            calc(h - var(--_hue-step) * 0 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-4: oklch(
          from var(--vaadin-user-color-0) l c calc(h - var(--_hue-step) * 2 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-5: oklch(
          from var(--vaadin-user-color-0) calc(0.62 + clamp(-0.15, (0.6201 - l) * 10000, 0.15)) c
            calc(h - var(--_hue-step) * -2 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-6: oklch(
          from var(--vaadin-user-color-0) l c calc(h - var(--_hue-step) * -4 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-7: oklch(
          from var(--vaadin-user-color-0) calc(0.62 + clamp(-0.15, (0.6201 - l) * 10000, 0.15)) c
            calc(h - var(--_hue-step) * 4 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-8: oklch(
          from var(--vaadin-user-color-0) l c calc(h - var(--_hue-step) * 4 * var(--_vaadin-safari-17-deg, 1))
        );
        --vaadin-user-color-9: oklch(
          from var(--vaadin-user-color-0) calc(0.62 + clamp(-0.15, (0.6201 - l) * 10000, 0.15)) c
            calc(h - var(--_hue-step) * 6 * var(--_vaadin-safari-17-deg, 1))
        );
      }
    }
  `
);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const fieldOutlineStyles = css$h`
  :host {
    display: block;
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    --_active-user-color: transparent;
    outline: 3px solid var(--_active-user-color);
    outline-offset: -1px;
    /* TODO doesn't inherit correctly from vaadin-input-container for some reason, so we use the internal _radius property */
    border-radius: var(--_radius, inherit);
  }

  :host([has-active-user]) {
    opacity: 1;
  }

  :host([context$='item']) {
    inset: 2px;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class FieldOutline extends ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-field-outline";
  }
  static get styles() {
    return fieldOutlineStyles;
  }
  static get properties() {
    return {
      /**
       * A user who last interacted with the field.
       */
      user: {
        type: Object,
        value: null,
        observer: "_userChanged",
        sync: true
      }
    };
  }
  /** @protected */
  render() {
    return html``;
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("part", "outline");
    this._field = this.getRootNode().host;
  }
  /** @private */
  _userChanged(user) {
    this.toggleAttribute("has-active-user", Boolean(user));
    const value = user ? `var(--vaadin-user-color-${user.colorIndex})` : "transparent";
    const prop = "--_active-user-color";
    this.style.setProperty(prop, value);
    if (this._field) {
      this._field.style.setProperty(prop, value);
    }
  }
}
defineCustomElement(FieldOutline);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const userTagStyles = css$h`
  :host {
    display: inline-block;
    box-sizing: border-box;
    opacity: 0;
    padding: var(--vaadin-user-tag-padding, 0.3em);
    background-color: var(--vaadin-user-tag-color);
    color: oklch(from var(--vaadin-user-tag-color) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    font-size: var(--vaadin-user-tag-font-size, 0.75em);
    font-weight: var(--vaadin-user-tag-font-weight, 500);
    line-height: var(--vaadin-user-tag-line-height, 1);
    border: var(--vaadin-user-tag-border-width, 0) solid
      var(--vaadin-user-tag-border-color, var(--vaadin-border-color-secondary));
    border-radius: var(--vaadin-user-tag-border-radius, var(--vaadin-radius-m));
    cursor: default;
  }

  :host(.show) {
    opacity: 1;
  }

  [part='name'] {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UserTag extends ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-user-tag";
  }
  static get styles() {
    return userTagStyles;
  }
  /** @protected */
  render() {
    return html`<div part="name">${this.name}</div>`;
  }
  static get properties() {
    return {
      /**
       * Name of the user.
       */
      name: {
        type: String
      },
      /**
       * Id of the user.
       */
      uid: {
        type: String
      },
      /**
       * Color index of the user.
       */
      colorIndex: {
        type: Number,
        observer: "_colorIndexChanged"
      }
    };
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("mousedown", this._onClick.bind(this), true);
  }
  /** @private */
  _colorIndexChanged(index) {
    if (index != null) {
      this.style.setProperty("--vaadin-user-tag-color", `var(--vaadin-user-color-${index})`);
    }
  }
  /**
   * @param {Event} e
   * @private
   */
  _onClick(e) {
    e.preventDefault();
    this.dispatchEvent(
      new CustomEvent("user-tag-click", {
        bubbles: true,
        composed: true,
        detail: {
          name: this.name
        }
      })
    );
  }
}
defineCustomElement(UserTag);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const userTagsOverlay = css$h`
  [part='overlay'] {
    all: initial;
    display: block;
    font: inherit;
    color: inherit;
  }

  [part='content'] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--vaadin-user-tag-overlay-gap, 0.2em);
    padding: 0.5em 0;
  }

  :host([opening]),
  :host([closing]) {
    animation: 0.14s user-tags-overlay-dummy-animation;
  }

  @keyframes user-tags-overlay-dummy-animation {
    0% {
      opacity: 1;
    }

    100% {
      opacity: 1;
    }
  }
`;
const userTagsOverlayStyles = [overlayStyles, userTagsOverlay];
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UserTagsOverlay extends PositionMixin(
  OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-user-tags-overlay";
  }
  static get styles() {
    return userTagsOverlayStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="overlay" id="overlay">
        <div part="content" id="content">
          <slot></slot>
        </div>
      </div>
    `;
  }
}
defineCustomElement(UserTagsOverlay);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const listenOnce$1 = (elem, type) => {
  return new Promise((resolve) => {
    const listener = () => {
      elem.removeEventListener(type, listener);
      resolve();
    };
    elem.addEventListener(type, listener);
  });
};
class UserTags extends PolylitMixin(LitElement) {
  static get is() {
    return "vaadin-user-tags";
  }
  static get styles() {
    return css$h`
      :host {
        position: absolute;
      }
    `;
  }
  /** @protected */
  render() {
    return html`
      <vaadin-user-tags-overlay
        id="overlay"
        exportparts="overlay:user-tags-overlay, content:user-tags-content"
        modeless
        .opened="${this.opened}"
        no-vertical-overlap
        @vaadin-overlay-open="${this._onOverlayOpen}"
      >
        <slot></slot>
      </vaadin-user-tags-overlay>
    `;
  }
  static get properties() {
    return {
      /**
       * True when the field has focus. In this case, the overlay
       * with a list of the user tags needs to be always visible.
       */
      hasFocus: {
        type: Boolean,
        value: false,
        observer: "_hasFocusChanged"
      },
      /**
       * True when the overlay is opened.
       */
      opened: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * True when the overlay is flashing: quickly shown and then hidden
       * once a different user starts to interact with the field.
       */
      flashing: {
        type: Boolean,
        value: false
      },
      /**
       * A target element that the overlay is positioned to.
       */
      target: {
        type: Object,
        observer: "__targetChanged"
      },
      /**
       * A list of users who focused the field.
       */
      users: {
        type: Array,
        value: () => []
      },
      duration: {
        type: Number,
        value: 200
      },
      delay: {
        type: Number,
        value: 2e3
      },
      /** @private */
      __flashQueue: {
        type: Array,
        value: () => []
      },
      /** @private */
      __isTargetVisible: {
        type: Boolean,
        value: false
      }
    };
  }
  constructor() {
    super();
    this.__targetVisibilityObserver = new IntersectionObserver(
      ([entry]) => {
        this.__onTargetVisibilityChange(entry.isIntersecting);
      },
      { threshold: 1 }
    );
  }
  /** @protected */
  get wrapper() {
    return this;
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this.target) {
      this.__targetVisibilityObserver.observe(this.target);
    }
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    this.opened = false;
    if (this.target) {
      this.__targetVisibilityObserver.unobserve(this.target);
    }
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("exportparts", "user-tags-overlay, user-tags-content");
  }
  /** @private */
  __onTargetVisibilityChange(isVisible) {
    this.__isTargetVisible = isVisible;
    if (isVisible && this.__flashQueue.length > 0 && !this.flashing) {
      this.flashTags(this.__flashQueue.shift());
      return;
    }
    if (isVisible && this.hasFocus) {
      this.opened = true;
      return;
    }
    if (!isVisible && this.opened) {
      this.opened = false;
    }
  }
  /** @private */
  __targetChanged(newTarget, oldTarget) {
    this.$.overlay.positionTarget = newTarget;
    if (oldTarget) {
      this.__targetVisibilityObserver.unobserve(oldTarget);
    }
    if (newTarget) {
      this.__targetVisibilityObserver.observe(newTarget);
    }
  }
  /** @private */
  _hasFocusChanged(hasFocus) {
    if (hasFocus && this.flashing) {
      this.stopFlash();
    }
  }
  createUserTag(user) {
    const tag = document.createElement("vaadin-user-tag");
    tag.setAttribute("part", "user-tag");
    tag.name = user.name;
    tag.uid = user.id;
    tag.colorIndex = user.colorIndex;
    return tag;
  }
  getTagForUser(user) {
    return Array.from(this.children).find((tag) => tag.uid === user.id);
  }
  getChangedTags(addedUsers, removedUsers) {
    const removed = removedUsers.map((user) => this.getTagForUser(user));
    const added = addedUsers.map((user) => this.getTagForUser(user) || this.createUserTag(user));
    return { added, removed };
  }
  applyTagsStart({ added, removed }) {
    removed.forEach((tag) => {
      if (tag) {
        tag.classList.add("removing");
        tag.classList.remove("show");
      }
    });
    added.forEach((tag) => this.insertBefore(tag, this.firstChild));
  }
  applyTagsEnd({ added, removed }) {
    removed.forEach((tag) => {
      if (tag && tag.parentNode === this) {
        this.removeChild(tag);
      }
    });
    added.forEach((tag) => tag && tag.classList.add("show"));
  }
  setUsers(users) {
    this.requestContentUpdate();
    let addedUsers = [];
    let removedUsers = [];
    const hasNewUsers = Array.isArray(users);
    const hasOldUsers = Array.isArray(this.users);
    if (hasOldUsers) {
      const newUserIds = (users || []).map((user) => user.id);
      removedUsers = this.users.filter((item) => !newUserIds.includes(item.id));
    }
    if (hasNewUsers) {
      const oldUserIds = (this.users || []).map((user) => user.id);
      addedUsers = users.filter((item) => !oldUserIds.includes(item.id)).reverse();
    }
    if (addedUsers.length === 0 && removedUsers.length === 0) {
      return;
    }
    const changedTags = this.getChangedTags(addedUsers, removedUsers);
    if (this.__flashQueue.length > 0) {
      removedUsers.forEach((user, i) => {
        if (changedTags.removed[i] === null) {
          return;
        }
        this.__flashQueue.forEach((tags) => {
          if (tags.some((tag) => tag.uid === user.id)) {
            this.__flashQueue = this.__flashQueue.filter((_2, index) => index !== i);
          }
        });
      });
    }
    if (this.opened && this.hasFocus) {
      this.updateTags(users, changedTags);
    } else if (addedUsers.length > 0 && document.visibilityState !== "hidden") {
      const addedTags = changedTags.added;
      const removedTags = changedTags.removed;
      this.updateTagsSync(users, {
        added: [],
        removed: removedTags
      });
      if (this.flashing || !this.__isTargetVisible) {
        this.__flashQueue = [...this.__flashQueue, addedTags];
      } else {
        this.flashTags(addedTags);
      }
    } else {
      this.updateTagsSync(users, changedTags);
    }
  }
  /** @private */
  _onOverlayOpen() {
    Array.from(this.children).forEach((tag) => {
      if (!tag.classList.contains("removing")) {
        tag.classList.add("show");
      }
    });
  }
  flashTags(added) {
    this.flashing = true;
    const hidden = Array.from(this.children);
    hidden.forEach((tag) => {
      tag.style.display = "none";
    });
    added.forEach((tag) => {
      this.insertBefore(tag, this.firstChild);
    });
    this.flashPromise = new Promise((resolve) => {
      listenOnce$1(this.$.overlay, "vaadin-overlay-open").then(() => {
        this._debounceFlashStart = Debouncer.debounce(
          this._debounceFlashStart,
          timeOut.after(this.duration + this.delay),
          () => {
            if (!this.hasFocus) {
              added.forEach((tag) => tag.classList.remove("show"));
            }
            this._debounceFlashEnd = Debouncer.debounce(this._debounceFlashEnd, timeOut.after(this.duration), () => {
              const finishFlash = () => {
                hidden.forEach((tag) => {
                  tag.style.display = "block";
                });
                this.flashing = false;
                resolve();
              };
              if (this.hasFocus) {
                finishFlash();
              } else {
                listenOnce$1(this.$.overlay, "animationend").then(() => {
                  finishFlash();
                });
                this.opened = false;
              }
            });
          }
        );
      });
    }).then(() => {
      if (this.__flashQueue.length > 0) {
        const tags = this.__flashQueue[0];
        this.__flashQueue = [...this.__flashQueue].slice(1);
        this.flashTags(tags);
      }
    });
    this.opened = true;
  }
  stopFlash() {
    if (this._debounceFlashStart) {
      this._debounceFlashStart.flush();
    }
    if (this._debounceFlashEnd) {
      this._debounceFlashEnd.flush();
    }
    this.$.overlay._flushAnimation("closing");
  }
  updateTags(users, changed) {
    this.applyTagsStart(changed);
    this._debounceRender = Debouncer.debounce(this._debounceRender, timeOut.after(this.duration), () => {
      this.users = users;
      this.applyTagsEnd(changed);
      if (users.length === 0 && this.opened) {
        this.opened = false;
      }
    });
  }
  updateTagsSync(users, changed) {
    this.applyTagsStart(changed);
    this.users = users;
    this.applyTagsEnd(changed);
  }
  show() {
    this.hasFocus = true;
    if (this.__isTargetVisible) {
      this.opened = true;
    }
  }
  hide() {
    this.hasFocus = false;
    this.opened = false;
  }
  requestContentUpdate() {
    if (this._debounceRender && this._debounceRender.isActive()) {
      this._debounceRender.flush();
    }
  }
}
defineCustomElement(UserTags);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const getOutlineTarget = (element, tagName) => {
  switch (tagName) {
    /* c8 ignore next */
    case "vaadin-big-decimal-field":
    case "vaadin-combo-box":
    case "vaadin-date-picker":
    case "vaadin-email-field":
    case "vaadin-integer-field":
    case "vaadin-number-field":
    case "vaadin-password-field":
    case "vaadin-select":
    case "vaadin-text-area":
    case "vaadin-text-field":
    case "vaadin-time-picker":
      return element.shadowRoot.querySelector('[part="input-field"]');
    /* c8 ignore next */
    case "vaadin-checkbox":
      return element.shadowRoot.querySelector('[part="checkbox"]');
    /* c8 ignore next */
    case "vaadin-radio-button":
      return element.shadowRoot.querySelector('[part="radio"]');
    /* c8 ignore next */
    default:
      return element;
  }
};
const fields = /* @__PURE__ */ new WeakMap();
const initOutline = (field2) => {
  if (!fields.has(field2)) {
    const tagName = field2.tagName.toLowerCase();
    const target = getOutlineTarget(field2, tagName);
    target.style.position = "relative";
    if (tagName.endsWith("text-area")) {
      target.style.overflow = "visible";
    }
    const style = document.createElement("style");
    style.textContent = `
      :host(:is([active], [focused])) [part="outline"] {
        display: none;
      }
    `;
    field2.shadowRoot.appendChild(style);
    const outline = document.createElement("vaadin-field-outline");
    (target === field2 ? field2.shadowRoot : target).appendChild(outline);
    outline.setAttribute("context", tagName);
    fields.set(field2, { root: field2, target, outline });
  }
  return fields.get(field2);
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class ComponentObserver {
  constructor(component) {
    this.component = component;
    this.initTags(component);
  }
  getFields() {
    return [this.component];
  }
  getFieldIndex(field2) {
    return this.getFields().indexOf(field2);
  }
  getFocusTarget(_event) {
    return this.component;
  }
  initTags(component) {
    const tags = document.createElement("vaadin-user-tags");
    component.shadowRoot.appendChild(tags);
    tags.target = component;
    this._tags = tags;
    component.addEventListener("mouseenter", (event) => {
      if (event.relatedTarget === this._tags.$.overlay) {
        return;
      }
      this._mouse = true;
      this._mouseDebouncer = Debouncer.debounce(this._mouseDebouncer, timeOut.after(200), () => {
        if (this._mouse) {
          this._tags.show();
        }
      });
    });
    component.addEventListener("mouseleave", (event) => {
      if (event.relatedTarget === this._tags.$.overlay) {
        return;
      }
      this._mouse = false;
      if (!this._hasFocus) {
        this._tags.hide();
      }
    });
    component.addEventListener("vaadin-highlight-show", (_event) => {
      this._hasFocus = true;
      if (this._debouncer && this._debouncer.isActive()) {
        this._debouncer.cancel();
      } else {
        this._tags.show();
      }
    });
    component.addEventListener("vaadin-highlight-hide", (_event) => {
      this._hasFocus = false;
      if (!this._mouse) {
        this._debouncer = Debouncer.debounce(this._debouncer, timeOut.after(1), () => {
          this._tags.hide();
        });
      }
    });
    this._tags.$.overlay.addEventListener("mouseleave", (event) => {
      if (event.relatedTarget === component) {
        return;
      }
      this._mouse = false;
      if (!component.hasAttribute("focused")) {
        this._tags.hide();
      }
    });
  }
  setOutlines(users) {
    const fields2 = this.getFields();
    fields2.forEach((field2, idx) => {
      const { outline } = initOutline(field2);
      const index = fields2.length === 1 ? 0 : users.map((user) => user.fieldIndex).indexOf(idx);
      outline.user = users[index];
    });
  }
  showOutline(field2) {
    this.fire("show", field2);
  }
  hideOutline(field2) {
    this.fire("hide", field2);
  }
  fire(action, field2) {
    this.component.dispatchEvent(
      new CustomEvent(`vaadin-highlight-${action}`, {
        bubbles: true,
        composed: true,
        detail: { fieldIndex: this.getFieldIndex(field2) }
      })
    );
  }
  redraw(users) {
    this._tags.setUsers(users);
    this.setOutlines(users);
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class FieldObserver extends ComponentObserver {
  constructor(field2) {
    super(field2);
    this.addListeners(field2);
  }
  addListeners(field2) {
    field2.addEventListener("focusin", (event) => this.onFocusIn(event));
    field2.addEventListener("focusout", (event) => this.onFocusOut(event));
  }
  onFocusIn(event) {
    const target = this.getFocusTarget(event);
    this.showOutline(target);
  }
  onFocusOut(event) {
    const target = this.getFocusTarget(event);
    this.hideOutline(target);
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class CheckboxGroupObserver extends FieldObserver {
  getFields() {
    return this.component.__checkboxes;
  }
  getFocusTarget(event) {
    const fields2 = this.getFields();
    return Array.from(event.composedPath()).find((node) => fields2.includes(node));
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DatePickerObserver extends ComponentObserver {
  constructor(datePicker) {
    super(datePicker);
    this.datePicker = datePicker;
    this.blurWhileOpened = false;
    this.addListeners(datePicker);
  }
  addListeners(datePicker) {
    this.overlay = datePicker.$.overlay;
    datePicker.addEventListener("opened-changed", (event) => this.onOpenedChanged(event));
    this.overlay.addEventListener("focusout", (event) => this.onOverlayFocusOut(event));
    datePicker.addEventListener("focusin", (event) => this.onFocusIn(event));
    datePicker.addEventListener("focusout", (event) => this.onFocusOut(event));
  }
  isEventInOverlay(node) {
    return this.datePicker._overlayContent && this.datePicker._overlayContent.contains(node);
  }
  isFullscreen() {
    const datePicker = this.datePicker;
    return datePicker._noInput && !isKeyboardActive();
  }
  onFocusIn(event) {
    if (this.isEventInOverlay(event.target)) {
      return;
    }
    if (this.isEventInOverlay(event.relatedTarget)) {
      return;
    }
    if (this.blurWhileOpened) {
      this.blurWhileOpened = false;
      return;
    }
    this.showOutline(this.datePicker);
  }
  onFocusOut(event) {
    if (this.isEventInOverlay(event.target) && this.component.contains(event.relatedTarget)) {
      return;
    }
    if (this.isEventInOverlay(event.relatedTarget)) {
      return;
    }
    if (!this.datePicker.opened) {
      this.hideOutline(this.datePicker);
    } else {
      this.blurWhileOpened = true;
    }
  }
  onOverlayFocusOut(event) {
    if (!this.datePicker.contains(event.relatedTarget)) {
      this.blurWhileOpened = true;
    }
  }
  onOpenedChanged(event) {
    if (event.detail.value === true && this.isFullscreen()) {
      this.showOutline(this.datePicker);
    }
    if (event.detail.value === false && this.blurWhileOpened) {
      this.blurWhileOpened = false;
      this.hideOutline(this.datePicker);
    }
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DateObserver extends DatePickerObserver {
  constructor(datePicker, host) {
    super(datePicker);
    this.component = host;
  }
  getFieldIndex() {
    return 0;
  }
}
class TimeObserver extends FieldObserver {
  constructor(timePicker, host) {
    super(timePicker);
    this.component = host;
    this.timePicker = timePicker;
  }
  getFocusTarget(_event) {
    return this.timePicker;
  }
  getFieldIndex() {
    return 1;
  }
}
class DateTimePickerObserver extends ComponentObserver {
  constructor(picker) {
    super(picker);
    const [datePicker, timePicker] = this.getFields();
    this.dateObserver = new DateObserver(datePicker, picker);
    this.timeObserver = new TimeObserver(timePicker, picker);
  }
  getFields() {
    return [this.component.querySelector("[slot=date-picker]"), this.component.querySelector("[slot=time-picker]")];
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class ListBoxObserver extends FieldObserver {
  getFields() {
    return this.component.items || [];
  }
  getFocusTarget(event) {
    const fields2 = this.getFields();
    return Array.from(event.composedPath()).find((node) => fields2.includes(node));
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class RadioGroupObserver extends FieldObserver {
  getFields() {
    return this.component.__radioButtons;
  }
  getFocusTarget(event) {
    const fields2 = this.getFields();
    return Array.from(event.composedPath()).find((node) => fields2.includes(node));
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class SelectObserver extends FieldObserver {
  constructor(select) {
    super(select);
    this.overlay = select._overlayElement;
  }
  onFocusIn(event) {
    if (this.overlay._contentRoot.contains(event.target)) {
      return;
    }
    if (this.overlay._contentRoot.contains(event.relatedTarget)) {
      return;
    }
    super.onFocusIn(event);
  }
  onFocusOut(event) {
    if (this.overlay._contentRoot.contains(event.relatedTarget)) {
      return;
    }
    if (this.overlay._contentRoot.contains(event.target) && this.component.contains(event.relatedTarget)) {
      return;
    }
    super.onFocusOut(event);
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const initFieldObserver = (field2) => {
  let result;
  switch (field2.tagName.toLowerCase()) {
    /* c8 ignore next */
    case "vaadin-date-picker":
      result = new DatePickerObserver(field2);
      break;
    /* c8 ignore next */
    case "vaadin-date-time-picker":
      result = new DateTimePickerObserver(field2);
      break;
    /* c8 ignore next */
    case "vaadin-select":
      result = new SelectObserver(field2);
      break;
    /* c8 ignore next 2 */
    case "vaadin-checkbox-group":
      result = new CheckboxGroupObserver(field2);
      break;
    case "vaadin-radio-group":
      result = new RadioGroupObserver(field2);
      break;
    case "vaadin-list-box":
      result = new ListBoxObserver(field2);
      break;
    default:
      result = new FieldObserver(field2);
  }
  return result;
};
class FieldHighlighterController {
  constructor(host) {
    this.host = host;
    this.user = null;
    this.users = [];
  }
  get user() {
    return this._user;
  }
  set user(user) {
    this._user = user;
    if (user) {
      const msg = `${user.name} started editing`;
      const { label } = this.host;
      announce(label ? `${msg} ${label}` : msg);
    }
  }
  hostConnected() {
    this.redraw();
  }
  addUser(user) {
    if (user) {
      this.users.push(user);
      this.redraw();
      this.user = user;
    }
  }
  setUsers(users) {
    if (Array.isArray(users)) {
      this.users = users;
      this.redraw();
      this.user = users[users.length - 1] || null;
    }
  }
  removeUser(user) {
    if (user && user.id !== void 0) {
      let index;
      for (let i = 0; i < this.users.length; i++) {
        if (this.users[i].id === user.id) {
          index = i;
          break;
        }
      }
      if (index !== void 0) {
        this.users.splice(index, 1);
        this.redraw();
        if (this.users.length > 0) {
          this.user = this.users[this.users.length - 1];
        } else {
          this.user = null;
        }
      }
    }
  }
  redraw() {
    this.observer.redraw([...this.users].reverse());
  }
}
class FieldHighlighter extends HTMLElement {
  static get is() {
    return "vaadin-field-highlighter";
  }
  static init(field2) {
    if (!field2._highlighterController) {
      const instance = new FieldHighlighterController(field2);
      field2.setAttribute("has-highlighter", "");
      instance.observer = initFieldObserver(field2);
      field2.addController(instance);
      field2._highlighterController = instance;
    }
    return field2._highlighterController;
  }
  static addUser(field2, user) {
    this.init(field2).addUser(user);
  }
  static removeUser(field2, user) {
    this.init(field2).removeUser(user);
  }
  static setUsers(field2, users) {
    this.init(field2).setUsers(users);
  }
}
defineCustomElement(FieldHighlighter);
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const accordionHeading = [
  detailsSummary("vaadin-accordion-heading"),
  css$h`
    button {
      align-items: center;
      appearance: none;
      background: transparent;
      border: 0;
      color: inherit;
      cursor: inherit;
      display: flex;
      font: inherit;
      gap: inherit;
      outline: none;
      padding: 0;
      touch-action: manipulation;
    }
  `
];
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AccordionHeading extends ActiveMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-accordion-heading";
  }
  static get shadowRootOptions() {
    return { ...LitElement.shadowRootOptions, delegatesFocus: true };
  }
  static get styles() {
    return accordionHeading;
  }
  static get properties() {
    return {
      /**
       * When true, the element is opened.
       */
      opened: {
        type: Boolean,
        reflectToAttribute: true,
        sync: true,
        value: false
      }
    };
  }
  /** @protected */
  render() {
    return html`
      <button id="button" part="content" ?disabled="${this.disabled}" aria-expanded="${this.opened ? "true" : "false"}">
        <span part="toggle" aria-hidden="true"></span>
        <slot></slot>
      </button>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "heading");
    }
  }
}
defineCustomElement(AccordionHeading);
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const accordionPanel = css$h`
  :host {
    display: block;
  }

  :host([hidden]) {
    display: none !important;
  }

  [part='content'] {
    box-sizing: border-box;
  }

  :host(:not([opened])) [part='content'] {
    display: none !important;
  }

  :host([focus-ring]) {
    --_focus-ring: 1;
  }
`;
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const AccordionPanelMixin = (superClass) => class AccordionPanelMixinClass extends CollapsibleMixin(DelegateFocusMixin(DelegateStateMixin(superClass))) {
  static get properties() {
    return {
      /**
       * A text that is displayed in the heading, if no
       * element is assigned to the `summary` slot.
       */
      summary: {
        type: String,
        observer: "_summaryChanged"
      }
    };
  }
  static get observers() {
    return ["__updateAriaAttributes(focusElement, _contentElements)"];
  }
  static get delegateProps() {
    return ["disabled", "opened", "_theme"];
  }
  constructor() {
    super();
    this._summaryController = new SummaryController(this, "vaadin-accordion-heading");
    this._summaryController.addEventListener("slot-content-changed", (event) => {
      const { node } = event.target;
      this._setFocusElement(node);
      this.stateTarget = node;
      this._tooltipController.setTarget(node);
    });
    this._tooltipController = new TooltipController(this);
    this._tooltipController.setPosition("bottom-start");
  }
  /**
   * @protected
   * @override
   */
  __forwardTabIndex(tabindex) {
    super.__forwardTabIndex(tabindex);
    if (tabindex !== void 0 && this.focusElement) {
      this.focusElement.$.button.tabIndex = tabindex;
      this.focusElement.tabIndex = -1;
    }
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(this._summaryController);
    this.addController(this._tooltipController);
  }
  /**
   * Override method from `DelegateStateMixin` to set delegate `theme`
   * using attribute instead of property (needed for the Lit version).
   * @protected
   * @override
   */
  _delegateProperty(name, value) {
    if (!this.stateTarget) {
      return;
    }
    if (name === "_theme") {
      this._delegateAttribute("theme", value);
      return;
    }
    super._delegateProperty(name, value);
  }
  /**
   * Override method inherited from `DisabledMixin`
   * to not set `aria-disabled` on the host element.
   *
   * @protected
   * @override
   */
  _setAriaDisabled() {
  }
  /** @private */
  _summaryChanged(summary) {
    this._summaryController.setSummary(summary);
  }
  /** @private */
  __updateAriaAttributes(focusElement, contentElements) {
    if (focusElement && contentElements) {
      const node = contentElements[0];
      if (node) {
        node.setAttribute("role", "region");
        node.setAttribute("aria-labelledby", focusElement.id);
      }
      if (node && node.id) {
        focusElement.setAttribute("aria-controls", node.id);
      } else {
        focusElement.removeAttribute("aria-controls");
      }
    }
  }
};
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AccordionPanel extends AccordionPanelMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-accordion-panel";
  }
  static get styles() {
    return accordionPanel;
  }
  /** @protected */
  render() {
    return html`
      <slot name="summary"></slot>

      <div part="content">
        <slot></slot>
      </div>

      <slot name="tooltip"></slot>
    `;
  }
}
defineCustomElement(AccordionPanel);
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const AccordionMixin = (superClass) => class AccordionMixinClass extends KeyboardDirectionMixin(superClass) {
  static get properties() {
    return {
      /**
       * The index of currently opened panel. First panel is opened by
       * default. Only one panel can be opened at the same time.
       * Setting null or undefined closes all the accordion panels.
       */
      opened: {
        type: Number,
        value: 0,
        notify: true,
        reflectToAttribute: true
      },
      /**
       * The list of `<vaadin-accordion-panel>` child elements.
       * It is populated from the elements passed to the light DOM,
       * and updated dynamically when adding or removing panels.
       * @type {!Array<!AccordionPanel>}
       */
      items: {
        type: Array,
        readOnly: true,
        notify: true
      }
    };
  }
  static get observers() {
    return ["_updateItems(items, opened)"];
  }
  constructor() {
    super();
    this._boundUpdateOpened = this._updateOpened.bind(this);
  }
  /**
   * Override getter from `KeyboardDirectionMixin`
   * to check if the heading element has focus.
   *
   * @return {Element | null}
   * @protected
   * @override
   */
  get focused() {
    return (this._getItems() || []).find((item) => isElementFocused(item.focusElement));
  }
  /**
   * @param {FocusOptions=} options
   * @protected
   * @override
   */
  focus(options2) {
    if (this._observer) {
      this._observer.flush();
    }
    super.focus(options2);
  }
  /** @protected */
  ready() {
    super.ready();
    const slot = this.shadowRoot.querySelector("slot");
    this._observer = new SlotObserver(slot, (info) => {
      this._setItems(this._filterItems(Array.from(this.children)));
      this._filterItems(info.addedNodes).forEach((el) => {
        el.addEventListener("opened-changed", this._boundUpdateOpened);
      });
    });
  }
  /**
   * Override method inherited from `KeyboardDirectionMixin`
   * to use the stored list of accordion panels as items.
   *
   * @return {Element[]}
   * @protected
   * @override
   */
  _getItems() {
    return this.items;
  }
  /**
   * @param {!Array<!Element>} array
   * @return {!Array<!AccordionPanel>}
   * @protected
   */
  _filterItems(array) {
    return array.filter((el) => el instanceof customElements.get("vaadin-accordion-panel"));
  }
  /** @private */
  _updateItems(items, opened) {
    if (items) {
      this.__itemsSync = true;
      const itemToOpen = items[opened];
      items.forEach((item) => {
        item.opened = item === itemToOpen;
      });
      this.__itemsSync = false;
    }
  }
  /**
   * Override an event listener from `KeyboardMixin`
   * to only handle details toggle buttons events.
   *
   * @param {!KeyboardEvent} event
   * @protected
   * @override
   */
  _onKeyDown(event) {
    if (!this.items.some((item) => item.focusElement === event.target)) {
      return;
    }
    super._onKeyDown(event);
  }
  /** @private */
  _updateOpened(e) {
    if (this.__itemsSync) {
      return;
    }
    const target = this._filterItems(e.composedPath())[0];
    const idx = this.items.indexOf(target);
    if (e.detail.value) {
      if (target.disabled || idx === -1) {
        return;
      }
      this.opened = idx;
    } else if (!this.items.some((item) => item.opened)) {
      this.opened = null;
    }
  }
};
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Accordion extends AccordionMixin(ThemableMixin(ElementMixin(PolylitMixin(LitElement)))) {
  static get is() {
    return "vaadin-accordion";
  }
  static get styles() {
    return css$h`
      :host {
        display: block;
      }

      :host([hidden]) {
        display: none !important;
      }
    `;
  }
  /** @protected */
  render() {
    return html`<slot></slot>`;
  }
}
defineCustomElement(Accordion);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const drawerToggle = css$h`
  [part='icon'] {
    background: currentColor;
    display: block;
    height: var(--vaadin-icon-size, 1lh);
    mask: var(--_vaadin-icon-menu) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
    width: var(--vaadin-icon-size, 1lh);
  }

  [hidden] {
    display: none !important;
  }

  @media (forced-colors: active) {
    [part='icon'] {
      background: CanvasText;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DrawerToggle extends ButtonMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-drawer-toggle";
  }
  static get styles() {
    return [buttonStyles, drawerToggle];
  }
  static get properties() {
    return {
      ariaLabel: {
        type: String,
        value: "Toggle navigation panel",
        reflectToAttribute: true,
        sync: true
      },
      /** @private */
      _showFallbackIcon: {
        type: Boolean,
        value: false
      }
    };
  }
  constructor() {
    super();
    this.addEventListener("click", () => {
      this.dispatchEvent(new CustomEvent("drawer-toggle-click", { bubbles: true, composed: true }));
    });
  }
  /** @protected */
  render() {
    return html`
      <slot id="slot" @slotchange="${this._toggleFallbackIcon}">
        <div part="icon"></div>
      </slot>
      <div part="icon" ?hidden="${!this._showFallbackIcon}"></div>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this._toggleFallbackIcon();
  }
  /** @private */
  _toggleFallbackIcon() {
    const nodes = this.$.slot.assignedNodes();
    this._showFallbackIcon = nodes.length > 0 && nodes.every((node) => isEmptyTextNode(node));
  }
}
defineCustomElement(DrawerToggle);
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const avatarStyles = css$h`
  :host {
    display: inline-block;
    flex: none;
    border-radius: 50%;
    cursor: default;
    color: var(--vaadin-avatar-text-color, var(--vaadin-text-color-secondary));
    overflow: hidden;
    --_size: var(--vaadin-avatar-size, calc(1lh + var(--vaadin-padding-block-container) * 2));
    height: var(--_size);
    width: var(--_size);
    border: var(--vaadin-focus-ring-width) solid transparent;
    margin: calc(var(--vaadin-focus-ring-width) * -1);
    background: var(--vaadin-avatar-background, var(--vaadin-background-container-strong));
    background-clip: content-box;
    vertical-align: middle;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    position: relative;
    font-weight: var(--vaadin-avatar-font-weight, 400);
    font-size: var(--vaadin-avatar-font-size, inherit);
    contain: strict;
  }

  /* Overlay border on top of image and icon as well */
  :host::before {
    position: absolute;
    content: '';
    inset: calc(var(--vaadin-focus-ring-width) * -1);
    border-radius: inherit;
    outline: var(--vaadin-avatar-border-width, 1px) solid var(--vaadin-avatar-border-color, transparent);
    outline-offset: calc((var(--vaadin-focus-ring-width) + var(--vaadin-avatar-border-width, 1px)) * -1);
  }

  :host([role='button']) {
    cursor: var(--vaadin-clickable-cursor);
  }

  img {
    height: 100%;
    width: 100%;
    object-fit: cover;
  }

  [part='icon'] {
    height: 100%;
    mask: var(--_vaadin-icon-user) no-repeat center / 74%;
    background: currentColor;
  }

  [part='abbr'] {
    font-size: 2.75em;
    fill: currentColor;
  }

  :host([hidden]),
  [hidden] {
    display: none !important;
  }

  :host([has-color-index]) {
    background-color: var(--vaadin-avatar-user-color);
    color: oklch(
      from var(--vaadin-avatar-user-color) clamp(0, (0.62 - l) * 1000, 1) 0 0 / clamp(0.8, (0.62 - l) * 1000, 1)
    );
    --vaadin-avatar-border-width: 2px;
    --vaadin-avatar-border-color: var(--vaadin-avatar-user-color);
  }

  :host([focus-ring]) {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
    outline-offset: calc((var(--vaadin-focus-ring-width)) * -1);
  }

  @media (forced-colors: active) {
    :host {
      border-color: Canvas !important;
    }

    [part='icon'] {
      background: CanvasText !important;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N$b = {
  anonymous: "anonymous"
};
const AvatarMixin = (superClass) => class AvatarMixinClass extends I18nMixin(DEFAULT_I18N$b, FocusMixin(superClass)) {
  static get properties() {
    return {
      /**
       * The path to the image
       */
      img: {
        type: String,
        reflectToAttribute: true,
        observer: "__imgChanged"
      },
      /**
       * A shortened form of name that is displayed
       * in the avatar when `img` is not provided.
       */
      abbr: {
        type: String,
        reflectToAttribute: true
      },
      /**
       * Full name of the user
       * used for the tooltip of the avatar.
       */
      name: {
        type: String,
        reflectToAttribute: true
      },
      /**
       * Color index used for avatar background.
       * @attr {number} color-index
       */
      colorIndex: {
        type: Number,
        observer: "__colorIndexChanged"
      },
      /**
       * When true, the avatar has tooltip shown on hover and focus.
       * The tooltip text is based on the `name` and `abbr` properties.
       * When neither is provided, `i18n.anonymous` is used instead.
       * @attr {boolean} with-tooltip
       */
      withTooltip: {
        type: Boolean,
        value: false,
        observer: "__withTooltipChanged"
      },
      /** @protected */
      __imgVisible: Boolean,
      /** @protected */
      __iconVisible: Boolean,
      /** @protected */
      __abbrVisible: Boolean,
      /** @private */
      __tooltipNode: Object
    };
  }
  static get observers() {
    return [
      "__imgOrAbbrOrNameChanged(img, abbr, name)",
      "__i18nChanged(__effectiveI18n)",
      "__tooltipChanged(__tooltipNode, name, abbr)"
    ];
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure and default values:
   * ```js
   * {
   *   // Translation of the anonymous user avatar tooltip.
   *   anonymous: 'anonymous'
   * }
   * ```
   * @type {!AvatarI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @protected */
  ready() {
    super.ready();
    this.__updateVisibility();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "img");
    }
    if (!this.name && !this.abbr) {
      this.__setTooltip();
    }
  }
  /** @private */
  __colorIndexChanged(index) {
    if (index != null) {
      this.setAttribute("has-color-index", "");
      this.style.setProperty("--vaadin-avatar-user-color", `var(--vaadin-user-color-${index})`);
    } else {
      this.removeAttribute("has-color-index");
      this.style.removeProperty("--vaadin-avatar-user-color");
    }
  }
  /** @private */
  __imgChanged() {
    this.__imgFailedToLoad = false;
  }
  /** @private */
  __imgOrAbbrOrNameChanged(_img, abbr, name) {
    this.__updateVisibility();
    if (abbr && abbr !== this.__generatedAbbr) {
      return;
    }
    if (name) {
      this.abbr = this.__generatedAbbr = name.split(" ").map((word) => word.charAt(0)).join("");
    } else {
      this.abbr = void 0;
    }
  }
  /** @private */
  __tooltipChanged(tooltipNode, name, abbr) {
    if (tooltipNode) {
      if (abbr && abbr !== this.__generatedAbbr) {
        this.__setTooltip(name ? `${name} (${abbr})` : abbr);
      } else {
        this.__setTooltip(name);
      }
    }
    if (abbr) {
      this.setAttribute("aria-label", !tooltipNode && name ? `${name} (${abbr})` : abbr);
    } else {
      this.removeAttribute("aria-label");
    }
  }
  /** @private */
  __withTooltipChanged(withTooltip, oldWithTooltip) {
    this.toggleAttribute("has-tooltip", withTooltip);
    if (withTooltip) {
      const tooltipNode = document.createElement("vaadin-tooltip");
      tooltipNode.setAttribute("slot", "tooltip");
      this.appendChild(tooltipNode);
      this.__tooltipNode = tooltipNode;
    } else if (oldWithTooltip) {
      this.__tooltipNode.target = null;
      this.__tooltipNode.remove();
      this.__tooltipNode = null;
    }
  }
  /** @private */
  __i18nChanged(effectiveI18n) {
    if (effectiveI18n && effectiveI18n.anonymous) {
      if (this.__oldAnonymous && this.__tooltipNode && this.__tooltipNode.text === this.__oldAnonymous) {
        this.__setTooltip();
      }
      this.__oldAnonymous = effectiveI18n.anonymous;
    }
  }
  /** @private */
  __updateVisibility() {
    this.__imgVisible = !!this.img && !this.__imgFailedToLoad;
    this.__abbrVisible = !this.__imgVisible && !!this.abbr;
    this.__iconVisible = !this.__imgVisible && !this.abbr;
  }
  /** @private */
  __setTooltip(tooltip) {
    const tooltipNode = this.__tooltipNode;
    if (tooltipNode) {
      tooltipNode.text = tooltip || this.__effectiveI18n.anonymous;
    }
  }
  /** @protected */
  __onImageLoadError() {
    if (this.img) {
      console.warn(`<vaadin-avatar> The specified image could not be loaded: ${this.img}`);
      this.__imgFailedToLoad = true;
      this.__updateVisibility();
    }
  }
};
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Avatar extends AvatarMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-avatar";
  }
  static get styles() {
    return avatarStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <img
        ?hidden="${!this.__imgVisible}"
        src="${ifDefined(this.img)}"
        aria-hidden="true"
        @error="${this.__onImageLoadError}"
        draggable="false"
      />
      <div part="icon" ?hidden="${!this.__iconVisible}" aria-hidden="true"></div>
      <svg
        part="abbr"
        ?hidden="${!this.__abbrVisible}"
        viewBox="-50 -50 100 100"
        preserveAspectRatio="xMidYMid meet"
        aria-hidden="true"
      >
        <text dy=".35em" text-anchor="middle">${this.abbr}</text>
      </svg>

      <slot name="tooltip"></slot>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
  }
}
defineCustomElement(Avatar);
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const avatarGroupMenuStyles = css$h`
  :host {
    display: block;
    padding: var(--vaadin-item-overlay-padding, 4px);
  }

  :host([hidden]) {
    display: none !important;
  }

  [part='items'] {
    display: contents;
  }
`;
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AvatarGroupMenu extends ListMixin(ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-avatar-group-menu";
  }
  static get styles() {
    return avatarGroupMenuStyles;
  }
  static get properties() {
    return {
      // We don't need to define this property since super default is vertical,
      // but we don't want it to be modified, or be shown in the API docs.
      /** @private */
      orientation: {
        readOnly: true
      }
    };
  }
  /**
   * @return {!HTMLElement}
   * @protected
   * @override
   */
  get _scrollerElement() {
    return this.shadowRoot.querySelector('[part="items"]');
  }
  /** @protected */
  render() {
    return html`
      <div part="items">
        <slot></slot>
      </div>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("role", "menu");
  }
}
defineCustomElement(AvatarGroupMenu);
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const menuItemStyles = css$h`
  [part='content'] {
    display: flex;
    align-items: center;
    gap: inherit;
  }
`;
const avatarGroupMenuItemStyles = [itemStyles, menuItemStyles];
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AvatarGroupMenuItem extends ItemMixin(ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-avatar-group-menu-item";
  }
  static get styles() {
    return avatarGroupMenuItemStyles;
  }
  /** @protected */
  render() {
    return html`
      <span part="checkmark" aria-hidden="true"></span>
      <div part="content">
        <slot></slot>
      </div>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("role", "menuitem");
  }
}
defineCustomElement(AvatarGroupMenuItem);
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AvatarGroupOverlay extends PositionMixin(
  OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-avatar-group-overlay";
  }
  static get styles() {
    return overlayStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="overlay" id="overlay">
        <div part="content" id="content">
          <slot></slot>
        </div>
      </div>
    `;
  }
}
defineCustomElement(AvatarGroupOverlay);
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const avatarGroupStyles = css$h`
  :host {
    display: block;
    width: 100%; /* prevent collapsing inside non-stretching column flex */
    /* 1: last on top */
    /* -1: first on top */
    --_dir: 1;
  }

  :host([theme~='reverse']) {
    --_dir: -1;
  }

  :host([hidden]) {
    display: none !important;
  }

  [part='container'] {
    display: flex;
    position: relative;
    width: 100%;
    flex-wrap: nowrap;
  }

  ::slotted(vaadin-avatar) {
    --_overlap: max(0px, var(--vaadin-avatar-group-overlap, 8px));
    --_gap: max(0px, var(--vaadin-avatar-group-gap, 2px));
    --_outline-width: var(--vaadin-focus-ring-width);
    --_d: var(--_dir);
    mask-image: url('data:image/svg+xml;utf8,<svg viewBox="0 0 300 300" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M300 0H0V300H300V0ZM150 200C177.614 200 200 177.614 200 150C200 122.386 177.614 100 150 100C122.386 100 100 122.386 100 150C100 177.614 122.386 200 150 200Z" fill="black"/></svg>');
    mask-size: calc((100% - var(--_outline-width) * 2) * 3);
    mask-position: calc(50% + (100% - var(--_outline-width) * 2 - var(--_overlap)) * var(--_d));
  }

  :host(:dir(rtl)) ::slotted(vaadin-avatar) {
    --_d: calc(var(--_dir) * -1);
  }

  ::slotted(vaadin-avatar:not(:first-of-type)) {
    margin-inline-start: calc((var(--_outline-width) + var(--_overlap) - var(--_gap)) * -1);
  }

  :host(:not([theme~='reverse'])) ::slotted(vaadin-avatar:last-child),
  :host(:not([theme~='reverse']):not([has-overflow])) ::slotted(vaadin-avatar:nth-last-child(2)),
  :host([theme~='reverse']) ::slotted(vaadin-avatar:first-of-type) {
    mask-image: none;
  }
`;
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const MINIMUM_DISPLAYED_AVATARS = 2;
const DEFAULT_I18N$a = {
  anonymous: "anonymous",
  activeUsers: {
    one: "Currently one active user",
    many: "Currently {count} active users"
  },
  joined: "{user} joined",
  left: "{user} left"
};
const AvatarGroupMixin = (superClass) => class AvatarGroupMixinClass extends I18nMixin(DEFAULT_I18N$a, ResizeMixin(superClass)) {
  static get properties() {
    return {
      /**
       * An array containing the items which will be stamped as avatars.
       *
       * The items objects allow to configure [`name`](#/elements/vaadin-avatar#property-name),
       * [`abbr`](#/elements/vaadin-avatar#property-abbr), [`img`](#/elements/vaadin-avatar#property-img)
       * and [`colorIndex`](#/elements/vaadin-avatar#property-colorIndex) properties on the
       * stamped avatars, and set `className` to provide CSS class names.
       *
       * #### Example
       *
       * ```js
       * group.items = [
       *   {
       *     name: 'User name',
       *     img: 'url-to-image.png',
       *     className: 'even'
       *   },
       *   {
       *     abbr: 'JD',
       *     colorIndex: 1,
       *     className: 'odd'
       *   },
       * ];
       * ```
       *
       * @type {!Array<!AvatarGroupItem> | undefined}
       */
      items: {
        type: Array,
        sync: true
      },
      /**
       * The maximum number of avatars to display. By default, all the avatars are displayed.
       * When _maxItemsVisible_ is set, the overflowing avatars are grouped into one avatar with
       * a dropdown. Setting 0 or 1 has no effect so there are always at least two avatars visible.
       * @attr {number} max-items-visible
       */
      maxItemsVisible: {
        type: Number,
        sync: true
      },
      /** @private */
      __itemsInView: {
        type: Number,
        value: null,
        sync: true
      },
      /** @private */
      _overflowItems: {
        type: Array
      },
      /** @private */
      _overflowLimit: {
        type: Number
      },
      /** @private */
      _opened: {
        type: Boolean,
        sync: true
      }
    };
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure and default values:
   * ```js
   * {
   *   // Translation of the anonymous user avatar tooltip.
   *   anonymous: 'anonymous',
   *   // Translation of the avatar group accessible label.
   *   // {count} is replaced with the actual count of users.
   *   activeUsers: {
   *     one: 'Currently one active user',
   *     many: 'Currently {count} active users'
   *   },
   *   // Screen reader announcement when user joins group.
   *   // {user} is replaced with the name or abbreviation.
   *   // When neither is set, "anonymous" is used instead.
   *   joined: '{user} joined',
   *   // Screen reader announcement when user leaves group.
   *   // {user} is replaced with the name or abbreviation.
   *   // When neither is set, "anonymous" is used instead.
   *   left: '{user} left'
   * }
   * ```
   * @type {!AvatarGroupI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @protected */
  get _avatars() {
    return [...this.children].filter((node) => node.localName === "vaadin-avatar");
  }
  /** @protected */
  ready() {
    super.ready();
    this._menuController = new SlotController(this, "overlay", "vaadin-avatar-group-menu", {
      initializer: (menu) => {
        menu.addEventListener("keydown", this._onListKeyDown.bind(this));
        this._menuElement = menu;
      }
    });
    this._overflowController = new SlotController(this, "overflow", "vaadin-avatar", {
      initializer: (overflow) => {
        overflow.setAttribute("role", "button");
        overflow.setAttribute("tabindex", "0");
        overflow.setAttribute("aria-haspopup", "menu");
        overflow.setAttribute("aria-expanded", "false");
        overflow.addEventListener("click", (e) => this._onOverflowClick(e));
        overflow.addEventListener("keydown", (e) => this._onOverflowKeyDown(e));
        const tooltip = document.createElement("vaadin-tooltip");
        tooltip.setAttribute("slot", "tooltip");
        overflow.appendChild(tooltip);
        this._overflow = overflow;
        this._overflowTooltip = tooltip;
      }
    });
    this.addController(this._menuController);
    this.addController(this._overflowController);
    this._overlayElement = this.$.overlay;
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    this._opened = false;
  }
  /** @protected */
  willUpdate(props) {
    super.willUpdate(props);
    if (props.has("items") || props.has("__itemsInView") || props.has("maxItemsVisible")) {
      const count = Array.isArray(this.items) ? this.items.length : 0;
      const limit = this.__getLimit(count, this.__itemsInView, this.maxItemsVisible);
      this._overflowLimit = limit;
      this._overflowItems = limit ? this.items.slice(limit) : [];
    }
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("items")) {
      this.__itemsChanged(this.items, props.get("items"));
    }
    if (props.has("items") || props.has("_overflowLimit") || props.has("__effectiveI18n") || props.has("_theme")) {
      const limit = this._overflowLimit;
      this.__renderAvatars(limit ? this.items.slice(0, limit) : this.items || []);
    }
    if (props.has("items") || props.has("_overflowLimit")) {
      this.__updateOverflowTooltip(this.items, this._overflowLimit);
      this.__updateOverflowAvatar(this.items, this._overflowLimit, this.__itemsInView);
    }
    if (props.has("__effectiveI18n") || props.has("items")) {
      this.__i18nItemsChanged(this.__effectiveI18n, this.items);
    }
    if (props.has("_opened")) {
      this.__openedChanged(this._opened, props.get("_opened"));
    }
    if (props.has("_theme")) {
      if (this._theme) {
        this._overflow.setAttribute("theme", this._theme);
      } else {
        this._overflow.removeAttribute("theme");
      }
    }
    if (props.has("_overflowItems") || props.has("__effectiveI18n") || props.has("_theme")) {
      this.__renderMenu();
    }
  }
  /** @private */
  __getMessage(user, action) {
    return action.replace("{user}", user.name || user.abbr || this.__effectiveI18n.anonymous);
  }
  /**
   * Renders items when they are provided by the `items` property and clears the content otherwise.
   * @private
   */
  __renderMenu() {
    render$1(
      html`
          ${(this._overflowItems || []).map(
        (item) => html`
              <vaadin-avatar-group-menu-item>
                <vaadin-avatar
                  .name="${item.name}"
                  .abbr="${item.abbr}"
                  .img="${item.img}"
                  .colorIndex="${item.colorIndex}"
                  .i18n="${this.__effectiveI18n}"
                  class="${ifDefined(item.className)}"
                  theme="${ifDefined(this._theme)}"
                  aria-hidden="true"
                ></vaadin-avatar>
                ${item.name || ""}
              </vaadin-avatar-group-menu-item>
            `
      )}
        `,
      this._menuElement,
      { host: this }
    );
  }
  /** @private */
  _onOverflowClick(e) {
    e.stopPropagation();
    if (this._opened) {
      this.$.overlay.close();
    } else if (!e.defaultPrevented) {
      this._opened = true;
    }
  }
  /** @private */
  _onOverflowKeyDown(e) {
    if (!this._opened) {
      if (/^(Enter|SpaceBar|\s)$/u.test(e.key)) {
        e.preventDefault();
        this._opened = true;
      }
    }
  }
  /** @private */
  _onListKeyDown(event) {
    if (event.key === "Escape" || event.key === "Tab") {
      this._opened = false;
    }
  }
  /**
   * @protected
   * @override
   */
  _onResize() {
    this.__setItemsInView();
  }
  /** @private */
  _onVaadinOverlayClose(e) {
    if (e.detail.sourceEvent && e.detail.sourceEvent.composedPath().includes(this)) {
      e.preventDefault();
    }
  }
  /** @private */
  _onVaadinOverlayOpen() {
    if (this._menuElement) {
      this._menuElement.focus();
    }
  }
  /** @private */
  __renderAvatars(items) {
    render$1(
      html`
          ${items.map(
        (item) => html`
              <vaadin-avatar
                .name="${item.name}"
                .abbr="${item.abbr}"
                .img="${item.img}"
                .colorIndex="${item.colorIndex}"
                .i18n="${this.__effectiveI18n}"
                theme="${ifDefined(this._theme)}"
                class="${ifDefined(item.className)}"
                tabindex="0"
                with-tooltip
              ></vaadin-avatar>
            `
      )}
        `,
      this,
      { renderBefore: this._overflow }
    );
  }
  /** @private */
  __updateOverflowAvatar(items, limit, itemsInView) {
    const overflow = this._overflow;
    if (overflow) {
      const count = Array.isArray(items) ? items.length : 0;
      const maxReached = this.maxItemsVisible != null && count > this.__getMax(this.maxItemsVisible);
      overflow.abbr = `+${count - limit}`;
      const hasOverflow = maxReached || itemsInView && itemsInView < count;
      overflow.toggleAttribute("hidden", !hasOverflow);
      this.toggleAttribute("has-overflow", hasOverflow);
    }
  }
  /** @private */
  __updateOverflowTooltip(items, limit) {
    if (!Array.isArray(items)) {
      return;
    }
    if (limit == null) {
      return;
    }
    const result = [];
    for (let i = limit; i < items.length; i++) {
      const item = items[i];
      if (item) {
        result.push(item.name || item.abbr || "anonymous");
      }
    }
    this._overflowTooltip.text = result.join("\n");
  }
  /** @private */
  __getLimit(items, itemsInView, maxItemsVisible) {
    let limit = null;
    const adjustedMax = this.__getMax(maxItemsVisible);
    if (maxItemsVisible != null && adjustedMax < items) {
      limit = adjustedMax - 1;
    } else if (itemsInView && itemsInView < items) {
      limit = itemsInView;
    }
    return Math.min(limit, this.__calculateAvatarsFitWidth());
  }
  /** @private */
  __getMax(maxItemsVisible) {
    return Math.max(maxItemsVisible, MINIMUM_DISPLAYED_AVATARS);
  }
  /** @private */
  __itemsChanged(items, oldItems) {
    this.__setItemsInView();
    let added = [];
    let removed = [];
    const hasNewItems = Array.isArray(items);
    const hasOldItems = Array.isArray(oldItems);
    if (hasOldItems) {
      removed = oldItems.filter((item) => hasNewItems && !items.includes(item));
    }
    if (hasNewItems) {
      added = items.filter((item) => hasOldItems && !oldItems.includes(item));
    }
    this.__announceItemsChange(added, removed);
  }
  /** @private */
  __announceItemsChange(added, removed) {
    let addedMsg = [];
    let removedMsg = [];
    if (added) {
      addedMsg = added.map((user) => this.__getMessage(user, this.__effectiveI18n.joined || "{user} joined"));
    }
    if (removed) {
      removedMsg = removed.map((user) => this.__getMessage(user, this.__effectiveI18n.left || "{user} left"));
    }
    const messages = removedMsg.concat(addedMsg);
    if (messages.length > 0) {
      announce(messages.join(", "));
    }
  }
  /** @private */
  __i18nItemsChanged(effectiveI18n, items) {
    if (effectiveI18n && effectiveI18n.activeUsers) {
      const count = Array.isArray(items) ? items.length : 0;
      const field2 = count === 1 ? "one" : "many";
      if (effectiveI18n.activeUsers[field2]) {
        this.setAttribute("aria-label", effectiveI18n.activeUsers[field2].replace("{count}", count || 0));
      }
    }
  }
  /** @private */
  __openedChanged(opened, oldOpened) {
    if (opened) {
      this._openedWithFocusRing = this._overflow.hasAttribute("focus-ring");
    } else if (oldOpened) {
      this._overflow.focus({ focusVisible: this._openedWithFocusRing });
    }
    this._overflow.setAttribute("aria-expanded", opened === true);
  }
  /** @private */
  __setItemsInView() {
    const avatars = this._avatars;
    const items = this.items;
    if (!items || !avatars || avatars.length < 3) {
      return;
    }
    let result = this.__calculateAvatarsFitWidth();
    if (result === items.length - 1) {
      result = items.length;
    }
    if (result >= items.length && this._opened) {
      this.$.overlay.close();
      this.$.overlay._flushAnimation("closing");
    }
    this.__itemsInView = result;
  }
  /** @private */
  __calculateAvatarsFitWidth() {
    if (!this.shadowRoot || this._avatars.length < MINIMUM_DISPLAYED_AVATARS) {
      return MINIMUM_DISPLAYED_AVATARS;
    }
    const avatars = this._avatars;
    const avatarWidth = avatars[0].clientWidth;
    const { marginLeft, marginRight } = getComputedStyle(avatars[1]);
    const offset2 = this.__isRTL ? parseInt(marginRight, 0) - parseInt(marginLeft, 0) : parseInt(marginLeft, 0) - parseInt(marginRight, 0);
    return Math.floor((this.$.container.offsetWidth - avatarWidth) / (avatarWidth + offset2));
  }
};
/**
 * @license
 * Copyright (c) 2020 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AvatarGroup extends AvatarGroupMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-avatar-group";
  }
  static get styles() {
    return avatarGroupStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <div id="container" part="container">
        <slot></slot>
        <slot name="overflow"></slot>
      </div>
      <vaadin-avatar-group-overlay
        id="overlay"
        .owner="${this}"
        .opened="${this._opened}"
        .positionTarget="${this._overflow}"
        no-vertical-overlap
        exportparts="overlay, content"
        @vaadin-overlay-close="${this._onVaadinOverlayClose}"
        @vaadin-overlay-open="${this._onVaadinOverlayOpen}"
        @opened-changed="${this._onOpenedChanged}"
      >
        <slot name="overlay"></slot>
      </vaadin-avatar-group-overlay>
    `;
  }
  /** @private */
  _onOpenedChanged(event) {
    this._opened = event.detail.value;
  }
}
defineCustomElement(AvatarGroup);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const CLASSES = {
  SMALL: "small",
  MEDIUM: "medium",
  LARGE: "large"
};
const BoardRowMixin = (superClass) => class BoardRowMixinClass extends ResizeMixin(superClass) {
  constructor() {
    super();
    this._oldWidth = 0;
    this._oldBreakpoints = { smallSize: 600, mediumSize: 960 };
    this._oldFlexBasis = [];
  }
  /** @protected */
  ready() {
    super.ready();
    this.$.insertionPoint.addEventListener("slotchange", () => this.redraw());
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this._onResize();
  }
  /**
   * Adds styles for board row based on width.
   * @private
   */
  _addStyleNames(width, breakpoints) {
    if (width < breakpoints.smallSize) {
      this.classList.add(CLASSES.SMALL);
      this.classList.remove(CLASSES.MEDIUM);
      this.classList.remove(CLASSES.LARGE);
    } else if (width < breakpoints.mediumSize) {
      this.classList.remove(CLASSES.SMALL);
      this.classList.add(CLASSES.MEDIUM);
      this.classList.remove(CLASSES.LARGE);
    } else {
      this.classList.remove(CLASSES.SMALL);
      this.classList.remove(CLASSES.MEDIUM);
      this.classList.add(CLASSES.LARGE);
    }
  }
  /**
   * Calculates flex basis based on colSpan, width and breakpoints.
   * @param {number} colSpan colspan value of the row
   * @param {number} width width of the row in px
   * @param {number} colsInRow number of columns in the row
   * @param {object} breakpoints object with smallSize and mediumSize number properties, which tells
   * where the row should switch rendering size in pixels.
   * @private
   */
  _calculateFlexBasis(colSpan, width, colsInRow, breakpoints) {
    if (width < breakpoints.smallSize) {
      colsInRow = 1;
    } else if (width < breakpoints.mediumSize && colsInRow === 4) {
      colsInRow = 2;
    }
    let flexBasis = colSpan / colsInRow * 100;
    flexBasis = flexBasis > 100 ? 100 : flexBasis;
    return `${flexBasis}%`;
  }
  /** @private */
  _reportError() {
    const errorMessage = "The column configuration is not valid; column count should add up to 3 or 4.";
    console.warn(errorMessage, `check: \r
${this.outerHTML}`);
  }
  /**
   * Parses board-cols from DOM.
   * If there is not enough space in the row drop board cols.
   * @param {!Array<!Node>} nodes array of nodes
   * @return {!Array<number>} array of boardCols
   * @private
   */
  _parseBoardCols(nodes) {
    const boardCols = nodes.map((node) => {
      if (node.getAttribute("board-cols")) {
        return parseInt(node.getAttribute("board-cols"));
      }
      return 1;
    });
    let spaceLeft = 4;
    let returnBoardCols = [];
    nodes.forEach((_node, i) => {
      spaceLeft -= boardCols[i];
    });
    if (spaceLeft < 0) {
      this._reportError();
      boardCols.forEach((_node, i) => {
        returnBoardCols[i] = 1;
      });
    } else {
      returnBoardCols = boardCols.slice(0);
    }
    return returnBoardCols;
  }
  /**
   * If there is not enough space in the row.
   * Extra items are dropped from DOM.
   * @param {!Array<number>} boardCols array of board-cols for every node
   * @param {!Array<!Node>} nodes array of nodes
   * @return {!Array<!Node>} filtered array of nodes
   * @private
   */
  _removeExtraNodesFromDOM(boardCols, nodes) {
    let isErrorReported = false;
    let spaceLeft = 4;
    const returnNodes = [];
    nodes.forEach((node, i) => {
      spaceLeft -= boardCols[i];
      if (spaceLeft < 0) {
        if (!isErrorReported) {
          isErrorReported = true;
          this._reportError();
        }
        this.removeChild(node);
      } else {
        returnNodes[i] = node;
      }
    });
    return returnNodes;
  }
  /**
   * Redraws the row, if necessary.
   *
   * In most cases, a board row will redraw itself if your reconfigure it.
   * If you dynamically change breakpoints
   * --vaadin-board-width-small or --vaadin-board-width-medium,
   * then you need to call this method.
   */
  redraw() {
    this._recalculateFlexBasis(true);
  }
  /**
   * @protected
   * @override
   */
  _onResize() {
    this._recalculateFlexBasis(false);
  }
  /** @private */
  _recalculateFlexBasis(forceResize) {
    const width = this.getBoundingClientRect().width;
    const breakpoints = this._measureBreakpointsInPx();
    if (forceResize || this._shouldRecalculate(width, breakpoints)) {
      const nodes = this.$.insertionPoint.assignedNodes({ flatten: true });
      const filteredNodes = nodes.filter((node) => node.nodeType === Node.ELEMENT_NODE);
      this._addStyleNames(width, breakpoints);
      const boardCols = this._parseBoardCols(filteredNodes);
      const colsInRow = boardCols.reduce((a, b) => a + b, 0);
      this._removeExtraNodesFromDOM(boardCols, filteredNodes).forEach((e, i) => {
        const newFlexBasis = this._calculateFlexBasis(boardCols[i], width, colsInRow, breakpoints);
        if (forceResize || !this._oldFlexBasis[i] || this._oldFlexBasis[i] !== newFlexBasis) {
          this._oldFlexBasis[i] = newFlexBasis;
          e.style.flexBasis = newFlexBasis;
        }
      });
      this._oldWidth = width;
      this._oldBreakpoints = breakpoints;
    }
  }
  /** @private */
  _shouldRecalculate(width, breakpoints) {
    if (isElementHidden(this)) {
      return false;
    }
    return width !== this._oldWidth || breakpoints.smallSize !== this._oldBreakpoints.smallSize || breakpoints.mediumSize !== this._oldBreakpoints.mediumSize;
  }
  /**
   * Measure the breakpoints in pixels.
   *
   * The breakpoints for `small` and `medium` can be given in any unit: `px`, `em`, `in` etc.
   * We need to know them in `px` so that they are comparable with the actual size.
   *
   * @return {object} object with smallSize and mediumSize number properties, which tells
   * where the row should switch rendering size in pixels.
   * @private
   */
  _measureBreakpointsInPx() {
    const breakpoints = {};
    const tmpStyleProp = "background-position";
    const smallSize = getComputedStyle(this).getPropertyValue("--small-size");
    const mediumSize = getComputedStyle(this).getPropertyValue("--medium-size");
    this.style.setProperty(tmpStyleProp, smallSize);
    breakpoints.smallSize = parseFloat(getComputedStyle(this).getPropertyValue(tmpStyleProp));
    this.style.setProperty(tmpStyleProp, mediumSize);
    breakpoints.mediumSize = parseFloat(getComputedStyle(this).getPropertyValue(tmpStyleProp));
    this.style.removeProperty(tmpStyleProp);
    return breakpoints;
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class BoardRow extends BoardRowMixin(ElementMixin(PolylitMixin(LitElement))) {
  static get is() {
    return "vaadin-board-row";
  }
  static get styles() {
    return css$h`
      :host {
        display: flex;
        flex-flow: row wrap;
        align-items: stretch;
        --small-size: var(--vaadin-board-width-small, 600px);
        --medium-size: var(--vaadin-board-width-medium, 960px);
      }

      :host([hidden]) {
        display: none !important;
      }

      :host ::slotted(*) {
        box-sizing: border-box;
        flex-grow: 1;
        overflow: hidden;
      }
    `;
  }
  /** @protected */
  render() {
    return html`<slot id="insertionPoint"></slot>`;
  }
}
defineCustomElement(BoardRow);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class Board extends ElementMixin(PolylitMixin(LitElement)) {
  static get is() {
    return "vaadin-board";
  }
  static get cvdlName() {
    return "vaadin-board";
  }
  static get styles() {
    return css$h`
      :host {
        display: block;
      }

      :host([hidden]) {
        display: none !important;
      }
    `;
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    issueWarning(
      "`<vaadin-board>` is deprecated and will be removed in Vaadin 26. Consider using `<vaadin-dashboard>` or `<vaadin-dashboard-layout>` as an alternative."
    );
  }
  /** @protected */
  render() {
    return html`<slot></slot>`;
  }
  /**
   * Redraws the board and all rows inside it, if necessary.
   *
   * In most cases, board will redraw itself if your reconfigure it. If you dynamically change
   * breakpoints `--vaadin-board-width-small` or `--vaadin-board-width-medium`,
   * then you need to call this method.
   */
  redraw() {
    [...this.querySelectorAll("*")].filter((node) => node instanceof BoardRow).forEach((row) => row.redraw());
  }
}
defineCustomElement(Board);
/**
 * @license
 * Copyright (c) 2024 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const cardStyles = css$h`
  :host {
    --_content: 0;
    --_footer: 0;
    --_gap: var(--vaadin-card-gap, var(--vaadin-gap-m));
    --_header: max(var(--_header-prefix), var(--_title), var(--_subtitle), var(--_header-suffix));
    --_header-prefix: 0;
    --_header-suffix: 0;
    --_media: 0;
    --_padding: var(--vaadin-card-padding, var(--vaadin-padding-m));
    --_subtitle: 0;
    --_title: 0;
    background: var(--vaadin-card-background, var(--vaadin-background-container));
    border-radius: var(--vaadin-card-border-radius, var(--vaadin-radius-m));
    box-shadow: var(--vaadin-card-shadow, none);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: var(--_gap);
    padding: var(--_padding);
    position: relative;
  }

  /* Could be an inset outline on the host as well, but let's reserve that for a potential focus outline */
  :host::before {
    border: var(--vaadin-card-border-width, 0) solid
      var(--vaadin-card-border-color, var(--vaadin-border-color-secondary));
    border-radius: inherit;
    content: '';
    inset: 0;
    pointer-events: none;
    position: absolute;
  }

  :host([hidden]) {
    display: none !important;
  }

  :host(:not([theme~='horizontal'])) {
    justify-content: space-between;
  }

  :host([_m]) {
    --_media: 1;
  }

  :host([_t]) {
    --_title: 1;
  }

  :host([_st]) {
    --_subtitle: 1;
  }

  :host([_h]) {
    --_header: 1;
    --_title: 0;
    --_subtitle: 0;
  }

  :host([_hp]) {
    --_header-prefix: 1;
  }

  :host([_hs]) {
    --_header-suffix: 1;
  }

  :host([_c]) {
    --_content: 1;
  }

  :host([_f]) {
    --_footer: 1;
  }

  [part='media'],
  [part='header'],
  [part='content'],
  [part='footer'] {
    display: none;
  }

  :host([_m]) [part='media'] {
    display: block;
  }

  :host(:is([_h], [_t], [_st], [_hp], [_hs])) [part='header'] {
    align-items: center;
    display: grid;
    gap: var(--_gap);
    row-gap: 0;
  }

  :host([_hs]) [part='header'] {
    grid-template-columns: 1fr auto;
  }

  :host([_hp]) [part='header'] {
    grid-template-columns: repeat(var(--_header-prefix), auto) 1fr;
  }

  :host([_c]) [part='content'] {
    display: block;
  }

  :host([_f]) [part='footer'] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--_gap);
  }

  slot {
    border-radius: inherit;
  }

  ::slotted([slot='header-prefix']) {
    grid-column: 1;
    grid-row: 1 / span calc(var(--_title) + var(--_subtitle));
  }

  ::slotted([slot='header']),
  ::slotted([slot='title']) {
    grid-column: calc(1 + var(--_header-prefix));
    grid-row: 1;
  }

  ::slotted([slot='title']) {
    color: var(--vaadin-card-title-color, var(--vaadin-text-color)) !important;
    font-size: var(--vaadin-card-title-font-size, inherit) !important;
    font-weight: var(--vaadin-card-title-font-weight, 500) !important;
    line-height: var(--vaadin-card-title-line-height, inherit) !important;
    margin: 0 !important;
  }

  ::slotted([slot='subtitle']) {
    color: var(--vaadin-card-subtitle-color, var(--vaadin-text-color-secondary)) !important;
    font-size: var(--vaadin-card-subtitle-font-size, inherit) !important;
    font-weight: var(--vaadin-card-subtitle-font-weight, 400) !important;
    line-height: var(--vaadin-card-subtitle-line-height, inherit) !important;
    margin: 0 !important;
    grid-column: calc(1 + var(--_header-prefix));
    grid-row: calc(1 + var(--_title));
  }

  ::slotted([slot='header-suffix']) {
    grid-column: calc(2 + var(--_header-prefix));
    grid-row: 1 / span calc(var(--_title) + var(--_subtitle));
  }

  /* Horizontal */
  :host([theme~='horizontal']) {
    align-items: start;
    display: grid;
    grid-template-columns: repeat(var(--_media), minmax(auto, max-content)) 1fr;
  }

  :host([theme~='horizontal'][_f]) {
    grid-template-rows: 1fr auto;
  }

  :host([theme~='horizontal'][_c]) {
    grid-template-rows: repeat(var(--_header), auto) 1fr;
  }

  [part='media'] {
    align-self: stretch;
    border-radius: inherit;
    grid-column: 1;
    grid-row: 1 / span calc(var(--_header) + var(--_content) + var(--_footer));
  }

  [part='header'] {
    margin-bottom: auto;
    grid-column: calc(1 + var(--_media));
    grid-row: 1;
  }

  [part='content'] {
    grid-column: calc(1 + var(--_media));
    grid-row: calc(1 + var(--_header));
    flex: auto;
    min-height: 0;
  }

  [part='footer'] {
    border-radius: inherit;
    grid-column: calc(1 + var(--_media));
    grid-row: calc(1 + var(--_header) + var(--_content));
  }

  :host([theme~='horizontal']) [part='footer'] {
    align-self: end;
  }

  :host(:not([theme~='horizontal'])) ::slotted([slot='media']:is(img, video, svg)) {
    max-width: 100%;
  }

  ::slotted([slot='media']) {
    vertical-align: middle;
  }

  :host(:is([theme~='cover-media'], [theme~='stretch-media']))
    ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
    aspect-ratio: var(--vaadin-card-media-aspect-ratio, 16/9);
    height: auto;
    object-fit: cover;
    /* Fixes an issue where an icon overflows the card boundaries on Firefox: https://github.com/vaadin/web-components/issues/8641 */
    overflow: hidden;
    width: 100%;
  }

  :host([theme~='horizontal']:is([theme~='cover-media'], [theme~='stretch-media'])) {
    grid-template-columns: repeat(var(--_media), minmax(auto, 0.5fr)) 1fr;
  }

  :host([theme~='horizontal']:is([theme~='cover-media'], [theme~='stretch-media']))
    ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
    aspect-ratio: auto;
    height: 100%;
  }

  :host([theme~='cover-media']) {
    --_media-width: calc(100% + var(--_padding) * 2);
  }

  :host([theme~='horizontal'][theme~='cover-media']) {
    --_media-width: calc(100% + var(--_padding));
  }

  :host([theme~='cover-media']) ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
    border-radius: inherit;
    border-end-end-radius: 0;
    border-end-start-radius: 0;
    margin-inline: calc(var(--_padding) * -1);
    margin-top: calc(var(--_padding) * -1);
    max-width: none;
    width: var(--_media-width);
  }

  :host([theme~='horizontal'][theme~='cover-media']) ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
    border-radius: inherit;
    border-end-end-radius: 0;
    border-start-end-radius: 0;
    height: calc(100% + var(--_padding) * 2);
    margin-inline-end: 0;
  }

  /* Scroller in content */
  [part='content'] ::slotted(vaadin-scroller) {
    margin-inline: calc(var(--_padding) * -1);
    padding-inline: var(--_padding);
  }

  [part='content'] ::slotted(vaadin-scroller)::before,
  [part='content'] ::slotted(vaadin-scroller)::after {
    margin-inline: calc(var(--_padding) * -1);
  }

  /* Outlined */
  :host([theme~='outlined']) {
    --vaadin-card-border-width: 1px;
  }

  /* Elevated */
  :host([theme~='elevated']) {
    --vaadin-card-background: var(--vaadin-background-color);
    box-shadow: var(--vaadin-card-shadow, 0 1px 4px -1px rgba(0, 0, 0, 0.3));
  }
`;
/**
 * @license
 * Copyright (c) 2024 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Card extends ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-card";
  }
  static get styles() {
    return cardStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  static get properties() {
    return {
      /**
       * The title of the card. When set, any custom slotted title is removed and this string-based title is used instead. If this title is used, an `aria-labelledby` attribute that points to the generated title element is set.
       *
       * @attr {string} card-title
       */
      cardTitle: {
        type: String,
        observer: "__cardTitleChanged"
      },
      /**
       * Sets the heading level (`aria-level`) for the string-based title. If not set, the level defaults to 2. Setting values outside the range [1, 6] can cause accessibility issues.
       *
       * @attr {number} title-heading-level
       */
      titleHeadingLevel: {
        type: Number,
        reflectToAttribute: true,
        observer: "__titleHeadingLevelChanged"
      }
    };
  }
  /** @protected */
  ready() {
    super.ready();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "region");
    }
  }
  /** @protected */
  render() {
    return html`
      <div part="media">
        <slot name="media"></slot>
      </div>
      <div part="header">
        <slot name="header-prefix"></slot>
        <slot name="header">
          <slot name="title"></slot>
          <slot name="subtitle"></slot>
        </slot>
        <slot name="header-suffix"></slot>
      </div>
      <div part="content">
        <slot></slot>
      </div>
      <div part="footer">
        <slot name="footer"></slot>
      </div>
    `;
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    this._onSlotChange();
  }
  /** @private */
  _onSlotChange() {
    this.toggleAttribute("_m", this.querySelector(':scope > [slot="media"]'));
    this.toggleAttribute("_h", this.querySelector(':scope > [slot="header"]'));
    this.toggleAttribute(
      "_t",
      this.querySelector(':scope > [slot="title"]') && !this.querySelector(':scope > [slot="header"]')
    );
    this.toggleAttribute(
      "_st",
      this.querySelector(':scope > [slot="subtitle"]') && !this.querySelector(':scope > [slot="header"]')
    );
    this.toggleAttribute("_hp", this.querySelector(':scope > [slot="header-prefix"]'));
    this.toggleAttribute("_hs", this.querySelector(':scope > [slot="header-suffix"]'));
    this.toggleAttribute("_c", this.__hasContent());
    this.toggleAttribute("_f", this.querySelector(':scope > [slot="footer"]'));
    if (this.__getCustomTitleElement()) {
      this.__clearStringTitle();
    }
  }
  /** @private */
  __hasContent() {
    const slot = this.shadowRoot.querySelector("slot:not([name])");
    return slot.assignedNodes({ flatten: true }).filter((node) => !isEmptyTextNode(node)).length > 0;
  }
  /** @private */
  __clearStringTitle() {
    const stringTitleElement = this.__getStringTitleElement();
    if (stringTitleElement) {
      this.removeChild(stringTitleElement);
    }
    const ariaLabelledby = this.getAttribute("aria-labelledby");
    if (ariaLabelledby && ariaLabelledby.startsWith("card-title-")) {
      this.removeAttribute("aria-labelledby");
    }
    if (this.cardTitle) {
      this.cardTitle = "";
    }
  }
  /** @private */
  __getCustomTitleElement() {
    return Array.from(this.querySelectorAll('[slot="title"]')).find((el) => {
      return !el.hasAttribute("card-string-title");
    });
  }
  /** @private */
  __cardTitleChanged(title) {
    if (!title) {
      this.__clearStringTitle();
      return;
    }
    const customTitleElement = this.__getCustomTitleElement();
    if (customTitleElement) {
      this.removeChild(customTitleElement);
    }
    let stringTitleElement = this.__getStringTitleElement();
    if (!stringTitleElement) {
      stringTitleElement = this.__createStringTitleElement();
      this.appendChild(stringTitleElement);
      this.setAttribute("aria-labelledby", stringTitleElement.id);
    }
    stringTitleElement.textContent = title;
  }
  /** @private */
  __createStringTitleElement() {
    const stringTitleElement = document.createElement("div");
    stringTitleElement.setAttribute("slot", "title");
    stringTitleElement.setAttribute("role", "heading");
    this.__setTitleHeadingLevel(stringTitleElement, this.titleHeadingLevel);
    stringTitleElement.setAttribute("card-string-title", "");
    stringTitleElement.id = `card-title-${generateUniqueId()}`;
    return stringTitleElement;
  }
  /** @private */
  __titleHeadingLevelChanged(titleHeadingLevel) {
    const stringTitleElement = this.__getStringTitleElement();
    if (stringTitleElement) {
      this.__setTitleHeadingLevel(stringTitleElement, titleHeadingLevel);
    }
  }
  /** @private */
  __setTitleHeadingLevel(stringTitleElement, titleHeadingLevel) {
    stringTitleElement.setAttribute("aria-level", titleHeadingLevel || 2);
  }
  /** @private */
  __getStringTitleElement() {
    return this.querySelector('[slot="title"][card-string-title]');
  }
  /**
   * @protected
   * @override
   */
  createRenderRoot() {
    const root = super.createRenderRoot();
    root.addEventListener("slotchange", () => this._onSlotChange());
    return root;
  }
}
defineCustomElement(Card);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
function inflateFunctions(config) {
  if (Array.isArray(config)) {
    config.forEach(inflateFunctions);
    return;
  }
  if (
    // Check if param is a primitive/null/undefined value
    !(config instanceof Object) || // Check if param is a plain object (not a HC object)
    config.constructor !== Object
  ) {
    return;
  }
  Object.entries(config).forEach(([attr, targetProperty]) => {
    if (attr.startsWith("_fn_") && (typeof targetProperty === "string" || targetProperty instanceof String)) {
      try {
        config[attr.substr(4)] = eval(`(${targetProperty})`);
      } catch (_) {
        config[attr.substr(4)] = eval(`(function(){${targetProperty}})`);
      }
      delete config[attr];
    } else if (targetProperty instanceof Object) {
      inflateFunctions(targetProperty);
    }
  });
}
function deepMerge(target, source) {
  const isObject2 = (item) => item && typeof item === "object" && !Array.isArray(item);
  if (isObject2(source) && isObject2(target)) {
    Object.keys(source).forEach((key2) => {
      if (isObject2(source[key2])) {
        if (!target[key2]) {
          Object.assign(target, { [key2]: {} });
        }
        deepMerge(target[key2], source[key2]);
      } else {
        Object.assign(target, { [key2]: source[key2] });
      }
    });
  }
  return target;
}
function prepareExport(chart) {
  if (!chart.tempBodyStyle) {
    let effectiveCss = "";
    if (chart.shadowRoot.adoptedStyleSheets) {
      chart.shadowRoot.adoptedStyleSheets.forEach((sheet) => {
        effectiveCss += `${[...sheet.cssRules].map((rule) => rule.cssText).join("\n")}
`;
      });
    }
    effectiveCss = effectiveCss.replace(/:host\(.+?\)/gu, (match2) => {
      const selector = match2.substr(6, match2.length - 7);
      return chart.matches(selector) ? "" : match2;
    });
    effectiveCss = `${effectiveCss}body {    -moz-transform: scale(0.9, 0.9);    zoom: 0.9;    zoom: 90%;}`;
    chart.tempBodyStyle = document.createElement("style");
    chart.tempBodyStyle.textContent = effectiveCss;
    document.body.appendChild(chart.tempBodyStyle);
    if (chart.__styledMode) {
      document.body.toggleAttribute("styled-mode", true);
    }
  }
}
function cleanupExport(chart) {
  if (chart.tempBodyStyle) {
    document.body.removeChild(chart.tempBodyStyle);
    delete chart.tempBodyStyle;
    if (chart.__styledMode) {
      document.body.removeAttribute("styled-mode");
    }
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const ChartSeriesMixin = (superClass) => class extends superClass {
  static get properties() {
    return {
      /**
       * An array of data used by the series.
       * Format depends on the chart type and can be:
       *   - An array of numerical values `[y0, y1, y2, y3,...]`
       *   - An array of arrays with 2 values (`x`, `y`) `[ [x0, y0], [x1, y1], [x2, y2], ... ]`
       *   - An array of objects, each one describing one point `[ {x: x0, y: y0, name: 'Point0', color: '#FF0000'}, {...}, ...]`
       *
       *  See more in [API Site](https://api.highcharts.com/highcharts/series)
       *
       * @type {ChartSeriesValues}
       */
      values: {
        type: Array,
        value: () => [],
        sync: true
      },
      /**
       * Value-axis minimum-value.
       * Sets the value to a series bound by 'unit' property.
       * Otherwise sets the value to the first series.
       * Undefined by default (determined from data).
       * @attr {number} value-min
       */
      valueMin: {
        type: Number,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Value-axis maximum-value.
       * See the 'valueMin'
       * @attr {number} value-max
       */
      valueMax: {
        type: Number,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * A string with the type of the series.
       * Defaults to `'line'` in case no type is set for the chart.
       * Note that `'bar'`, `'gauge'` and `'solidgauge'` should be set as default series type on `<vaadin-chart>`.
       */
      type: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * The name of the series as shown in the legend, tooltip etc.
       */
      title: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Shows/hides data-point markers for line-like series.
       * Acceptable input are:
       *  - `shown`: markers are always visible
       *  - `hidden`: markers are always hidden
       *  - `auto`: markers are visible for widespread data and hidden, when data is dense *(default)*
       */
      markers: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Used to connect the series to an axis; if multiple series have the same `unit`, they will share axis.
       * Displayed as a title for the axis.
       * If no unit is defined, then series will be connected to the first axis.
       */
      unit: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Used to group series in a different stacks.
       * "stacking" property should be specified either for each series or in plotOptions.
       * It is recommended to place series in a single stack, when they belong to the same yAxis.
       * @type {number | string}
       */
      stack: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * The height of the neck, the lower part of the funnel.
       * A number defines pixel width, a percentage string defines a percentage of the plot area height. Defaults to 30%.
       * Note that this property only applies for "funnel" charts.
       * @attr {number | string} neck-position
       * @type {number | string}
       */
      neckPosition: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * The width of the neck, the lower part of the funnel.
       * A number defines pixel width, a percentage string defines a percentage of the plot area width. Defaults to 30%.
       * Note that this property only applies for "funnel" charts.
       * @attr {number | string} neck-width
       * @type {number | string}
       */
      neckWidth: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Object with the configured options defined and used to create a series.
       * @type {!ChartSeriesOptions}
       * @readonly
       */
      options: {
        type: Object,
        sync: true
      },
      /**
       * Represents additional JSON configuration.
       * @type {SeriesOptionsType | undefined}
       */
      additionalOptions: {
        type: Object,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * @type {!Series | undefined}
       * @protected
       */
      _series: {
        type: Object,
        sync: true
      }
    };
  }
  static get observers() {
    return [
      "__additionalOptionsObserver(additionalOptions, _series)",
      "__markersObserver(markers, _series)",
      "__neckPositionObserver(neckPosition, _series)",
      "__neckWidthObserver(neckWidth, _series)",
      "__stackObserver(stack, _series)",
      "__titleObserver(title, _series)",
      "__typeObserver(type, _series)",
      "__unitObserver(unit, valueMin, valueMax, _series)",
      "__valueMinObserver(valueMin, _series)",
      "__valueMaxObserver(valueMax, _series)",
      "__valuesObserver(values, _series)"
    ];
  }
  get options() {
    const options2 = deepMerge({}, this.additionalOptions);
    if (this.type) {
      options2.type = this.type;
    }
    if (this.title) {
      options2.name = this.title;
    }
    if (this.values) {
      options2.data = this.values;
    }
    if (this.markers) {
      if (!this.__isMarkersValid()) {
        this.markers = "auto";
      }
      options2.marker = this.__markersConfiguration;
    }
    if (this.unit) {
      options2.yAxis = this.unit;
    }
    if (this.stack) {
      options2.stack = this.stack;
    }
    if (isFinite(this.valueMin)) {
      options2.yAxisValueMin = this.valueMin;
    }
    if (isFinite(this.valueMax)) {
      options2.yAxisValueMax = this.valueMax;
    }
    if (this.neckWidth) {
      options2.neckWidth = this.neckWidth;
    }
    if (this.neckPosition) {
      options2.neckHeight = this.neckPosition;
    }
    return options2;
  }
  /** @private */
  get __markersConfiguration() {
    const config2 = {};
    switch (this.markers) {
      case "shown":
        config2.enabled = true;
        break;
      case "hidden":
        config2.enabled = false;
        break;
      case "auto":
      default:
        config2.enabled = null;
        break;
    }
    return config2;
  }
  /**
   * Method to attach a series object of type `Highcharts.Series`.
   * @param {!Series} series Object of type `Highcharts.Series`
   */
  setSeries(series) {
    this._series = series;
  }
  /** @private */
  __valuesObserver(values, series) {
    if (series) {
      series.setData(values);
    }
  }
  /** @private */
  __additionalOptionsObserver(additionalOptions, series) {
    if (series && additionalOptions) {
      series.update(additionalOptions);
    }
  }
  /** @private */
  __updateAxis(series, value, key2) {
    if (!isFinite(value)) {
      this.__showWarn(`value-${key2}`, "Numbers or null");
      return;
    }
    if (series && series.yAxis) {
      series.yAxis.update({ [key2]: value });
    }
  }
  /** @private */
  __valueMinObserver(valueMin, series) {
    if (valueMin === void 0 || series == null) {
      return;
    }
    this.__updateAxis(series, valueMin, "min");
  }
  /** @private */
  __valueMaxObserver(valueMax, series) {
    if (valueMax === void 0 || series == null) {
      return;
    }
    this.__updateAxis(series, valueMax, "max");
  }
  /** @private */
  __typeObserver(type, series) {
    if (type && series) {
      series.update({ type });
    }
  }
  /** @private */
  __titleObserver(title, series) {
    if (title === void 0 || series == null) {
      return;
    }
    series.update({ name: title });
  }
  /** @private */
  __stackObserver(stack, series) {
    if (stack === void 0 || series == null) {
      return;
    }
    series.update({ stack });
  }
  /** @private */
  __neckPositionObserver(neckPosition, series) {
    if (neckPosition === void 0 || series == null) {
      return;
    }
    series.update({ neckHeight: neckPosition });
  }
  /** @private */
  __neckWidthObserver(neckWidth, series) {
    if (neckWidth === void 0 || series == null) {
      return;
    }
    series.update({ neckWidth });
  }
  /** @private */
  __unitObserver(unit, valueMin, valueMax, series) {
    if (series && unit !== this.__oldUnit) {
      const Chart3 = customElements.get("vaadin-chart");
      this.__oldUnit = unit;
      const parent = this.parentNode instanceof Chart3 && this.parentNode;
      if (parent && parent instanceof Chart3) {
        if (unit && !parent.__getAxis(unit)) {
          const title = { title: { text: unit } };
          parent.__addAxis({ id: unit, axisGenerated: true, ...title });
        }
        series.update({ yAxis: unit || 0 });
        if (valueMin !== void 0) {
          this.__updateAxis(series, valueMin, "min");
        }
        if (valueMax !== void 0) {
          this.__updateAxis(series, valueMax, "max");
        }
        parent.__removeAxisIfEmpty();
      }
    }
  }
  /** @private */
  __isMarkersValid() {
    if (["shown", "hidden", "auto"].indexOf(this.markers) === -1) {
      this.__showWarn("markers", '"shown", "hidden" or "auto"');
      return false;
    }
    return true;
  }
  /** @private */
  __markersObserver(markers, series) {
    if (markers === void 0 || series == null) {
      return;
    }
    if (!this.__isMarkersValid()) {
      this.markers = "auto";
      return;
    }
    series.update({
      marker: this.__markersConfiguration
    });
  }
  /** @private */
  __showWarn(propertyName, acceptedValues) {
    console.warn(`<vaadin-chart-series> Acceptable values for "${propertyName}" are ${acceptedValues}`);
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class ChartSeries extends ChartSeriesMixin(PolylitMixin(LitElement)) {
  static get is() {
    return "vaadin-chart-series";
  }
}
defineCustomElement(ChartSeries);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const tooltipStyles = (scope) => css$h`
  ${unsafeCSS(scope)} .highcharts-tooltip {
    cursor: default;
    pointer-events: none;
    white-space: nowrap;
    transition: stroke 150ms;
    filter: drop-shadow(var(--vaadin-charts-tooltip-shadow, 0 4px 8px rgba(0, 0, 0, 0.2))) !important;
  }

  ${unsafeCSS(scope)} .highcharts-tooltip text,
  ${unsafeCSS(scope)} .highcharts-tooltip foreignObject span {
    fill: var(--highcharts-neutral-color-80, var(--vaadin-charts-data-label, var(--vaadin-text-color)));
  }

  ${unsafeCSS(scope)} .highcharts-tooltip .highcharts-tracker {
    fill: none;
    stroke: none;
  }

  ${unsafeCSS(scope)} .highcharts-tooltip .highcharts-header {
    font-size: 0.85em;
    color: var(--highcharts-neutral-color-60, var(--vaadin-text-color-secondary));
  }

  ${unsafeCSS(scope)} .highcharts-tooltip-box {
    stroke-width: 0;
    fill: var(--highcharts-background-color, var(--vaadin-charts-tooltip-background, var(--vaadin-background-color)));
  }

  ${unsafeCSS(scope)} .highcharts-tooltip-box .highcharts-label-box {
    fill: var(--highcharts-background-color, var(--vaadin-charts-tooltip-background, var(--vaadin-background-color)));
  }

  ${unsafeCSS(scope)} div.highcharts-tooltip {
    filter: none;
    font-size: 0.8em;
  }
`;
addGlobalStyles(
  "vaadin-charts-tooltip",
  css$h`
    .highcharts-tooltip-container .highcharts-root {
      overflow: visible;
      font-size: var(--vaadin-charts-font-size, 0.75rem);
      line-height: normal;
    }
  `,
  tooltipStyles(".highcharts-tooltip-container")
);
const chartStyles = css$h`
  :host {
    display: block;
    width: 100%;
    height: 100%;
    overflow: hidden;
  }

  :host,
  :root {
    font-size: var(--vaadin-charts-font-size, 0.75rem);
    line-height: normal;

    /* Needs to be a color, not a background image */
    --_bg: var(--vaadin-charts-background, var(--vaadin-background-color));

    --_color-0: var(--highcharts-color-0, var(--vaadin-charts-color-0, var(--vaadin-user-color-0)));
    --_color-1: var(--highcharts-color-1, var(--vaadin-charts-color-1, var(--vaadin-user-color-1)));
    --_color-2: var(--highcharts-color-2, var(--vaadin-charts-color-2, var(--vaadin-user-color-2)));
    --_color-3: var(--highcharts-color-3, var(--vaadin-charts-color-3, var(--vaadin-user-color-3)));
    --_color-4: var(--highcharts-color-4, var(--vaadin-charts-color-4, var(--vaadin-user-color-4)));
    --_color-5: var(--highcharts-color-5, var(--vaadin-charts-color-5, var(--vaadin-user-color-5)));
    --_color-6: var(--highcharts-color-6, var(--vaadin-charts-color-6, var(--vaadin-user-color-6)));
    --_color-7: var(--highcharts-color-7, var(--vaadin-charts-color-7, var(--vaadin-user-color-7)));
    --_color-8: var(--highcharts-color-8, var(--vaadin-charts-color-8, var(--vaadin-user-color-8)));
    --_color-9: var(--highcharts-color-9, var(--vaadin-charts-color-9, var(--vaadin-user-color-9)));

    --_color-0-label: oklch(from var(--_color-0) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-1-label: oklch(from var(--_color-1) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-2-label: oklch(from var(--_color-2) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-3-label: oklch(from var(--_color-3) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-4-label: oklch(from var(--_color-4) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-5-label: oklch(from var(--_color-5) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-6-label: oklch(from var(--_color-6) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-7-label: oklch(from var(--_color-7) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-8-label: oklch(from var(--_color-8) clamp(0, (0.62 - l) * 1000, 1) 0 0);
    --_color-9-label: oklch(from var(--_color-9) clamp(0, (0.62 - l) * 1000, 1) 0 0);

    --_color-positive: light-dark(#19b156, #1ccc62);
    --_color-negative: light-dark(#dc0611, #f7353f);

    --_label: var(--vaadin-charts-label, var(--vaadin-text-color));
    --_secondary-label: var(--vaadin-charts-secondary-label, var(--vaadin-text-color-secondary));
    --_disabled-label: var(--vaadin-charts-disabled-label, var(--vaadin-text-color-disabled));
    --_point-border: var(--vaadin-charts-point-border, var(--_bg));
    --_axis-line: var(--vaadin-charts-axis-line, var(--vaadin-border-color-secondary));
    --_axis-title: var(--vaadin-charts-axis-title, var(--_secondary-label));
    --_axis-label: var(--vaadin-charts-axis-label, var(--_secondary-label));
    --_grid-line: var(--vaadin-charts-grid-line, var(--vaadin-border-color-secondary));
    --_minor-grid-line: var(
      --vaadin-charts-minor-grid-line,
      color-mix(in srgb, var(--vaadin-border-color-secondary) 60%, transparent)
    );
    --_data-label: var(--vaadin-charts-data-label, var(--_label));
  }

  /* Safari 17 doesn't support relative colors from light-dark() */
  @supports not (color: oklch(from light-dark(red, red) l c h)) {
    :host {
      /* Safari 17 wants degrees instead of raw numbers */
      --_hue-scale: 180deg;
    }
  }

  :host([hidden]) {
    display: none !important;
  }

  .highcharts-container {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
    text-align: left;
    line-height: normal;
    z-index: 0; /* highcharts/highcharts#1072 */
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    user-select: none;
    touch-action: manipulation;
    outline: none;
  }

  :where([styled-mode]) .highcharts-no-touch-action {
    touch-action: none;
  }

  :where([styled-mode]) .highcharts-root {
    display: block;
  }

  :where([styled-mode]) .highcharts-root text {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-strong {
    font-weight: bold;
  }

  :where([styled-mode]) .highcharts-emphasized {
    font-style: italic;
  }

  :where([styled-mode]) .highcharts-anchor {
    cursor: pointer;
  }

  :where([styled-mode]) .highcharts-background {
    fill: var(--highcharts-background-color, var(--_bg));
  }

  :where([styled-mode]) .highcharts-plot-border,
  :where([styled-mode]) .highcharts-plot-background {
    fill: none;
  }

  :where([styled-mode]) .highcharts-label-box {
    fill: none;
  }

  :where([styled-mode]) .highcharts-label text {
    fill: var(--highcharts-neutral-color-80, var(--_data-label));
  }

  :where([styled-mode]) .highcharts-button-box {
    fill: inherit;
    rx: var(--vaadin-charts-button-border-radius, var(--vaadin-radius-m));
    ry: var(--vaadin-charts-button-border-radius, var(--vaadin-radius-m));
  }

  :where([styled-mode]) .highcharts-tracker-line {
    stroke-linejoin: round;
    stroke: rgba(192, 192, 192, 0.0001);
    stroke-width: 22;
    fill: none;
  }

  :where([styled-mode]) .highcharts-tracker-area {
    fill: rgba(192, 192, 192, 0.0001);
    stroke-width: 0;
  }

  /* Titles */
  :where([styled-mode]) .highcharts-title {
    fill: var(--highcharts-neutral-color-80, var(--vaadin-charts-title-label, var(--_label)));
    font-size: 1.6em;
    font-weight: bold;
  }

  :where([styled-mode]) .highcharts-subtitle {
    fill: var(--highcharts-neutral-color-60, var(--_secondary-label));
    font-size: 1em;
  }

  /* Axes */
  :where([styled-mode]) .highcharts-axis-line {
    fill: none;
    stroke: var(--highcharts-neutral-color-80, var(--_axis-line));
  }

  :where([styled-mode]) .highcharts-yaxis .highcharts-axis-line {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-axis-title {
    fill: var(--highcharts-neutral-color-60, var(--_axis-title));
    font-size: 1em;
  }

  :where([styled-mode]) .highcharts-axis-labels {
    fill: var(--highcharts-neutral-color-80, var(--_axis-label));
    cursor: default;
  }

  :where([styled-mode]) .highcharts-grid-line {
    fill: none;
    stroke: var(--highcharts-neutral-color-10, var(--_grid-line));
  }

  :where([styled-mode]) .highcharts-xaxis-grid .highcharts-grid-line {
    stroke-width: var(--vaadin-charts-xaxis-line-width, 0);
  }

  :where([styled-mode]) .highcharts-tick {
    stroke: var(--highcharts-neutral-color-80, var(--_grid-line));
  }

  :where([styled-mode]) .highcharts-yaxis .highcharts-tick {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-minor-grid-line {
    stroke: var(--highcharts-neutral-color-5, var(--_minor-grid-line));
  }

  :where([styled-mode]) .highcharts-crosshair-thin {
    stroke-width: 1px;
    stroke: var(--highcharts-neutral-color-20, var(--_grid-line));
  }

  :where([styled-mode]) .highcharts-crosshair-category {
    stroke: var(--highcharts-highlight-color-20, var(--_color-0));
    stroke-opacity: 0.25;
  }

  /* Credits */
  :where([styled-mode]) .highcharts-credits {
    cursor: pointer;
    fill: var(--highcharts-neutral-color-40, var(--_disabled-label));
    font-size: 0.7em;
    transition:
      fill 250ms,
      font-size 250ms;
  }

  :where([styled-mode]) .highcharts-credits:hover {
    fill: var(--highcharts-neutral-color-100, black);
    font-size: 0.8em;
  }

  /* Tooltip */
  ${unsafeCSS(tooltipStyles(":where([styled-mode])"))};

  :where([styled-mode]) .highcharts-selection-marker {
    fill: var(--highcharts-highlight-color-80, var(--_color-0));
    fill-opacity: 0.25;
  }

  :where([styled-mode]) .highcharts-graph {
    fill: none;
    stroke-width: var(--vaadin-chart-graph-stroke-width, 2);
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  :where([styled-mode]) .highcharts-empty-series {
    stroke-width: 1px;
    fill: none;
    stroke: var(--highcharts-neutral-color-20, var(--_color-0));
  }

  :where([styled-mode]) .highcharts-state-hover .highcharts-graph {
    stroke-width: calc(var(--vaadin-chart-graph-stroke-width, 2) + 1);
  }

  :where([styled-mode]) .highcharts-point-inactive {
    opacity: 0.2;
    transition: opacity 50ms; /* quick in */
  }

  :where([styled-mode]) .highcharts-series-inactive {
    opacity: 0.2;
    transition: opacity 50ms; /* quick in */
  }

  :where([styled-mode]) .highcharts-state-hover path {
    transition: stroke-width 50ms; /* quick in */
  }

  :where([styled-mode]) .highcharts-state-normal path {
    transition: stroke-width 250ms; /* slow out */
  }

  /* Legend hover affects points and series */
  :where([styled-mode]) g.highcharts-series,
  :where([styled-mode]) .highcharts-point,
  :where([styled-mode]) .highcharts-markers,
  :where([styled-mode]) .highcharts-data-labels {
    transition: opacity 250ms;
  }

  :where([styled-mode]) .highcharts-legend-series-active g.highcharts-series:not(.highcharts-series-hover),
  :where([styled-mode])
    .highcharts-legend-point-active
    .highcharts-point:not(.highcharts-point-hover, .highcharts-point-select),
  :where([styled-mode]) .highcharts-legend-series-active .highcharts-markers:not(.highcharts-series-hover),
  :where([styled-mode]) .highcharts-legend-series-active .highcharts-data-labels:not(.highcharts-series-hover) {
    opacity: 0.2;
  }

  /* Series options */

  /* Default colors */
  :where([styled-mode]) .highcharts-color-0 {
    fill: var(--_color-0);
    stroke: var(--_color-0);
  }

  :where([styled-mode]) .highcharts-color-1 {
    fill: var(--_color-1);
    stroke: var(--_color-1);
  }

  :where([styled-mode]) .highcharts-color-2 {
    fill: var(--_color-2);
    stroke: var(--_color-2);
  }

  :where([styled-mode]) .highcharts-color-3 {
    fill: var(--_color-3);
    stroke: var(--_color-3);
  }

  :where([styled-mode]) .highcharts-color-4 {
    fill: var(--_color-4);
    stroke: var(--_color-4);
  }

  :where([styled-mode]) .highcharts-color-5 {
    fill: var(--_color-5);
    stroke: var(--_color-5);
  }

  :where([styled-mode]) .highcharts-color-6 {
    fill: var(--_color-6);
    stroke: var(--_color-6);
  }

  :where([styled-mode]) .highcharts-color-7 {
    fill: var(--_color-7);
    stroke: var(--_color-7);
  }

  :where([styled-mode]) .highcharts-color-8 {
    fill: var(--_color-8);
    stroke: var(--_color-8);
  }

  :where([styled-mode]) .highcharts-color-9 {
    fill: var(--_color-9);
    stroke: var(--_color-9);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-0 {
    color: var(--_color-0-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-1 {
    color: var(--_color-1-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-2 {
    color: var(--_color-2-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-3 {
    color: var(--_color-3-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-4 {
    color: var(--_color-4-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-5 {
    color: var(--_color-5-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-6 {
    color: var(--_color-6-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-7 {
    color: var(--_color-7-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-8 {
    color: var(--_color-8-label);
  }

  :where([styled-mode])
    :where(.highcharts-treemap-series, .highcharts-organization-series, .highcharts-gantt-series)
    .highcharts-data-label-color-9 {
    color: var(--_color-9-label);
  }

  :where([styled-mode]) [class*='highcharts-data-label-color-'] {
    fill: currentColor;
  }

  /* Various series-specific */
  :where([styled-mode]) .highcharts-area {
    fill-opacity: 0.75;
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-markers {
    stroke-width: 1px;
    stroke: var(--highcharts-background-color, var(--_bg));
  }

  :where([styled-mode])
    .highcharts-a11y-markers-hidden
    .highcharts-point:not(.highcharts-point-hover, .highcharts-a11y-marker-visible),
  :where([styled-mode]) .highcharts-a11y-marker-hidden {
    opacity: 0;
  }

  :where([styled-mode]) .highcharts-point {
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-dense-data .highcharts-point {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-data-label text,
  :where([styled-mode]) .highcharts-data-label span,
  :where([styled-mode]) text.highcharts-data-label {
    font-size: 0.9em;
  }

  :where([styled-mode]) .highcharts-data-label-box {
    fill: none;
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-data-label text,
  :where([styled-mode]) text.highcharts-data-label {
    fill: var(--highcharts-neutral-color-80, var(--_data-label));
  }

  :where([styled-mode]) .highcharts-data-label-connector {
    fill: none;
  }

  :where([styled-mode]) .highcharts-data-label-hidden {
    pointer-events: none;
  }

  :where([styled-mode]) .highcharts-halo {
    fill-opacity: 0.25;
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-series-label text {
    fill: inherit;
    font-weight: bold;
  }

  :where([styled-mode]) .highcharts-series:not(.highcharts-pie-series) .highcharts-point-select,
  :where([styled-mode]) .highcharts-markers .highcharts-point-select {
    fill: var(--highcharts-neutral-color-20, var(--_grid-line));
    stroke: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
  }

  :where([styled-mode]) .highcharts-column-series path.highcharts-point,
  :where([styled-mode]) .highcharts-bar-series path.highcharts-point {
    /* path to prevent stroke on 3D columns and bars */
    stroke: var(--highcharts-background-color, var(--_point-border));
  }

  :where([styled-mode]) .highcharts-column-series .highcharts-point,
  :where([styled-mode]) .highcharts-bar-series .highcharts-point {
    transition: fill-opacity 250ms;
  }

  :where([styled-mode]) .highcharts-column-series .highcharts-point-hover,
  :where([styled-mode]) .highcharts-bar-series .highcharts-point-hover {
    fill-opacity: 0.75;
    transition: fill-opacity 50ms;
  }

  :where([styled-mode]) .highcharts-pie-series .highcharts-point {
    stroke-linejoin: round;
    stroke: var(--highcharts-background-color, var(--_point-border));
  }

  :where([styled-mode]) .highcharts-pie-series .highcharts-point-hover {
    fill-opacity: 0.75;
    transition: fill-opacity 50ms;
  }

  :where([styled-mode]) .highcharts-funnel-series .highcharts-point {
    stroke-linejoin: round;
    stroke: var(--highcharts-background-color, var(--_point-border));
  }

  :where([styled-mode]) .highcharts-funnel-series .highcharts-point-hover {
    fill-opacity: 0.75;
    transition: fill-opacity 50ms;
  }

  :where([styled-mode]) .highcharts-funnel-series .highcharts-point-select {
    fill: inherit;
    stroke: inherit;
  }

  :where([styled-mode]) .highcharts-pyramid-series .highcharts-point {
    stroke-linejoin: round;
    stroke: var(--highcharts-background-color, var(--_point-border));
  }

  :where([styled-mode]) .highcharts-pyramid-series .highcharts-point-hover {
    fill-opacity: 0.75;
    transition: fill-opacity 50ms;
  }

  :where([styled-mode]) .highcharts-pyramid-series .highcharts-point-select {
    fill: inherit;
    stroke: inherit;
  }

  :where([styled-mode]) .highcharts-solidgauge-series .highcharts-point {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-treemap-series .highcharts-point {
    stroke-width: 1px;
    stroke: var(--highcharts-background-color, var(--_point-border));
    transition:
      stroke 250ms,
      fill 250ms,
      fill-opacity 250ms;
  }

  :where([styled-mode]) .highcharts-treemap-series .highcharts-point-hover {
    stroke: var(--highcharts-neutral-color-40, var(--_point-border));
    transition:
      stroke 25ms,
      fill 25ms,
      fill-opacity 25ms;
  }

  :where([styled-mode]) .highcharts-treemap-series .highcharts-above-level {
    display: none;
  }

  :where([styled-mode]) .highcharts-treemap-series .highcharts-internal-node {
    fill: none;
  }

  :where([styled-mode]) .highcharts-treemap-series .highcharts-internal-node-interactive {
    fill-opacity: 0.15;
    cursor: pointer;
  }

  :where([styled-mode]) .highcharts-treemap-series .highcharts-internal-node-interactive:hover {
    fill-opacity: 0.75;
  }

  :where([styled-mode]) .highcharts-vector-series .highcharts-point {
    fill: none;
    stroke-width: 2px;
  }

  :where([styled-mode]) .highcharts-windbarb-series .highcharts-point {
    fill: none;
    stroke-width: 2px;
  }

  :where([styled-mode]) .highcharts-lollipop-stem {
    stroke: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
  }

  :where([styled-mode]) .highcharts-focus-border {
    fill: none;
    stroke-width: 2px;
  }

  :where([styled-mode]) .highcharts-legend-item-hidden .highcharts-focus-border {
    fill: none !important;
  }

  /* Legend */
  :where([styled-mode]) .highcharts-legend-box {
    fill: none;
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-legend-item > text,
  :where([styled-mode]) .highcharts-legend-item span {
    fill: var(--highcharts-neutral-color-80, var(--_data-label));
    font-size: 1em;
    cursor: pointer;
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-legend-item:hover text {
    fill: var(--highcharts-neutral-color-100, var(--vaadin-charts-title-label, var(--_label)));
  }

  :where([styled-mode]) .highcharts-legend-item-hidden * {
    fill: var(--highcharts-neutral-color-60, var(--_disabled-label)) !important;
    stroke: var(--highcharts-neutral-color-60, var(--_disabled-label)) !important;
    transition: fill 250ms;
    text-decoration: line-through;
  }

  :where([styled-mode]) .highcharts-legend-nav-active {
    fill: var(--highcharts-highlight-color-100, var(--vaadin-charts-button-label, var(--_label)));
    cursor: pointer;
  }

  :where([styled-mode]) .highcharts-legend-nav-inactive {
    fill: var(--highcharts-neutral-color-20, var(--_disabled-label));
  }

  :where([styled-mode]) circle.highcharts-legend-nav-active,
  :where([styled-mode]) circle.highcharts-legend-nav-inactive {
    /* tracker */
    fill: rgba(192, 192, 192, 0.0001);
  }

  :where([styled-mode]) .highcharts-legend-title-box {
    fill: none;
    stroke-width: 0;
  }

  /* Bubble legend */
  :where([styled-mode]) .highcharts-bubble-legend-symbol {
    stroke-width: 2;
    fill-opacity: 0.5;
  }

  :where([styled-mode]) .highcharts-bubble-legend-connectors {
    stroke-width: 1;
  }

  :where([styled-mode]) .highcharts-bubble-legend-labels {
    fill: var(--highcharts-neutral-color-80, var(--_data-label));
    font-size: 0.95em;
  }

  /* Loading */
  :where([styled-mode]) .highcharts-loading {
    position: absolute;
    background-color: var(--highcharts-background-color, var(--_bg));
    opacity: 0.5;
    text-align: center;
    z-index: 10;
    transition: opacity 250ms;
  }

  :where([styled-mode]) .highcharts-loading-hidden {
    height: 0 !important;
    opacity: 0;
    overflow: hidden;
    transition:
      opacity 250ms,
      height 250ms step-end;
  }

  :where([styled-mode]) .highcharts-loading-inner {
    font-weight: bold;
    position: relative;
    top: 45%;
  }

  /* Plot bands and polar pane backgrounds */
  :where([styled-mode]) .highcharts-plot-band,
  :where([styled-mode]) .highcharts-pane {
    fill: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
    fill-opacity: 0.05;
  }

  :where([styled-mode]) .highcharts-plot-line {
    fill: none;
    stroke: var(
      --highcharts-neutral-color-40,
      color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 60%, transparent)
    );
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-plot-line-label {
    font-size: 1em;
  }

  /* Highcharts More and modules */
  :where([styled-mode]) .highcharts-boxplot-box {
    fill: var(--highcharts-background-color, var(--_bg));
  }

  :where([styled-mode]) .highcharts-boxplot-median {
    stroke-width: 2px;
  }

  :where([styled-mode]) .highcharts-bubble-series .highcharts-point {
    fill-opacity: 0.5;
  }

  :where([styled-mode]) .highcharts-errorbar-series .highcharts-point {
    stroke: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
  }

  :where([styled-mode]) .highcharts-gauge-series .highcharts-data-label-box {
    stroke: var(--highcharts-neutral-color-20, var(--_grid-line));
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-gauge-series .highcharts-dial {
    fill: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-organization-series .highcharts-null-point {
    fill: transparent;
  }

  :where([styled-mode]) .highcharts-polygon-series .highcharts-graph {
    fill: inherit;
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-waterfall-series .highcharts-graph {
    stroke: var(
      --highcharts-neutral-color-80,
      color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 60%, transparent)
    );
    stroke-dasharray: 1, 3;
  }

  :where([styled-mode]) .highcharts-sankey-series .highcharts-point {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-sankey-series .highcharts-link {
    transition:
      fill 250ms,
      fill-opacity 250ms;
    fill-opacity: 0.5;
  }

  :where([styled-mode]) .highcharts-sankey-series .highcharts-point-hover.highcharts-link {
    transition:
      fill 50ms,
      fill-opacity 50ms;
    fill-opacity: 1;
  }

  :where([styled-mode]) .highcharts-venn-series .highcharts-point {
    fill-opacity: 0.75;
    stroke: var(--highcharts-neutral-color-20, var(--_point-border));
    transition:
      stroke 250ms,
      fill-opacity 250ms;
  }

  :where([styled-mode]) .highcharts-venn-series .highcharts-point-hover {
    fill-opacity: 1;
    stroke: var(--highcharts-neutral-color-20, var(--_point-border));
  }

  :where([styled-mode]) .highcharts-timeline-series .highcharts-graph {
    stroke: var(--highcharts-neutral-color-20, var(--_point-border));
  }

  /* Highstock */
  :where([styled-mode]) .highcharts-navigator-mask-outside {
    fill-opacity: 0;
  }

  :where([styled-mode]) .highcharts-navigator-mask-inside {
    fill: var(--highcharts-highlight-color-60, var(--_color-0)); /* navigator.maskFill option */
    fill-opacity: 0.25;
    cursor: ew-resize;
  }

  :where([styled-mode]) .highcharts-navigator-outline {
    stroke: var(--highcharts-neutral-color-40, var(--_grid-line));
    fill: none;
  }

  :where([styled-mode]) .highcharts-navigator-handle {
    stroke: var(--highcharts-neutral-color-40, var(--_grid-line));
    fill: var(--highcharts-neutral-color-5, var(--_bg));
    cursor: ew-resize;
  }

  :where([styled-mode]) .highcharts-navigator-series {
    fill: var(--highcharts-highlight-color-80, var(--_color-1));
    stroke: var(--highcharts-highlight-color-80, var(--_color-1));
  }

  :where([styled-mode]) .highcharts-navigator-series .highcharts-graph {
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-navigator-series .highcharts-area {
    fill-opacity: 0.05;
  }

  :where([styled-mode]) .highcharts-navigator-xaxis .highcharts-axis-line {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-navigator-xaxis .highcharts-grid-line {
    stroke-width: 1px;
    stroke: var(--highcharts-neutral-color-10, var(--_grid-line));
  }

  :where([styled-mode]) .highcharts-navigator-xaxis.highcharts-axis-labels {
    fill: var(--highcharts-neutral-color-100, var(--_secondary-label));
    font-size: 0.95em;
    opacity: 0.6;
  }

  :where([styled-mode]) .highcharts-navigator-yaxis .highcharts-grid-line {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-scrollbar-thumb {
    fill: var(
      --highcharts-neutral-color-20,
      color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 20%, transparent)
    );
  }

  :where([styled-mode]) .highcharts-scrollbar-button {
    fill: var(--highcharts-neutral-color-10, var(--_bg));
    stroke: var(--highcharts-neutral-color-20);
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-scrollbar-arrow {
    fill: var(--highcharts-neutral-color-60, var(--_data-label));
  }

  :where([styled-mode]) .highcharts-scrollbar-rifles {
    stroke: none;
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-scrollbar-track {
    fill: color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 5%, transparent);
    stroke: var(--highcharts-neutral-color-20);
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-button {
    fill: var(--highcharts-neutral-color-3, var(--vaadin-charts-button-background, var(--vaadin-background-container)));
    stroke: var(--highcharts-neutral-color-20);
    cursor: default;
    stroke-width: 1px;
    transition: fill 250ms;
  }

  :where([styled-mode]) .highcharts-button text {
    fill: var(--highcharts-neutral-color-80, var(--vaadin-charts-button-label, var(--_label)));
    font-size: 1em;
  }

  :where([styled-mode]) .highcharts-button-hover {
    transition: fill 0ms;
    fill: var(
      --highcharts-neutral-color-10,
      var(--vaadin-charts-button-hover-background, var(--vaadin-background-container))
    );
    stroke: var(--highcharts-neutral-color-20);
  }

  :where([styled-mode]) .highcharts-button-hover text {
    fill: var(--highcharts-neutral-color-80, var(--vaadin-charts-button-label, var(--_label)));
  }

  :where([styled-mode]) .highcharts-button-pressed {
    font-weight: bold;
    fill: var(--highcharts-highlight-color-10, var(--vaadin-charts-button-active-background, var(--_label)));
    stroke: var(--highcharts-neutral-color-20);
  }

  :where([styled-mode]) .highcharts-button-pressed text {
    fill: var(--highcharts-neutral-color-80, var(--vaadin-charts-button-active-label, var(--_bg)));
    font-weight: bold;
  }

  :where([styled-mode]) .highcharts-button-disabled text {
    fill: var(
      --highcharts-neutral-color-80,
      var(--vaadin-charts-button-disabled-label, var(--vaadin-text-color-disabled))
    );
  }

  :where([styled-mode]) .highcharts-range-selector-buttons .highcharts-button {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-range-label rect {
    fill: none;
  }

  :where([styled-mode]) .highcharts-range-label text {
    fill: var(--highcharts-neutral-color-60, var(--_secondary-label));
  }

  :where([styled-mode]) .highcharts-range-input rect {
    fill: var(--vaadin-charts-range-input-background, var(--vaadin-background-container));
    rx: var(--vaadin-charts-button-border-radius, var(--vaadin-radius-m));
    ry: var(--vaadin-charts-button-border-radius, var(--vaadin-radius-m));
    transition: fill 250ms;
  }

  :where([styled-mode]) .highcharts-range-input:hover rect {
    fill: var(--vaadin-charts-range-input-background-hover, var(--vaadin-background-container));
  }

  :where([styled-mode]) .highcharts-range-input text {
    fill: var(--highcharts-neutral-color-80, var(--_data-label));
    font-size: 1em;
  }

  :where([styled-mode]) .highcharts-range-input {
    stroke-width: 1px;
    stroke: var(--highcharts-neutral-color-20);
  }

  :where([styled-mode]) input.highcharts-range-selector {
    position: absolute;
    border: 0;
    padding: 0;
    text-align: center;
    top: -9999em;
  }

  :where([styled-mode]) .highcharts-crosshair-label text {
    fill: var(--highcharts-background-color, var(--_bg));
    font-size: 0.9em;
  }

  :where([styled-mode]) .highcharts-crosshair-label .highcharts-label-box {
    fill: inherit;
  }

  :where([styled-mode]) .highcharts-candlestick-series .highcharts-point {
    stroke: var(--highcharts-neutral-color-100, var(--vaadin-charts-candlestick-line, var(--vaadin-border-color)));
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-candlestick-series .highcharts-point-up {
    fill: var(--highcharts-background-color, var(--_color-positive));
  }

  :where([styled-mode]) .highcharts-renko-series .highcharts-point-down,
  :where([styled-mode]) .highcharts-hollowcandlestick-series .highcharts-point-down {
    fill: var(--highcharts-negative-color, var(--_color-negative));
    stroke: var(--highcharts-negative-color, var(--_color-negative));
  }

  :where([styled-mode]) .highcharts-renko-series .highcharts-point-up,
  :where([styled-mode]) .highcharts-hollowcandlestick-series .highcharts-point-down-bearish-up {
    fill: var(--highcharts-positive-color, var(--_color-positive));
    stroke: var(--highcharts-positive-color, var(--_color-positive));
  }

  :where([styled-mode]) .highcharts-hollowcandlestick-series .highcharts-point-up {
    fill: transparent;
    stroke: var(--highcharts-positive-color, var(--_color-positive));
  }

  :where([styled-mode]) .highcharts-ohlc-series .highcharts-point-hover {
    stroke-width: 3px;
  }

  :where([styled-mode]) .highcharts-flags-series .highcharts-point .highcharts-label-box {
    stroke: var(--highcharts-neutral-color-40, var(--_grid-line));
    fill: var(--highcharts-background-color, var(--_bg));
    transition: fill 250ms;
  }

  :where([styled-mode]) .highcharts-flags-series .highcharts-point-hover .highcharts-label-box {
    stroke: var(
      --highcharts-neutral-color-100,
      color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 60%, transparent)
    );
    fill: var(--highcharts-highlight-color-20, var(--_bg));
  }

  :where([styled-mode]) .highcharts-flags-series .highcharts-point text {
    fill: var(--highcharts-neutral-color-100, var(--_data-label));
    font-size: 0.9em;
    font-weight: bold;
  }

  /* Highcharts Maps */
  :where([styled-mode]) .highcharts-map-series .highcharts-point {
    transition:
      fill 500ms,
      fill-opacity 500ms,
      stroke-width 250ms;
    stroke: var(--highcharts-neutral-color-20);
    stroke-width: inherit;
  }

  :where([styled-mode]) .highcharts-map-series .highcharts-point-hover {
    transition:
      fill 0ms,
      fill-opacity 0ms;
    fill-opacity: 0.5;
  }

  :where([styled-mode]) .highcharts-mapline-series .highcharts-point {
    fill: none;
  }

  :where([styled-mode]) .highcharts-heatmap-series .highcharts-point {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-map-navigation {
    font-size: 1.3em;
    font-weight: bold;
    text-align: center;
  }

  :where([styled-mode]) .highcharts-map-navigation.highcharts-button {
    fill: var(--highcharts-background-color);
    stroke: var(--highcharts-neutral-color-10);
  }

  :where([styled-mode]) .highcharts-map-navigation.highcharts-button:hover {
    fill: var(--highcharts-neutral-color-10);
  }

  :where([styled-mode]) .highcharts-map-navigation.highcharts-button .highcharts-button-symbol {
    stroke-width: 2px;
  }

  :where([styled-mode]) .highcharts-mapview-inset-border {
    stroke: var(--highcharts-neutral-color-20);
    stroke-width: 1px;
    fill: none;
  }

  :where([styled-mode]) .highcharts-coloraxis {
    stroke-width: 0;
  }

  :where([styled-mode]) .highcharts-coloraxis-marker {
    fill: var(--highcharts-neutral-color-40);
  }

  :where([styled-mode]) .highcharts-null-point {
    fill: var(--highcharts-neutral-color-3, var(--vaadin-charts-button-background, var(--vaadin-background-container)));
  }

  /* 3d charts */
  :where([styled-mode]) .highcharts-3d-frame {
    fill: transparent;
  }

  /* Exporting module */
  :where([styled-mode]) .highcharts-contextbutton {
    /* Fill is needed to capture hover */
    fill: var(--highcharts-background-color, var(--_bg));
    stroke: none;
    stroke-linecap: round;
  }

  :where([styled-mode]) .highcharts-contextbutton:hover {
    fill: var(--highcharts-neutral-color-10, #e6e6e6);
    stroke: var(--highcharts-neutral-color-10, #e6e6e6);
  }

  :where([styled-mode]) .highcharts-button-symbol {
    stroke: var(--highcharts-neutral-color-60, var(--_secondary-label));
    stroke-width: 3px;
  }

  :where([styled-mode]) .highcharts-menu {
    border: none;
    background: var(--highcharts-background-color, var(--_bg));
    border-radius: 3px;
    padding: 0.5em;
    box-shadow: 3px 3px 10px #888;
  }

  :where([styled-mode]) .highcharts-menu-item {
    background: none;
    border-radius: 3px;
    color: var(--highcharts-neutral-color-80, var(--vaadin-charts-button-label, var(--_label)));
    cursor: pointer;
    font-size: 1em;
    list-style-type: none;
    padding: 0.5em;
    transition:
      background 250ms,
      color 250ms;
  }

  :where([styled-mode]) .highcharts-menu-item:hover {
    background: var(--highcharts-neutral-color-5, var(--_bg));
  }

  /* Breadcrumbs */
  :where([styled-mode]) .highcharts-breadcrumbs-button {
    fill: none;
    stroke-width: 0;
    cursor: pointer;
  }

  :where([styled-mode]) .highcharts-breadcrumbs-separator {
    fill: var(--highcharts-neutral-color-60, var(--_secondary-label));
  }

  /* Drilldown module */
  :where([styled-mode]) .highcharts-drilldown-point {
    cursor: pointer;
  }

  :where([styled-mode]) .highcharts-drilldown-data-label text,
  :where([styled-mode]) text.highcharts-drilldown-data-label,
  :where([styled-mode]) .highcharts-drilldown-axis-label {
    cursor: pointer;
    fill: var(--highcharts-highlight-color-100, var(--vaadin-charts-button-label, var(--_label)));
    font-weight: bold;
    text-decoration: underline;
  }

  /* No-data module */
  :where([styled-mode]) .highcharts-no-data text {
    font-weight: bold;
    font-size: 1em;
    fill: var(--highcharts-neutral-color-60, var(--_secondary-label));
  }

  /* Drag-panes module */
  :where([styled-mode]) .highcharts-axis-resizer {
    cursor: ns-resize;
    stroke: var(--highcharts-neutral-color-100, black);
    stroke-width: 2px;
  }

  /* Bullet type series */
  :where([styled-mode]) .highcharts-bullet-target {
    stroke-width: 0;
  }

  /* Lineargauge type series */
  :where([styled-mode]) .highcharts-lineargauge-target {
    stroke-width: 1px;
    stroke: var(
      --highcharts-neutral-color-80,
      color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 60%, transparent)
    );
  }

  :where([styled-mode]) .highcharts-lineargauge-target-line {
    stroke-width: 1px;
    stroke: var(
      --highcharts-neutral-color-80,
      color-mix(in srgb, var(--vaadin-charts-contrast, var(--_label)) 60%, transparent)
    );
  }

  /* Advanced annotations module */
  :where([styled-mode]) .highcharts-fibonacci-background-0,
  :where([styled-mode]) .highcharts-pitchfork-inner-background,
  :where([styled-mode]) .highcharts-measure-background {
    fill: var(--highcharts-annotation-color-0);
  }

  :where([styled-mode]) .highcharts-fibonacci-background-1 {
    fill: var(--highcharts-annotation-color-1);
  }

  :where([styled-mode]) .highcharts-fibonacci-background-2 {
    fill: var(--highcharts-annotation-color-2);
  }

  :where([styled-mode]) .highcharts-fibonacci-background-3,
  :where([styled-mode]) .highcharts-pitchfork-outer-background {
    fill: var(--highcharts-annotation-color-3);
  }

  :where([styled-mode]) .highcharts-fibonacci-background-4 {
    fill: var(--highcharts-annotation-color-4);
  }

  :where([styled-mode]) .highcharts-fibonacci-background-5 {
    fill: var(--highcharts-annotation-color-5);
  }

  :where([styled-mode]) .highcharts-fibonacci-line {
    stroke: var(--highcharts-neutral-color-40);
  }

  :where([styled-mode]) .highcharts-crooked-lines,
  :where([styled-mode]) .highcharts-tunnel-lines,
  :where([styled-mode]) .highcharts-infinity-lines,
  :where([styled-mode]) .highcharts-timecycles-lines,
  :where([styled-mode]) .highcharts-fibonacci-timezones-lines,
  :where([styled-mode]) .highcharts-pitchfork-lines,
  :where([styled-mode]) .highcharts-vertical-line,
  :where([styled-mode]) .highcharts-measure-crosshair-x,
  :where([styled-mode]) .highcharts-measure-crosshair-y {
    stroke: var(--highcharts-neutral-color-100);
    stroke-opacity: 0.75;
    fill: none;
  }

  :where([styled-mode]) .highcharts-measure-crosshair-x,
  :where([styled-mode]) .highcharts-measure-crosshair-y {
    stroke-dasharray: 1, 3;
  }

  :where([styled-mode]) .highcharts-tunnel-background {
    fill: var(--highcharts-color-0);
  }

  :where([styled-mode]) .highcharts-annotation-shapes {
    cursor: move;
  }

  :where([styled-mode]) .highcharts-basic-shape {
    fill: var(--highcharts-neutral-color-100);
    stroke: var(--highcharts-neutral-color-100);
    opacity: 0.74;
  }

  /* Annotations module */

  :where([styled-mode]) .highcharts-annotation-label-box {
    stroke-width: 1px;
    stroke: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
    fill: var(--highcharts-neutral-color-100, var(--vaadin-charts-contrast, var(--_label)));
    fill-opacity: 0.75;
  }

  :where([styled-mode]) .highcharts-annotation-label text {
    fill: var(--highcharts-neutral-color-10, var(--_label));
    font-size: 1em;
  }

  /* A11y module */
  :where([styled-mode]) .highcharts-a11y-proxy-element {
    border-width: 0;
    background-color: transparent;
    cursor: pointer;
    outline: none;
    opacity: 0.001;
    z-index: 999;
    overflow: hidden;
    padding: 0;
    margin: 0;
    display: block;
    position: absolute;
  }

  :where([styled-mode]) .highcharts-a11y-proxy-group li {
    list-style: none;
  }

  :where([styled-mode]) .highcharts-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    white-space: nowrap;
    clip: rect(1px, 1px, 1px, 1px);
    margin-top: -3px;
    opacity: 0.01;
  }

  :where([styled-mode]) .highcharts-a11y-invisible {
    visibility: hidden;
  }

  :where([styled-mode]) .highcharts-a11y-proxy-container,
  :where([styled-mode]) .highcharts-a11y-proxy-container-before,
  :where([styled-mode]) .highcharts-a11y-proxy-container-after {
    position: absolute;
    white-space: nowrap;
  }

  :where([styled-mode]) g.highcharts-series,
  :where([styled-mode]) .highcharts-markers,
  :where([styled-mode]) .highcharts-point {
    outline: none;
  }

  /* Gantt */
  :where([styled-mode]) .highcharts-treegrid-node-collapsed,
  :where([styled-mode]) .highcharts-treegrid-node-expanded {
    cursor: pointer;
  }

  :where([styled-mode]) .highcharts-point-connecting-path {
    fill: none;
  }

  :where([styled-mode]) .highcharts-grid-axis .highcharts-tick {
    stroke: var(--highcharts-neutral-color-20, var(--_grid-line));
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-grid-axis .highcharts-axis-line {
    stroke: var(--highcharts-neutral-color-20, var(--_grid-line));
    stroke-width: 1px;
  }

  :where([styled-mode]) .highcharts-gantt-series .highcharts-partfill-overlay {
    fill: hsla(0, 0%, 0%, 0.3);
    stroke: hsla(0, 0%, 0%, 0.3);
  }

  /* RTL styles */
  :host([dir='rtl']) :where([styled-mode]) .highcharts-container {
    text-align: right;
  }

  :host([dir='rtl']) :where([styled-mode]) input.highcharts-range-selector {
    left: auto;
    right: -9em;
  }

  :host([dir='rtl']) :where([styled-mode]) .highcharts-menu {
    box-shadow: -3px 3px 10px #888;
  }
`;
var Globals;
(function(Globals2) {
  Globals2.SVG_NS = "http://www.w3.org/2000/svg", Globals2.product = "Highcharts", Globals2.version = "12.2.0", Globals2.win = typeof window !== "undefined" ? window : {}, // eslint-disable-line node/no-unsupported-features/es-builtins
  Globals2.doc = Globals2.win.document, Globals2.svg = !!Globals2.doc?.createElementNS?.(Globals2.SVG_NS, "svg")?.createSVGRect, Globals2.pageLang = Globals2.doc?.documentElement?.closest("[lang]")?.lang, Globals2.userAgent = Globals2.win.navigator?.userAgent || "", Globals2.isChrome = Globals2.win.chrome, Globals2.isFirefox = Globals2.userAgent.indexOf("Firefox") !== -1, Globals2.isMS = /(edge|msie|trident)/i.test(Globals2.userAgent) && !Globals2.win.opera, Globals2.isSafari = !Globals2.isChrome && Globals2.userAgent.indexOf("Safari") !== -1, Globals2.isTouchDevice = /(Mobile|Android|Windows Phone)/.test(Globals2.userAgent), Globals2.isWebKit = Globals2.userAgent.indexOf("AppleWebKit") !== -1, Globals2.deg2rad = Math.PI * 2 / 360, Globals2.marginNames = [
    "plotTop",
    "marginRight",
    "marginBottom",
    "plotLeft"
  ], Globals2.noop = function() {
  }, Globals2.supportsPassiveEvents = (function() {
    let supportsPassive = false;
    if (!Globals2.isMS) {
      const opts = Object.defineProperty({}, "passive", {
        get: function() {
          supportsPassive = true;
        }
      });
      if (Globals2.win.addEventListener && Globals2.win.removeEventListener) {
        Globals2.win.addEventListener("testPassive", Globals2.noop, opts);
        Globals2.win.removeEventListener("testPassive", Globals2.noop, opts);
      }
    }
    return supportsPassive;
  })();
  Globals2.charts = [];
  Globals2.composed = [];
  Globals2.dateFormats = {};
  Globals2.seriesTypes = {};
  Globals2.symbolSizes = {};
  Globals2.chartCount = 0;
})(Globals || (Globals = {}));
const Highcharts = Globals;
const { charts: charts$4, doc: doc$s, win: win$h } = Highcharts;
function error$b(code, stop2, chart, params2) {
  const severity = stop2 ? "Highcharts error" : "Highcharts warning";
  if (code === 32) {
    code = `${severity}: Deprecated member`;
  }
  const isCode = isNumber$1d(code);
  let message2 = isCode ? `${severity} #${code}: www.highcharts.com/errors/${code}/` : code.toString();
  const defaultHandler = function() {
    if (stop2) {
      throw new Error(message2);
    }
    if (win$h.console && error$b.messages.indexOf(message2) === -1) {
      console.warn(message2);
    }
  };
  if (typeof params2 !== "undefined") {
    let additionalMessages = "";
    if (isCode) {
      message2 += "?";
    }
    objectEach$z(params2, function(value, key2) {
      additionalMessages += `
 - ${key2}: ${value}`;
      if (isCode) {
        message2 += encodeURI(key2) + "=" + encodeURI(value);
      }
    });
    message2 += additionalMessages;
  }
  fireEvent$N(Highcharts, "displayError", { chart, code, message: message2, params: params2 }, defaultHandler);
  error$b.messages.push(message2);
}
(function(error2) {
  error2.messages = [];
})(error$b || (error$b = {}));
function merge$1K(extendOrSource, ...sources) {
  let i, args = [extendOrSource, ...sources], ret = {};
  const doCopy = function(copy, original) {
    if (typeof copy !== "object") {
      copy = {};
    }
    objectEach$z(original, function(value, key2) {
      if (key2 === "__proto__" || key2 === "constructor") {
        return;
      }
      if (isObject$p(value, true) && !isClass(value) && !isDOMElement(value)) {
        copy[key2] = doCopy(copy[key2] || {}, value);
      } else {
        copy[key2] = original[key2];
      }
    });
    return copy;
  };
  if (extendOrSource === true) {
    ret = args[1];
    args = Array.prototype.slice.call(args, 2);
  }
  const len = args.length;
  for (i = 0; i < len; i++) {
    ret = doCopy(ret, args[i]);
  }
  return ret;
}
function clamp$o(value, min2, max2) {
  return value > min2 ? value < max2 ? value : max2 : min2;
}
function crisp$g(value, lineWidth = 0, inverted) {
  const mod = lineWidth % 2 / 2, inverter = inverted ? -1 : 1;
  return (Math.round(value * inverter - mod) + mod) * inverter;
}
function diffObjects$5(newer, older, keepOlder, collectionsWithUpdate) {
  const ret = {};
  function diff(newer2, older2, ret2, depth) {
    const keeper = keepOlder ? older2 : newer2;
    objectEach$z(newer2, function(newerVal, key2) {
      if (!depth && collectionsWithUpdate && collectionsWithUpdate.indexOf(key2) > -1 && older2[key2]) {
        newerVal = splat$n(newerVal);
        ret2[key2] = [];
        for (let i = 0; i < Math.max(newerVal.length, older2[key2].length); i++) {
          if (older2[key2][i]) {
            if (newerVal[i] === void 0) {
              ret2[key2][i] = older2[key2][i];
            } else {
              ret2[key2][i] = {};
              diff(newerVal[i], older2[key2][i], ret2[key2][i], depth + 1);
            }
          }
        }
      } else if (isObject$p(newerVal, true) && !newerVal.nodeType) {
        ret2[key2] = isArray$s(newerVal) ? [] : {};
        diff(newerVal, older2[key2] || {}, ret2[key2], depth + 1);
        if (Object.keys(ret2[key2]).length === 0 && // Except colorAxis which is a special case where the empty
        // object means it is enabled. Which is unfortunate and we
        // should try to find a better way.
        !(key2 === "colorAxis" && depth === 0)) {
          delete ret2[key2];
        }
      } else if (newer2[key2] !== older2[key2] || // If the newer key is explicitly undefined, keep it (#10525)
      key2 in newer2 && !(key2 in older2)) {
        if (key2 !== "__proto__" && key2 !== "constructor") {
          ret2[key2] = keeper[key2];
        }
      }
    });
  }
  diff(newer, older, ret, 0);
  return ret;
}
function pInt$8(s, mag) {
  return parseInt(s, mag || 10);
}
function isString$l(s) {
  return typeof s === "string";
}
function isArray$s(obj) {
  const str = Object.prototype.toString.call(obj);
  return str === "[object Array]" || str === "[object Array Iterator]";
}
function isObject$p(obj, strict) {
  return !!obj && typeof obj === "object" && (!strict || !isArray$s(obj));
}
function isDOMElement(obj) {
  return isObject$p(obj) && typeof obj.nodeType === "number";
}
function isClass(obj) {
  const c = obj?.constructor;
  return !!(isObject$p(obj, true) && !isDOMElement(obj) && (c?.name && c.name !== "Object"));
}
function isNumber$1d(n) {
  return typeof n === "number" && !isNaN(n) && n < Infinity && n > -Infinity;
}
function erase$c(arr, item) {
  let i = arr.length;
  while (i--) {
    if (arr[i] === item) {
      arr.splice(i, 1);
      break;
    }
  }
}
function insertItem$2(item, collection) {
  const indexOption = item.options.index, length = collection.length;
  let i;
  for (
    // Internal item (navigator) should always be pushed to the end
    i = item.options.isInternal ? length : 0;
    i < length + 1;
    i++
  ) {
    if (
      // No index option, reached the end of the collection,
      // equivalent to pushing
      !collection[i] || // Handle index option, the element to insert has lower index
      isNumber$1d(indexOption) && indexOption < pick$1S(collection[i].options.index, collection[i]._i) || // Insert the new item before other internal items
      // (navigator)
      collection[i].options.isInternal
    ) {
      collection.splice(i, 0, item);
      break;
    }
  }
  return i;
}
function pushUnique$B(array, item) {
  return array.indexOf(item) < 0 && !!array.push(item);
}
function defined$1h(obj) {
  return typeof obj !== "undefined" && obj !== null;
}
function attr$f(elem, keyOrAttribs, value) {
  const isGetter = isString$l(keyOrAttribs) && !defined$1h(value);
  let ret;
  const attrSingle = (value2, key2) => {
    if (defined$1h(value2)) {
      elem.setAttribute(key2, value2);
    } else if (isGetter) {
      ret = elem.getAttribute(key2);
      if (!ret && key2 === "class") {
        ret = elem.getAttribute(key2 + "Name");
      }
    } else {
      elem.removeAttribute(key2);
    }
  };
  if (isString$l(keyOrAttribs)) {
    attrSingle(value, keyOrAttribs);
  } else {
    objectEach$z(keyOrAttribs, attrSingle);
  }
  return ret;
}
function splat$n(obj) {
  return isArray$s(obj) ? obj : [obj];
}
function syncTimeout$c(fn, delay, context) {
  if (delay > 0) {
    return setTimeout(fn, delay, context);
  }
  fn.call(0, context);
  return -1;
}
function internalClearTimeout(id) {
  if (defined$1h(id)) {
    clearTimeout(id);
  }
}
function extend$1u(a, b) {
  let n;
  if (!a) {
    a = {};
  }
  for (n in b) {
    a[n] = b[n];
  }
  return a;
}
function pick$1S() {
  const args = arguments;
  const length = args.length;
  for (let i = 0; i < length; i++) {
    const arg = args[i];
    if (typeof arg !== "undefined" && arg !== null) {
      return arg;
    }
  }
}
function css$g(el, styles) {
  extend$1u(el.style, styles);
}
function createElement$e(tag, attribs, styles, parent, nopad) {
  const el = doc$s.createElement(tag);
  if (attribs) {
    extend$1u(el, attribs);
  }
  if (nopad) {
    css$g(el, { padding: "0", border: "none", margin: "0" });
  }
  if (styles) {
    css$g(el, styles);
  }
  if (parent) {
    parent.appendChild(el);
  }
  return el;
}
function extendClass$1(parent, members) {
  const obj = (function() {
  });
  obj.prototype = new parent();
  extend$1u(obj.prototype, members);
  return obj;
}
function pad$1(number, length, padder) {
  return new Array((length || 2) + 1 - String(number).replace("-", "").length).join(padder || "0") + number;
}
function relativeLength$i(value, base2, offset2) {
  return /%$/.test(value) ? base2 * parseFloat(value) / 100 + (offset2 || 0) : parseFloat(value);
}
function replaceNested$3(text, ...replacements) {
  let previous, replacement;
  do {
    previous = text;
    for (replacement of replacements) {
      text = text.replace(replacement[0], replacement[1]);
    }
  } while (text !== previous);
  return text;
}
function wrap$g(obj, method, func) {
  const proceed = obj[method];
  obj[method] = function() {
    const outerArgs = arguments, scope = this;
    return func.apply(this, [
      function() {
        return proceed.apply(scope, arguments.length ? arguments : outerArgs);
      }
    ].concat([].slice.call(arguments)));
  };
}
function getMagnitude$1(num) {
  return Math.pow(10, Math.floor(Math.log(num) / Math.LN10));
}
function normalizeTickInterval$3(interval, multiples, magnitude, allowDecimals, hasTickAmount) {
  let i, retInterval = interval;
  magnitude = pick$1S(magnitude, getMagnitude$1(interval));
  const normalized = interval / magnitude;
  if (!multiples) {
    multiples = hasTickAmount ? (
      // Finer grained ticks when the tick amount is hard set, including
      // when alignTicks is true on multiple axes (#4580).
      [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10]
    ) : (
      // Else, let ticks fall on rounder numbers
      [1, 2, 2.5, 5, 10]
    );
    if (allowDecimals === false) {
      if (magnitude === 1) {
        multiples = multiples.filter(function(num) {
          return num % 1 === 0;
        });
      } else if (magnitude <= 0.1) {
        multiples = [1 / magnitude];
      }
    }
  }
  for (i = 0; i < multiples.length; i++) {
    retInterval = multiples[i];
    if (hasTickAmount && retInterval * magnitude >= interval || !hasTickAmount && normalized <= (multiples[i] + (multiples[i + 1] || multiples[i])) / 2) {
      break;
    }
  }
  retInterval = correctFloat$g(retInterval * magnitude, -Math.round(Math.log(1e-3) / Math.LN10));
  return retInterval;
}
function stableSort$8(arr, sortFunction) {
  const length = arr.length;
  let sortValue, i;
  for (i = 0; i < length; i++) {
    arr[i].safeI = i;
  }
  arr.sort(function(a, b) {
    sortValue = sortFunction(a, b);
    return sortValue === 0 ? a.safeI - b.safeI : sortValue;
  });
  for (i = 0; i < length; i++) {
    delete arr[i].safeI;
  }
}
function arrayMin$9(data) {
  let i = data.length, min2 = data[0];
  while (i--) {
    if (data[i] < min2) {
      min2 = data[i];
    }
  }
  return min2;
}
function arrayMax$b(data) {
  let i = data.length, max2 = data[0];
  while (i--) {
    if (data[i] > max2) {
      max2 = data[i];
    }
  }
  return max2;
}
function destroyObjectProperties$b(obj, except, destructablesOnly) {
  objectEach$z(obj, function(val, n) {
    if (val !== except && val?.destroy) {
      val.destroy();
    }
    if (val?.destroy || !destructablesOnly) {
      delete obj[n];
    }
  });
}
function discardElement$6(element) {
  element?.parentElement?.removeChild(element);
}
function correctFloat$g(num, prec) {
  return num > 1e14 ? num : parseFloat(num.toPrecision(prec || 14));
}
const timeUnits$5 = {
  millisecond: 1,
  second: 1e3,
  minute: 6e4,
  hour: 36e5,
  day: 24 * 36e5,
  week: 7 * 24 * 36e5,
  month: 28 * 24 * 36e5,
  year: 364 * 24 * 36e5
};
Math.easeInOutSine = function(pos) {
  return -0.5 * (Math.cos(Math.PI * pos) - 1);
};
const getAlignFactor$b = (align = "") => ({
  center: 0.5,
  right: 1,
  middle: 0.5,
  bottom: 1
})[align] || 0;
function getClosestDistance$2(arrays, onError) {
  const allowNegative = !onError;
  let closest, loopLength, distance, i;
  arrays.forEach((xData) => {
    if (xData.length > 1) {
      loopLength = xData.length - 1;
      for (i = loopLength; i > 0; i--) {
        distance = xData[i] - xData[i - 1];
        if (distance < 0 && !allowNegative) {
          onError?.();
          onError = void 0;
        } else if (distance && (typeof closest === "undefined" || distance < closest)) {
          closest = distance;
        }
      }
    }
  });
  return closest;
}
function getNestedProperty$4(path, parent) {
  const pathElements = path.split(".");
  while (pathElements.length && defined$1h(parent)) {
    const pathElement = pathElements.shift();
    if (typeof pathElement === "undefined" || pathElement === "__proto__") {
      return;
    }
    if (pathElement === "this") {
      let thisProp;
      if (isObject$p(parent)) {
        thisProp = parent["@this"];
      }
      return thisProp ?? parent;
    }
    const child = parent[pathElement.replace(/[\\'"]/g, "")];
    if (!defined$1h(child) || typeof child === "function" || typeof child.nodeType === "number" || child === win$h) {
      return;
    }
    parent = child;
  }
  return parent;
}
function getStyle$2(el, prop, toInt) {
  let style;
  if (prop === "width") {
    let offsetWidth = Math.min(el.offsetWidth, el.scrollWidth);
    const boundingClientRectWidth = el.getBoundingClientRect?.().width;
    if (boundingClientRectWidth < offsetWidth && boundingClientRectWidth >= offsetWidth - 1) {
      offsetWidth = Math.floor(boundingClientRectWidth);
    }
    return Math.max(
      0,
      // #8377
      offsetWidth - (getStyle$2(el, "padding-left", true) || 0) - (getStyle$2(el, "padding-right", true) || 0)
    );
  }
  if (prop === "height") {
    return Math.max(
      0,
      // #8377
      Math.min(el.offsetHeight, el.scrollHeight) - (getStyle$2(el, "padding-top", true) || 0) - (getStyle$2(el, "padding-bottom", true) || 0)
    );
  }
  const css2 = win$h.getComputedStyle(el, void 0);
  if (css2) {
    style = css2.getPropertyValue(prop);
    if (pick$1S(toInt, prop !== "opacity")) {
      style = pInt$8(style);
    }
  }
  return style;
}
const find$j = Array.prototype.find ? function(arr, callback) {
  return arr.find(callback);
} : (
  // Legacy implementation. PhantomJS, IE <= 11 etc. #7223.
  (function(arr, callback) {
    let i;
    const length = arr.length;
    for (i = 0; i < length; i++) {
      if (callback(arr[i], i)) {
        return arr[i];
      }
    }
  })
);
function offset$1(el) {
  const docElem = doc$s.documentElement, box = el.parentElement || el.parentNode ? el.getBoundingClientRect() : { top: 0, left: 0, width: 0, height: 0 };
  return {
    top: box.top + (win$h.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
    left: box.left + (win$h.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0),
    width: box.width,
    height: box.height
  };
}
function objectEach$z(obj, fn, ctx) {
  for (const key2 in obj) {
    if (Object.hasOwnProperty.call(obj, key2)) {
      fn.call(ctx || obj[key2], obj[key2], key2, obj);
    }
  }
}
function addEvent$1w(el, type, fn, options2 = {}) {
  const owner = typeof el === "function" && el.prototype || el;
  if (!Object.hasOwnProperty.call(owner, "hcEvents")) {
    owner.hcEvents = {};
  }
  const events = owner.hcEvents;
  if (Highcharts.Point && // Without H a dependency loop occurs
  el instanceof Highcharts.Point && el.series && el.series.chart) {
    el.series.chart.runTrackerClick = true;
  }
  const addEventListener = el.addEventListener;
  if (addEventListener) {
    addEventListener.call(el, type, fn, Highcharts.supportsPassiveEvents ? {
      passive: options2.passive === void 0 ? type.indexOf("touch") !== -1 : options2.passive,
      capture: false
    } : false);
  }
  if (!events[type]) {
    events[type] = [];
  }
  const eventObject = {
    fn,
    order: typeof options2.order === "number" ? options2.order : Infinity
  };
  events[type].push(eventObject);
  events[type].sort((a, b) => a.order - b.order);
  return function() {
    removeEvent$d(el, type, fn);
  };
}
function removeEvent$d(el, type, fn) {
  function removeOneEvent(type2, fn2) {
    const removeEventListener = el.removeEventListener;
    if (removeEventListener) {
      removeEventListener.call(el, type2, fn2, false);
    }
  }
  function removeAllEvents(eventCollection) {
    let types, len;
    if (!el.nodeName) {
      return;
    }
    if (type) {
      types = {};
      types[type] = true;
    } else {
      types = eventCollection;
    }
    objectEach$z(types, function(_val, n) {
      if (eventCollection[n]) {
        len = eventCollection[n].length;
        while (len--) {
          removeOneEvent(n, eventCollection[n][len].fn);
        }
      }
    });
  }
  const owner = typeof el === "function" && el.prototype || el;
  if (Object.hasOwnProperty.call(owner, "hcEvents")) {
    const events = owner.hcEvents;
    if (type) {
      const typeEvents = events[type] || [];
      if (fn) {
        events[type] = typeEvents.filter(function(obj) {
          return fn !== obj.fn;
        });
        removeOneEvent(type, fn);
      } else {
        removeAllEvents(events);
        events[type] = [];
      }
    } else {
      removeAllEvents(events);
      delete owner.hcEvents;
    }
  }
}
function fireEvent$N(el, type, eventArguments, defaultFunction) {
  eventArguments = eventArguments || {};
  if (doc$s?.createEvent && (el.dispatchEvent || el.fireEvent && // Enable firing events on Highcharts instance.
  el !== Highcharts)) {
    const e = doc$s.createEvent("Events");
    e.initEvent(type, true, true);
    eventArguments = extend$1u(e, eventArguments);
    if (el.dispatchEvent) {
      el.dispatchEvent(eventArguments);
    } else {
      el.fireEvent(type, eventArguments);
    }
  } else if (el.hcEvents) {
    if (!eventArguments.target) {
      extend$1u(eventArguments, {
        // Attach a simple preventDefault function to skip
        // default handler if called. The built-in
        // defaultPrevented property is not overwritable (#5112)
        preventDefault: function() {
          eventArguments.defaultPrevented = true;
        },
        // Setting target to native events fails with clicking
        // the zoom-out button in Chrome.
        target: el,
        // If the type is not set, we're running a custom event
        // (#2297). If it is set, we're running a browser event.
        type
      });
    }
    const events = [];
    let object = el;
    let multilevel = false;
    while (object.hcEvents) {
      if (Object.hasOwnProperty.call(object, "hcEvents") && object.hcEvents[type]) {
        if (events.length) {
          multilevel = true;
        }
        events.unshift.apply(events, object.hcEvents[type]);
      }
      object = Object.getPrototypeOf(object);
    }
    if (multilevel) {
      events.sort((a, b) => a.order - b.order);
    }
    events.forEach((obj) => {
      if (obj.fn.call(el, eventArguments) === false) {
        eventArguments.preventDefault();
      }
    });
  }
  if (defaultFunction && !eventArguments.defaultPrevented) {
    defaultFunction.call(el, eventArguments);
  }
}
let serialMode;
const uniqueKey$a = (function() {
  const hash2 = Math.random().toString(36).substring(2, 9) + "-";
  let id = 0;
  return function() {
    return "highcharts-" + (serialMode ? "" : hash2) + id++;
  };
})();
function useSerialIds(mode2) {
  return serialMode = pick$1S(mode2, serialMode);
}
function isFunction$6(obj) {
  return typeof obj === "function";
}
function ucfirst$2(s) {
  return isString$l(s) ? s.substring(0, 1).toUpperCase() + s.substring(1) : String(s);
}
if (win$h.jQuery) {
  win$h.jQuery.fn.highcharts = function() {
    const args = [].slice.call(arguments);
    if (this[0]) {
      if (args[0]) {
        new Highcharts[
          // eslint-disable-line computed-property-spacing, no-new
          // Constructor defaults to Chart
          isString$l(args[0]) ? args.shift() : "Chart"
        ](this[0], args[0], args[1]);
        return this;
      }
      return charts$4[attr$f(this[0], "data-highcharts-chart")];
    }
  };
}
const Utilities = {
  addEvent: addEvent$1w,
  arrayMax: arrayMax$b,
  arrayMin: arrayMin$9,
  attr: attr$f,
  clamp: clamp$o,
  clearTimeout: internalClearTimeout,
  correctFloat: correctFloat$g,
  createElement: createElement$e,
  crisp: crisp$g,
  css: css$g,
  defined: defined$1h,
  destroyObjectProperties: destroyObjectProperties$b,
  diffObjects: diffObjects$5,
  discardElement: discardElement$6,
  erase: erase$c,
  error: error$b,
  extend: extend$1u,
  extendClass: extendClass$1,
  find: find$j,
  fireEvent: fireEvent$N,
  getAlignFactor: getAlignFactor$b,
  getClosestDistance: getClosestDistance$2,
  getMagnitude: getMagnitude$1,
  getNestedProperty: getNestedProperty$4,
  getStyle: getStyle$2,
  insertItem: insertItem$2,
  isArray: isArray$s,
  isClass,
  isDOMElement,
  isFunction: isFunction$6,
  isNumber: isNumber$1d,
  isObject: isObject$p,
  isString: isString$l,
  merge: merge$1K,
  normalizeTickInterval: normalizeTickInterval$3,
  objectEach: objectEach$z,
  offset: offset$1,
  pad: pad$1,
  pick: pick$1S,
  pInt: pInt$8,
  pushUnique: pushUnique$B,
  relativeLength: relativeLength$i,
  removeEvent: removeEvent$d,
  replaceNested: replaceNested$3,
  splat: splat$n,
  stableSort: stableSort$8,
  syncTimeout: syncTimeout$c,
  timeUnits: timeUnits$5,
  ucfirst: ucfirst$2,
  uniqueKey: uniqueKey$a,
  useSerialIds,
  wrap: wrap$g
};
const ChartDefaults = {
  /**
   * Default `mapData` for all series, in terms of a GeoJSON or TopoJSON
   * object. If set to a string, it functions as an index into the
   * `Highcharts.maps` array.
   *
   * For picking out individual shapes and geometries to use for each series
   * of the map, see [series.mapData](#series.map.mapData).
   *
   * @sample    maps/demo/geojson
   *            Loading GeoJSON data
   * @sample    maps/chart/topojson
   *            Loading TopoJSON data
   *
   * @type      {string|Array<*>|Highcharts.GeoJSON|Highcharts.TopoJSON}
   * @since     5.0.0
   * @product   highmaps
   * @apioption chart.map
   */
  /**
   * Set lat/lon transformation definitions for the chart. If not defined,
   * these are extracted from the map data.
   *
   * @type      {*}
   * @since     5.0.0
   * @product   highmaps
   * @apioption chart.mapTransforms
   */
  /**
   * When using multiple axes, the ticks of two or more opposite axes
   * will automatically be aligned by adding ticks to the axis or axes
   * with the least ticks, as if `tickAmount` were specified.
   *
   * This can be prevented by setting `alignTicks` to false. If the grid
   * lines look messy, it's a good idea to hide them for the secondary
   * axis by setting `gridLineWidth` to 0.
   *
   * If `startOnTick` or `endOnTick` in the axis options are set to false,
   * then the `alignTicks ` will be disabled for the axis.
   *
   * Disabled for logarithmic axes.
   *
   * @sample {highcharts} highcharts/chart/alignticks-true/
   *         True by default
   * @sample {highcharts} highcharts/chart/alignticks-false/
   *         False
   * @sample {highstock} stock/chart/alignticks-true/
   *         True by default
   * @sample {highstock} stock/chart/alignticks-false/
   *         False
   *
   * @type      {boolean}
   * @default   true
   * @product   highcharts highstock gantt
   * @apioption chart.alignTicks
   */
  /**
   * When using multiple axes, align the thresholds. When this is true, other
   * ticks will also be aligned.
   *
   * Note that for line series and some other series types, the `threshold`
   * option is set to `null` by default. This will in turn cause their y-axis
   * to not have a threshold. In order to avoid that, set the series
   * `threshold` to 0 or another number.
   *
   * If `startOnTick` or `endOnTick` in the axis options are set to false, or
   * if the axis is logarithmic, the threshold will not be aligned.
   *
   * @sample {highcharts} highcharts/chart/alignthresholds/ Set to true
   *
   * @since 10.0.0
   * @product   highcharts highstock gantt
   * @apioption chart.alignThresholds
   */
  alignThresholds: false,
  /**
   * Set the overall animation for all chart updating. Animation can be
   * disabled throughout the chart by setting it to false here. It can
   * be overridden for each individual API method as a function parameter.
   * The only animation not affected by this option is the initial series
   * animation, see [plotOptions.series.animation](
   * #plotOptions.series.animation).
   *
   * The animation can either be set as a boolean or a configuration
   * object. If `true`, it will use the 'swing' jQuery easing and a
   * duration of 500 ms. If used as a configuration object, the following
   * properties are supported:
   *
   * - `defer`: The animation delay time in milliseconds.
   *
   * - `duration`: The duration of the animation in milliseconds.
   *
   * - `easing`: A string reference to an easing function set on the
   *   `Math` object. See
   *   [the easing demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-animation-easing/).
   *
   * When zooming on a series with less than 100 points, the chart redraw
   * will be done with animation, but in case of more data points, it is
   * necessary to set this option to ensure animation on zoom.
   *
   * @sample {highcharts} highcharts/chart/animation-none/
   *         Updating with no animation
   * @sample {highcharts} highcharts/chart/animation-duration/
   *         With a longer duration
   * @sample {highcharts} highcharts/chart/animation-easing/
   *         With a jQuery UI easing
   * @sample {highmaps} maps/chart/animation-none/
   *         Updating with no animation
   * @sample {highmaps} maps/chart/animation-duration/
   *         With a longer duration
   *
   * @type      {boolean|Partial<Highcharts.AnimationOptionsObject>}
   * @default   true
   * @apioption chart.animation
   */
  /**
   * A CSS class name to apply to the charts container `div`, allowing
   * unique CSS styling for each chart.
   *
   * @type      {string}
   * @apioption chart.className
   */
  /**
   * Event listeners for the chart.
   *
   * @apioption chart.events
   */
  /**
   * Fires when a series is added to the chart after load time, using the
   * `addSeries` method. One parameter, `event`, is passed to the
   * function, containing common event information. Through
   * `event.options` you can access the series options that were passed to
   * the `addSeries` method. Returning false prevents the series from
   * being added.
   *
   * @sample {highcharts} highcharts/chart/events-addseries/
   *         Alert on add series
   * @sample {highstock} stock/chart/events-addseries/
   *         Alert on add series
   *
   * @type      {Highcharts.ChartAddSeriesCallbackFunction}
   * @since     1.2.0
   * @context   Highcharts.Chart
   * @apioption chart.events.addSeries
   */
  /**
   * Fires when clicking on the plot background. One parameter, `event`,
   * is passed to the function, containing common event information.
   *
   * Information on the clicked spot can be found through `event.xAxis`
   * and `event.yAxis`, which are arrays containing the axes of each
   * dimension and each axis' value at the clicked spot. The primary axes
   * are `event.xAxis[0]` and `event.yAxis[0]`. Remember the unit of a
   * datetime axis is milliseconds since 1970-01-01 00:00:00.
   *
   * ```js
   * click: function(e) {
   *     console.log(
   *         Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', e.xAxis[0].value),
   *         e.yAxis[0].value
   *     )
   * }
   * ```
   *
   * @sample {highcharts} highcharts/chart/events-click/
   *         Alert coordinates on click
   * @sample {highcharts} highcharts/chart/events-container/
   *         Alternatively, attach event to container
   * @sample {highstock} stock/chart/events-click/
   *         Alert coordinates on click
   * @sample {highstock} highcharts/chart/events-container/
   *         Alternatively, attach event to container
   * @sample {highmaps} maps/chart/events-click/
   *         Record coordinates on click
   * @sample {highmaps} highcharts/chart/events-container/
   *         Alternatively, attach event to container
   *
   * @type      {Highcharts.ChartClickCallbackFunction}
   * @since     1.2.0
   * @context   Highcharts.Chart
   * @apioption chart.events.click
   */
  /**
   * Fires when the chart is finished loading. Since v4.2.2, it also waits
   * for images to be loaded, for example from point markers. One
   * parameter, `event`, is passed to the function, containing common
   * event information.
   *
   * There is also a second parameter to the chart constructor where a
   * callback function can be passed to be executed on chart.load.
   *
   * @sample {highcharts} highcharts/chart/events-load/
   *         Alert on chart load
   * @sample {highcharts} highcharts/chart/events-render/
   *         Load vs Redraw vs Render
   * @sample {highstock} stock/chart/events-load/
   *         Alert on chart load
   * @sample {highmaps} maps/chart/events-load/
   *         Add series on chart load
   *
   * @type      {Highcharts.ChartLoadCallbackFunction}
   * @context   Highcharts.Chart
   * @apioption chart.events.load
   */
  /**
   * Fires when the chart is redrawn, either after a call to
   * `chart.redraw()` or after an axis, series or point is modified with
   * the `redraw` option set to `true`. One parameter, `event`, is passed
   * to the function, containing common event information.
   *
   * @sample {highcharts} highcharts/chart/events-redraw/
   *         Alert on chart redraw
   * @sample {highcharts} highcharts/chart/events-render/
   *         Load vs Redraw vs Render
   * @sample {highstock} stock/chart/events-redraw/
   *         Alert on chart redraw when adding a series or moving the
   *         zoomed range
   * @sample {highmaps} maps/chart/events-redraw/
   *         Set subtitle on chart redraw
   *
   * @type      {Highcharts.ChartRedrawCallbackFunction}
   * @since     1.2.0
   * @context   Highcharts.Chart
   * @apioption chart.events.redraw
   */
  /**
   * Fires after initial load of the chart (directly after the `load`
   * event), and after each redraw (directly after the `redraw` event).
   *
   * @sample {highcharts} highcharts/chart/events-render/
   *         Load vs Redraw vs Render
   *
   * @type      {Highcharts.ChartRenderCallbackFunction}
   * @since     5.0.7
   * @context   Highcharts.Chart
   * @apioption chart.events.render
   */
  /**
   * Fires when an area of the chart has been selected. Selection is
   * enabled by setting the chart's zoomType. One parameter, `event`, is
   * passed to the function, containing common event information. The
   * default action for the selection event is to zoom the chart to the
   * selected area. It can be prevented by calling
   * `event.preventDefault()` or return false.
   *
   * Information on the selected area can be found through `event.xAxis`
   * and `event.yAxis`, which are arrays containing the axes of each
   * dimension and each axis' min and max values. The primary axes are
   * `event.xAxis[0]` and `event.yAxis[0]`. Remember the unit of a
   * datetime axis is milliseconds since 1970-01-01 00:00:00.
   *
   * ```js
   * selection: function(event) {
   *     // log the min and max of the primary, datetime x-axis
   *     console.log(
   *         Highcharts.dateFormat(
   *             '%Y-%m-%d %H:%M:%S',
   *             event.xAxis[0].min
   *         ),
   *         Highcharts.dateFormat(
   *             '%Y-%m-%d %H:%M:%S',
   *             event.xAxis[0].max
   *         )
   *     );
   *     // log the min and max of the y axis
   *     console.log(event.yAxis[0].min, event.yAxis[0].max);
   * }
   * ```
   *
   * @sample {highcharts} highcharts/chart/events-selection/
   *         Report on selection and reset
   * @sample {highcharts} highcharts/chart/events-selection-points/
   *         Select a range of points through a drag selection
   * @sample {highstock} stock/chart/events-selection/
   *         Report on selection and reset
   * @sample {highstock} highcharts/chart/events-selection-points/
   *         Select a range of points through a drag selection
   *         (Highcharts)
   *
   * @type      {Highcharts.ChartSelectionCallbackFunction}
   * @apioption chart.events.selection
   */
  /**
   * The margin between the outer edge of the chart and the plot area.
   * The numbers in the array designate top, right, bottom and left
   * respectively. Use the options `marginTop`, `marginRight`,
   * `marginBottom` and `marginLeft` for shorthand setting of one option.
   *
   * By default there is no margin. The actual space is dynamically
   * calculated from the offset of axis labels, axis title, title,
   * subtitle and legend in addition to the `spacingTop`, `spacingRight`,
   * `spacingBottom` and `spacingLeft` options.
   *
   * @sample {highcharts} highcharts/chart/margins-zero/
   *         Zero margins
   * @sample {highstock} stock/chart/margin-zero/
   *         Zero margins
   *
   * @type      {number|Array<number>}
   * @apioption chart.margin
   */
  /**
   * The margin between the bottom outer edge of the chart and the plot
   * area. Use this to set a fixed pixel value for the margin as opposed
   * to the default dynamic margin. See also `spacingBottom`.
   *
   * @sample {highcharts} highcharts/chart/marginbottom/
   *         100px bottom margin
   * @sample {highstock} stock/chart/marginbottom/
   *         100px bottom margin
   * @sample {highmaps} maps/chart/margin/
   *         100px margins
   *
   * @type      {number}
   * @since     2.0
   * @apioption chart.marginBottom
   */
  /**
   * The margin between the left outer edge of the chart and the plot
   * area. Use this to set a fixed pixel value for the margin as opposed
   * to the default dynamic margin. See also `spacingLeft`.
   *
   * @sample {highcharts} highcharts/chart/marginleft/
   *         150px left margin
   * @sample {highstock} stock/chart/marginleft/
   *         150px left margin
   * @sample {highmaps} maps/chart/margin/
   *         100px margins
   *
   * @type      {number}
   * @since     2.0
   * @apioption chart.marginLeft
   */
  /**
   * The margin between the right outer edge of the chart and the plot
   * area. Use this to set a fixed pixel value for the margin as opposed
   * to the default dynamic margin. See also `spacingRight`.
   *
   * @sample {highcharts} highcharts/chart/marginright/
   *         100px right margin
   * @sample {highstock} stock/chart/marginright/
   *         100px right margin
   * @sample {highmaps} maps/chart/margin/
   *         100px margins
   *
   * @type      {number}
   * @since     2.0
   * @apioption chart.marginRight
   */
  /**
   * The margin between the top outer edge of the chart and the plot area.
   * Use this to set a fixed pixel value for the margin as opposed to
   * the default dynamic margin. See also `spacingTop`.
   *
   * @sample {highcharts} highcharts/chart/margintop/ 100px top margin
   * @sample {highstock} stock/chart/margintop/
   *         100px top margin
   * @sample {highmaps} maps/chart/margin/
   *         100px margins
   *
   * @type      {number}
   * @since     2.0
   * @apioption chart.marginTop
   */
  /**
   * Callback function to override the default function that formats all
   * the numbers in the chart. Returns a string with the formatted number.
   *
   * @sample highcharts/members/highcharts-numberformat
   *      Arabic digits in Highcharts
   * @type {Highcharts.NumberFormatterCallbackFunction}
   * @since 8.0.0
   * @apioption chart.numberFormatter
   */
  /**
   * When a chart with an x and a y-axis is rendered, we first pre-render the
   * labels of both in order to measure them. Then, if either of the axis
   * labels take up so much space that it significantly affects the length of
   * the other axis, we repeat the process.
   *
   * By default we stop at two axis layout runs, but it may be that the second
   * run also alter the space required by either axis, for example if it
   * causes the labels to rotate. In this situation, a subsequent redraw of
   * the chart may cause the tick and label placement to change for apparently
   * no reason.
   *
   * Use the `axisLayoutRuns` option to set the maximum allowed number of
   * repetitions. But keep in mind that the default value of 2 is set because
   * every run costs performance time.
   *
   * **Note:** Changing that option to higher than the default might decrease
   * performance significantly, especially with bigger sets of data.
   *
   * @type      {number}
   * @default   2
   * @since     11.3.0
   * @apioption chart.axisLayoutRuns
   */
  /**
   * Allows setting a key to switch between zooming and panning. Can be
   * one of `alt`, `ctrl`, `meta` (the command key on Mac and Windows
   * key on Windows) or `shift`. The keys are mapped directly to the key
   * properties of the click event argument (`event.altKey`,
   * `event.ctrlKey`, `event.metaKey` and `event.shiftKey`).
   *
   * @type       {string}
   * @since      4.0.3
   * @product    highcharts gantt
   * @validvalue ["alt", "ctrl", "meta", "shift"]
   * @apioption  chart.panKey
   */
  /**
   * Allow panning in a chart. Best used with [panKey](#chart.panKey)
   * to combine zooming and panning.
   *
   * On touch devices, when the [tooltip.followTouchMove](
   * #tooltip.followTouchMove) option is `true` (default), panning
   * requires two fingers. To allow panning with one finger, set
   * `followTouchMove` to `false`.
   *
   * @sample  {highcharts} highcharts/chart/pankey/ Zooming and panning
   * @sample  {highstock} stock/chart/panning/ Zooming and xy panning
   */
  panning: {
    /**
     * Enable or disable chart panning.
     *
     * @type      {boolean}
     * @default   {highcharts} false
     * @default   {highstock|highmaps} true
     */
    enabled: false,
    /**
     * Decides in what dimensions the user can pan the chart. Can be
     * one of `x`, `y`, or `xy`.
     *
     * During panning, all axes will behave as if
     * [`startOnTick`](#yAxis.startOnTick) and
     * [`endOnTick`](#yAxis.endOnTick) were set to `false`. After the
     * panning action is finished, the axes will adjust to their actual
     * settings.
     *
     * @sample {highcharts} highcharts/chart/panning-type
     *         Zooming and xy panning
     *
     * @declare    Highcharts.OptionsChartPanningTypeValue
     * @type       {string}
     * @validvalue ["x", "y", "xy"]
     * @product    highcharts highstock gantt
     */
    type: "x"
  },
  /**
   * Equivalent to [zoomType](#chart.zoomType), but for multitouch
   * gestures only. By default, the `pinchType` is the same as the
   * `zoomType` setting. However, pinching can be enabled separately in
   * some cases, for example in stock charts where a mouse drag pans the
   * chart, while pinching is enabled. When [tooltip.followTouchMove](
   * #tooltip.followTouchMove) is true, pinchType only applies to
   * two-finger touches.
   *
   * @type       {string}
   * @default    {highcharts} undefined
   * @default    {highstock} undefined
   * @since      3.0
   * @product    highcharts highstock gantt
   * @deprecated
   * @validvalue ["x", "y", "xy"]
   * @apioption  chart.pinchType
   */
  /**
   * Whether to apply styled mode. When in styled mode, no presentational
   * attributes or CSS are applied to the chart SVG. Instead, CSS rules
   * are required to style the chart. The default style sheet is
   * available from `https://code.highcharts.com/css/highcharts.css`.
   *
   * [Read more in the docs](https://www.highcharts.com/docs/chart-design-and-style/style-by-css)
   * on what classes and variables are available.
   *
   * @sample highcharts/css/colors
   *         Color theming with CSS
   * @sample highcharts/css/prefers-color-scheme
   *         Dynamic theme based on system settings
   * @type       {boolean}
   * @default    false
   * @since      7.0
   * @apioption  chart.styledMode
   */
  styledMode: false,
  /**
   * The corner radius of the outer chart border.
   *
   * @sample {highcharts} highcharts/chart/borderradius/
   *         20px radius
   * @sample {highstock} stock/chart/border/
   *         10px radius
   * @sample {highmaps} maps/chart/border/
   *         Border options
   *
   */
  borderRadius: 0,
  /**
   * In styled mode, this sets how many colors the class names
   * should rotate between. With ten colors, series (or points) are
   * given class names like `highcharts-color-0`, `highcharts-color-1`
   * [...] `highcharts-color-9`. The equivalent in non-styled mode
   * is to set colors using the [colors](#colors) setting.
   *
   * @since      5.0.0
   */
  colorCount: 10,
  /**
   * By default, (because of memory and performance reasons) the chart does
   * not copy the data but keeps it as a reference. In some cases, this might
   * result in mutating the original data source. In order to prevent that,
   * set that property to false. Please note that changing that might decrease
   * performance, especially with bigger sets of data.
   *
   * @type       {boolean}
   * @since 10.1.0
   */
  allowMutatingData: true,
  /**
   * If true, the axes will scale to the remaining visible series once
   * one series is hidden. If false, hiding and showing a series will
   * not affect the axes or the other series. For stacks, once one series
   * within the stack is hidden, the rest of the stack will close in
   * around it even if the axis is not affected.
   *
   * @sample {highcharts} highcharts/chart/ignorehiddenseries-true/
   *         True by default
   * @sample {highcharts} highcharts/chart/ignorehiddenseries-false/
   *         False
   * @sample {highcharts} highcharts/chart/ignorehiddenseries-true-stacked/
   *         True with stack
   * @sample {highstock} stock/chart/ignorehiddenseries-true/
   *         True by default
   * @sample {highstock} stock/chart/ignorehiddenseries-false/
   *         False
   *
   * @since   1.2.0
   * @product highcharts highstock gantt
   */
  ignoreHiddenSeries: true,
  /**
   * Whether to invert the axes so that the x axis is vertical and y axis
   * is horizontal. When `true`, the x axis is [reversed](#xAxis.reversed)
   * by default.
   *
   * @productdesc {highcharts}
   * If a bar series is present in the chart, it will be inverted
   * automatically. Inverting the chart doesn't have an effect if there
   * are no cartesian series in the chart.
   *
   * @sample {highcharts} highcharts/chart/inverted/
   *         Inverted line
   * @sample {highstock} stock/navigator/inverted/
   *         Inverted stock chart
   *
   * @type      {boolean}
   * @default   false
   * @product   highcharts highstock gantt
   * @apioption chart.inverted
   */
  /**
   * The distance between the outer edge of the chart and the content,
   * like title or legend, or axis title and labels if present. The
   * numbers in the array designate top, right, bottom and left
   * respectively. Use the options spacingTop, spacingRight, spacingBottom
   * and spacingLeft options for shorthand setting of one option.
   *
   * @type    {Array<number>}
   * @see     [chart.margin](#chart.margin)
   * @default [10, 10, 15, 10]
   * @since   3.0.6
   */
  spacing: [10, 10, 15, 10],
  /**
   * The button that appears after a selection zoom, allowing the user
   * to reset zoom. This option is deprecated in favor of
   * [zooming](#chart.zooming).
   *
   * @since      2.2
   * @deprecated 10.2.1
   */
  resetZoomButton: {
    /**
     * What frame the button placement should be related to. Can be
     * either `plotBox` or `spacingBox`.
     *
     * @sample {highcharts} highcharts/chart/resetzoombutton-relativeto/
     *         Relative to the chart
     * @sample {highstock} highcharts/chart/resetzoombutton-relativeto/
     *         Relative to the chart
     *
     * @type      {Highcharts.ButtonRelativeToValue}
     * @apioption chart.resetZoomButton.relativeTo
     */
    /**
     * A collection of attributes for the button. The object takes SVG
     * attributes like `fill`, `stroke`, `stroke-width` or `r`, the
     * border radius. The theme also supports `style`, a collection of
     * CSS properties for the text. Equivalent attributes for the hover
     * state are given in `theme.states.hover`.
     *
     * @sample {highcharts} highcharts/chart/resetzoombutton-theme/
     *         Theming the button
     * @sample {highstock} highcharts/chart/resetzoombutton-theme/
     *         Theming the button
     *
     * @type {Highcharts.SVGAttributes}
     */
    theme: {
      /**
       * The z-index of the button.
       *
       * @type {number}
       * @apioption chart.resetZoomButton.theme.zIndex
       */
    },
    /**
     * The position of the button.
     *
     * @sample {highcharts} highcharts/chart/resetzoombutton-position/
     *         Above the plot area
     * @sample {highstock} highcharts/chart/resetzoombutton-position/
     *         Above the plot area
     * @sample {highmaps} highcharts/chart/resetzoombutton-position/
     *         Above the plot area
     *
     * @type {Highcharts.AlignObject}
     */
    position: {
      /**
       * The horizontal alignment of the button.
       *
       * @type {number}
       * @apioption chart.resetZoomButton.position.align
       */
      /**
       * The horizontal offset of the button.
       *
       * @type {number}
       * @apioption chart.resetZoomButton.position.x
       */
      /**
       * The vertical alignment of the button.
       *
       * @type      {Highcharts.VerticalAlignValue}
       * @apioption chart.resetZoomButton.position.verticalAlign
       */
      /**
       * The vertical offset of the button.
       *
       * @type {number}
       * @apioption chart.resetZoomButton.position.y
       */
    }
  },
  /**
   * The pixel width of the plot area border.
   *
   * @sample {highcharts} highcharts/chart/plotborderwidth/
   *         1px border
   * @sample {highstock} stock/chart/plotborder/
   *         2px border
   * @sample {highmaps} maps/chart/plotborder/
   *         Plot border options
   *
   * @type      {number}
   * @default   0
   * @apioption chart.plotBorderWidth
   */
  /**
   * Whether to apply a drop shadow to the plot area. Requires that
   * plotBackgroundColor be set. The shadow can be an object configuration
   * containing `color`, `offsetX`, `offsetY`, `opacity` and `width`.
   *
   * @sample {highcharts} highcharts/chart/plotshadow/
   *         Plot shadow
   * @sample {highstock} stock/chart/plotshadow/
   *         Plot shadow
   * @sample {highmaps} maps/chart/plotborder/
   *         Plot border options
   *
   * @type      {boolean|Highcharts.ShadowOptionsObject}
   * @default   false
   * @apioption chart.plotShadow
   */
  /**
   * When true, cartesian charts like line, spline, area and column are
   * transformed into the polar coordinate system. This produces _polar
   * charts_, also known as _radar charts_.
   *
   * @sample {highcharts} highcharts/demo/polar/
   *         Polar chart
   * @sample {highcharts} highcharts/demo/polar-wind-rose/
   *         Wind rose, stacked polar column chart
   * @sample {highcharts} highcharts/demo/polar-spider/
   *         Spider web chart
   * @sample {highcharts} highcharts/parallel-coordinates/polar/
   *         Star plot, multivariate data in a polar chart
   *
   * @type      {boolean}
   * @default   false
   * @since     2.3.0
   * @product   highcharts
   * @requires  highcharts-more
   * @apioption chart.polar
   */
  /**
   * Whether to reflow the chart to fit the width of the container div
   * on resizing the window.
   *
   * @sample {highcharts} highcharts/chart/reflow-true/
   *         True by default
   * @sample {highcharts} highcharts/chart/reflow-false/
   *         False
   * @sample {highstock} stock/chart/reflow-true/
   *         True by default
   * @sample {highstock} stock/chart/reflow-false/
   *         False
   * @sample {highmaps} maps/chart/reflow-true/
   *         True by default
   * @sample {highmaps} maps/chart/reflow-false/
   *         False
   *
   * @since     2.1
   */
  reflow: true,
  /**
   * The HTML element where the chart will be rendered. If it is a string,
   * the element by that id is used. The HTML element can also be passed
   * by direct reference, or as the first argument of the chart
   * constructor, in which case the option is not needed.
   *
   * @sample {highcharts} highcharts/chart/reflow-true/
   *         String
   * @sample {highcharts} highcharts/chart/renderto-object/
   *         Object reference
   * @sample {highstock} stock/chart/renderto-string/
   *         String
   * @sample {highstock} stock/chart/renderto-object/
   *         Object reference
   *
   * @type      {string|Highcharts.HTMLDOMElement}
   * @apioption chart.renderTo
   */
  /**
   * The background color of the marker square when selecting (zooming
   * in on) an area of the chart.
   *
   * @see In styled mode, the selection marker fill is set with the
   *      `.highcharts-selection-marker` class.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default   rgba(51,92,173,0.25)
   * @since     2.1.7
   * @apioption chart.selectionMarkerFill
   */
  /**
   * Whether to apply a drop shadow to the global series group. This causes
   * all the series to have the same shadow. Contrary to the `series.shadow`
   * option, this prevents items from casting shadows on each other, like for
   * others series in a stack. The shadow can be an object configuration
   * containing `color`, `offsetX`, `offsetY`, `opacity` and `width`.
   *
   * @sample highcharts/chart/seriesgroupshadow/ Shadow
   *
   * @type      {boolean|Highcharts.ShadowOptionsObject}
   * @default   false
   * @apioption chart.shadow
   */
  /**
   * Whether to apply a drop shadow to the outer chart area. Requires
   * that backgroundColor be set. The shadow can be an object
   * configuration containing `color`, `offsetX`, `offsetY`, `opacity` and
   * `width`.
   *
   * @sample {highcharts} highcharts/chart/shadow/
   *         Shadow
   * @sample {highstock} stock/chart/shadow/
   *         Shadow
   * @sample {highmaps} maps/chart/border/
   *         Chart border and shadow
   *
   * @type      {boolean|Highcharts.ShadowOptionsObject}
   * @default   false
   * @apioption chart.shadow
   */
  /**
   * Whether to show the axes initially. This only applies to empty charts
   * where series are added dynamically, as axes are automatically added
   * to cartesian series.
   *
   * @sample {highcharts} highcharts/chart/showaxes-false/
   *         False by default
   * @sample {highcharts} highcharts/chart/showaxes-true/
   *         True
   *
   * @type      {boolean}
   * @since     1.2.5
   * @product   highcharts gantt
   * @apioption chart.showAxes
   */
  /**
   * The space between the bottom edge of the chart and the content (plot
   * area, axis title and labels, title, subtitle or legend in top
   * position).
   *
   * @sample {highcharts} highcharts/chart/spacingbottom/
   *         Spacing bottom set to 100
   * @sample {highstock} stock/chart/spacingbottom/
   *         Spacing bottom set to 100
   * @sample {highmaps} maps/chart/spacing/
   *         Spacing 100 all around
   *
   * @type      {number}
   * @default   15
   * @since     2.1
   * @apioption chart.spacingBottom
   */
  /**
   * The space between the left edge of the chart and the content (plot
   * area, axis title and labels, title, subtitle or legend in top
   * position).
   *
   * @sample {highcharts} highcharts/chart/spacingleft/
   *         Spacing left set to 100
   * @sample {highstock} stock/chart/spacingleft/
   *         Spacing left set to 100
   * @sample {highmaps} maps/chart/spacing/
   *         Spacing 100 all around
   *
   * @type      {number}
   * @default   10
   * @since     2.1
   * @apioption chart.spacingLeft
   */
  /**
   * The space between the right edge of the chart and the content (plot
   * area, axis title and labels, title, subtitle or legend in top
   * position).
   *
   * @sample {highcharts} highcharts/chart/spacingright-100/
   *         Spacing set to 100
   * @sample {highcharts} highcharts/chart/spacingright-legend/
   *         Legend in right position with default spacing
   * @sample {highstock} stock/chart/spacingright/
   *         Spacing set to 100
   * @sample {highmaps} maps/chart/spacing/
   *         Spacing 100 all around
   *
   * @type      {number}
   * @default   10
   * @since     2.1
   * @apioption chart.spacingRight
   */
  /**
   * The space between the top edge of the chart and the content (plot
   * area, axis title and labels, title, subtitle or legend in top
   * position).
   *
   * @sample {highcharts} highcharts/chart/spacingtop-100/
   *         A top spacing of 100
   * @sample {highcharts} highcharts/chart/spacingtop-10/
   *         Floating chart title makes the plot area align to the default
   *         spacingTop of 10.
   * @sample {highstock} stock/chart/spacingtop/
   *         A top spacing of 100
   * @sample {highmaps} maps/chart/spacing/
   *         Spacing 100 all around
   *
   * @type      {number}
   * @default   10
   * @since     2.1
   * @apioption chart.spacingTop
   */
  /**
   * Additional CSS styles to apply inline to the container `div` and the root
   * SVG.
   *
   * According to the CSS syntax documentation, it is recommended to quote
   * font family names that contain white space, digits, or punctuation
   * characters other than hyphens. In such cases, wrap the fontFamily
   * name as follows: `fontFamily: '"Font name"'`.
   *
   * Since v11, the root font size is 1rem by default, and all child element
   * are given a relative `em` font size by default. This allows implementers
   * to control all the chart's font sizes by only setting the root level.
   *
   * @see    In styled mode, general chart styles can be set with the
   *         `.highcharts-root` class.
   * @sample {highcharts} highcharts/chart/style-serif-font/
   *         Using a serif type font
   * @sample {highcharts} highcharts/chart/style-special-font/
   *         Using a font with special character in name
   * @sample {highcharts} highcharts/members/relative-font-size/
   *         Relative font sizes
   * @sample {highcharts} highcharts/css/em/
   *         Styled mode with relative font sizes
   * @sample {highstock} stock/chart/style/
   *         Using a serif type font
   * @sample {highmaps} maps/chart/style-serif-font/
   *         Using a serif type font
   *
   * @type      {Highcharts.CSSObject}
   * @default   {"fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', sans-serif", "fontSize":"1rem"}
   * @apioption chart.style
   */
  /**
   * The default series type for the chart. Can be any of the chart types
   * listed under [plotOptions](#plotOptions) and [series](#series) or can
   * be a series provided by an additional module.
   *
   * In TypeScript this option has no effect in sense of typing and
   * instead the `type` option must always be set in the series.
   *
   * @sample {highcharts} highcharts/chart/type-bar/
   *         Bar
   * @sample {highstock} stock/chart/type/
   *         Areaspline
   * @sample {highmaps} maps/chart/type-mapline/
   *         Mapline
   *
   * @type       {string}
   * @default    {highcharts} line
   * @default    {highstock} line
   * @default    {highmaps} map
   * @since      2.1.0
   * @apioption  chart.type
   */
  type: "line",
  /**
   * Decides in what dimensions the user can zoom by dragging the mouse.
   * Can be one of `x`, `y` or `xy`.
   *
   * @see [panKey](#chart.panKey)
   *
   * @sample {highcharts} highcharts/chart/zoomtype-none/
   *         None by default
   * @sample {highcharts} highcharts/chart/zoomtype-x/
   *         X
   * @sample {highcharts} highcharts/chart/zoomtype-y/
   *         Y
   * @sample {highcharts} highcharts/chart/zoomtype-xy/
   *         Xy
   * @sample {highcharts} highcharts/chart/zoomtype-polar/
   *         Zoom on polar chart
   * @sample {highstock} stock/demo/basic-line/
   *         None by default
   * @sample {highstock} stock/chart/zoomtype-x/
   *         X
   * @sample {highstock} stock/chart/zoomtype-y/
   *         Y
   * @sample {highstock} stock/chart/zoomtype-xy/
   *         Xy
   * @sample {highmaps} maps/chart/zoomtype-xy/
   *         Map with selection zoom
   *
   * @type       {string}
   * @validvalue ["x", "y", "xy"]
   * @deprecated
   * @apioption  chart.zoomType
   */
  /**
   * Enables zooming by a single touch, in combination with
   * [chart.zoomType](#chart.zoomType). When enabled, two-finger pinch
   * will still work as set up by [chart.pinchType](#chart.pinchType).
   * However, `zoomBySingleTouch` will interfere with touch-dragging the
   * chart to read the tooltip. And especially when vertical zooming is
   * enabled, it will make it hard to scroll vertically on the page.
   * @since      9.0.0
   * @sample     highcharts/chart/zoombysingletouch
   *             Zoom by single touch enabled, with buttons to toggle
   * @product    highcharts highstock gantt
   * @deprecated
   */
  /**
   * Chart zooming options.
   * @since 10.2.1
   */
  zooming: {
    /**
     * Equivalent to [type](#chart.zooming.type), but for multitouch
     * gestures only. By default, the `pinchType` is the same as the
     * `type` setting. However, pinching can be enabled separately in
     * some cases, for example in stock charts where a mouse drag pans the
     * chart, while pinching is enabled. When [tooltip.followTouchMove](
     * #tooltip.followTouchMove) is true, pinchType only applies to
     * two-finger touches.
     *
     * @type       {string}
     * @default    {highcharts} undefined
     * @default    {highstock} x
     * @product    highcharts highstock gantt
     * @validvalue ["x", "y", "xy"]
     * @apioption  chart.zooming.pinchType
     */
    /**
     * Decides in what dimensions the user can zoom by dragging the mouse.
     * Can be one of `x`, `y` or `xy`.
     *
     * @declare    Highcharts.OptionsChartZoomingTypeValue
     * @type       {string}
     * @default    {highcharts} undefined
     * @product    highcharts highstock gantt
     * @validvalue ["x", "y", "xy"]
     * @apioption  chart.zooming.type
     */
    /**
     * Set a key to hold when dragging to zoom the chart. This is useful to
     * avoid zooming while moving points. Should be set different than
     * [chart.panKey](#chart.panKey).
     *
     * @type       {string}
     * @default    {highcharts} undefined
     * @validvalue ["alt", "ctrl", "meta", "shift"]
     * @requires   modules/draggable-points
     * @apioption  chart.zooming.key
     */
    /**
     * Enables zooming by a single touch, in combination with
     * [chart.zooming.type](#chart.zooming.type). When enabled, two-finger
     * pinch will still work as set up by [chart.zooming.pinchType]
     * (#chart.zooming.pinchType). However, `singleTouch` will interfere
     * with touch-dragging the chart to read the tooltip. And especially
     * when vertical zooming is enabled, it will make it hard to scroll
     * vertically on the page.
     *
     * @sample  highcharts/chart/zoombysingletouch
     *          Zoom by single touch enabled, with buttons to toggle
     *
     * @product highcharts highstock gantt
     */
    singleTouch: false,
    /**
     * The button that appears after a selection zoom, allowing the user
     * to reset zoom.
     */
    resetButton: {
      /**
       * What frame the button placement should be related to. Can be
       * either `plotBox` or `spacingBox`.
       *
       * @sample {highcharts} highcharts/chart/resetzoombutton-relativeto/
       *         Relative to the chart
       * @sample {highstock} highcharts/chart/resetzoombutton-relativeto/
       *         Relative to the chart
       *
       * @type      {Highcharts.ButtonRelativeToValue}
       * @default   plot
       * @apioption chart.zooming.resetButton.relativeTo
       */
      /**
       * A collection of attributes for the button. The object takes SVG
       * attributes like `fill`, `stroke`, `stroke-width` or `r`, the
       * border radius. The theme also supports `style`, a collection of
       * CSS properties for the text. Equivalent attributes for the hover
       * state are given in `theme.states.hover`.
       *
       * @sample {highcharts} highcharts/chart/resetzoombutton-theme/
       *         Theming the button
       * @sample {highstock} highcharts/chart/resetzoombutton-theme/
       *         Theming the button
       *
       * @type  {Highcharts.SVGAttributes}
       * @since 10.2.1
       */
      theme: {
        /** @internal */
        zIndex: 6
      },
      /**
       * The position of the button.
       *
       * Note: Adjusting position values might cause overlap with chart
       * elements. Ensure coordinates do not obstruct other components or
       * data visibility.
       *
       * @sample {highcharts} highcharts/chart/resetzoombutton-position/
       *         Above the plot area
       * @sample {highstock} highcharts/chart/resetzoombutton-position/
       *         Above the plot area
       * @sample {highmaps} highcharts/chart/resetzoombutton-position/
       *         Above the plot area
       *
       * @type  {Highcharts.AlignObject}
       * @since 10.2.1
       */
      position: {
        /**
         * The horizontal alignment of the button.
         */
        align: "right",
        /**
         * The horizontal offset of the button.
         */
        x: -10,
        /**
         * The vertical alignment of the button.
         *
         * @type       {Highcharts.VerticalAlignValue}
         * @default    top
         * @apioption  chart.zooming.resetButton.position.verticalAlign
         */
        /**
         * The vertical offset of the button.
         */
        y: 10
      }
    }
  },
  /**
   * An explicit width for the chart. By default (when `null`) the width
   * is calculated from the offset width of the containing element.
   *
   * @sample {highcharts} highcharts/chart/width/
   *         800px wide
   * @sample {highstock} stock/chart/width/
   *         800px wide
   * @sample {highmaps} maps/chart/size/
   *         Chart with explicit size
   *
   * @type {null|number|string}
   */
  width: null,
  /**
   * An explicit height for the chart. If a _number_, the height is
   * given in pixels. If given a _percentage string_ (for example
   * `'56%'`), the height is given as the percentage of the actual chart
   * width. This allows for preserving the aspect ratio across responsive
   * sizes.
   *
   * By default (when `null`) the height is calculated from the offset
   * height of the containing element, or 400 pixels if the containing
   * element's height is 0.
   *
   * @sample {highcharts} highcharts/chart/height/
   *         Forced 200px height
   * @sample {highstock} stock/chart/height/
   *         300px height
   * @sample {highmaps} maps/chart/size/
   *         Chart with explicit size
   * @sample highcharts/chart/height-percent/
   *         Highcharts with percentage height
   * @sample highcharts/chart/height-inherited/
   *         Chart with inherited height
   *
   * @type {null|number|string}
   */
  height: null,
  /**
   * The color of the outer chart border.
   *
   * @see In styled mode, the stroke is set with the
   *      `.highcharts-background` class.
   *
   * @sample {highcharts} highcharts/chart/bordercolor/
   *         Brown border
   * @sample {highstock} stock/chart/border/
   *         Brown border
   * @sample {highmaps} maps/chart/border/
   *         Border options
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  borderColor: "#334eff",
  /**
   * The pixel width of the outer chart border.
   *
   * @see In styled mode, the stroke is set with the
   *      `.highcharts-background` class.
   *
   * @sample {highcharts} highcharts/chart/borderwidth/
   *         5px border
   * @sample {highstock} stock/chart/border/
   *         2px border
   * @sample {highmaps} maps/chart/border/
   *         Border options
   *
   * @type      {number}
   * @default   0
   * @apioption chart.borderWidth
   */
  /**
   * The background color or gradient for the outer chart area.
   *
   * @see In styled mode, the background is set with the
   *      `.highcharts-background` class.
   *
   * @sample {highcharts} highcharts/chart/backgroundcolor-color/
   *         Color
   * @sample {highcharts} highcharts/chart/backgroundcolor-gradient/
   *         Gradient
   * @sample {highstock} stock/chart/backgroundcolor-color/
   *         Color
   * @sample {highstock} stock/chart/backgroundcolor-gradient/
   *         Gradient
   * @sample {highmaps} maps/chart/backgroundcolor-color/
   *         Color
   * @sample {highmaps} maps/chart/backgroundcolor-gradient/
   *         Gradient
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  backgroundColor: "#ffffff",
  /**
   * The background color or gradient for the plot area.
   *
   * @see In styled mode, the plot background is set with the
   *      `.highcharts-plot-background` class.
   *
   * @sample {highcharts} highcharts/chart/plotbackgroundcolor-color/
   *         Color
   * @sample {highcharts} highcharts/chart/plotbackgroundcolor-gradient/
   *         Gradient
   * @sample {highstock} stock/chart/plotbackgroundcolor-color/
   *         Color
   * @sample {highstock} stock/chart/plotbackgroundcolor-gradient/
   *         Gradient
   * @sample {highmaps} maps/chart/plotbackgroundcolor-color/
   *         Color
   * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
   *         Gradient
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @apioption chart.plotBackgroundColor
   */
  /**
   * The URL for an image to use as the plot background. To set an image
   * as the background for the entire chart, set a CSS background image
   * to the container element. Note that for the image to be applied to
   * exported charts, its URL needs to be accessible by the export server.
   *
   * @see In styled mode, a plot background image can be set with the
   *      `.highcharts-plot-background` class and a [custom pattern](
   *      https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns).
   *
   * @sample {highcharts} highcharts/chart/plotbackgroundimage/
   *         Skies
   * @sample {highstock} stock/chart/plotbackgroundimage/
   *         Skies
   *
   * @type      {string}
   * @apioption chart.plotBackgroundImage
   */
  /**
   * The color of the inner chart or plot area border.
   *
   * @see In styled mode, a plot border stroke can be set with the
   *      `.highcharts-plot-border` class.
   *
   * @sample {highcharts} highcharts/chart/plotbordercolor/
   *         Blue border
   * @sample {highstock} stock/chart/plotborder/
   *         Blue border
   * @sample {highmaps} maps/chart/plotborder/
   *         Plot border options
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  plotBorderColor: "#cccccc"
  /* Palette.neutralColor20 */
};
const SeriesPalettes = {
  /**
   * Colors for data series and points
   */
  colors: [
    "#2caffe",
    "#544fc5",
    "#00e272",
    "#fe6a35",
    "#6b8abc",
    "#d568fb",
    "#2ee0ca",
    "#fa4b42",
    "#feb56a",
    "#91e8e1"
  ]
};
const { pageLang: pageLang$1, win: win$g } = Highcharts;
const { defined: defined$1g, error: error$a, extend: extend$1t, isNumber: isNumber$1c, isObject: isObject$o, isString: isString$k, merge: merge$1J, objectEach: objectEach$y, pad, splat: splat$m, timeUnits: timeUnits$4, ucfirst: ucfirst$1 } = Utilities;
const hasOldSafariBug = Highcharts.isSafari && win$g.Intl && !win$g.Intl.DateTimeFormat.prototype.formatRange;
const isDateTimeFormatOptions = (obj) => obj.main === void 0;
class TimeBase {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(options2, lang2) {
    this.options = {
      timezone: "UTC"
    };
    this.variableTimezone = false;
    this.Date = win$g.Date;
    this.update(options2);
    this.lang = lang2;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Update the Time object with current options. It is called internally on
   * initializing Highcharts, after running `Highcharts.setOptions` and on
   * `Chart.update`.
   *
   * @private
   * @function Highcharts.Time#update
   *
   * @param {Highcharts.TimeOptions} [options]
   *
   */
  update(options2 = {}) {
    this.dTLCache = {};
    this.options = options2 = merge$1J(true, this.options, options2);
    const { timezoneOffset, useUTC } = options2;
    this.Date = options2.Date || win$g.Date || Date;
    let timezone = options2.timezone;
    if (defined$1g(useUTC)) {
      timezone = useUTC ? "UTC" : void 0;
    }
    if (timezoneOffset && timezoneOffset % 60 === 0) {
      timezone = "Etc/GMT" + (timezoneOffset > 0 ? "+" : "") + timezoneOffset / 60;
    }
    this.variableTimezone = timezone !== "UTC" && timezone?.indexOf("Etc/GMT") !== 0;
    this.timezone = timezone;
    ["months", "shortMonths", "weekdays", "shortWeekdays"].forEach((name) => {
      const isMonth = /months/i.test(name), isShort = /short/.test(name), options3 = {
        timeZone: "UTC"
      };
      options3[isMonth ? "month" : "weekday"] = isShort ? "short" : "long";
      this[name] = (isMonth ? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] : [3, 4, 5, 6, 7, 8, 9]).map((position) => this.dateFormat(options3, (isMonth ? 31 : 1) * 24 * 36e5 * position));
    });
  }
  /**
   * Get a date in terms of numbers (year, month, day etc) for further
   * processing. Takes the current `timezone` setting into account. Inverse of
   * `makeTime` and the native `Date` constructor and `Date.UTC`.
   *
   * The date is returned in array format with the following indices:
   *
   * 0: year,
   * 1: month (zero based),
   * 2: day,
   * 3: hours,
   * 4: minutes,
   * 5: seconds,
   * 6: milliseconds,
   * 7: weekday (Sunday as 0)
   *
   * @function Highcharts.Time#toParts
   *
   * @param {number|Date} [timestamp]
   *                 The timestamp in milliseconds since January 1st 1970.
   *                 A Date object is also accepted.
   *
   * @return {Array<number>} The date parts in array format.
   */
  toParts(timestamp) {
    const [weekday, dayOfMonth, month, year, hours, minutes, seconds] = this.dateTimeFormat({
      weekday: "narrow",
      day: "numeric",
      month: "numeric",
      year: "numeric",
      hour: "numeric",
      minute: "numeric",
      second: "numeric"
    }, timestamp, "es").split(/(?:, | |\/|:)/g);
    return [
      year,
      +month - 1,
      dayOfMonth,
      hours,
      minutes,
      seconds,
      // Milliseconds
      Math.floor(Number(timestamp) || 0) % 1e3,
      // Spanish weekday index
      "DLMXJVS".indexOf(weekday)
    ].map(Number);
  }
  /**
   * Shorthand to get a cached `Intl.DateTimeFormat` instance.
   */
  dateTimeFormat(options2, timestamp, locale = this.options.locale || pageLang$1) {
    const cacheKey = JSON.stringify(options2) + locale;
    if (isString$k(options2)) {
      options2 = this.str2dtf(options2);
    }
    let dTL = this.dTLCache[cacheKey];
    if (!dTL) {
      options2.timeZone ?? (options2.timeZone = this.timezone);
      try {
        dTL = new Intl.DateTimeFormat(locale, options2);
      } catch (e) {
        if (/Invalid time zone/i.test(e.message)) {
          error$a(34);
          options2.timeZone = "UTC";
          dTL = new Intl.DateTimeFormat(locale, options2);
        } else {
          error$a(e.message, false);
        }
      }
    }
    this.dTLCache[cacheKey] = dTL;
    return dTL?.format(timestamp) || "";
  }
  /**
   * Take a locale-aware string format and return a full DateTimeFormat in
   * object form.
   */
  str2dtf(s, dtf = {}) {
    const mapping = {
      L: { fractionalSecondDigits: 3 },
      S: { second: "2-digit" },
      M: { minute: "numeric" },
      H: { hour: "2-digit" },
      k: { hour: "numeric" },
      E: { weekday: "narrow" },
      a: { weekday: "short" },
      A: { weekday: "long" },
      d: { day: "2-digit" },
      e: { day: "numeric" },
      b: { month: "short" },
      B: { month: "long" },
      m: { month: "2-digit" },
      o: { month: "numeric" },
      y: { year: "2-digit" },
      Y: { year: "numeric" }
    };
    Object.keys(mapping).forEach((key2) => {
      if (s.indexOf(key2) !== -1) {
        extend$1t(dtf, mapping[key2]);
      }
    });
    return dtf;
  }
  /**
   * Make a time and returns milliseconds. Similar to `Date.UTC`, but takes
   * the current `timezone` setting into account.
   *
   * @function Highcharts.Time#makeTime
   *
   * @param {number} year
   *        The year
   *
   * @param {number} month
   *        The month. Zero-based, so January is 0.
   *
   * @param {number} [date=1]
   *        The day of the month
   *
   * @param {number} [hours=0]
   *        The hour of the day, 0-23.
   *
   * @param {number} [minutes=0]
   *        The minutes
   *
   * @param {number} [seconds=0]
   *        The seconds
   *
   * @return {number}
   *         The time in milliseconds since January 1st 1970.
   */
  makeTime(year, month, date = 1, hours = 0, minutes, seconds, milliseconds) {
    let d = this.Date.UTC(year, month, date, hours, minutes || 0, seconds || 0, milliseconds || 0);
    if (this.timezone !== "UTC") {
      const offset2 = this.getTimezoneOffset(d);
      d += offset2;
      if (
        // Optimize for speed by limiting the number of calls to
        // `getTimezoneOffset`. According to
        // https://en.wikipedia.org/wiki/Daylight_saving_time_by_country,
        // DST change may only occur in these months.
        [2, 3, 8, 9, 10, 11].indexOf(month) !== -1 && // DST transitions occur only in the night-time
        (hours < 5 || hours > 20)
      ) {
        const newOffset = this.getTimezoneOffset(d);
        if (offset2 !== newOffset) {
          d += newOffset - offset2;
        } else if (offset2 - 36e5 === this.getTimezoneOffset(d - 36e5) && !hasOldSafariBug) {
          d -= 36e5;
        }
      }
    }
    return d;
  }
  /**
   * Parse a datetime string. Unless the string contains time zone
   * information, apply the current `timezone` from options. If the argument
   * is a number, return it.
   *
   * @function Highcharts.Time#parse
   * @param    {string|number|undefined} s The datetime string to parse
   * @return   {number|undefined}          Parsed JavaScript timestamp
   */
  parse(s) {
    if (!isString$k(s)) {
      return s ?? void 0;
    }
    s = s.replace(/\//g, "-").replace(/(GMT|UTC)/, "");
    const hasTimezone = s.indexOf("Z") > -1 || /([+-][0-9]{2}):?[0-9]{2}$/.test(s), isYYYYMMDD = /^[0-9]{4}-[0-9]{2}(-[0-9]{2}|)$/.test(s);
    if (!hasTimezone && !isYYYYMMDD) {
      s += "Z";
    }
    const ts = Date.parse(s);
    if (isNumber$1c(ts)) {
      return ts + (!hasTimezone || isYYYYMMDD ? this.getTimezoneOffset(ts) : 0);
    }
  }
  /**
   * Get the time zone offset based on the current timezone information as
   * set in the global options.
   *
   * @function Highcharts.Time#getTimezoneOffset
   *
   * @param {number} timestamp
   *        The JavaScript timestamp to inspect.
   *
   * @return {number}
   *         The timezone offset in minutes compared to UTC.
   */
  getTimezoneOffset(timestamp) {
    if (this.timezone !== "UTC") {
      const [date, gmt, hours, colon, minutes = 0] = this.dateTimeFormat({ timeZoneName: "shortOffset" }, timestamp, "en").split(/(GMT|:)/).map(Number), offset2 = -(hours + minutes / 60) * 60 * 6e4;
      if (isNumber$1c(offset2)) {
        return offset2;
      }
    }
    return 0;
  }
  /**
   * Formats a JavaScript date timestamp (milliseconds since January 1 1970)
   * into a human readable date string.
   *
   * The `format` parameter accepts two types of values:
   * - An object containing settings that are passed directly on to
   *   [Intl.DateTimeFormat.prototype.format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format).
   * - A format string containing either individual or locale-aware format
   *   keys. **Individual keys**, for example `%Y-%m-%d`, are listed below.
   *   **Locale-aware keys** are grouped by square brackets, for example
   *   `%[Ymd]`. The order of keys within the square bracket doesn't affect
   *   the output, which is determined by the locale. See example below.
   *   Internally, the locale-aware format keys are just a shorthand for the
   *   full object formats, but are particularly practical in
   *   [templating](https://www.highcharts.com/docs/chart-concepts/templating)
   *   where full object definitions are not an option.
   *
   * The available string format keys are listed below. Additional formats can
   * be given in the {@link Highcharts.dateFormats} hook.
   *
   * Supported format keys:
   * | Key  | Description                     | Notes on locale-aware format |
   * -------|----------------------------------------------|-------|
   * | `%A` | Long weekday, like 'Monday'                  |       |
   * | `%a` | Short weekday, like 'Mon'                    |       |
   * | `%E` | Narrow weekday, single character             |       |
   * | `%d` | Two digit day of the month, 01 to 31         |       |
   * | `%e` | Day of the month, 1 through 31               |       |
   * | `%w` | Day of the week, 0 through 6                 | N/A   |
   * | `%v` | The prefix "week from", read from `lang.weekFrom` | N/A |
   * | `%b` | Short month, like 'Jan'                      |       |
   * | `%B` | Long month, like 'January'                   |       |
   * | `%m` | Two digit month number, 01 through 12        |       |
   * | `%o` | Month number, 1 through 12                   |       |
   * | `%y` | Two digits year, like 24 for 2024            |       |
   * | `%Y` | Four digits year, like 2024                  |       |
   * | `%H` | Two digits hours in 24h format, 00 through 23 | Depending on the locale, 12h format may be instered. |
   * | `%k` | Hours in 24h format, 0 through 23            | Depending on the locale, 12h format may be instered. |
   * | `%I` | Two digits hours in 12h format, 00 through 11 | N/A. The locale determines the hour format. |
   * | `%l` | Hours in 12h format, 1 through 12            | N/A. The locale determines the hour format. |
   * | `%M` | Two digits minutes, 00 through 59            |       |
   * | `%p` | Upper case AM or PM                          | N/A. The locale determines whether to add AM and PM. |
   * | `%P` | Lower case AM or PM                          | N/A. The locale determines whether to add AM and PM. |
   * | `%S` | Two digits seconds, 00 through 59            |       |
   * | `%L` | Milliseconds (naming from Ruby)              |       |
   *
   * @example
   * // Object format, US English
   * const time1 = new Highcharts.Time({ locale: 'en-US' });
   * console.log(
   *     time1.dateFormat({
   *         day: 'numeric',
   *         month: 'short',
   *         year: 'numeric',
   *         hour: 'numeric',
   *         minute: 'numeric'
   *     }, Date.UTC(2024, 11, 31))
   * ); // => Dec 31, 2024, 12:00 AM
   *
   * // Object format, British English
   * const time2 = new Highcharts.Time({ locale: 'en-GB' });
   * console.log(
   *     time2.dateFormat({
   *         day: 'numeric',
   *         month: 'short',
   *         year: 'numeric',
   *         hour: 'numeric',
   *         minute: 'numeric'
   *     }, Date.UTC(2024, 11, 31))
   * ); // => 31 Dec 2024, 00:00
   *
   * // Individual key string replacement
   * const time3 = new Highcharts.Time();
   * console.log(
   *     time3.dateFormat('%Y-%m-%d %H:%M:%S', Date.UTC(2024, 11, 31))
   * ); // => 2024-12-31 00:00:00
   *
   * // Locale-aware keys, US English
   * const time4 = new Highcharts.Time({ locale: 'en-US' });
   * console.log(
   *     time4.dateFormat('%[YebHM]', Date.UTC(2024, 11, 31))
   * ); // => Dec 31, 2024, 12:00 AM
   *
   * // Locale-aware keys, British English
   * const time5 = new Highcharts.Time({ locale: 'en-GB' });
   * console.log(
   *     time5.dateFormat('%[YebHM]', Date.UTC(2024, 11, 31))
   * ); // => 31 Dec 2024, 00:00
   *
   * // Mixed locale-aware and individual keys
   * console.log(
   *     time5.dateFormat('%[Yeb], %H:%M', Date.UTC(2024, 11, 31))
   * ); // => 31 Dec 2024, 00:00
   *
   * @function Highcharts.Time#dateFormat
   *
   * @param {string|Highcharts.DateTimeFormatOptions} format
   *        The desired string format where various time representations are
   *        prefixed with %, or an object representing the locale-aware format
   *        options.
   *
   * @param {number} [timestamp]
   *        The JavaScript timestamp.
   *
   * @param {boolean} [upperCaseFirst=false]
   *        Upper case first letter in the return.
   *
   * @return {string}
   *         The formatted date.
   */
  dateFormat(format2, timestamp, upperCaseFirst) {
    const lang2 = this.lang;
    if (!defined$1g(timestamp) || isNaN(timestamp)) {
      return lang2?.invalidDate || "";
    }
    format2 = format2 ?? "%Y-%m-%d %H:%M:%S";
    if (isString$k(format2)) {
      const localeAwareRegex = /%\[([a-zA-Z]+)\]/g;
      let match2;
      while (match2 = localeAwareRegex.exec(format2)) {
        format2 = format2.replace(match2[0], this.dateTimeFormat(match2[1], timestamp, lang2?.locale));
      }
    }
    if (isString$k(format2) && format2.indexOf("%") !== -1) {
      const time = this, [fullYear, month, dayOfMonth, hours, minutes, seconds, milliseconds, weekday] = this.toParts(timestamp), langWeekdays = lang2?.weekdays || this.weekdays, shortWeekdays = lang2?.shortWeekdays || this.shortWeekdays, months = lang2?.months || this.months, shortMonths = lang2?.shortMonths || this.shortMonths, replacements = extend$1t({
        // Day
        // Short weekday, like 'Mon'
        a: shortWeekdays ? shortWeekdays[weekday] : langWeekdays[weekday].substr(0, 3),
        // Long weekday, like 'Monday'
        A: langWeekdays[weekday],
        // Two digit day of the month, 01 to 31
        d: pad(dayOfMonth),
        // Day of the month, 1 through 31
        e: pad(dayOfMonth, 2, " "),
        // Day of the week, 0 through 6
        w: weekday,
        // Week (none implemented)
        // 'W': weekNumber(),
        v: lang2?.weekFrom ?? "",
        // Month
        // Short month, like 'Jan'
        b: shortMonths[month],
        // Long month, like 'January'
        B: months[month],
        // Two digit month number, 01 through 12
        m: pad(month + 1),
        // Month number, 1 through 12 (#8150)
        o: month + 1,
        // Year
        // Two digits year, like 09 for 2009
        y: fullYear.toString().substr(2, 2),
        // Four digits year, like 2009
        Y: fullYear,
        // Time
        // Two digits hours in 24h format, 00 through 23
        H: pad(hours),
        // Hours in 24h format, 0 through 23
        k: hours,
        // Two digits hours in 12h format, 00 through 11
        I: pad(hours % 12 || 12),
        // Hours in 12h format, 1 through 12
        l: hours % 12 || 12,
        // Two digits minutes, 00 through 59
        M: pad(minutes),
        // Upper case AM or PM
        p: hours < 12 ? "AM" : "PM",
        // Lower case AM or PM
        P: hours < 12 ? "am" : "pm",
        // Two digits seconds, 00 through 59
        S: pad(seconds),
        // Milliseconds (naming from Ruby)
        L: pad(milliseconds, 3)
      }, Highcharts.dateFormats);
      objectEach$y(replacements, function(val, key2) {
        if (isString$k(format2)) {
          while (format2.indexOf("%" + key2) !== -1) {
            format2 = format2.replace("%" + key2, typeof val === "function" ? val.call(time, timestamp) : val);
          }
        }
      });
    } else if (isObject$o(format2)) {
      const tzHours = (this.getTimezoneOffset(timestamp) || 0) / (6e4 * 60), timeZone = this.timezone || "Etc/GMT" + (tzHours >= 0 ? "+" : "") + tzHours, { prefix = "", suffix = "" } = format2;
      format2 = prefix + this.dateTimeFormat(extend$1t({ timeZone }, format2), timestamp) + suffix;
    }
    return upperCaseFirst ? ucfirst$1(format2) : format2;
  }
  /**
   * Resolve legacy formats of dateTimeLabelFormats (strings and arrays) into
   * an object.
   * @private
   * @param {string|Array<T>|Highcharts.Dictionary<T>} f
   * General format description
   * @return {Highcharts.Dictionary<T>}
   * The object definition
   */
  resolveDTLFormat(f) {
    if (!isObject$o(f, true)) {
      f = splat$m(f);
      return {
        main: f[0],
        from: f[1],
        to: f[2]
      };
    }
    if (isObject$o(f, true) && isDateTimeFormatOptions(f)) {
      return { main: f };
    }
    return f;
  }
  /**
   * Get the optimal date format for a point, based on a range.
   *
   * @private
   * @function Highcharts.Time#getDateFormat
   *
   * @param {number} range
   *        The time range
   *
   * @param {number} timestamp
   *        The timestamp of the date
   *
   * @param {number} startOfWeek
   *        An integer representing the first day of the week, where 0 is
   *        Sunday.
   *
   * @param {Highcharts.Dictionary<string>} dateTimeLabelFormats
   *        A map of time units to formats.
   *
   * @return {string}
   *         The optimal date format for a point.
   */
  getDateFormat(range2, timestamp, startOfWeek2, dateTimeLabelFormats) {
    const dateStr = this.dateFormat("%m-%d %H:%M:%S.%L", timestamp), blank = "01-01 00:00:00.000", strpos = {
      millisecond: 15,
      second: 12,
      minute: 9,
      hour: 6,
      day: 3
    };
    let n = "millisecond", lastN = n;
    for (n in timeUnits$4) {
      if (range2 && range2 === timeUnits$4.week && +this.dateFormat("%w", timestamp) === startOfWeek2 && dateStr.substr(6) === blank.substr(6)) {
        n = "week";
        break;
      }
      if (range2 && timeUnits$4[n] > range2) {
        n = lastN;
        break;
      }
      if (strpos[n] && dateStr.substr(strpos[n]) !== blank.substr(strpos[n])) {
        break;
      }
      if (n !== "week") {
        lastN = n;
      }
    }
    return this.resolveDTLFormat(dateTimeLabelFormats[n]).main;
  }
}
const { defined: defined$1f, extend: extend$1s, timeUnits: timeUnits$3 } = Utilities;
class Time extends TimeBase {
  /**
   * Return an array with time positions distributed on round time values
   * right and right after min and max. Used in datetime axes as well as for
   * grouping data on a datetime axis.
   *
   * @function Highcharts.Time#getTimeTicks
   *
   * @param {Highcharts.TimeNormalizedObject} normalizedInterval
   *        The interval in axis values (ms) and the count
   *
   * @param {number} [min]
   *        The minimum in axis values
   *
   * @param {number} [max]
   *        The maximum in axis values
   *
   * @param {number} [startOfWeek=1]
   *
   * @return {Highcharts.AxisTickPositionsArray}
   * Time positions
   */
  getTimeTicks(normalizedInterval, min2, max2, startOfWeek2) {
    const time = this, tickPositions = [], higherRanks = {}, { count = 1, unitRange } = normalizedInterval;
    let [year, month, dayOfMonth, hours, minutes, seconds] = time.toParts(min2), milliseconds = (min2 || 0) % 1e3, variableDayLength;
    startOfWeek2 ?? (startOfWeek2 = 1);
    if (defined$1f(min2)) {
      milliseconds = unitRange >= timeUnits$3.second ? 0 : (
        // #3935
        count * Math.floor(milliseconds / count)
      );
      if (unitRange >= timeUnits$3.second) {
        seconds = unitRange >= timeUnits$3.minute ? 0 : (
          // #3935
          count * Math.floor(seconds / count)
        );
      }
      if (unitRange >= timeUnits$3.minute) {
        minutes = unitRange >= timeUnits$3.hour ? 0 : count * Math.floor(minutes / count);
      }
      if (unitRange >= timeUnits$3.hour) {
        hours = unitRange >= timeUnits$3.day ? 0 : count * Math.floor(hours / count);
      }
      if (unitRange >= timeUnits$3.day) {
        dayOfMonth = unitRange >= timeUnits$3.month ? 1 : Math.max(1, count * Math.floor(dayOfMonth / count));
      }
      if (unitRange >= timeUnits$3.month) {
        month = unitRange >= timeUnits$3.year ? 0 : count * Math.floor(month / count);
      }
      if (unitRange >= timeUnits$3.year) {
        year -= year % count;
      }
      if (unitRange === timeUnits$3.week) {
        if (count) {
          min2 = time.makeTime(year, month, dayOfMonth, hours, minutes, seconds, milliseconds);
        }
        const weekday = this.dateTimeFormat({
          timeZone: this.timezone,
          weekday: "narrow"
        }, min2, "es"), weekdayNo = "DLMXJVS".indexOf(weekday);
        dayOfMonth += -weekdayNo + startOfWeek2 + // We don't want to skip days that are before
        // startOfWeek (#7051)
        (weekdayNo < startOfWeek2 ? -7 : 0);
      }
      min2 = time.makeTime(year, month, dayOfMonth, hours, minutes, seconds, milliseconds);
      if (time.variableTimezone && defined$1f(max2)) {
        variableDayLength = // Long range, assume we're crossing over.
        max2 - min2 > 4 * timeUnits$3.month || // Short range, check if min and max are in different time
        // zones.
        time.getTimezoneOffset(min2) !== time.getTimezoneOffset(max2);
      }
      let t = min2, i = 1;
      while (t < max2) {
        tickPositions.push(t);
        if (unitRange === timeUnits$3.year) {
          t = time.makeTime(year + i * count, 0);
        } else if (unitRange === timeUnits$3.month) {
          t = time.makeTime(year, month + i * count);
        } else if (variableDayLength && (unitRange === timeUnits$3.day || unitRange === timeUnits$3.week)) {
          t = time.makeTime(year, month, dayOfMonth + i * count * (unitRange === timeUnits$3.day ? 1 : 7));
        } else if (variableDayLength && unitRange === timeUnits$3.hour && count > 1) {
          t = time.makeTime(year, month, dayOfMonth, hours + i * count);
        } else {
          t += unitRange * count;
        }
        i++;
      }
      tickPositions.push(t);
      if (unitRange <= timeUnits$3.hour && tickPositions.length < 1e4) {
        tickPositions.forEach((t2) => {
          if (
            // Speed optimization, no need to run dateFormat unless
            // we're on a full or half hour
            t2 % 18e5 === 0 && // Check for local or global midnight
            time.dateFormat("%H%M%S%L", t2) === "000000000"
          ) {
            higherRanks[t2] = "day";
          }
        });
      }
    }
    tickPositions.info = extend$1s(normalizedInterval, {
      higherRanks,
      totalRange: unitRange * count
    });
    return tickPositions;
  }
}
const { isTouchDevice: isTouchDevice$6 } = Highcharts;
const { fireEvent: fireEvent$M, merge: merge$1I } = Utilities;
const defaultOptions$n = {
  /**
   * An array containing the default colors for the chart's series. When
   * all colors are used, new colors are pulled from the start again.
   *
   * Default colors can also be set on a series or series.type basis,
   * see [column.colors](#plotOptions.column.colors),
   * [pie.colors](#plotOptions.pie.colors).
   *
   * In styled mode, the colors option doesn't exist. Instead, colors
   * are defined in CSS and applied either through series or point class
   * names, or through the [chart.colorCount](#chart.colorCount) option.
   *
   * @sample {highcharts} highcharts/chart/colors/
   *         Assign a global color theme
   * @sample highcharts/members/theme-v10/
   *         Latest release styled like version 10
   *
   * @type    {Array<(Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject)>}
   * @default [
   *     "#2caffe",
   *     "#544fc5",
   *     "#00e272",
   *     "#fe6a35",
   *     "#6b8abc",
   *     "#d568fb",
   *     "#2ee0ca",
   *     "#fa4b42",
   *     "#feb56a",
   *     "#91e8e1"
   * ]
   */
  colors: SeriesPalettes.colors,
  /**
   * Styled mode only. Configuration object for adding SVG definitions for
   * reusable elements. See [gradients, shadows and
   * patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns)
   * for more information and code examples.
   *
   * @type      {*}
   * @since     5.0.0
   * @apioption defs
   */
  /**
   * @ignore-option
   */
  symbols: ["circle", "diamond", "square", "triangle", "triangle-down"],
  /**
   * An object containing language-related strings and settings. A typical
   * setup uses `Highcharts.setOptions` to make the options apply to all
   * charts in the same page.
   *
   * ```js
   * Highcharts.setOptions({
   *     lang: {
   *         locale: 'fr'
   *     }
   * });
   * ```
   *
   * @optionparent lang
   */
  lang: {
    weekFrom: "week from",
    /**
     * The default chart title.
     *
     * @since 12.2.0
     */
    chartTitle: "Chart title",
    /**
     * The browser locale to use for date and number formatting. The actual
     * locale used for each chart is determined in three steps:
     * 1. If this `lang.locale` option is specified, it is used.
     * 2. Else, look for the closest ancestor HTML element with a `lang`
     *    attribute, typically the `<html>` element.
     * 3. If no 'lang' attribute is found, use the default browser locale.
     *
     * Use `en-GB`, British English, for approximate consistency with
     * Highcharts v < 12.
     *
     * @sample highcharts/lang/locale/
     *         Set the locale using the `lang.locale` option
     * @sample highcharts/lang/locale-attribute/
     *         Pick up the locale from the HTML `lang` attribute
     * @sample highcharts/members/highcharts-numberformat
     *         Arabic locale with digits and dates         *
     *
     * @since 12.0.0
     * @type {string|Array<string>}
     */
    locale: void 0,
    /**
     * The loading text that appears when the chart is set into the loading
     * state following a call to `chart.showLoading`.
     */
    loading: "Loading...",
    /**
     * An array containing the months names. Corresponds to the `%B` format
     * in `Highcharts.dateFormat()`. Defaults to 'undefined',
     * meaning the default month names are used according to the
     * `lang.locale` setting.
     *
     * @type    {Array<string>}
     */
    months: void 0,
    /**
     * [Format string](https://www.highcharts.com/docs/chart-concepts/templating) for the default series name.
     *
     * @since 12.2.0
     */
    seriesName: "Series {add index 1}",
    /**
     * An array containing the months names in abbreviated form. Corresponds
     * to the `%b` format in `Highcharts.dateFormat()`. Defaults to
     * 'undefined', meaning the default short month names are used according
     * to the `lang.locale` setting.
     *
     * @type    {Array<string>}
     */
    shortMonths: void 0,
    /**
     * An array containing the weekday names. Defaults to 'undefined',
     * meaning the default weekday names are used according to the
     * `lang.locale` setting.
     *
     * @type    {Array<string>}
     */
    weekdays: void 0,
    /**
     * Short week days, starting Sunday. Defaults to 'undefined', meaning
     * the default short weekday names are used according to the
     * `lang.locale` setting.
     *
     * @sample highcharts/lang/shortweekdays/
     *         Finnish two-letter abbreviations
     *
     * @type      {Array<string>}
     * @since     4.2.4
     * @apioption lang.shortWeekdays
     */
    /**
     * What to show in a date field for invalid dates. Defaults to an empty
     * string.
     *
     * @type      {string}
     * @since     4.1.8
     * @product   highcharts highstock
     * @apioption lang.invalidDate
     */
    /**
     * The title appearing on hovering the zoom in button. The text itself
     * defaults to "+" and can be changed in the button options.
     *
     * @type      {string}
     * @default   Zoom in
     * @product   highmaps
     * @apioption lang.zoomIn
     */
    /**
     * The title appearing on hovering the zoom out button. The text itself
     * defaults to "-" and can be changed in the button options.
     *
     * @type      {string}
     * @default   Zoom out
     * @product   highmaps
     * @apioption lang.zoomOut
     */
    /**
     * The default decimal point used in the `Highcharts.numberFormat`
     * method unless otherwise specified in the function arguments. Defaults
     * to the locale decimal point as determined by `lang.locale`.
     *
     * @type      {string}
     * @default   undefined
     * @since     1.2.2
     * @apioption lang.decimalPoint
     */
    /**
     * [Metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix) used
     * to shorten high numbers in axis labels. Replacing any of the
     * positions with `null` causes the full number to be written. Setting
     * `numericSymbols` to `undefined` disables shortening altogether.
     *
     * @sample {highcharts} highcharts/lang/numericsymbols/
     *         Replacing the symbols with text
     * @sample {highstock} highcharts/lang/numericsymbols/
     *         Replacing the symbols with text
     *
     * @type    {Array<string>}
     * @default ["k", "M", "G", "T", "P", "E"]
     * @since   2.3.0
     */
    numericSymbols: ["k", "M", "G", "T", "P", "E"],
    /**
     * The default name for a pie slice (point).
     * @since 12.2.0
     */
    pieSliceName: "Slice",
    /**
     * The magnitude of [numericSymbols](#lang.numericSymbol) replacements.
     * Use 10000 for Japanese, Korean and various Chinese locales, which
     * use symbols for 10^4, 10^8 and 10^12.
     *
     * @sample highcharts/lang/numericsymbolmagnitude/
     *         10000 magnitude for Japanese
     *
     * @type      {number}
     * @default   1000
     * @since     5.0.3
     * @apioption lang.numericSymbolMagnitude
     */
    /**
     * The default thousands separator used in the `Highcharts.numberFormat`
     * method unless otherwise specified in the function arguments. Defaults
     * to the locale thousands separator as determined by `lang.locale`.
     *
     * @type      {string}
     * @default   undefined
     * @since     1.2.2
     * @apioption lang.thousandsSep
     */
    /**
     * The text for the label appearing when a chart is zoomed.
     *
     * @since 1.2.4
     */
    resetZoom: "Reset zoom",
    /**
     * The tooltip title for the label appearing when a chart is zoomed.
     *
     * @since 1.2.4
     */
    /**
     * The default title of the Y axis
     *
     * @since 12.2.0
     */
    yAxisTitle: "Values",
    resetZoomTitle: "Reset zoom level 1:1"
  },
  /**
   * Global options that don't apply to each chart. These options must be set
   * using the `Highcharts.setOptions` method.
   *
   * ```js
   * Highcharts.setOptions({
   *     global: {
   *         buttonTheme: {
   *             fill: '#d0d0d0'
   *         }
   *     }
   * });
   * ```
   */
  global: {
    /**
     * General theme for buttons. This applies to the zoom button, exporting
     * context menu, map navigation, range selector buttons and custom
     * buttons generated using the `SVGRenderer.button` function. However,
     * each of these may be overridden with more specific options.
     *
     * @sample highcharts/global/buttontheme
     *         General button theme
     * @since 11.4.2
     */
    buttonTheme: {
      /**
       * The fill color for buttons
       */
      fill: "#f7f7f7",
      /**
       * The padding of buttons
       */
      padding: 8,
      /**
       * The border radius for buttons
       */
      r: 2,
      /**
       * The stroke color for buttons
       */
      stroke: "#cccccc",
      /**
       * The stroke width for buttons
       */
      "stroke-width": 1,
      /**
       * CSS styling for the buttons' text
       */
      style: {
        color: "#333333",
        cursor: "pointer",
        fontSize: "0.8em",
        fontWeight: "normal"
      },
      /**
       * State overrides for the buttons
       */
      states: {
        /**
         * Hover state overrides for the buttons are applied in addition
         * to the normal state options
         */
        hover: {
          fill: "#e6e6e6"
          /* Palette.neutralColor10 */
        },
        /**
         * Select state overrides for the buttons are applied in
         * addition to the normal state options
         */
        select: {
          fill: "#e6e9ff",
          style: {
            color: "#000000",
            fontWeight: "bold"
          }
        },
        /**
         * Disabled state overrides for the buttons are applied in
         * addition to the normal state options
         */
        disabled: {
          /**
           * Disabled state CSS style overrides for the buttons' text
           */
          style: {
            color: "#cccccc"
            /* Palette.neutralColor20 */
          }
        }
      }
    }
  },
  /**
   * Time options that can apply globally or to individual charts. These
   * settings affect how `datetime` axes are laid out, how tooltips are
   * formatted, how series
   * [pointIntervalUnit](#plotOptions.series.pointIntervalUnit) works and how
   * the Highcharts Stock range selector handles time.
   *
   * The common use case is that all charts in the same Highcharts object
   * share the same time settings, in which case the global settings are set
   * using `setOptions`.
   *
   * ```js
   * // Apply time settings globally
   * Highcharts.setOptions({
   *     time: {
   *         timezone: 'Europe/London'
   *     }
   * });
   * // Apply time settings by instance
   * const chart = Highcharts.chart('container', {
   *     time: {
   *         timezone: 'America/New_York'
   *     },
   *     series: [{
   *         data: [1, 4, 3, 5]
   *     }]
   * });
   *
   * // Use the Time object
   * console.log(
   *        'Current time in New York',
   *        chart.time.dateFormat('%Y-%m-%d %H:%M:%S', Date.now())
   * );
   * ```
   *
   * Since v6.0.5, the time options were moved from the `global` object to the
   * `time` object, and time options can be set on each individual chart.
   *
   * @sample {highcharts|highstock}
   *         highcharts/time/timezone/
   *         Set the timezone globally
   * @sample {highcharts}
   *         highcharts/time/individual/
   *         Set the timezone per chart instance
   * @sample {highstock}
   *         stock/time/individual/
   *         Set the timezone per chart instance
   *
   * @since     6.0.5
   * @optionparent time
   */
  time: {
    /**
     * A custom `Date` class for advanced date handling. For example,
     * [JDate](https://github.com/tahajahangir/jdate) can be hooked in to
     * handle Jalali dates.
     *
     * @type      {*}
     * @since     4.0.4
     * @product   highcharts highstock gantt
     */
    Date: void 0,
    /**
     * A named time zone. Supported time zone names rely on the browser
     * implementations, as described in the [mdn
     * docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#timezone).
     * If the given time zone is not recognized by the browser, Highcharts
     * provides a warning and falls back to returning a 0 offset,
     * corresponding to the UTC time zone.
     *
     * The time zone affects axis scaling, tickmark placement and
     * time display in `Highcharts.dateFormat`.
     *
     * Setting `timezone` to `undefined` falls back to the default browser
     * timezone setting.
     *
     * Until v11.2.0, this option depended on moment.js.
     *
     * @sample {highcharts|highstock} highcharts/time/timezone/ Europe/Oslo
     *
     * @type      {string}
     * @since     5.0.7
     * @product   highcharts highstock gantt
     */
    timezone: "UTC",
    /**
     * The timezone offset in minutes. Positive values are west, negative
     * values are east of UTC, as in the ECMAScript
     * [getTimezoneOffset](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset)
     * method. Use this to display UTC based data in a predefined time zone.
     *
     * This option is deprecated as of v11.4.1 and will be removed in a
     * future release. Use the [time.timezone](#time.timezone) option
     * instead.
     *
     * @see [time.getTimezoneOffset](#time.getTimezoneOffset)
     *
     * @sample {highcharts|highstock} highcharts/time/timezoneoffset/
     *         Timezone offset
     *
     * @since     3.0.8
     * @deprecated 11.4.2
     * @product   highcharts highstock gantt
     */
    timezoneOffset: 0,
    /**
     * Whether to use UTC time for axis scaling, tickmark placement and
     * time display in `Highcharts.dateFormat`. Advantages of using UTC
     * is that the time displays equally regardless of the user agent's
     * time zone settings. Local time can be used when the data is loaded
     * in real time or when correct Daylight Saving Time transitions are
     * required.
     *
     * Setting `useUTC` to true is equivalent to setting `time.timezone` to
     * `"UTC"`. Setting `useUTC` to false is equivalent to setting
     * `time.timezone` to `undefined`.
     *
     * @see [time.timezone](#timezone)
     *
     * @sample {highcharts} highcharts/time/useutc-true/
     *         True by default
     * @sample {highcharts} highcharts/time/useutc-false/
     *         False
     *
     * @deprecated
     */
    useUTC: void 0
  },
  chart: ChartDefaults,
  /**
   * The chart's main title.
   *
   * @sample {highmaps} maps/title/title/
   *         Title options demonstrated
   * @sample {highcharts} highcharts/title/align-auto/
   *         Default title alignment
   */
  title: {
    /**
     * When the title is floating, the plot area will not move to make space
     * for it.
     *
     * @sample {highcharts} highcharts/chart/zoomtype-none/
     *         False by default
     * @sample {highcharts} highcharts/title/floating/
     *         True - title on top of the plot area
     * @sample {highstock} stock/chart/title-floating/
     *         True - title on top of the plot area
     *
     * @type      {boolean}
     * @default   false
     * @since     2.1
     * @apioption title.floating
     */
    /**
     * Whether to
     * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the text.
     *
     * @type      {boolean}
     * @default   false
     * @apioption title.useHTML
     */
    /**
     * The vertical alignment of the title. Can be one of `"top"`,
     * `"middle"` and `"bottom"`. When a value is given, the title behaves
     * as if [floating](#title.floating) were `true`.
     *
     * @sample {highcharts} highcharts/title/verticalalign/
     *         Chart title in bottom right corner
     * @sample {highstock} stock/chart/title-verticalalign/
     *         Chart title in bottom right corner
     *
     * @type      {Highcharts.VerticalAlignValue}
     * @since     2.1
     * @apioption title.verticalAlign
     */
    /**
     * The x position of the title relative to the alignment within
     * `chart.spacingLeft` and `chart.spacingRight`.
     *
     * @sample {highcharts} highcharts/title/align/
     *         Aligned to the plot area (x = 70px = margin left - spacing
     *         left)
     * @sample {highstock} stock/chart/title-align/
     *         Aligned to the plot area (x = 50px = margin left - spacing
     *         left)
     *
     * @type      {number}
     * @default   0
     * @since     2.0
     * @apioption title.x
     */
    /**
     * The y position of the title relative to the alignment within
     * [chart.spacingTop](#chart.spacingTop) and [chart.spacingBottom](
     * #chart.spacingBottom). By default it depends on the font size.
     *
     * @sample {highcharts} highcharts/title/y/
     *         Title inside the plot area
     * @sample {highstock} stock/chart/title-verticalalign/
     *         Chart title in bottom right corner
     *
     * @type      {number}
     * @since     2.0
     * @apioption title.y
     */
    /**
     * CSS styles for the title. Use this for font styling, but use `align`,
     * `x` and `y` for text alignment.
     *
     * Note that the default [title.minScale](#title.minScale) option also
     * affects the rendered font size. In order to keep the font size fixed
     * regardless of title length, set `minScale` to 1.
     *
     * In styled mode, the title style is given in the `.highcharts-title`
     * class.
     *
     * @sample {highcharts} highcharts/title/style/
     *         Custom color and weight
     * @sample {highstock} stock/chart/title-style/
     *         Custom color and weight
     * @sample highcharts/css/titles/
     *         Styled mode
     *
     * @type      {Highcharts.CSSObject}
     * @default   {highcharts|highmaps} { "color": "#333333", "fontSize": "18px" }
     * @default   {highstock} { "color": "#333333", "fontSize": "16px" }
     */
    style: {
      color: "#333333",
      fontWeight: "bold"
    },
    /**
     * The title of the chart. To disable the title, set the `text` to
     * `undefined`.
     *
     * @sample {highcharts} highcharts/title/text/
     *         Custom title
     * @sample {highstock} stock/chart/title-text/
     *         Custom title
     *
     * @default {highcharts|highmaps} Chart title
     * @default {highstock} undefined
     */
    text: "Chart title",
    /**
     * The horizontal alignment of the title. Can be one of "left", "center"
     * and "right".
     *
     * Since v12 it defaults to `undefined`, meaning the alignment is
     * computed for best fit. If the text fits in one line, it aligned to
     * the center, but if it is wrapped into multiple lines, it is aligned
     * to the left.
     *
     * @sample {highcharts} highcharts/title/align-auto/
     *         Default alignment, dynamic
     * @sample {highcharts} highcharts/title/align/
     *         Aligned to the plot area (x = 70px = margin left - spacing
     *         left)
     * @sample {highstock} stock/chart/title-align/
     *         Aligned to the plot area (x = 50px = margin left - spacing
     *         left)
     *
     * @type      {Highcharts.AlignValue}
     * @default   undefined
     * @since     2.0
     * @apioption title.align
     */
    /**
     * The margin between the title and the plot area, or if a subtitle
     * is present, the margin between the subtitle and the plot area.
     *
     * @sample {highcharts} highcharts/title/margin-50/
     *         A chart title margin of 50
     * @sample {highcharts} highcharts/title/margin-subtitle/
     *         The same margin applied with a subtitle
     * @sample {highstock} stock/chart/title-margin/
     *         A chart title margin of 50
     *
     * @since 2.1
     */
    margin: 15,
    /**
     * When the title is too wide to fit in the chart, the default behavior
     * is to scale it down to fit, or apply word wrap if it is scaled down
     * to `minScale` and still doesn't fit.
     *
     * The default value reflects the scale, when using default font sizes,
     * when the title font size matches that of the subtitle. The title
     * still stands out as it is bold by default.
     *
     * Set `minScale` to 1 to avoid downscaling.
     *
     * @sample {highcharts} highcharts/title/align-auto/
     *         Downscaling demonstrated
     *
     * @since 12.0.0
     */
    minScale: 0.67
  },
  /**
   * The chart's subtitle. This can be used both to display a subtitle below
   * the main title, and to display random text anywhere in the chart. The
   * subtitle can be updated after chart initialization through the
   * `Chart.setTitle` method.
   *
   * @sample {highcharts} highcharts/title/align-auto/
   *         Default title alignment
   * @sample {highmaps} maps/title/subtitle/
   *         Subtitle options demonstrated
   */
  subtitle: {
    /**
     * The horizontal alignment of the subtitle. Can be one of "left",
     * "center" and "right". Since v12, it defaults to `undefined`, meaning
     * the actual alignment is inherited from the alignment of the main
     * title.
     *
     * @sample {highcharts} highcharts/title/align-auto/
     *         Default title and subtitle alignment, dynamic
     * @sample {highcharts} highcharts/subtitle/align/
     *         Footnote at right of plot area
     * @sample {highstock} stock/chart/subtitle-footnote
     *         Footnote at bottom right of plot area
     *
     * @type  {Highcharts.AlignValue}
     * @default undefined
     * @since 2.0
     * @apioption subtitle.align
     */
    /**
     * When the subtitle is floating, the plot area will not move to make
     * space for it.
     *
     * @sample {highcharts} highcharts/subtitle/floating/
     *         Floating title and subtitle
     * @sample {highstock} stock/chart/subtitle-footnote
     *         Footnote floating at bottom right of plot area
     *
     * @type      {boolean}
     * @default   false
     * @since     2.1
     * @apioption subtitle.floating
     */
    /**
     * CSS styles for the title.
     *
     * In styled mode, the subtitle style is given in the
     * `.highcharts-subtitle` class.
     *
     * @sample {highcharts} highcharts/subtitle/style/
     *         Custom color and weight
     * @sample {highcharts} highcharts/css/titles/
     *         Styled mode
     * @sample {highstock} stock/chart/subtitle-style
     *         Custom color and weight
     * @sample {highstock} highcharts/css/titles/
     *         Styled mode
     * @sample {highmaps} highcharts/css/titles/
     *         Styled mode
     *
     * @type      {Highcharts.CSSObject}
     * @default   {"color": "#666666"}
     * @apioption subtitle.style
     */
    /**
     * Whether to
     * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the text.
     *
     * @type      {boolean}
     * @default   false
     * @apioption subtitle.useHTML
     */
    /**
     * The vertical alignment of the title. Can be one of `"top"`,
     * `"middle"` and `"bottom"`. When middle, the subtitle behaves as
     * floating.
     *
     * @sample {highcharts} highcharts/subtitle/verticalalign/
     *         Footnote at the bottom right of plot area
     * @sample {highstock} stock/chart/subtitle-footnote
     *         Footnote at the bottom right of plot area
     *
     * @type      {Highcharts.VerticalAlignValue}
     * @since     2.1
     * @apioption subtitle.verticalAlign
     */
    /**
     * The x position of the subtitle relative to the alignment within
     * `chart.spacingLeft` and `chart.spacingRight`.
     *
     * @sample {highcharts} highcharts/subtitle/align/
     *         Footnote at right of plot area
     * @sample {highstock} stock/chart/subtitle-footnote
     *         Footnote at the bottom right of plot area
     *
     * @type      {number}
     * @default   0
     * @since     2.0
     * @apioption subtitle.x
     */
    /**
     * The y position of the subtitle relative to the alignment within
     * `chart.spacingTop` and `chart.spacingBottom`. By default the subtitle
     * is laid out below the title unless the title is floating.
     *
     * @sample {highcharts} highcharts/subtitle/verticalalign/
     *         Footnote at the bottom right of plot area
     * @sample {highstock} stock/chart/subtitle-footnote
     *         Footnote at the bottom right of plot area
     *
     * @type      {number}
     * @since     2.0
     * @apioption subtitle.y
     */
    /**
     * CSS styles for the title.
     *
     * In styled mode, the subtitle style is given in the
     * `.highcharts-subtitle` class.
     *
     * @sample {highcharts} highcharts/subtitle/style/
     *         Custom color and weight
     * @sample {highcharts} highcharts/css/titles/
     *         Styled mode
     * @sample {highstock} stock/chart/subtitle-style
     *         Custom color and weight
     * @sample {highstock} highcharts/css/titles/
     *         Styled mode
     * @sample {highmaps} highcharts/css/titles/
     *         Styled mode
     *
     * @type      {Highcharts.CSSObject}
     * @default   {"color": "#666666"}
     */
    style: {
      color: "#666666",
      /**
       * @type {number|string}
       */
      fontSize: "0.8em"
    },
    /**
     * The subtitle of the chart.
     *
     * @sample {highcharts|highstock} highcharts/subtitle/text/
     *         Custom subtitle
     * @sample {highcharts|highstock} highcharts/subtitle/text-formatted/
     *         Formatted and linked text.
     */
    text: ""
  },
  /**
   * The chart's caption, which will render below the chart and will be part
   * of exported charts. The caption can be updated after chart initialization
   * through the `Chart.update` or `Chart.caption.update` methods.
   *
   * @sample highcharts/caption/text/
   *         A chart with a caption
   * @since  7.2.0
   */
  caption: {
    /**
     * When the caption is floating, the plot area will not move to make
     * space for it.
     *
     * @type      {boolean}
     * @default   false
     * @apioption caption.floating
     */
    /**
     * The margin between the caption and the plot area.
     */
    margin: 15,
    /**
     * Whether to
     * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the text.
     *
     * @type      {boolean}
     * @default   false
     * @apioption caption.useHTML
     */
    /**
     * The x position of the caption relative to the alignment within
     * `chart.spacingLeft` and `chart.spacingRight`.
     *
     * @type      {number}
     * @default   0
     * @apioption caption.x
     */
    /**
     * The y position of the caption relative to the alignment within
     * `chart.spacingTop` and `chart.spacingBottom`.
     *
     * @type      {number}
     * @apioption caption.y
     */
    /**
     * CSS styles for the caption.
     *
     * In styled mode, the caption style is given in the
     * `.highcharts-caption` class.
     *
     * @sample {highcharts} highcharts/css/titles/
     *         Styled mode
     *
     * @type      {Highcharts.CSSObject}
     * @default   {"color": "#666666"}
     */
    style: {
      color: "#666666",
      /**
       * @type {number|string}
       */
      fontSize: "0.8em"
    },
    /**
     * The caption text of the chart.
     *
     * @sample {highcharts} highcharts/caption/text/
     *         Custom caption
     */
    text: "",
    /**
     * The horizontal alignment of the caption. Can be one of "left",
     *  "center" and "right".
     *
     * @type  {Highcharts.AlignValue}
     */
    align: "left",
    /**
     * The vertical alignment of the caption. Can be one of `"top"`,
     * `"middle"` and `"bottom"`. When middle, the caption behaves as
     * floating.
     *
     * @type      {Highcharts.VerticalAlignValue}
     */
    verticalAlign: "bottom"
  },
  /**
   * The plotOptions is a wrapper object for config objects for each series
   * type. The config objects for each series can also be overridden for
   * each series item as given in the series array.
   *
   * Configuration options for the series are given in three levels. Options
   * for all series in a chart are given in the [plotOptions.series](
   * #plotOptions.series) object. Then options for all series of a specific
   * type are given in the plotOptions of that type, for example
   * `plotOptions.line`. Next, options for one single series are given in
   * [the series array](#series).
   */
  plotOptions: {},
  /**
   * The legend is a box containing a symbol and name for each series
   * item or point item in the chart. Each series (or points in case
   * of pie charts) is represented by a symbol and its name in the legend.
   *
   * It is possible to override the symbol creator function and create
   * [custom legend symbols](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/studies/legend-custom-symbol/).
   *
   * @productdesc {highmaps}
   * A Highmaps legend by default contains one legend item per series, but if
   * a `colorAxis` is defined, the axis will be displayed in the legend.
   * Either as a gradient, or as multiple legend items for `dataClasses`.
   */
  legend: {
    /**
     * The background color of the legend.
     *
     * @see In styled mode, the legend background fill can be applied with
     *      the `.highcharts-legend-box` class.
     *
     * @sample {highcharts} highcharts/legend/backgroundcolor/
     *         Yellowish background
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/border-background/
     *         Border and background options
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption legend.backgroundColor
     */
    /**
     * The width of the drawn border around the legend.
     *
     * @see In styled mode, the legend border stroke width can be applied
     *      with the `.highcharts-legend-box` class.
     *
     * @sample {highcharts} highcharts/legend/borderwidth/
     *         2px border width
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/border-background/
     *         Border and background options
     *
     * @type      {number}
     * @default   0
     * @apioption legend.borderWidth
     */
    /**
     * Enable or disable the legend. There is also a series-specific option,
     * [showInLegend](#plotOptions.series.showInLegend), that can hide the
     * series from the legend. In some series types this is `false` by
     * default, so it must set to `true` in order to show the legend for the
     * series.
     *
     * @sample {highcharts} highcharts/legend/enabled-false/ Legend disabled
     * @sample {highstock} stock/legend/align/ Various legend options
     * @sample {highmaps} maps/legend/enabled-false/ Legend disabled
     *
     * @default {highstock} false
     * @default {highmaps} true
     * @default {gantt} false
     */
    enabled: true,
    /**
     * The horizontal alignment of the legend box within the chart area.
     * Valid values are `left`, `center` and `right`.
     *
     * In the case that the legend is aligned in a corner position, the
     * `layout` option will determine whether to place it above/below
     * or on the side of the plot area.
     *
     * @sample {highcharts} highcharts/legend/align/
     *         Legend at the right of the chart
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/alignment/
     *         Legend alignment
     *
     * @type  {Highcharts.AlignValue}
     * @since 2.0
     */
    align: "center",
    /**
     * If the [layout](legend.layout) is `horizontal` and the legend items
     * span over two lines or more, whether to align the items into vertical
     * columns. Setting this to `false` makes room for more items, but will
     * look more messy.
     *
     * @since 6.1.0
     */
    alignColumns: true,
    /**
     * A CSS class name to apply to the legend group.
     */
    className: "highcharts-no-tooltip",
    /**
     * General event handlers for the legend. These event hooks can
     * also be attached to the legend at run time using the
     * `Highcharts.addEvent` function.
     *
     * @declare Highcharts.LegendEventsOptionsObject
     *
     * @private
     */
    events: {},
    /**
     * Fires when the legend item belonging to the series is clicked. One
     * parameter, `event`, is passed to the function. The default action
     * is to toggle the visibility of the series, point or data class. This
     * can be prevented by returning `false` or calling
     * `event.preventDefault()`.
     *
     * @sample {highcharts} highcharts/legend/itemclick/
     *         Confirm hiding and showing
     * @sample {highcharts} highcharts/legend/pie-legend-itemclick/
     *         Confirm toggle visibility of pie slices
     *
     * @type      {Highcharts.LegendItemClickCallbackFunction}
     * @context   Highcharts.Legend
     * @apioption legend.events.itemClick
     */
    /**
     * When the legend is floating, the plot area ignores it and is allowed
     * to be placed below it.
     *
     * @sample {highcharts} highcharts/legend/floating-false/
     *         False by default
     * @sample {highcharts} highcharts/legend/floating-true/
     *         True
     * @sample {highmaps} maps/legend/alignment/
     *         Floating legend
     *
     * @type      {boolean}
     * @default   false
     * @since     2.1
     * @apioption legend.floating
     */
    /**
     * The layout of the legend items. Can be one of `horizontal` or
     * `vertical` or `proximate`. When `proximate`, the legend items will be
     * placed as close as possible to the graphs they're representing,
     * except in inverted charts or when the legend position doesn't allow
     * it.
     *
     * @sample {highcharts} highcharts/legend/layout-horizontal/
     *         Horizontal by default
     * @sample {highcharts} highcharts/legend/layout-vertical/
     *         Vertical
     * @sample highcharts/legend/layout-proximate
     *         Labels proximate to the data
     * @sample {highstock} stock/legend/layout-horizontal/
     *         Horizontal by default
     * @sample {highmaps} maps/legend/padding-itemmargin/
     *         Vertical with data classes
     * @sample {highmaps} maps/legend/layout-vertical/
     *         Vertical with color axis gradient
     *
     * @validvalue ["horizontal", "vertical", "proximate"]
     */
    layout: "horizontal",
    /**
     * In a legend with horizontal layout, the itemDistance defines the
     * pixel distance between each item.
     *
     * @sample {highcharts} highcharts/legend/layout-horizontal/
     *         50px item distance
     * @sample {highstock} highcharts/legend/layout-horizontal/
     *         50px item distance
     *
     * @type      {number}
     * @default   {highcharts} 20
     * @default   {highstock} 20
     * @default   {highmaps} 8
     * @since     3.0.3
     * @apioption legend.itemDistance
     */
    /**
     * The pixel bottom margin for each legend item.
     *
     * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     * @sample {highmaps} maps/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     *
     * @since     2.2.0
     */
    itemMarginBottom: 2,
    /**
     * The pixel top margin for each legend item.
     *
     * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     * @sample {highmaps} maps/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     *
     * @since     2.2.0
     */
    itemMarginTop: 2,
    /**
     * The width for each legend item. By default the items are laid out
     * successively. In a [horizontal layout](legend.layout), if the items
     * are laid out across two rows or more, they will be vertically aligned
     * depending on the [legend.alignColumns](legend.alignColumns) option.
     *
     * @sample {highcharts} highcharts/legend/itemwidth-default/
     *         Undefined by default
     * @sample {highcharts} highcharts/legend/itemwidth-80/
     *         80 for aligned legend items
     *
     * @type      {number}
     * @since     2.0
     * @apioption legend.itemWidth
     */
    /**
     * A [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * for each legend label. Available variables relates to properties on
     * the series, or the point in case of pies.
     *
     * @type      {string}
     * @default   {name}
     * @since     1.3
     * @apioption legend.labelFormat
     */
    /* eslint-disable valid-jsdoc */
    /**
     * Callback function to format each of the series' labels. The `this`
     * keyword refers to the series object, or the point object in case of
     * pie charts. By default the series or point name is printed.
     *
     * @productdesc {highmaps}
     * In Highmaps the context can also be a data class in case of a
     * `colorAxis`.
     *
     * @sample {highcharts} highcharts/legend/labelformatter/
     *         Add text
     * @sample {highmaps} maps/legend/labelformatter/
     *         Data classes with label formatter
     *
     * @type {Highcharts.FormatterCallbackFunction<Point|Series>}
     */
    labelFormatter: function() {
      return this.name;
    },
    /**
     * Line height for the legend items. Deprecated as of 2.1\. Instead,
     * the line height for each item can be set using
     * `itemStyle.lineHeight`, and the padding between items using
     * `itemMarginTop` and `itemMarginBottom`.
     *
     * @sample {highcharts} highcharts/legend/lineheight/
     *         Setting padding
     *
     * @deprecated
     *
     * @type      {number}
     * @default   16
     * @since     2.0
     * @product   highcharts gantt
     * @apioption legend.lineHeight
     */
    /**
     * If the plot area sized is calculated automatically and the legend is
     * not floating, the legend margin is the space between the legend and
     * the axis labels or plot area.
     *
     * @sample {highcharts} highcharts/legend/margin-default/
     *         12 pixels by default
     * @sample {highcharts} highcharts/legend/margin-30/
     *         30 pixels
     *
     * @type      {number}
     * @default   12
     * @since     2.1
     * @apioption legend.margin
     */
    /**
     * Maximum pixel height for the legend. When the maximum height is
     * extended, navigation will show.
     *
     * @type      {number}
     * @since     2.3.0
     * @apioption legend.maxHeight
     */
    /**
     * The color of the drawn border around the legend.
     *
     * @see In styled mode, the legend border stroke can be applied with the
     *      `.highcharts-legend-box` class.
     *
     * @sample {highcharts} highcharts/legend/bordercolor/
     *         Brown border
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/border-background/
     *         Border and background options
     *
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    borderColor: "#999999",
    /**
     * The border corner radius of the legend.
     *
     * @sample {highcharts} highcharts/legend/borderradius-default/
     *         Square by default
     * @sample {highcharts} highcharts/legend/borderradius-round/
     *         5px rounded
     * @sample {highmaps} maps/legend/border-background/
     *         Border and background options
     */
    borderRadius: 0,
    /**
     * Options for the paging or navigation appearing when the legend is
     * overflown. Navigation works well on screen, but not in static
     * exported images. One way of working around that is to
     * [increase the chart height in
     * export](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/legend/navigation-enabled-false/).
     *
     * @sample highcharts/legend/scrollable-vertical/
     *         Legend with vertical scrollable extension
     * @sample highcharts/legend/scrollable-horizontal/
     *         Legend with horizontal scrollable extension
     *
     */
    navigation: {
      /**
       * How to animate the pages when navigating up or down. A value of
       * `true` applies the default navigation given in the
       * `chart.animation` option. Additional options can be given as an
       * object containing values for easing and duration.
       *
       * @sample {highcharts} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       * @sample {highstock} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       *
       * @type      {boolean|Partial<Highcharts.AnimationOptionsObject>}
       * @default   true
       * @since     2.2.4
       * @apioption legend.navigation.animation
       */
      /**
       * The pixel size of the up and down arrows in the legend paging
       * navigation.
       *
       * @sample {highcharts} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       * @sample {highstock} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       *
       * @type      {number}
       * @default   12
       * @since     2.2.4
       * @apioption legend.navigation.arrowSize
       */
      /**
       * Whether to enable the legend navigation. In most cases, disabling
       * the navigation results in an unwanted overflow.
       *
       * See also the
       * [adapt chart to legend](https://github.com/highcharts/adapt-chart-to-legend)
       * plugin for a solution to extend the chart height to make room for
       * the legend, optionally in exported charts only.
       *
       * @type      {boolean}
       * @default   true
       * @since     4.2.4
       * @apioption legend.navigation.enabled
       */
      /**
       * Text styles for the legend page navigation.
       *
       * @see In styled mode, the navigation items are styled with the
       *      `.highcharts-legend-navigation` class.
       *
       * @sample {highcharts} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       * @sample {highstock} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       *
       * @type      {Highcharts.CSSObject}
       * @since     2.2.4
       * @apioption legend.navigation.style
       */
      style: {
        /**
         * @type {number|string}
         */
        fontSize: "0.8em"
      },
      /**
       * The color for the active up or down arrow in the legend page
       * navigation.
       *
       * @see In styled mode, the active arrow be styled with the
       *      `.highcharts-legend-nav-active` class.
       *
       * @sample  {highcharts} highcharts/legend/navigation/
       *          Legend page navigation demonstrated
       * @sample  {highstock} highcharts/legend/navigation/
       *          Legend page navigation demonstrated
       *
       * @type  {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @since 2.2.4
       */
      activeColor: "#0022ff",
      /**
       * The color of the inactive up or down arrow in the legend page
       * navigation. .
       *
       * @see In styled mode, the inactive arrow be styled with the
       *      `.highcharts-legend-nav-inactive` class.
       *
       * @sample {highcharts} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       * @sample {highstock} highcharts/legend/navigation/
       *         Legend page navigation demonstrated
       *
       * @type  {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @since 2.2.4
       */
      inactiveColor: "#cccccc"
      /* Palette.neutralColor20 */
    },
    /**
     * The inner padding of the legend box.
     *
     * @sample {highcharts|highstock} highcharts/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     * @sample {highmaps} maps/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     *
     * @type      {number}
     * @default   8
     * @since     2.2.0
     * @apioption legend.padding
     */
    /**
     * Whether to reverse the order of the legend items compared to the
     * order of the series or points as defined in the configuration object.
     *
     * @see [yAxis.reversedStacks](#yAxis.reversedStacks),
     *      [series.legendIndex](#series.legendIndex)
     *
     * @sample {highcharts} highcharts/legend/reversed/
     *         Stacked bar with reversed legend
     *
     * @type      {boolean}
     * @default   false
     * @since     1.2.5
     * @apioption legend.reversed
     */
    /**
     * Whether to show the symbol on the right side of the text rather than
     * the left side. This is common in Arabic and Hebrew.
     *
     * @sample {highcharts} highcharts/legend/rtl/
     *         Symbol to the right
     *
     * @type      {boolean}
     * @default   false
     * @since     2.2
     * @apioption legend.rtl
     */
    /**
     * CSS styles for the legend area. In the 1.x versions the position
     * of the legend area was determined by CSS. In 2.x, the position is
     * determined by properties like `align`, `verticalAlign`, `x` and `y`,
     * but the styles are still parsed for backwards compatibility.
     *
     * @deprecated
     *
     * @type      {Highcharts.CSSObject}
     * @product   highcharts highstock
     * @apioption legend.style
     */
    /**
     * CSS styles for each legend item. Only a subset of CSS is supported,
     * notably those options related to text. The default `textOverflow`
     * property makes long texts truncate. Set it to `undefined` to wrap
     * text instead. A `width` property can be added to control the text
     * width.
     *
     * @see In styled mode, the legend items can be styled with the
     *      `.highcharts-legend-item` class.
     *
     * @sample {highcharts} highcharts/legend/itemstyle/
     *         Bold black text
     * @sample {highmaps} maps/legend/itemstyle/
     *         Item text styles
     *
     * @type    {Highcharts.CSSObject}
     * @default {"color": "#333333", "cursor": "pointer", "fontSize": "0.8em", "fontWeight": "bold", "textOverflow": "ellipsis"}
     */
    itemStyle: {
      /**
       * @ignore
       */
      color: "#333333",
      /**
       * @ignore
       */
      cursor: "pointer",
      /**
       * @ignore
       */
      fontSize: "0.8em",
      /**
       * @ignore
       */
      textDecoration: "none",
      /**
       * @ignore
       */
      textOverflow: "ellipsis"
    },
    /**
     * CSS styles for each legend item in hover mode. Only a subset of
     * CSS is supported, notably those options related to text. Properties
     * are inherited from `style` unless overridden here.
     *
     * @see In styled mode, the hovered legend items can be styled with
     *      the `.highcharts-legend-item:hover` pseudo-class.
     *
     * @sample {highcharts} highcharts/legend/itemhoverstyle/
     *         Red on hover
     * @sample {highmaps} maps/legend/itemstyle/
     *         Item text styles
     *
     * @type    {Highcharts.CSSObject}
     * @default {"color": "#000000"}
     */
    itemHoverStyle: {
      /**
       * @ignore
       */
      color: "#000000"
      /* Palette.neutralColor100 */
    },
    /**
     * CSS styles for each legend item when the corresponding series or
     * point is hidden. Only a subset of CSS is supported, notably those
     * options related to text. Properties are inherited from `style`
     * unless overridden here.
     *
     * @see In styled mode, the hidden legend items can be styled with
     *      the `.highcharts-legend-item-hidden` class.
     *
     * @sample {highcharts} highcharts/legend/itemhiddenstyle/
     *         Darker gray color
     *
     * @type    {Highcharts.CSSObject}
     * @default {"color": "#cccccc"}
     */
    itemHiddenStyle: {
      /**
       * @ignore
       */
      color: "#666666",
      /**
       * @ignore
       */
      textDecoration: "line-through"
    },
    /**
     * Whether to apply a drop shadow to the legend. A `backgroundColor`
     * also needs to be applied for this to take effect. The shadow can be
     * an object configuration containing `color`, `offsetX`, `offsetY`,
     * `opacity` and `width`.
     *
     * @sample {highcharts} highcharts/legend/shadow/
     *         White background and drop shadow
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/border-background/
     *         Border and background options
     *
     * @type {boolean|Highcharts.CSSObject}
     */
    shadow: false,
    /**
     * Default styling for the checkbox next to a legend item when
     * `showCheckbox` is true.
     *
     * @type {Highcharts.CSSObject}
     * @default {"width": "13px", "height": "13px", "position":"absolute"}
     */
    itemCheckboxStyle: {
      /**
       * @ignore
       */
      position: "absolute",
      /**
       * @ignore
       */
      width: "13px",
      // For IE precision
      /**
       * @ignore
       */
      height: "13px"
    },
    /// itemWidth: undefined,
    /**
     * When this is true, the legend symbol width will be the same as
     * the symbol height, which in turn defaults to the font size of the
     * legend items.
     *
     * @since 5.0.0
     */
    squareSymbol: true,
    /**
     * The pixel height of the symbol for series types that use a rectangle
     * in the legend. Defaults to the font size of legend items.
     *
     * Note: This option is a default source of color axis height, if the
     * [colorAxis.height](https://api.highcharts.com/highcharts/colorAxis.height)
     * option is not set.
     *
     * @productdesc {highmaps}
     * In Highmaps, when the symbol is the gradient of a vertical color
     * axis, the height defaults to 200.
     *
     * @sample {highmaps} maps/legend/layout-vertical-sized/
     *         Sized vertical gradient
     * @sample {highmaps} maps/legend/padding-itemmargin/
     *         No distance between data classes
     *
     * @type      {number}
     * @since     3.0.8
     * @apioption legend.symbolHeight
     */
    /**
     * The border radius of the symbol for series types that use a rectangle
     * in the legend. Defaults to half the `symbolHeight`, effectively
     * creating a circle.
     *
     * For color axis scales, it defaults to 3.
     *
     * @sample {highcharts} highcharts/legend/symbolradius/
     *         Round symbols
     * @sample {highstock} highcharts/legend/symbolradius/
     *         Round symbols
     * @sample {highmaps} highcharts/legend/symbolradius/
     *         Round symbols
     *
     * @type      {number}
     * @since     3.0.8
     * @apioption legend.symbolRadius
     */
    /**
     * The pixel width of the legend item symbol. When the `squareSymbol`
     * option is set, this defaults to the `symbolHeight`, otherwise 16.
     *
     * Note: This option is a default source of color axis width, if the
     * [colorAxis.width](https://api.highcharts.com/highcharts/colorAxis.width)
     * option is not set.
     *
     * @productdesc {highmaps}
     * In Highmaps, when the symbol is the gradient of a horizontal color
     * axis, the width defaults to 200.
     *
     * @sample {highcharts} highcharts/legend/symbolwidth/
     *         Greater symbol width and padding
     * @sample {highmaps} maps/legend/padding-itemmargin/
     *         Padding and item margins demonstrated
     * @sample {highmaps} maps/legend/layout-vertical-sized/
     *         Sized vertical gradient
     *
     * @type      {number}
     * @apioption legend.symbolWidth
     */
    /**
     * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the legend item texts.
     *
     * Prior to 4.1.7, when using HTML, [legend.navigation](
     * #legend.navigation) was disabled.
     *
     * @sample highcharts/legend/scrollable-vertical/
     *         Legend with vertical scrollable extension
     * @sample highcharts/legend/scrollable-horizontal/
     *         Legend with horizontal scrollable extension
     *
     * @type      {boolean}
     * @default   false
     * @apioption legend.useHTML
     */
    /**
     * For a color axis with data classes, how many decimals to render in
     * the legend. The default preserves the decimals of the range numbers.
     *
     * @type      {number}
     * @default   -1
     * @product   highcharts highmaps
     * @apioption legend.valueDecimals
     */
    /**
     * For a color axis with data classes, a suffix for the range numbers in
     * the legend.
     *
     * @type      {string}
     * @default   ''
     * @product   highcharts highmaps
     * @apioption legend.valueSuffix
     */
    /**
     * The width of the legend box. If a number is set, it translates to
     * pixels. Since v7.0.2 it allows setting a percent string of the full
     * chart width, for example `40%`.
     *
     * Defaults to the full chart width for legends below or above the
     * chart, half the chart width for legends to the left and right.
     *
     * @sample {highcharts} highcharts/legend/width/
     *         Aligned to the plot area
     * @sample {highcharts} highcharts/legend/width-percent/
     *         A percent of the chart width
     *
     * @type      {number|string}
     * @since     2.0
     * @apioption legend.width
     */
    /**
     * The pixel padding between the legend item symbol and the legend
     * item text.
     *
     * @sample {highcharts} highcharts/legend/symbolpadding/
     *         Greater symbol width and padding
     */
    symbolPadding: 5,
    /**
     * The vertical alignment of the legend box. Can be one of `top`,
     * `middle` or `bottom`. Vertical position can be further determined
     * by the `y` option.
     *
     * In the case that the legend is aligned in a corner position, the
     * `layout` option will determine whether to place it above/below
     * or on the side of the plot area.
     *
     * When the [layout](#legend.layout) option is `proximate`, the
     * `verticalAlign` option doesn't apply.
     *
     * @sample {highcharts} highcharts/legend/verticalalign/
     *         Legend 100px from the top of the chart
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/alignment/
     *         Legend alignment
     *
     * @type  {Highcharts.VerticalAlignValue}
     * @since 2.0
     */
    verticalAlign: "bottom",
    // Width: undefined,
    /**
     * The x offset of the legend relative to its horizontal alignment
     * `align` within chart.spacingLeft and chart.spacingRight. Negative
     * x moves it to the left, positive x moves it to the right.
     *
     * @sample {highcharts} highcharts/legend/width/
     *         Aligned to the plot area
     *
     * @since 2.0
     */
    x: 0,
    /**
     * The vertical offset of the legend relative to it's vertical alignment
     * `verticalAlign` within chart.spacingTop and chart.spacingBottom.
     *  Negative y moves it up, positive y moves it down.
     *
     * @sample {highcharts} highcharts/legend/verticalalign/
     *         Legend 100px from the top of the chart
     * @sample {highstock} stock/legend/align/
     *         Various legend options
     * @sample {highmaps} maps/legend/alignment/
     *         Legend alignment
     *
     * @since 2.0
     */
    y: 0,
    /**
     * A title to be added on top of the legend.
     *
     * @sample {highcharts} highcharts/legend/title/
     *         Legend title
     * @sample {highmaps} maps/legend/alignment/
     *         Legend with title
     *
     * @since 3.0
     */
    title: {
      /**
       * A text or HTML string for the title.
       *
       * @type      {string}
       * @since     3.0
       * @apioption legend.title.text
       */
      /**
       * Generic CSS styles for the legend title.
       *
       * @see In styled mode, the legend title is styled with the
       *      `.highcharts-legend-title` class.
       *
       * @type    {Highcharts.CSSObject}
       * @default {"fontSize": "0.8em", "fontWeight": "bold"}
       * @since   3.0
       */
      style: {
        /**
         * @ignore
         */
        fontSize: "0.8em",
        /**
         * @ignore
         */
        fontWeight: "bold"
      }
    }
  },
  /**
   * The loading options control the appearance of the loading screen
   * that covers the plot area on chart operations. This screen only
   * appears after an explicit call to `chart.showLoading()`. It is a
   * utility for developers to communicate to the end user that something
   * is going on, for example while retrieving new data via an XHR connection.
   * The "Loading..." text itself is not part of this configuration
   * object, but part of the `lang` object.
   */
  loading: {
    /**
     * The duration in milliseconds of the fade out effect.
     *
     * @sample highcharts/loading/hideduration/
     *         Fade in and out over a second
     *
     * @type      {number}
     * @default   100
     * @since     1.2.0
     * @apioption loading.hideDuration
     */
    /**
     * The duration in milliseconds of the fade in effect.
     *
     * @sample highcharts/loading/hideduration/
     *         Fade in and out over a second
     *
     * @type      {number}
     * @default   100
     * @since     1.2.0
     * @apioption loading.showDuration
     */
    /**
     * CSS styles for the loading label `span`.
     *
     * @see In styled mode, the loading label is styled with the
     *      `.highcharts-loading-inner` class.
     *
     * @sample {highcharts|highmaps} highcharts/loading/labelstyle/
     *         Vertically centered
     * @sample {highstock} stock/loading/general/
     *         Label styles
     *
     * @type    {Highcharts.CSSObject}
     * @default {"fontWeight": "bold", "position": "relative", "top": "45%"}
     * @since   1.2.0
     */
    labelStyle: {
      /**
       * @ignore
       */
      fontWeight: "bold",
      /**
       * @ignore
       */
      position: "relative",
      /**
       * @ignore
       */
      top: "45%"
    },
    /**
     * CSS styles for the loading screen that covers the plot area.
     *
     * In styled mode, the loading label is styled with the
     * `.highcharts-loading` class.
     *
     * @sample  {highcharts|highmaps} highcharts/loading/style/
     *          Gray plot area, white text
     * @sample  {highstock} stock/loading/general/
     *          Gray plot area, white text
     *
     * @type    {Highcharts.CSSObject}
     * @default {"position": "absolute", "backgroundColor": "#ffffff", "opacity": 0.5, "textAlign": "center"}
     * @since   1.2.0
     */
    style: {
      /**
       * @ignore
       */
      position: "absolute",
      /**
       * @ignore
       */
      backgroundColor: "#ffffff",
      /**
       * @ignore
       */
      opacity: 0.5,
      /**
       * @ignore
       */
      textAlign: "center"
    }
  },
  /**
   * Options for the tooltip that appears when the user hovers over a
   * series or point.
   *
   * @declare Highcharts.TooltipOptions
   */
  tooltip: {
    /**
     * The color of the tooltip border. When `undefined`, the border takes
     * the color of the corresponding series or point.
     *
     * Note that the [borderWidth](#tooltip.borderWidth) is usually 0 by
     * default, so the border color may not be visible until a border width
     * is set.
     *
     * @sample {highcharts} highcharts/tooltip/bordercolor-default/ Follow
     *         series by default
     * @sample {highcharts} highcharts/tooltip/bordercolor-black/ Black
     *         border
     * @sample {highstock} stock/tooltip/general/ Styled tooltip
     * @sample {highmaps} maps/tooltip/background-border/ Background and
     *         border demo
     *
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption tooltip.borderColor
     */
    /**
     * A CSS class name to apply to the tooltip's container div,
     * allowing unique CSS styling for each chart.
     *
     * @type      {string}
     * @apioption tooltip.className
     */
    /**
     * Since 4.1, the crosshair definitions are moved to the Axis object
     * in order for a better separation from the tooltip. See
     * [xAxis.crosshair](#xAxis.crosshair).
     *
     * @sample {highcharts} highcharts/tooltip/crosshairs-x/
     *         Enable a crosshair for the x value
     *
     * @deprecated
     *
     * @type      {*}
     * @default   true
     * @apioption tooltip.crosshairs
     */
    /**
     * Distance from point to tooltip in pixels.
     *
     * @type      {number}
     * @default   16
     * @apioption tooltip.distance
     */
    /**
     * Whether the tooltip should be fixed to one position in the chart, or
     * located next to the point or mouse. When the tooltip is fixed, the
     * position can be further specified with the
     * [tooltip.position](#tooltip.position) options set.
     *
     * @sample    highcharts/tooltip/fixed/
     *            Fixed tooltip and position options
     * @sample    {highstock} stock/tooltip/fixed/
     *            Stock chart with fixed tooltip
     * @sample    {highmaps} maps/tooltip/fixed/
     *            Map with fixed tooltip
     *
     * @type      {boolean}
     * @default   false
     * @since 12.2.0
     * @apioption tooltip.fixed
     */
    /**
     * Whether the tooltip should follow the mouse as it moves across
     * columns, pie slices and other point types with an extent.
     * By default it behaves this way for pie, polygon, map, sankey
     * and wordcloud series by override in the `plotOptions`
     * for those series types.
     *
     * Does not apply if [split](#tooltip.split) is `true`.
     *
     * For touch moves to behave the same way, [followTouchMove](
     * #tooltip.followTouchMove) must be `true` also.
     *
     * @sample highcharts/tooltip/followpointer/
     *         Tooltip follow pointer comparison
     *
     * @type      {boolean}
     * @default   {highcharts} false
     * @default   {highstock} false
     * @default   {highmaps} true
     * @since     3.0
     * @apioption tooltip.followPointer
     */
    /**
     * Whether the tooltip should update as the finger moves on a touch
     * device. If this is `true` and [chart.panning](#chart.panning) is
     * set,`followTouchMove` will take over one-finger touches, so the user
     * needs to use two fingers for zooming and panning.
     *
     * Note the difference to [followPointer](#tooltip.followPointer) that
     * only defines the _position_ of the tooltip. If `followPointer` is
     * false in for example a column series, the tooltip will show above or
     * below the column, but as `followTouchMove` is true, the tooltip will
     * jump from column to column as the user swipes across the plot area.
     *
     * @type      {boolean}
     * @default   {highcharts} true
     * @default   {highstock} true
     * @default   {highmaps} false
     * @since     3.0.1
     * @apioption tooltip.followTouchMove
     */
    /**
     * A [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * for the whole shared tooltip. When format strings are a requirement,
     * it is usually more convenient to use `headerFormat`, `pointFormat`
     * and `footerFormat`, but the `format` option allows combining them
     * into one setting.
     *
     * The context of the format string is the same as that of the
     * `tooltip.formatter` callback.
     *
     * @sample {highcharts} highcharts/tooltip/format-shared/
     *         Format for shared tooltip
     *
     * @type      {string}
     * @default   undefined
     * @since     11.1.0
     * @apioption tooltip.format
     */
    /**
     * Callback function to format the text of the tooltip from scratch. In
     * case of single or [shared](#tooltip.shared) tooltips, a string should
     * be returned. In case of [split](#tooltip.split) tooltips, it should
     * return an array where the first item is the header, and subsequent
     * items are mapped to the points. Return `false` to disable tooltip for
     * a specific point on series.
     *
     * A subset of HTML is supported. Unless `useHTML` is true, the HTML of
     * the tooltip is parsed and converted to SVG, therefore this isn't a
     * complete HTML renderer. The following HTML tags are supported: `b`,
     * `br`, `em`, `i`, `span`, `strong`. Spans can be styled with a `style`
     * attribute, but only text-related CSS, that is shared with SVG, is
     * handled.
     *
     * The context of the formatter (since v12) is the
     * [Point](https://api.highcharts.com/class-reference/Highcharts.Point)
     * instance. If the tooltip is shared or split, an array `this.points`
     * contains all points of the hovered x-value.
     *
     * Common properties from the Point to use in the formatter include:
     *
     * - **Point.percentage**:
     *   Stacked series and pies only. The point's percentage of the total.
     *
     * - **Point.points**:
     *   In a shared or split tooltip, this is an array containing all the
     *   hovered points.
     *
     * - **this.series**:
     *   The series object. The series name is available through
     *   `this.series.name`.
     *
     * - **this.total**:
     *   The total value at this point's x value in a stacked series, or the
     *   sum of all slices in a pie series.
     *
     * - **this.x**:
     *   The x value.
     *
     * - **this.y**:
     *   The y value.
     *
     * @sample {highcharts} highcharts/tooltip/formatter-simple/
     *         Simple string formatting
     * @sample {highcharts} highcharts/tooltip/formatter-shared/
     *         Formatting with shared tooltip
     * @sample {highcharts|highstock} highcharts/tooltip/formatter-split/
     *         Formatting with split tooltip
     * @sample highcharts/tooltip/formatter-conditional-default/
     *         Extending default formatter
     * @sample {highstock} stock/tooltip/formatter/
     *         Formatting with shared tooltip
     * @sample {highmaps} maps/tooltip/formatter/
     *         String formatting
     *
     * @type      {Highcharts.TooltipFormatterCallbackFunction}
     * @apioption tooltip.formatter
     */
    /**
     * Callback function to format the text of the tooltip for
     * visible null points.
     * Works analogously to [formatter](#tooltip.formatter).
     *
     * @sample highcharts/plotoptions/series-nullformat
     *         Format data label and tooltip for null point.
     *
     * @type      {Highcharts.TooltipFormatterCallbackFunction}
     * @apioption tooltip.nullFormatter
     */
    /**
     * Whether to allow the tooltip to render outside the chart's SVG
     * element box. By default (`false`), the tooltip is rendered within the
     * chart's SVG element, which results in the tooltip being aligned
     * inside the chart area. For small charts, this may result in clipping
     * or overlapping. When `true`, a separate SVG element is created and
     * overlaid on the page, allowing the tooltip to be aligned inside the
     * page itself. Beware that with this option active, CSS classes on the
     * chart's target container, with classnames matching the pattern
     * 'highcharts-*', will be set on the tooltip as well. This is done to
     * support theming for tooltips with this option.
     *
     * Defaults to `true` if `chart.scrollablePlotArea` is activated,
     * otherwise `false`.
     *
     * @sample highcharts/tooltip/outside
     *         Small charts with tooltips outside
     *
     * @type      {boolean|undefined}
     * @default   undefined
     * @since     6.1.1
     * @apioption tooltip.outside
     */
    /**
     * A callback function for formatting the HTML output for a single point
     * in the tooltip. Like the `pointFormat` string, but with more
     * flexibility.
     *
     * @type      {Highcharts.FormatterCallbackFunction<Highcharts.Point>}
     * @since     4.1.0
     * @context   Highcharts.Point
     * @apioption tooltip.pointFormatter
     */
    /**
     * A callback function to place the tooltip in a custom position. The
     * callback receives three parameters: `labelWidth`, `labelHeight` and
     * `point`, where point contains values for `plotX` and `plotY` telling
     * where the reference point is in the plot area. Add `chart.plotLeft`
     * and `chart.plotTop` to get the full coordinates.
     *
     * To find the actual hovered `Point` instance, use
     * `this.chart.hoverPoint`. For shared or split tooltips, all the hover
     * points are available in `this.chart.hoverPoints`.
     *
     * Since v7, when [tooltip.split](#tooltip.split) option is enabled,
     * positioner is called for each of the boxes separately, including
     * xAxis header. xAxis header is not a point, instead `point` argument
     * contains info: `{ plotX: Number, plotY: Number, isHeader: Boolean }`
     *
     * Since v12.2, the [tooltip.fixed](#tooltip.fixed) option combined with
     * [tooltip.position](#tooltip.position) covers most of the use cases
     * for custom tooltip positioning.
     *
     * The return should be an object containing x and y values, for example
     * `{ x: 100, y: 100 }`.
     *
     * @sample {highcharts} highcharts/tooltip/positioner/
     *         A fixed tooltip position
     * @sample {highstock} stock/tooltip/positioner/
     *         A fixed tooltip position on top of the chart
     * @sample {highmaps} maps/tooltip/positioner/
     *         A fixed tooltip position
     * @sample {highstock} stock/tooltip/split-positioner/
     *         Split tooltip with fixed positions
     * @sample {highstock} stock/tooltip/positioner-scrollable-plotarea/
     *         Scrollable plot area combined with tooltip positioner
     *
     * @see [position](#tooltip.position)
     *
     * @type      {Highcharts.TooltipPositionerCallbackFunction}
     * @since     2.2.4
     * @apioption tooltip.positioner
     */
    /**
     * Shows tooltip for all points with the same X value. Splits the
     * tooltip into one label per series, with the header close to the axis.
     * This is recommended over [shared](#tooltip.shared)
     * tooltips for charts with multiple line series, generally making them
     * easier to read. This option takes precedence over `tooltip.shared`.
     *
     * Not supported for [polar](#chart.polar) and [inverted](#chart.inverted) charts.
     *
     * @productdesc {highstock} In Highcharts Stock, tooltips are split
     * by default since v6.0.0. Stock charts typically contain
     * multi-dimension points and multiple panes, making split tooltips
     * the preferred layout over
     * the previous `shared` tooltip.
     *
     * @sample highcharts/tooltip/split/
     *         Split tooltip
     * @sample {highcharts|highstock} highcharts/tooltip/formatter-split/
     *         Split tooltip and custom formatter callback
     *
     * @type      {boolean}
     * @default   {highcharts} false
     * @default   {highstock} true
     * @since     5.0.0
     * @product   highcharts highstock
     * @apioption tooltip.split
     */
    /**
     * Prevents the tooltip from switching or closing, when touched or
     * pointed.
     *
     * @sample highcharts/tooltip/stickoncontact/
     *         Tooltip sticks on pointer contact
     *
     * @type      {boolean}
     * @since     8.0.1
     * @apioption tooltip.stickOnContact
     */
    /**
     * Use HTML to render the contents of the tooltip instead of SVG. Using
     * HTML allows advanced formatting like tables and images in the
     * tooltip. It is also recommended for rtl languages as it works around
     * rtl bugs in early Firefox.
     *
     * @sample {highcharts|highstock} highcharts/tooltip/footerformat/
     *         A table for value alignment
     * @sample {highcharts|highstock} highcharts/tooltip/fullhtml/
     *         Full HTML tooltip
     * @sample {highmaps} maps/tooltip/usehtml/
     *         Pure HTML tooltip
     *
     * @type      {boolean}
     * @default   false
     * @since     2.2
     * @apioption tooltip.useHTML
     */
    /**
     * How many decimals to show in each series' y value. This is
     * overridable in each series' tooltip options object. The default is to
     * preserve all decimals.
     *
     * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
     *         Set decimals, prefix and suffix for the value
     * @sample {highmaps} maps/tooltip/valuedecimals/
     *         Set decimals, prefix and suffix for the value
     *
     * @type      {number|undefined}
     * @since     2.2
     * @apioption tooltip.valueDecimals
     */
    /**
     * A string to prepend to each series' y value. Overridable in each
     * series' tooltip options object.
     *
     * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
     *         Set decimals, prefix and suffix for the value
     * @sample {highmaps} maps/tooltip/valuedecimals/
     *         Set decimals, prefix and suffix for the value
     *
     * @type      {string}
     * @since     2.2
     * @apioption tooltip.valuePrefix
     */
    /**
     * A string to append to each series' y value. Overridable in each
     * series' tooltip options object.
     *
     * @sample {highcharts|highstock} highcharts/tooltip/valuedecimals/
     *         Set decimals, prefix and suffix for the value
     * @sample {highmaps} maps/tooltip/valuedecimals/
     *         Set decimals, prefix and suffix for the value
     *
     * @type      {string}
     * @since     2.2
     * @apioption tooltip.valueSuffix
     */
    /**
     * The format for the date in the tooltip header if the X axis is a
     * datetime axis. The default is a best guess based on the smallest
     * distance between points in the chart.
     *
     * @sample {highcharts} highcharts/tooltip/xdateformat/
     *         A different format
     *
     * @type      {string|Highcharts.DateTimeFormatOptions}
     * @product   highcharts highstock gantt
     * @apioption tooltip.xDateFormat
     */
    /**
     * How many decimals to show for the `point.change`
     * or the `point.cumulativeSum` value when the `series.compare`
     * or the `series.cumulative` option is set.
     * This is overridable in each series' tooltip options object.
     *
     * @type      {number}
     * @default   2
     * @since     1.0.1
     * @product   highstock
     * @apioption tooltip.changeDecimals
     */
    /**
     * Enable or disable the tooltip.
     *
     * @sample {highcharts} highcharts/tooltip/enabled/
     *         Disabled
     * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
     *         Disable tooltip and show values on chart instead
     */
    enabled: true,
    /**
     * Enable or disable animation of the tooltip.
     *
     * @type       {boolean|Partial<Highcharts.AnimationOptionsObject>}
     * @since      2.3.0
     */
    animation: {
      duration: 300,
      // EaseOutCirc
      easing: (x) => Math.sqrt(1 - Math.pow(x - 1, 2))
    },
    /**
     * The radius of the rounded border corners.
     *
     * @sample {highcharts} highcharts/tooltip/bordercolor-default/
     *         Default border radius
     * @sample {highcharts} highcharts/tooltip/borderradius-0/
     *         Square borders
     * @sample {highmaps} maps/tooltip/background-border/
     *         Background and border demo
     */
    borderRadius: 3,
    /**
     * For series on datetime axes, the date format in the tooltip's
     * header will by default be guessed based on the closest data points.
     * This member gives the default string representations used for
     * each unit. For an overview of the string or object configuration, see
     * [dateFormat](/class-reference/Highcharts.Time#dateFormat).
     *
     * @see [xAxis.dateTimeLabelFormats](#xAxis.dateTimeLabelFormats)
     *
     * @type    {Highcharts.Dictionary<string|Highcharts.DateTimeFormatOptions>}
     * @product highcharts highstock gantt
     */
    dateTimeLabelFormats: {
      /** @internal */
      millisecond: "%[AebHMSL]",
      /** @internal */
      second: "%[AebHMS]",
      /** @internal */
      minute: "%[AebHM]",
      /** @internal */
      hour: "%[AebHM]",
      /** @internal */
      day: "%[AebY]",
      /** @internal */
      week: "%v %[AebY]",
      /** @internal */
      month: "%[BY]",
      /** @internal */
      year: "%Y"
    },
    /**
     * A string to append to the tooltip format.
     *
     * @sample {highcharts} highcharts/tooltip/footerformat/
     *         A table for value alignment
     * @sample {highmaps} maps/tooltip/format/
     *         Format demo
     *
     * @since 2.2
     */
    footerFormat: "",
    /**
     * The name of a symbol to use for the border around the tooltip
     * header. Applies only when [tooltip.split](#tooltip.split) is
     * enabled.
     *
     * Custom callbacks for symbol path generation can also be added to
     * `Highcharts.SVGRenderer.prototype.symbols` the same way as for
     * [series.marker.symbol](plotOptions.line.marker.symbol).
     *
     * @see [tooltip.shape](#tooltip.shape)
     *
     * @sample {highstock} stock/tooltip/split-positioner/
     *         Different shapes for header and split boxes
     *
     * @type       {Highcharts.TooltipShapeValue}
     * @validvalue ["callout", "rect"]
     * @since      7.0
     */
    headerShape: "callout",
    /**
     * The number of milliseconds to wait until the tooltip is hidden when
     * mouse out from a point or chart.
     *
     * @since 3.0
     */
    hideDelay: 500,
    /**
     * Padding inside the tooltip, in pixels.
     *
     * @since 5.0.0
     */
    padding: 8,
    /**
     * Positioning options for fixed tooltip, taking effect only when
     * [tooltip.fixed](#tooltip.fixed) is `true`.
     *
     * @sample {highcharts} highcharts/tooltip/fixed/
     *         Fixed tooltip and position options
     * @sample {highstock} stock/tooltip/fixed/
     *         Stock chart with fixed tooltip
     * @sample {highmaps} maps/tooltip/fixed/
     *         Map with fixed tooltip
     *
     * @since 12.2.0
     */
    position: {
      /**
       * The horizontal alignment of the fixed tooltip.
       *
       * @sample highcharts/tooltip/fixed/
       *         Fixed tooltip
       * @sample {highstock} stock/tooltip/fixed/
       *         Stock chart with fixed tooltip
       *
       * @type {Highcharts.AlignValue}
       * @default left
       * @apioption tooltip.position.align
       */
      /**
       * The vertical alignment of the fixed tooltip.
       *
       * @sample highcharts/tooltip/fixed/
       *         Fixed tooltip
       * @sample {highstock} stock/tooltip/fixed/
       *         Stock chart with fixed tooltip
       *
       * @type {Highcharts.VerticalAlignValue}
       * @default top
       * @apioption tooltip.position.verticalAlign
       */
      /**
       * What the fixed tooltip alignment should be relative to.
       *
       * The default, `pane`, means that it is aligned within the plot
       * area for that given series. If the tooltip is split (as default
       * in Stock charts), each partial tooltip is aligned within the
       * series' pane.
       *
       * @sample highcharts/tooltip/fixed/
       *         Fixed tooltip
       * @sample {highstock} stock/tooltip/fixed/
       *         Stock chart with fixed tooltip
       *
       * @type {string}
       * @default pane
       * @validvalue ["pane", "chart", "plotBox", "spacingBox"]
       * @apioption tooltip.position.relativeTo
       */
      /**
       * X pixel offset from the given position. Can be used to shy away
       * from axis lines, grid lines etc to avoid the tooltip overlapping
       * other elements.
       *
       * @sample highcharts/tooltip/fixed/
       *         Fixed tooltip
       * @sample {highstock} stock/tooltip/fixed/
       *         Stock chart with fixed tooltip
       */
      x: 0,
      /**
       * Y pixel offset from the given position. Can be used to shy away
       * from axis lines, grid lines etc to avoid the tooltip overlapping
       * other elements.
       *
       * @sample highcharts/tooltip/fixed/
       *         Fixed tooltip
       * @sample {highstock} stock/tooltip/fixed/
       *         Stock chart with fixed tooltip
       */
      y: 3
    },
    /**
     * The name of a symbol to use for the border around the tooltip. Can
     * be one of: `"callout"`, `"circle"` or `"rect"`. When
     * [tooltip.split](#tooltip.split)
     * option is enabled, shape is applied to all boxes except header, which
     * is controlled by
     * [tooltip.headerShape](#tooltip.headerShape).
     *
     * Custom callbacks for symbol path generation can also be added to
     * `Highcharts.SVGRenderer.prototype.symbols` the same way as for
     * [series.marker.symbol](plotOptions.line.marker.symbol).
     *
     * Defaults to `callout` for floating tooltip, `rect` for
     * [fixed](#tooltip.fixed) tooltip.
     *
     * @type  {Highcharts.TooltipShapeValue}
     * @since 4.0
     * @default undefined
     * @apioption tooltip.shape
     */
    /**
     * Shows information in the tooltip for all points with the same X
     * value. When the tooltip is shared, the entire plot area will capture
     * mouse movement or touch events. Tooltip texts for series types with
     * ordered data (not pie, scatter, flags etc) will be shown in a single
     * bubble. This is recommended for single series charts and for
     * tablet/mobile optimized charts.
     *
     * See also [tooltip.split](#tooltip.split), that is better suited for
     * charts with many series, especially line-type series. The
     * `tooltip.split` option takes precedence over `tooltip.shared`.
     *
     * @sample {highcharts} highcharts/tooltip/shared-false/
     *         False by default
     * @sample {highcharts} highcharts/tooltip/shared-true/
     *         True
     * @sample {highcharts} highcharts/tooltip/shared-x-crosshair/
     *         True with x axis crosshair
     * @sample {highcharts} highcharts/tooltip/shared-true-mixed-types/
     *         True with mixed series types
     *
     * @since   2.1
     * @product highcharts highstock
     */
    shared: false,
    /**
     * Proximity snap for graphs or single points. It defaults to 10 for
     * mouse-powered devices and 25 for touch devices.
     *
     * Note that in most cases the whole plot area captures the mouse
     * movement, and in these cases `tooltip.snap` doesn't make sense. This
     * applies when [stickyTracking](#plotOptions.series.stickyTracking)
     * is `true` (default) and when the tooltip is [shared](#tooltip.shared)
     * or [split](#tooltip.split).
     *
     * @sample {highcharts} highcharts/tooltip/bordercolor-default/
     *         10 px by default
     * @sample {highcharts} highcharts/tooltip/snap-50/
     *         50 px on graph
     *
     * @type    {number}
     * @default 10/25
     * @since   1.2.0
     * @product highcharts highstock
     */
    snap: isTouchDevice$6 ? 25 : 10,
    /**
     * The HTML of the tooltip header line. The context is the
     * [Point class](https://api.highcharts.com/class-reference/Highcharts.Point).
     * Variables are enclosed in curly brackets. Examples of common
     * variables to include are `x`, `y`, `series.name` and `series.color`
     * and other properties on the same form. The `point.key` variable
     * contains the category name, x value or datetime string depending on
     * the type of axis. For datetime axes, the `point.key` date format can
     * be set using `tooltip.xDateFormat`.
     *
     * @sample {highcharts} highcharts/tooltip/footerformat/
     *         An HTML table in the tooltip
     * @sample {highstock} highcharts/tooltip/footerformat/
     *         An HTML table in the tooltip
     * @sample {highmaps} maps/tooltip/format/
     *         Format demo
     *
     * @type      {string}
     * @apioption tooltip.headerFormat
     */
    headerFormat: '<span style="font-size: 0.8em">{ucfirst point.key}</span><br/>',
    /**
     * The HTML of the null point's line in the tooltip. Works analogously
     * to [pointFormat](#tooltip.pointFormat).
     *
     * @sample {highcharts} highcharts/series/null-interaction
     *         Line chart with null interaction
     * @sample {highcharts} highcharts/plotoptions/series-nullformat
     *         Heatmap with null interaction
     *
     * @type      {string}
     * @apioption tooltip.nullFormat
     */
    /**
     * The HTML of the point's line in the tooltip. The context is the
     * [Point class](https://api.highcharts.com/class-reference/Highcharts.Point).
     * Variables are enclosed in curly brackets. Examples of common
     * variables to include are `x`, `y`, `series.name` and `series.color`
     * and other properties on the same form. Furthermore, `y` can be
     * extended by the `tooltip.valuePrefix` and `tooltip.valueSuffix`
     * variables. This can also be overridden for each series, which makes
     * it a good hook for displaying units.
     *
     * In styled mode, the dot is colored by a class name rather than the
     * point color.
     *
     * @sample {highcharts} highcharts/tooltip/pointformat/
     *         A different point format with value suffix
     * @sample {highcharts|highstock} highcharts/tooltip/pointformat-extra-information/
     *         Show extra information about points in the tooltip
     * @sample {highmaps} maps/tooltip/format/
     *         Format demo
     *
     * @type       {string}
     * @since      2.2
     * @apioption  tooltip.pointFormat
     */
    pointFormat: '<span style="color:{point.color}">●</span> {series.name}: <b>{point.y}</b><br/>',
    /**
     * The background color or gradient for the tooltip.
     *
     * In styled mode, the stroke width is set in the
     * `.highcharts-tooltip-box` class.
     *
     * @sample {highcharts} highcharts/tooltip/backgroundcolor-solid/
     *         Yellowish background
     * @sample {highcharts} highcharts/tooltip/backgroundcolor-gradient/
     *         Gradient
     * @sample {highcharts} highcharts/css/tooltip-border-background/
     *         Tooltip in styled mode
     * @sample {highstock} stock/tooltip/general/
     *         Custom tooltip
     * @sample {highstock} highcharts/css/tooltip-border-background/
     *         Tooltip in styled mode
     * @sample {highmaps} maps/tooltip/background-border/
     *         Background and border demo
     * @sample {highmaps} highcharts/css/tooltip-border-background/
     *         Tooltip in styled mode
     *
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    backgroundColor: "#ffffff",
    /**
     * The pixel width of the tooltip border. Defaults to 0 for single
     * tooltips and fixed tooltips, otherwise 1 for split tooltips.
     *
     * In styled mode, the stroke width is set in the
     * `.highcharts-tooltip-box` class.
     *
     * @sample {highcharts} highcharts/tooltip/bordercolor-default/
     *         2 pixels
     * @sample {highcharts} highcharts/tooltip/borderwidth/
     *         No border (shadow only)
     * @sample {highcharts} highcharts/css/tooltip-border-background/
     *         Tooltip in styled mode
     * @sample {highstock} stock/tooltip/general/
     *         Custom tooltip
     * @sample {highstock} highcharts/css/tooltip-border-background/
     *         Tooltip in styled mode
     * @sample {highmaps} maps/tooltip/background-border/
     *         Background and border demo
     * @sample {highmaps} highcharts/css/tooltip-border-background/
     *         Tooltip in styled mode
     *
     * @type {number}
     */
    borderWidth: void 0,
    /**
     * Whether to apply a drop shadow to the tooltip. Defaults to true,
     * unless the tooltip is [fixed](#tooltip.fixed).
     *
     * @sample {highcharts} highcharts/tooltip/bordercolor-default/
     *         True by default
     * @sample {highcharts} highcharts/tooltip/shadow/
     *         False
     * @sample {highmaps} maps/tooltip/positioner/
     *         Fixed tooltip position, border and shadow disabled
     *
     * @type {boolean|Highcharts.ShadowOptionsObject}
     * @default undefined
     * @apioption tooltip.shadow
     */
    /**
     * Prevents the tooltip from switching or closing when touched or
     * pointed.
     *
     * @sample highcharts/tooltip/stickoncontact/
     *         Tooltip sticks on pointer contact
     *
     * @since 8.0.1
     */
    stickOnContact: false,
    /**
     * CSS styles for the tooltip. The tooltip can also be styled through
     * the CSS class `.highcharts-tooltip`.
     *
     * Note that the default `pointerEvents` style makes the tooltip ignore
     * mouse events, so in order to use clickable tooltips, this value must
     * be set to `auto`.
     *
     * @sample {highcharts} highcharts/tooltip/style/
     *         Greater padding, bold text
     *
     * @type {Highcharts.CSSObject}
     */
    style: {
      /** @internal */
      color: "#333333",
      /** @internal */
      cursor: "default",
      /**
       * @type {number|string}
       */
      fontSize: "0.8em"
    },
    /**
     * Use HTML to render the contents of the tooltip instead of SVG. Using
     * HTML allows advanced formatting like tables and images in the
     * tooltip. It is also recommended for rtl languages as it works around
     * rtl bugs in early Firefox.
     *
     * @sample {highcharts|highstock} highcharts/tooltip/footerformat/
     *         A table for value alignment
     * @sample {highcharts|highstock} highcharts/tooltip/fullhtml/
     *         Full HTML tooltip
     * @sample {highmaps} maps/tooltip/usehtml/
     *         Pure HTML tooltip
     *
     * @since 2.2
     */
    useHTML: false
  },
  /**
   * Highchart by default puts a credits label in the lower right corner
   * of the chart. This can be changed using these options.
   */
  credits: {
    /**
     * Credits for map source to be concatenated with conventional credit
     * text. By default this is a format string that collects copyright
     * information from the map if available.
     *
     * @see [mapTextFull](#credits.mapTextFull)
     * @see [text](#credits.text)
     *
     * @type      {string}
     * @default   \u00a9 <a href="{geojson.copyrightUrl}">{geojson.copyrightShort}</a>
     * @since     4.2.2
     * @product   highmaps
     * @apioption credits.mapText
     */
    /**
     * Detailed credits for map source to be displayed on hover of credits
     * text. By default this is a format string that collects copyright
     * information from the map if available.
     *
     * @see [mapText](#credits.mapText)
     * @see [text](#credits.text)
     *
     * @type      {string}
     * @default   {geojson.copyright}
     * @since     4.2.2
     * @product   highmaps
     * @apioption credits.mapTextFull
     */
    /**
     * Whether to show the credits text.
     *
     * @sample {highcharts} highcharts/credits/enabled-false/
     *         Credits disabled
     * @sample {highstock} stock/credits/enabled/
     *         Credits disabled
     * @sample {highmaps} maps/credits/enabled-false/
     *         Credits disabled
     */
    enabled: true,
    /**
     * The URL for the credits label.
     *
     * @sample {highcharts} highcharts/credits/href/
     *         Custom URL and text
     * @sample {highmaps} maps/credits/customized/
     *         Custom URL and text
     */
    href: "https://www.highcharts.com?credits",
    /**
     * Position configuration for the credits label.
     *
     * @sample {highcharts} highcharts/credits/position-left/
     *         Left aligned
     * @sample {highcharts} highcharts/credits/position-left/
     *         Left aligned
     * @sample {highmaps} maps/credits/customized/
     *         Left aligned
     * @sample {highmaps} maps/credits/customized/
     *         Left aligned
     *
     * @type    {Highcharts.AlignObject}
     * @since   2.1
     */
    position: {
      /** @internal */
      align: "right",
      /** @internal */
      x: -10,
      /** @internal */
      verticalAlign: "bottom",
      /** @internal */
      y: -5
    },
    /**
     * CSS styles for the credits label.
     *
     * @see In styled mode, credits styles can be set with the
     *      `.highcharts-credits` class.
     *
     * @type {Highcharts.CSSObject}
     */
    style: {
      /** @internal */
      cursor: "pointer",
      /** @internal */
      color: "#999999",
      /**
       * @type {number|string}
       */
      fontSize: "0.6em"
    },
    /**
     * The text for the credits label.
     *
     * @productdesc {highmaps}
     * If a map is loaded as GeoJSON, the text defaults to
     * `Highcharts @ {map-credits}`. Otherwise, it defaults to
     * `Highcharts.com`.
     *
     * @sample {highcharts} highcharts/credits/href/
     *         Custom URL and text
     * @sample {highmaps} maps/credits/customized/
     *         Custom URL and text
     */
    text: "Highcharts.com"
  }
};
const defaultTime$1 = new Time(defaultOptions$n.time, defaultOptions$n.lang);
function getOptions$3() {
  return defaultOptions$n;
}
function setOptions$4(options2) {
  fireEvent$M(Highcharts, "setOptions", { options: options2 });
  merge$1I(true, defaultOptions$n, options2);
  if (options2.time) {
    defaultTime$1.update(defaultOptions$n.time);
  }
  if (options2.lang && "locale" in options2.lang) {
    defaultTime$1.update({
      locale: options2.lang.locale
    });
  }
  if (options2.lang?.chartTitle) {
    defaultOptions$n.title = {
      ...defaultOptions$n.title,
      text: options2.lang.chartTitle
    };
  }
  return defaultOptions$n;
}
const DefaultOptions = {
  defaultOptions: defaultOptions$n,
  defaultTime: defaultTime$1,
  getOptions: getOptions$3,
  setOptions: setOptions$4
};
const { win: win$f } = Highcharts;
const { isNumber: isNumber$1b, isString: isString$j, merge: merge$1H, pInt: pInt$7, defined: defined$1e } = Utilities;
const colorMix = (color1, color2, weight) => `color-mix(in srgb,${color1},${color2} ${weight * 100}%)`;
const isStringColor = (color2) => isString$j(color2) && !!color2 && color2 !== "none";
class Color {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * Creates a color instance out of a color string or object.
   *
   * @function Highcharts.Color.parse
   *
   * @param {Highcharts.ColorType} [input]
   * The input color in either rgba or hex format.
   *
   * @return {Highcharts.Color}
   * Color instance.
   */
  static parse(input) {
    return input ? new Color(input) : Color.None;
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(input) {
    this.rgba = [NaN, NaN, NaN, NaN];
    this.input = input;
    const GlobalColor = Highcharts.Color;
    if (GlobalColor && GlobalColor !== Color) {
      return new GlobalColor(input);
    }
    let result, rgba, i, parser;
    if (typeof input === "object" && typeof input.stops !== "undefined") {
      this.stops = input.stops.map((stop2) => new Color(stop2[1]));
    } else if (typeof input === "string") {
      this.input = input = Color.names[input.toLowerCase()] || input;
      i = Color.parsers.length;
      while (i-- && !rgba) {
        parser = Color.parsers[i];
        result = parser.regex.exec(input);
        if (result) {
          rgba = parser.parse(result);
        }
      }
    }
    if (rgba) {
      this.rgba = rgba;
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Return the color or gradient stops in the specified format
   *
   * @function Highcharts.Color#get
   *
   * @param {string} [format]
   * Possible values are 'a', 'rgb', 'rgba' (default).
   *
   * @return {Highcharts.ColorType}
   * This color as a string or gradient stops.
   */
  get(format2) {
    const input = this.input, rgba = this.rgba;
    if (this.output) {
      return this.output;
    }
    if (typeof input === "object" && typeof this.stops !== "undefined") {
      const ret = merge$1H(input);
      ret.stops = [].slice.call(ret.stops);
      this.stops.forEach((stop2, i) => {
        ret.stops[i] = [
          ret.stops[i][0],
          stop2.get(format2)
        ];
      });
      return ret;
    }
    if (rgba && isNumber$1b(rgba[0])) {
      if (format2 === "rgb" || !format2 && rgba[3] === 1) {
        return "rgb(" + rgba[0] + "," + rgba[1] + "," + rgba[2] + ")";
      }
      if (format2 === "a") {
        return `${rgba[3]}`;
      }
      return "rgba(" + rgba.join(",") + ")";
    }
    return input;
  }
  /**
   * Brighten the color instance.
   *
   * @function Highcharts.Color#brighten
   *
   * @param {number} alpha
   * The alpha value.
   *
   * @return {Highcharts.Color}
   * This color with modifications.
   */
  brighten(alpha) {
    const rgba = this.rgba;
    if (this.stops) {
      this.stops.forEach(function(stop2) {
        stop2.brighten(alpha);
      });
    } else if (isNumber$1b(alpha) && alpha !== 0) {
      if (isNumber$1b(rgba[0])) {
        for (let i = 0; i < 3; i++) {
          rgba[i] += pInt$7(alpha * 255);
          if (rgba[i] < 0) {
            rgba[i] = 0;
          }
          if (rgba[i] > 255) {
            rgba[i] = 255;
          }
        }
      } else if (Color.useColorMix && isStringColor(this.input)) {
        this.output = colorMix(this.input, alpha > 0 ? "white" : "black", Math.abs(alpha));
      }
    }
    return this;
  }
  /**
   * Set the color's opacity to a given alpha value.
   *
   * @function Highcharts.Color#setOpacity
   *
   * @param {number} alpha
   *        Opacity between 0 and 1.
   *
   * @return {Highcharts.Color}
   *         Color with modifications.
   */
  setOpacity(alpha) {
    this.rgba[3] = alpha;
    return this;
  }
  /**
   * Return an intermediate color between two colors.
   *
   * @function Highcharts.Color#tweenTo
   *
   * @param {Highcharts.Color} to
   * The color object to tween to.
   *
   * @param {number} pos
   * The intermediate position, where 0 is the from color (current color
   * item), and 1 is the `to` color.
   *
   * @return {Highcharts.ColorType}
   * The intermediate color in rgba notation, or unsupported type.
   */
  tweenTo(to, pos) {
    const fromRgba = this.rgba, toRgba = to.rgba;
    if (!isNumber$1b(fromRgba[0]) || !isNumber$1b(toRgba[0])) {
      if (Color.useColorMix && isStringColor(this.input) && isStringColor(to.input) && pos < 0.99) {
        return colorMix(this.input, to.input, pos);
      }
      return to.input || "none";
    }
    const hasAlpha = toRgba[3] !== 1 || fromRgba[3] !== 1, channel = (to2, i) => to2 + (fromRgba[i] - to2) * (1 - pos), rgba = toRgba.slice(0, 3).map(channel).map(Math.round);
    if (hasAlpha) {
      rgba.push(channel(toRgba[3], 3));
    }
    return (hasAlpha ? "rgba(" : "rgb(") + rgba.join(",") + ")";
  }
}
Color.names = {
  white: "#ffffff",
  black: "#000000"
};
Color.parsers = [{
  // RGBA color
  // eslint-disable-next-line max-len
  regex: /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d?(?:\.\d+)?)\s*\)/,
  parse: function(result) {
    return [
      pInt$7(result[1]),
      pInt$7(result[2]),
      pInt$7(result[3]),
      parseFloat(result[4], 10)
    ];
  }
}, {
  // RGB color
  regex: /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/,
  parse: function(result) {
    return [pInt$7(result[1]), pInt$7(result[2]), pInt$7(result[3]), 1];
  }
}, {
  // RGBA 3 & 4 digit hex color, e.g. #F0F, #F0FA
  regex: /^#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?$/i,
  parse: function(result) {
    return [
      pInt$7(result[1] + result[1], 16),
      pInt$7(result[2] + result[2], 16),
      pInt$7(result[3] + result[3], 16),
      !defined$1e(result[4]) ? 1 : pInt$7(result[4] + result[4], 16) / 255
    ];
  }
}, {
  // RGBA 6 & 8 digit hex color, e.g. #FFCC00, #FFCC00FF
  regex: /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?$/i,
  parse: function(result) {
    return [
      pInt$7(result[1], 16),
      pInt$7(result[2], 16),
      pInt$7(result[3], 16),
      !defined$1e(result[4]) ? 1 : pInt$7(result[4], 16) / 255
    ];
  }
}];
Color.useColorMix = win$f.CSS?.supports("color", "color-mix(in srgb,red,blue 9%)");
Color.None = new Color("");
const { parse: color$c } = Color;
const { win: win$e } = Highcharts;
const { isNumber: isNumber$1a, objectEach: objectEach$x } = Utilities;
class Fx {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(elem, options2, prop) {
    this.pos = NaN;
    this.options = options2;
    this.elem = elem;
    this.prop = prop;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Set the current step of a path definition on SVGElement.
   *
   * @function Highcharts.Fx#dSetter
   *
   */
  dSetter() {
    const paths = this.paths, start2 = paths?.[0], end = paths?.[1], now = this.now || 0;
    let path = [];
    if (now === 1 || !start2 || !end) {
      path = this.toD || [];
    } else if (start2.length === end.length && now < 1) {
      for (let i = 0; i < end.length; i++) {
        const startSeg = start2[i];
        const endSeg = end[i];
        const tweenSeg = [];
        for (let j = 0; j < endSeg.length; j++) {
          const startItem = startSeg[j];
          const endItem = endSeg[j];
          if (isNumber$1a(startItem) && isNumber$1a(endItem) && // Arc boolean flags
          !(endSeg[0] === "A" && (j === 4 || j === 5))) {
            tweenSeg[j] = startItem + now * (endItem - startItem);
          } else {
            tweenSeg[j] = endItem;
          }
        }
        path.push(tweenSeg);
      }
    } else {
      path = end;
    }
    this.elem.attr("d", path, void 0, true);
  }
  /**
   * Update the element with the current animation step.
   *
   * @function Highcharts.Fx#update
   *
   */
  update() {
    const elem = this.elem, prop = this.prop, now = this.now, step = this.options.step;
    if (this[prop + "Setter"]) {
      this[prop + "Setter"]();
    } else if (elem.attr) {
      if (elem.element) {
        elem.attr(prop, now, null, true);
      }
    } else {
      elem.style[prop] = now + this.unit;
    }
    if (step) {
      step.call(elem, now, this);
    }
  }
  /**
   * Run an animation.
   *
   * @function Highcharts.Fx#run
   *
   * @param {number} from
   *        The current value, value to start from.
   *
   * @param {number} to
   *        The end value, value to land on.
   *
   * @param {string} unit
   *        The property unit, for example `px`.
   *
   */
  run(from, to, unit) {
    const self2 = this, options2 = self2.options, timer = function(gotoEnd) {
      return timer.stopped ? false : self2.step(gotoEnd);
    }, requestAnimationFrame2 = win$e.requestAnimationFrame || function(step2) {
      setTimeout(step2, 13);
    }, step = function() {
      for (let i = 0; i < Fx.timers.length; i++) {
        if (!Fx.timers[i]()) {
          Fx.timers.splice(i--, 1);
        }
      }
      if (Fx.timers.length) {
        requestAnimationFrame2(step);
      }
    };
    if (from === to && !this.elem["forceAnimate:" + this.prop]) {
      delete options2.curAnim[this.prop];
      if (options2.complete && Object.keys(options2.curAnim).length === 0) {
        options2.complete.call(this.elem);
      }
    } else {
      this.startTime = +/* @__PURE__ */ new Date();
      this.start = from;
      this.end = to;
      this.unit = unit;
      this.now = this.start;
      this.pos = 0;
      timer.elem = this.elem;
      timer.prop = this.prop;
      if (timer() && Fx.timers.push(timer) === 1) {
        requestAnimationFrame2(step);
      }
    }
  }
  /**
   * Run a single step in the animation.
   *
   * @function Highcharts.Fx#step
   *
   * @param {boolean} [gotoEnd]
   *        Whether to go to the endpoint of the animation after abort.
   *
   * @return {boolean}
   *         Returns `true` if animation continues.
   */
  step(gotoEnd) {
    const t = +/* @__PURE__ */ new Date(), options2 = this.options, elem = this.elem, complete = options2.complete, duration = options2.duration, curAnim = options2.curAnim;
    let ret, done;
    if (!!elem.attr && !elem.element) {
      ret = false;
    } else if (gotoEnd || t >= duration + this.startTime) {
      this.now = this.end;
      this.pos = 1;
      this.update();
      curAnim[this.prop] = true;
      done = true;
      objectEach$x(curAnim, function(val) {
        if (val !== true) {
          done = false;
        }
      });
      if (done && complete) {
        complete.call(elem);
      }
      ret = false;
    } else {
      this.pos = options2.easing((t - this.startTime) / duration);
      this.now = this.start + (this.end - this.start) * this.pos;
      this.update();
      ret = true;
    }
    return ret;
  }
  /**
   * Prepare start and end values so that the path can be animated one to one.
   *
   * @function Highcharts.Fx#initPath
   *
   * @param {Highcharts.SVGElement} elem
   *        The SVGElement item.
   *
   * @param {Highcharts.SVGPathArray|undefined} fromD
   *        Starting path definition.
   *
   * @param {Highcharts.SVGPathArray} toD
   *        Ending path definition.
   *
   * @return {Array<Highcharts.SVGPathArray,Highcharts.SVGPathArray>}
   *         An array containing start and end paths in array form so that
   *         they can be animated in parallel.
   */
  initPath(elem, fromD, toD) {
    const startX = elem.startX, endX = elem.endX, end = toD.slice(), isArea = elem.isArea, positionFactor = isArea ? 2 : 1, disableAnimation = fromD && toD.length > fromD.length && toD.hasStackedCliffs;
    let shift, fullLength, i, reverse, start2 = fromD?.slice();
    if (!start2 || disableAnimation) {
      return [end, end];
    }
    function prepend(arr, other) {
      while (arr.length < fullLength) {
        const moveSegment = arr[0], otherSegment = other[fullLength - arr.length];
        if (otherSegment && moveSegment[0] === "M") {
          if (otherSegment[0] === "C") {
            arr[0] = [
              "C",
              moveSegment[1],
              moveSegment[2],
              moveSegment[1],
              moveSegment[2],
              moveSegment[1],
              moveSegment[2]
            ];
          } else {
            arr[0] = ["L", moveSegment[1], moveSegment[2]];
          }
        }
        arr.unshift(moveSegment);
        if (isArea) {
          const z = arr.pop();
          arr.push(arr[arr.length - 1], z);
        }
      }
    }
    function append(arr) {
      while (arr.length < fullLength) {
        const segmentToAdd = arr[Math.floor(arr.length / positionFactor) - 1].slice();
        if (segmentToAdd[0] === "C") {
          segmentToAdd[1] = segmentToAdd[5];
          segmentToAdd[2] = segmentToAdd[6];
        }
        if (!isArea) {
          arr.push(segmentToAdd);
        } else {
          const lowerSegmentToAdd = arr[Math.floor(arr.length / positionFactor)].slice();
          arr.splice(arr.length / 2, 0, segmentToAdd, lowerSegmentToAdd);
        }
      }
    }
    if (startX && endX && endX.length) {
      for (i = 0; i < startX.length; i++) {
        if (startX[i] === endX[0]) {
          shift = i;
          break;
        } else if (startX[0] === endX[endX.length - startX.length + i]) {
          shift = i;
          reverse = true;
          break;
        } else if (startX[startX.length - 1] === endX[endX.length - startX.length + i]) {
          shift = startX.length - i;
          break;
        }
      }
      if (typeof shift === "undefined") {
        start2 = [];
      }
    }
    if (start2.length && isNumber$1a(shift)) {
      fullLength = end.length + shift * positionFactor;
      if (!reverse) {
        prepend(end, start2);
        append(start2);
      } else {
        prepend(start2, end);
        append(end);
      }
    }
    return [start2, end];
  }
  /**
   * Handle animation of the color attributes directly.
   *
   * @function Highcharts.Fx#fillSetter
   *
   */
  fillSetter() {
    Fx.prototype.strokeSetter.apply(this, arguments);
  }
  /**
   * Handle animation of the color attributes directly.
   *
   * @function Highcharts.Fx#strokeSetter
   *
   */
  strokeSetter() {
    this.elem.attr(this.prop, color$c(this.start).tweenTo(color$c(this.end), this.pos), void 0, true);
  }
}
Fx.timers = [];
const { defined: defined$1d, getStyle: getStyle$1, isArray: isArray$r, isNumber: isNumber$19, isObject: isObject$n, merge: merge$1G, objectEach: objectEach$w, pick: pick$1R } = Utilities;
function setAnimation$5(animation, chart) {
  chart.renderer.globalAnimation = pick$1R(animation, chart.options.chart.animation, true);
}
function animObject$g(animation) {
  return isObject$n(animation) ? merge$1G({ duration: 500, defer: 0 }, animation) : { duration: animation ? 500 : 0, defer: 0 };
}
function getDeferredAnimation$3(chart, animation, series) {
  const labelAnimation = animObject$g(animation), s = series ? [series] : chart.series;
  let defer = 0, duration = 0;
  s.forEach((series2) => {
    const seriesAnim = animObject$g(series2.options.animation);
    defer = isObject$n(animation) && defined$1d(animation.defer) ? labelAnimation.defer : Math.max(defer, seriesAnim.duration + seriesAnim.defer);
    duration = Math.min(labelAnimation.duration, seriesAnim.duration);
  });
  if (chart.renderer.forExport) {
    defer = 0;
  }
  const anim = {
    defer: Math.max(0, defer - duration),
    duration: Math.min(defer, duration)
  };
  return anim;
}
function animate$2(el, params2, opt) {
  let start2, unit = "", end, fx, args;
  if (!isObject$n(opt)) {
    args = arguments;
    opt = {
      duration: args[2],
      easing: args[3],
      complete: args[4]
    };
  }
  if (!isNumber$19(opt.duration)) {
    opt.duration = 400;
  }
  opt.easing = typeof opt.easing === "function" ? opt.easing : Math[opt.easing] || Math.easeInOutSine;
  opt.curAnim = merge$1G(params2);
  objectEach$w(params2, function(val, prop) {
    stop$2(el, prop);
    fx = new Fx(el, opt, prop);
    end = void 0;
    if (prop === "d" && isArray$r(params2.d)) {
      fx.paths = fx.initPath(el, el.pathArray, params2.d);
      fx.toD = params2.d;
      start2 = 0;
      end = 1;
    } else if (el.attr) {
      start2 = el.attr(prop);
    } else {
      start2 = parseFloat(getStyle$1(el, prop)) || 0;
      if (prop !== "opacity") {
        unit = "px";
      }
    }
    if (!end) {
      end = val;
    }
    if (typeof end === "string" && end.match("px")) {
      end = end.replace(/px/g, "");
    }
    fx.run(start2, end, unit);
  });
}
function stop$2(el, prop) {
  let i = Fx.timers.length;
  while (i--) {
    if (Fx.timers[i].elem === el && (!prop || prop === Fx.timers[i].prop)) {
      Fx.timers[i].stopped = true;
    }
  }
}
const animationExports = {
  animate: animate$2,
  animObject: animObject$g,
  getDeferredAnimation: getDeferredAnimation$3,
  setAnimation: setAnimation$5,
  stop: stop$2
};
const { SVG_NS: SVG_NS$4, win: win$d } = Highcharts;
const { attr: attr$e, createElement: createElement$d, css: css$f, error: error$9, isFunction: isFunction$5, isString: isString$i, objectEach: objectEach$v, splat: splat$l } = Utilities;
const { trustedTypes } = win$d;
const trustedTypesPolicy = trustedTypes && isFunction$5(trustedTypes.createPolicy) && trustedTypes.createPolicy("highcharts", {
  createHTML: (s) => s
});
const emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML("") : "";
class AST {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * Filter an object of SVG or HTML attributes against the allow list.
   *
   * @static
   *
   * @function Highcharts.AST#filterUserAttributes
   *
   * @param {Highcharts.SVGAttributes} attributes The attributes to filter
   *
   * @return {Highcharts.SVGAttributes}
   * The filtered attributes
   */
  static filterUserAttributes(attributes) {
    objectEach$v(attributes, (val, key2) => {
      let valid = true;
      if (AST.allowedAttributes.indexOf(key2) === -1) {
        valid = false;
      }
      if (["background", "dynsrc", "href", "lowsrc", "src"].indexOf(key2) !== -1) {
        valid = isString$i(val) && AST.allowedReferences.some((ref) => val.indexOf(ref) === 0);
      }
      if (!valid) {
        error$9(33, false, void 0, {
          "Invalid attribute in config": `${key2}`
        });
        delete attributes[key2];
      }
      if (isString$i(val) && attributes[key2]) {
        attributes[key2] = val.replace(/</g, "&lt;");
      }
    });
    return attributes;
  }
  static parseStyle(style) {
    return style.split(";").reduce((styles, line2) => {
      const pair = line2.split(":").map((s) => s.trim()), key2 = pair.shift();
      if (key2 && pair.length) {
        styles[key2.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = pair.join(":");
      }
      return styles;
    }, {});
  }
  /**
   * Utility function to set html content for an element by passing in a
   * markup string. The markup is safely parsed by the AST class to avoid
   * XSS vulnerabilities. This function should be used instead of setting
   * `innerHTML` in all cases where the content is not fully trusted.
   *
   * @static
   * @function Highcharts.AST#setElementHTML
   *
   * @param {SVGDOMElement|HTMLDOMElement} el
   * Node to set content of.
   *
   * @param {string} html
   * Markup string
   */
  static setElementHTML(el, html2) {
    el.innerHTML = AST.emptyHTML;
    if (html2) {
      const ast = new AST(html2);
      ast.addToDOM(el);
    }
  }
  /* *
   *
   *  Constructor
   *
   * */
  // Construct an AST from HTML markup, or wrap an array of existing AST nodes
  constructor(source) {
    this.nodes = typeof source === "string" ? this.parseMarkup(source) : source;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Add the tree defined as a hierarchical JS structure to the DOM
   *
   * @function Highcharts.AST#addToDOM
   *
   * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} parent
   * The node where it should be added
   *
   * @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement}
   * The inserted node.
   */
  addToDOM(parent) {
    function recurse(subtree, subParent) {
      let ret;
      splat$l(subtree).forEach(function(item) {
        const tagName = item.tagName;
        const textNode = item.textContent ? Highcharts.doc.createTextNode(item.textContent) : void 0;
        const bypassHTMLFiltering = AST.bypassHTMLFiltering;
        let node;
        if (tagName) {
          if (tagName === "#text") {
            node = textNode;
          } else if (AST.allowedTags.indexOf(tagName) !== -1 || bypassHTMLFiltering) {
            const NS = tagName === "svg" ? SVG_NS$4 : subParent.namespaceURI || SVG_NS$4;
            const element = Highcharts.doc.createElementNS(NS, tagName);
            const attributes = item.attributes || {};
            objectEach$v(item, function(val, key2) {
              if (key2 !== "tagName" && key2 !== "attributes" && key2 !== "children" && key2 !== "style" && key2 !== "textContent") {
                attributes[key2] = val;
              }
            });
            attr$e(element, bypassHTMLFiltering ? attributes : AST.filterUserAttributes(attributes));
            if (item.style) {
              css$f(element, item.style);
            }
            if (textNode) {
              element.appendChild(textNode);
            }
            recurse(item.children || [], element);
            node = element;
          } else {
            error$9(33, false, void 0, {
              "Invalid tagName in config": tagName
            });
          }
        }
        if (node) {
          subParent.appendChild(node);
        }
        ret = node;
      });
      return ret;
    }
    return recurse(this.nodes, parent);
  }
  /**
   * Parse HTML/SVG markup into AST Node objects. Used internally from the
   * constructor.
   *
   * @private
   *
   * @function Highcharts.AST#getNodesFromMarkup
   *
   * @param {string} markup The markup string.
   *
   * @return {Array<Highcharts.ASTNode>} The parsed nodes.
   */
  parseMarkup(markup) {
    const nodes = [];
    markup = markup.trim().replace(/ style=(["'])/g, " data-style=$1");
    let doc2;
    try {
      doc2 = new DOMParser().parseFromString(trustedTypesPolicy ? trustedTypesPolicy.createHTML(markup) : markup, "text/html");
    } catch (e) {
    }
    if (!doc2) {
      const body = createElement$d("div");
      body.innerHTML = markup;
      doc2 = { body };
    }
    const appendChildNodes = (node, addTo) => {
      const tagName = node.nodeName.toLowerCase();
      const astNode = {
        tagName
      };
      if (tagName === "#text") {
        astNode.textContent = node.textContent || "";
      }
      const parsedAttributes = node.attributes;
      if (parsedAttributes) {
        const attributes = {};
        [].forEach.call(parsedAttributes, (attrib) => {
          if (attrib.name === "data-style") {
            astNode.style = AST.parseStyle(attrib.value);
          } else {
            attributes[attrib.name] = attrib.value;
          }
        });
        astNode.attributes = attributes;
      }
      if (node.childNodes.length) {
        const children = [];
        [].forEach.call(node.childNodes, (childNode) => {
          appendChildNodes(childNode, children);
        });
        if (children.length) {
          astNode.children = children;
        }
      }
      addTo.push(astNode);
    };
    [].forEach.call(doc2.body.childNodes, (childNode) => appendChildNodes(childNode, nodes));
    return nodes;
  }
}
AST.allowedAttributes = [
  "alt",
  "aria-controls",
  "aria-describedby",
  "aria-expanded",
  "aria-haspopup",
  "aria-hidden",
  "aria-label",
  "aria-labelledby",
  "aria-live",
  "aria-pressed",
  "aria-readonly",
  "aria-roledescription",
  "aria-selected",
  "class",
  "clip-path",
  "color",
  "colspan",
  "cx",
  "cy",
  "d",
  "dx",
  "dy",
  "disabled",
  "fill",
  "filterUnits",
  "flood-color",
  "flood-opacity",
  "height",
  "href",
  "id",
  "in",
  "in2",
  "markerHeight",
  "markerWidth",
  "offset",
  "opacity",
  "operator",
  "orient",
  "padding",
  "paddingLeft",
  "paddingRight",
  "patternUnits",
  "r",
  "radius",
  "refX",
  "refY",
  "role",
  "scope",
  "slope",
  "src",
  "startOffset",
  "stdDeviation",
  "stroke",
  "stroke-linecap",
  "stroke-width",
  "style",
  "tableValues",
  "result",
  "rowspan",
  "summary",
  "target",
  "tabindex",
  "text-align",
  "text-anchor",
  "textAnchor",
  "textLength",
  "title",
  "type",
  "valign",
  "width",
  "x",
  "x1",
  "x2",
  "xlink:href",
  "y",
  "y1",
  "y2",
  "zIndex"
];
AST.allowedReferences = [
  "https://",
  "http://",
  "mailto:",
  "/",
  "../",
  "./",
  "#"
];
AST.allowedTags = [
  "a",
  "abbr",
  "b",
  "br",
  "button",
  "caption",
  "circle",
  "clipPath",
  "code",
  "dd",
  "defs",
  "div",
  "dl",
  "dt",
  "em",
  "feComponentTransfer",
  "feComposite",
  "feDropShadow",
  "feFlood",
  "feFuncA",
  "feFuncB",
  "feFuncG",
  "feFuncR",
  "feGaussianBlur",
  "feMorphology",
  "feOffset",
  "feMerge",
  "feMergeNode",
  "filter",
  "h1",
  "h2",
  "h3",
  "h4",
  "h5",
  "h6",
  "hr",
  "i",
  "img",
  "li",
  "linearGradient",
  "marker",
  "ol",
  "p",
  "path",
  "pattern",
  "pre",
  "rect",
  "small",
  "span",
  "stop",
  "strong",
  "style",
  "sub",
  "sup",
  "svg",
  "table",
  "text",
  "textPath",
  "thead",
  "title",
  "tbody",
  "tspan",
  "td",
  "th",
  "tr",
  "u",
  "ul",
  "#text"
];
AST.emptyHTML = emptyHTML;
AST.bypassHTMLFiltering = false;
const { defaultOptions: defaultOptions$m, defaultTime } = DefaultOptions;
const { pageLang } = Highcharts;
const { extend: extend$1r, getNestedProperty: getNestedProperty$3, isArray: isArray$q, isNumber: isNumber$18, isObject: isObject$m, isString: isString$h, pick: pick$1Q, ucfirst } = Utilities;
const helpers = {
  // Built-in helpers
  add: (a, b) => a + b,
  divide: (a, b) => b !== 0 ? a / b : "",
  // eslint-disable-next-line eqeqeq
  eq: (a, b) => a == b,
  each: function(arr) {
    const match2 = arguments[arguments.length - 1];
    return isArray$q(arr) ? arr.map((item, i) => format$h(match2.body, extend$1r(isObject$m(item) ? item : { "@this": item }, {
      "@index": i,
      "@first": i === 0,
      "@last": i === arr.length - 1
    }))).join("") : false;
  },
  ge: (a, b) => a >= b,
  gt: (a, b) => a > b,
  "if": (condition) => !!condition,
  le: (a, b) => a <= b,
  lt: (a, b) => a < b,
  multiply: (a, b) => a * b,
  // eslint-disable-next-line eqeqeq
  ne: (a, b) => a != b,
  subtract: (a, b) => a - b,
  ucfirst,
  unless: (condition) => !condition
};
const numberFormatCache = {};
const isQuotedString = (str) => /^["'].+["']$/.test(str);
function dateFormat(format2, timestamp, upperCaseFirst) {
  return defaultTime.dateFormat(format2, timestamp, upperCaseFirst);
}
function format$h(str = "", ctx, owner) {
  const regex = /\{([a-zA-Z\u00C0-\u017F\d:\.,;\-\/<>\[\]%_@+"'’= #\(\)]+)\}/g, subRegex = /\(([a-zA-Z\u00C0-\u017F\d:\.,;\-\/<>\[\]%_@+"'= ]+)\)/g, matches = [], floatRegex = /f$/, decRegex = /\.(\d)/, lang2 = owner?.options?.lang || defaultOptions$m.lang, time = owner?.time || defaultTime, numberFormatter = owner?.numberFormatter || numberFormat$2;
  const resolveProperty = (key2 = "") => {
    let n;
    if (key2 === "true") {
      return true;
    }
    if (key2 === "false") {
      return false;
    }
    if ((n = Number(key2)).toString() === key2) {
      return n;
    }
    if (isQuotedString(key2)) {
      return key2.slice(1, -1);
    }
    return getNestedProperty$3(key2, ctx);
  };
  let match2, currentMatch, depth = 0, hasSub;
  while ((match2 = regex.exec(str)) !== null) {
    const mainMatch = match2, subMatch = subRegex.exec(match2[1]);
    if (subMatch) {
      match2 = subMatch;
      hasSub = true;
    }
    if (!currentMatch?.isBlock) {
      currentMatch = {
        ctx,
        expression: match2[1],
        find: match2[0],
        isBlock: match2[1].charAt(0) === "#",
        start: match2.index,
        startInner: match2.index + match2[0].length,
        length: match2[0].length
      };
    }
    const fn = (currentMatch.isBlock ? mainMatch : match2)[1].split(" ")[0].replace("#", "");
    if (helpers[fn]) {
      if (currentMatch.isBlock && fn === currentMatch.fn) {
        depth++;
      }
      if (!currentMatch.fn) {
        currentMatch.fn = fn;
      }
    }
    const startingElseSection = match2[1] === "else";
    if (currentMatch.isBlock && currentMatch.fn && (match2[1] === `/${currentMatch.fn}` || startingElseSection)) {
      if (!depth) {
        const start2 = currentMatch.startInner, body = str.substr(start2, match2.index - start2);
        if (currentMatch.body === void 0) {
          currentMatch.body = body;
          currentMatch.startInner = match2.index + match2[0].length;
        } else {
          currentMatch.elseBody = body;
        }
        currentMatch.find += body + match2[0];
        if (!startingElseSection) {
          matches.push(currentMatch);
          currentMatch = void 0;
        }
      } else if (!startingElseSection) {
        depth--;
      }
    } else if (!currentMatch.isBlock) {
      matches.push(currentMatch);
    }
    if (subMatch && !currentMatch?.isBlock) {
      break;
    }
  }
  matches.forEach((match3) => {
    const { body, elseBody, expression, fn } = match3;
    let replacement, i;
    if (fn) {
      const args = [match3], parts = [], len = expression.length;
      let start2 = 0, startChar;
      for (i = 0; i <= len; i++) {
        const char = expression.charAt(i);
        if (!startChar && (char === '"' || char === "'")) {
          startChar = char;
        } else if (startChar === char) {
          startChar = "";
        }
        if (!startChar && (char === " " || i === len)) {
          parts.push(expression.substr(start2, i - start2));
          start2 = i + 1;
        }
      }
      i = helpers[fn].length;
      while (i--) {
        args.unshift(resolveProperty(parts[i + 1]));
      }
      replacement = helpers[fn].apply(ctx, args);
      if (match3.isBlock && typeof replacement === "boolean") {
        replacement = format$h(replacement ? body : elseBody, ctx, owner);
      }
    } else {
      const valueAndFormat = isQuotedString(expression) ? [expression] : expression.split(":");
      replacement = resolveProperty(valueAndFormat.shift() || "");
      if (valueAndFormat.length && typeof replacement === "number") {
        const segment = valueAndFormat.join(":");
        if (floatRegex.test(segment)) {
          const decimals = parseInt((segment.match(decRegex) || ["", "-1"])[1], 10);
          if (replacement !== null) {
            replacement = numberFormatter(replacement, decimals, lang2.decimalPoint, segment.indexOf(",") > -1 ? lang2.thousandsSep : "");
          }
        } else {
          replacement = time.dateFormat(segment, replacement);
        }
      }
      subRegex.lastIndex = 0;
      if (subRegex.test(match3.find) && isString$h(replacement)) {
        replacement = `"${replacement}"`;
      }
    }
    str = str.replace(match3.find, pick$1Q(replacement, ""));
  });
  return hasSub ? format$h(str, ctx, owner) : str;
}
function numberFormat$2(number, decimals, decimalPoint, thousandsSep) {
  number = +number || 0;
  decimals = +decimals;
  let ret, fractionDigits, [mantissa, exp] = number.toString().split("e").map(Number);
  const lang2 = this?.options?.lang || defaultOptions$m.lang, origDec = (number.toString().split(".")[1] || "").split("e")[0].length, firstDecimals = decimals, options2 = {};
  decimalPoint ?? (decimalPoint = lang2.decimalPoint);
  thousandsSep ?? (thousandsSep = lang2.thousandsSep);
  if (decimals === -1) {
    decimals = Math.min(origDec, 20);
  } else if (!isNumber$18(decimals)) {
    decimals = 2;
  } else if (decimals && exp < 0) {
    fractionDigits = decimals + exp;
    if (fractionDigits >= 0) {
      mantissa = +mantissa.toExponential(fractionDigits).split("e")[0];
      decimals = fractionDigits;
    } else {
      mantissa = Math.floor(mantissa);
      if (decimals < 20) {
        number = +(mantissa * Math.pow(10, exp)).toFixed(decimals);
      } else {
        number = 0;
      }
      exp = 0;
    }
  }
  if (exp) {
    decimals ?? (decimals = 2);
    number = mantissa;
  }
  if (isNumber$18(decimals) && decimals >= 0) {
    options2.minimumFractionDigits = decimals;
    options2.maximumFractionDigits = decimals;
  }
  if (thousandsSep === "") {
    options2.useGrouping = false;
  }
  const hasSeparators = thousandsSep || decimalPoint, locale = hasSeparators ? "en" : this?.locale || lang2.locale || pageLang, cacheKey = JSON.stringify(options2) + locale, nf = numberFormatCache[cacheKey] ?? (numberFormatCache[cacheKey] = new Intl.NumberFormat(locale, options2));
  ret = nf.format(number);
  if (hasSeparators) {
    ret = ret.replace(/([,\.])/g, "_$1").replace(/_\,/g, thousandsSep ?? ",").replace("_.", decimalPoint ?? ".");
  }
  if (
    // Remove signed zero (#20564)
    !decimals && +ret === 0 || // Small numbers, no decimals (#14023)
    exp < 0 && !firstDecimals
  ) {
    ret = "0";
  }
  if (exp && +ret !== 0) {
    ret += "e" + (exp < 0 ? "" : "+") + exp;
  }
  return ret;
}
const Templating = {
  dateFormat,
  format: format$h,
  helpers,
  numberFormat: numberFormat$2
};
var RendererRegistry;
(function(RendererRegistry2) {
  RendererRegistry2.rendererTypes = {};
  let defaultRenderer;
  function getRendererType2(rendererType = defaultRenderer) {
    return RendererRegistry2.rendererTypes[rendererType] || RendererRegistry2.rendererTypes[defaultRenderer];
  }
  RendererRegistry2.getRendererType = getRendererType2;
  function registerRendererType(rendererType, rendererClass, setAsDefault) {
    RendererRegistry2.rendererTypes[rendererType] = rendererClass;
    if (!defaultRenderer || setAsDefault) {
      defaultRenderer = rendererType;
      Highcharts.Renderer = rendererClass;
    }
  }
  RendererRegistry2.registerRendererType = registerRendererType;
})(RendererRegistry || (RendererRegistry = {}));
const RendererRegistry$1 = RendererRegistry;
const { clamp: clamp$n, pick: pick$1P, pushUnique: pushUnique$A, stableSort: stableSort$7 } = Utilities;
var RendererUtilities;
(function(RendererUtilities2) {
  function distribute2(boxes, len, maxDistance) {
    const origBoxes = boxes, reducedLen = origBoxes.reducedLen || len, sortByRank = (a, b) => (b.rank || 0) - (a.rank || 0), sortByTarget = (a, b) => a.target - b.target, restBoxes = [], boxesLength = boxes.length, forDeletion = [], push = restBoxes.push;
    let i, cursor, step, overlapping = true, box, target, total = 0, equalRank;
    i = boxesLength;
    while (i--) {
      total += boxes[i].size;
    }
    if (total > reducedLen) {
      stableSort$7(boxes, sortByRank);
      equalRank = boxes[0].rank === boxes[boxes.length - 1].rank;
      step = equalRank ? boxesLength / 2 : -1;
      cursor = equalRank ? step : boxesLength - 1;
      while (step && total > reducedLen) {
        i = Math.floor(cursor);
        box = boxes[i];
        if (pushUnique$A(forDeletion, i)) {
          total -= box.size;
        }
        cursor += step;
        if (equalRank && cursor >= boxes.length) {
          step /= 2;
          cursor = step;
        }
      }
      forDeletion.sort((a, b) => b - a).forEach((i2) => push.apply(restBoxes, boxes.splice(i2, 1)));
    }
    stableSort$7(boxes, sortByTarget);
    boxes = boxes.map((box2) => ({
      size: box2.size,
      targets: [box2.target],
      align: pick$1P(box2.align, 0.5)
    }));
    while (overlapping) {
      i = boxes.length;
      while (i--) {
        box = boxes[i];
        target = (Math.min.apply(0, box.targets) + Math.max.apply(0, box.targets)) / 2;
        box.pos = clamp$n(target - box.size * box.align, 0, len - box.size);
      }
      i = boxes.length;
      overlapping = false;
      while (i--) {
        if (i > 0 && boxes[i - 1].pos + boxes[i - 1].size > boxes[i].pos) {
          boxes[i - 1].size += boxes[i].size;
          boxes[i - 1].targets = boxes[i - 1].targets.concat(boxes[i].targets);
          boxes[i - 1].align = 0.5;
          if (boxes[i - 1].pos + boxes[i - 1].size > len) {
            boxes[i - 1].pos = len - boxes[i - 1].size;
          }
          boxes.splice(i, 1);
          overlapping = true;
        }
      }
    }
    push.apply(origBoxes, restBoxes);
    i = 0;
    boxes.some((box2) => {
      let posInCompositeBox = 0;
      return (box2.targets || []).some(() => {
        origBoxes[i].pos = box2.pos + posInCompositeBox;
        if (typeof maxDistance !== "undefined" && Math.abs(origBoxes[i].pos - origBoxes[i].target) > maxDistance) {
          origBoxes.slice(0, i + 1).forEach((box3) => delete box3.pos);
          origBoxes.reducedLen = (origBoxes.reducedLen || len) - len * 0.1;
          if (origBoxes.reducedLen > len * 0.1) {
            distribute2(origBoxes, len, maxDistance);
          }
          return true;
        }
        posInCompositeBox += origBoxes[i].size;
        i++;
        return false;
      });
    });
    stableSort$7(origBoxes, sortByTarget);
    return origBoxes;
  }
  RendererUtilities2.distribute = distribute2;
})(RendererUtilities || (RendererUtilities = {}));
const R$1 = RendererUtilities;
const { animate: animate$1, animObject: animObject$f, stop: stop$1 } = animationExports;
const { deg2rad: deg2rad$a, doc: doc$r, svg: svg$2, SVG_NS: SVG_NS$3, win: win$c, isFirefox: isFirefox$3 } = Highcharts;
const { addEvent: addEvent$1v, attr: attr$d, createElement: createElement$c, crisp: crisp$f, css: css$e, defined: defined$1c, erase: erase$b, extend: extend$1q, fireEvent: fireEvent$L, getAlignFactor: getAlignFactor$a, isArray: isArray$p, isFunction: isFunction$4, isNumber: isNumber$17, isObject: isObject$l, isString: isString$g, merge: merge$1F, objectEach: objectEach$u, pick: pick$1O, pInt: pInt$6, pushUnique: pushUnique$z, replaceNested: replaceNested$2, syncTimeout: syncTimeout$b, uniqueKey: uniqueKey$9 } = Utilities;
let SVGElement$1 = class SVGElement2 {
  // @todo public zIndex?: number;
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Get the current value of an attribute or pseudo attribute,
   * used mainly for animation. Called internally from
   * the {@link Highcharts.SVGRenderer#attr} function.
   *
   * @private
   * @function Highcharts.SVGElement#_defaultGetter
   *
   * @param {string} key
   *        Property key.
   *
   * @return {number|string}
   *         Property value.
   */
  _defaultGetter(key2) {
    let ret = pick$1O(
      this[key2 + "Value"],
      // Align getter
      this[key2],
      this.element ? this.element.getAttribute(key2) : null,
      0
    );
    if (/^-?[\d\.]+$/.test(ret)) {
      ret = parseFloat(ret);
    }
    return ret;
  }
  /**
   * @private
   * @function Highcharts.SVGElement#_defaultSetter
   *
   * @param {string} value
   *
   * @param {string} key
   *
   * @param {Highcharts.SVGDOMElement} element
   *
   */
  _defaultSetter(value, key2, element) {
    element.setAttribute(key2, value);
  }
  /**
   * Add the element to the DOM. All elements must be added this way.
   *
   * @sample highcharts/members/renderer-g
   *         Elements added to a group
   *
   * @function Highcharts.SVGElement#add
   *
   * @param {Highcharts.SVGElement} [parent]
   *        The parent item to add it to. If undefined, the element is added
   *        to the {@link Highcharts.SVGRenderer.box}.
   *
   * @return {Highcharts.SVGElement}
   *         Returns the SVGElement for chaining.
   */
  add(parent) {
    const renderer = this.renderer, element = this.element;
    let inserted;
    if (parent) {
      this.parentGroup = parent;
    }
    if (typeof this.textStr !== "undefined" && this.element.nodeName === "text") {
      renderer.buildText(this);
    }
    this.added = true;
    if (!parent || parent.handleZ || this.zIndex) {
      inserted = this.zIndexSetter();
    }
    if (!inserted) {
      (parent ? parent.element : renderer.box).appendChild(element);
    }
    if (this.onAdd) {
      this.onAdd();
    }
    return this;
  }
  /**
   * Add a class name to an element.
   *
   * @function Highcharts.SVGElement#addClass
   *
   * @param {string} className
   * The new class name to add.
   *
   * @param {boolean} [replace=false]
   * When true, the existing class name(s) will be overwritten with the new
   * one. When false, the new one is added.
   *
   * @return {Highcharts.SVGElement}
   * Return the SVG element for chainability.
   */
  addClass(className, replace) {
    const currentClassName = replace ? "" : this.attr("class") || "";
    className = (className || "").split(/ /g).reduce(function(newClassName, name) {
      if (currentClassName.indexOf(name) === -1) {
        newClassName.push(name);
      }
      return newClassName;
    }, currentClassName ? [currentClassName] : []).join(" ");
    if (className !== currentClassName) {
      this.attr("class", className);
    }
    return this;
  }
  /**
   * This method is executed in the end of `attr()`, after setting all
   * attributes in the hash. In can be used to efficiently consolidate
   * multiple attributes in one SVG property -- e.g., translate, rotate and
   * scale are merged in one "transform" attribute in the SVG node.
   *
   * @private
   * @function Highcharts.SVGElement#afterSetters
   */
  afterSetters() {
    if (this.doTransform) {
      this.updateTransform();
      this.doTransform = false;
    }
  }
  /**
   * Align the element relative to the chart or another box.
   *
   * @function Highcharts.SVGElement#align
   *
   * @param {Highcharts.AlignObject} [alignOptions]
   *        The alignment options. The function can be called without this
   *        parameter in order to re-align an element after the box has been
   *        updated.
   *
   * @param {boolean} [alignByTranslate]
   *        Align element by translation.
   *
   * @param {string|Highcharts.BBoxObject} [alignTo]
   *        The box to align to, needs a width and height. When the box is a
   *        string, it refers to an object in the Renderer. For example, when
   *        box is `spacingBox`, it refers to `Renderer.spacingBox` which
   *        holds `width`, `height`, `x` and `y` properties.
   *
   * @param {boolean} [redraw]
   *        Decide if SVGElement should be redrawn with new alignment or
   *        just change its attributes.
   *
   * @return {Highcharts.SVGElement} Returns the SVGElement for chaining.
   */
  align(alignOptions, alignByTranslate, alignTo, redraw = true) {
    const renderer = this.renderer, alignedObjects = renderer.alignedObjects, initialAlignment = Boolean(alignOptions);
    if (alignOptions) {
      this.alignOptions = alignOptions;
      this.alignByTranslate = alignByTranslate;
      this.alignTo = alignTo;
    } else {
      alignOptions = this.alignOptions || {};
      alignByTranslate = this.alignByTranslate;
      alignTo = this.alignTo;
    }
    const alignToKey = !alignTo || isString$g(alignTo) ? alignTo || "renderer" : void 0;
    if (alignToKey) {
      if (initialAlignment) {
        pushUnique$z(alignedObjects, this);
      }
      alignTo = void 0;
    }
    const alignToBox = pick$1O(alignTo, renderer[alignToKey], renderer), x = (alignToBox.x || 0) + (alignOptions.x || 0) + ((alignToBox.width || 0) - (alignOptions.width || 0)) * getAlignFactor$a(alignOptions.align), y = (alignToBox.y || 0) + (alignOptions.y || 0) + ((alignToBox.height || 0) - (alignOptions.height || 0)) * getAlignFactor$a(alignOptions.verticalAlign), attribs = {
      "text-align": alignOptions?.align
    };
    attribs[alignByTranslate ? "translateX" : "x"] = Math.round(x);
    attribs[alignByTranslate ? "translateY" : "y"] = Math.round(y);
    if (redraw) {
      this[this.placed ? "animate" : "attr"](attribs);
      this.placed = true;
    }
    this.alignAttr = attribs;
    return this;
  }
  /**
   * @private
   * @function Highcharts.SVGElement#alignSetter
   * @param {"left"|"center"|"right"} value
   */
  alignSetter(value) {
    const convert = {
      left: "start",
      center: "middle",
      right: "end"
    };
    if (convert[value]) {
      this.alignValue = value;
      this.element.setAttribute("text-anchor", convert[value]);
    }
  }
  /**
   * Animate to given attributes or CSS properties.
   *
   * @sample highcharts/members/element-on/
   *         Setting some attributes by animation
   *
   * @function Highcharts.SVGElement#animate
   *
   * @param {Highcharts.SVGAttributes} params
   *        SVG attributes or CSS to animate.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [options]
   *        Animation options.
   *
   * @param {Function} [complete]
   *        Function to perform at the end of animation.
   *
   * @return {Highcharts.SVGElement}
   *         Returns the SVGElement for chaining.
   */
  animate(params2, options2, complete) {
    const animOptions = animObject$f(pick$1O(options2, this.renderer.globalAnimation, true)), deferTime = animOptions.defer;
    if (doc$r.hidden) {
      animOptions.duration = 0;
    }
    if (animOptions.duration !== 0) {
      if (complete) {
        animOptions.complete = complete;
      }
      syncTimeout$b(() => {
        if (this.element) {
          animate$1(this, params2, animOptions);
        }
      }, deferTime);
    } else {
      this.attr(params2, void 0, complete || animOptions.complete);
      objectEach$u(params2, function(val, prop) {
        if (animOptions.step) {
          animOptions.step.call(this, val, { prop, pos: 1, elem: this });
        }
      }, this);
    }
    return this;
  }
  /**
   * Apply a text outline through a custom CSS property, by copying the text
   * element and apply stroke to the copy. Used internally. Contrast checks at
   * [example](https://jsfiddle.net/highcharts/43soe9m1/2/).
   *
   * @example
   * // Specific color
   * text.css({
   *    textOutline: '1px black'
   * });
   * // Automatic contrast
   * text.css({
   *    color: '#000000', // black text
   *    textOutline: '1px contrast' // => white outline
   * });
   *
   * @private
   * @function Highcharts.SVGElement#applyTextOutline
   *
   * @param {string} textOutline
   *        A custom CSS `text-outline` setting, defined by `width color`.
   */
  applyTextOutline(textOutline) {
    const elem = this.element, hasContrast = textOutline.indexOf("contrast") !== -1;
    if (hasContrast) {
      textOutline = textOutline.replace(/contrast/g, this.renderer.getContrast(elem.style.fill));
    }
    const spacePos = textOutline.indexOf(" "), color2 = textOutline.substring(spacePos + 1);
    let strokeWidth = textOutline.substring(0, spacePos);
    if (strokeWidth && strokeWidth !== "none" && Highcharts.svg) {
      this.fakeTS = true;
      strokeWidth = strokeWidth.replace(/(^[\d\.]+)(.*?)$/g, function(match2, digit, unit) {
        return 2 * Number(digit) + unit;
      });
      this.removeTextOutline();
      const outline = doc$r.createElementNS(SVG_NS$3, "tspan");
      attr$d(outline, {
        "class": "highcharts-text-outline",
        fill: color2,
        stroke: color2,
        "stroke-width": strokeWidth,
        "stroke-linejoin": "round"
      });
      const parentElem = elem.querySelector("textPath") || elem;
      [].forEach.call(parentElem.childNodes, (childNode) => {
        const clone2 = childNode.cloneNode(true);
        if (clone2.removeAttribute) {
          ["fill", "stroke", "stroke-width", "stroke"].forEach((prop) => clone2.removeAttribute(prop));
        }
        outline.appendChild(clone2);
      });
      let totalHeight = 0;
      [].forEach.call(parentElem.querySelectorAll("text tspan"), (element) => {
        totalHeight += Number(element.getAttribute("dy"));
      });
      const br = doc$r.createElementNS(SVG_NS$3, "tspan");
      br.textContent = "​";
      attr$d(br, {
        x: Number(elem.getAttribute("x")),
        dy: -totalHeight
      });
      outline.appendChild(br);
      parentElem.insertBefore(outline, parentElem.firstChild);
    }
  }
  /**
   * @function Highcharts.SVGElement#attr
   * @param {string} key
   * @return {number|string}
   */
  /**
  * Apply native and custom attributes to the SVG elements.
  *
  * In order to set the rotation center for rotation, set x and y to 0 and
  * use `translateX` and `translateY` attributes to position the element
  * instead.
  *
  * Attributes frequently used in Highcharts are `fill`, `stroke`,
  * `stroke-width`.
  *
  * @sample highcharts/members/renderer-rect/
  *         Setting some attributes
  *
  * @example
  * // Set multiple attributes
  * element.attr({
  *     stroke: 'red',
  *     fill: 'blue',
  *     x: 10,
  *     y: 10
  * });
  *
  * // Set a single attribute
  * element.attr('stroke', 'red');
  *
  * // Get an attribute
  * element.attr('stroke'); // => 'red'
  *
  * @function Highcharts.SVGElement#attr
  *
  * @param {string|Highcharts.SVGAttributes} [hash]
  *        The native and custom SVG attributes.
  *
  * @param {number|string|Highcharts.SVGPathArray} [val]
  *        If the type of the first argument is `string`, the second can be a
  *        value, which will serve as a single attribute setter. If the first
  *        argument is a string and the second is undefined, the function
  *        serves as a getter and the current value of the property is
  *        returned.
  *
  * @param {Function} [complete]
  *        A callback function to execute after setting the attributes. This
  *        makes the function compliant and interchangeable with the
  *        {@link SVGElement#animate} function.
  *
  * @param {boolean} [continueAnimation=true]
  *        Used internally when `.attr` is called as part of an animation
  *        step. Otherwise, calling `.attr` for an attribute will stop
  *        animation for that attribute.
  *
  * @return {Highcharts.SVGElement}
  *         If used as a setter, it returns the current
  *         {@link Highcharts.SVGElement} so the calls can be chained. If
  *         used as a getter, the current value of the attribute is returned.
  */
  attr(hash2, val, complete, continueAnimation) {
    const { element } = this, symbolCustomAttribs = SVGElement2.symbolCustomAttribs;
    let key2, hasSetSymbolSize, ret = this, skipAttr, setter;
    if (typeof hash2 === "string" && typeof val !== "undefined") {
      key2 = hash2;
      hash2 = {};
      hash2[key2] = val;
    }
    if (typeof hash2 === "string") {
      ret = (this[hash2 + "Getter"] || this._defaultGetter).call(this, hash2, element);
    } else {
      objectEach$u(hash2, function eachAttribute(val2, key3) {
        skipAttr = false;
        if (!continueAnimation) {
          stop$1(this, key3);
        }
        if (this.symbolName && symbolCustomAttribs.indexOf(key3) !== -1) {
          if (!hasSetSymbolSize) {
            this.symbolAttr(hash2);
            hasSetSymbolSize = true;
          }
          skipAttr = true;
        }
        if (this.rotation && (key3 === "x" || key3 === "y")) {
          this.doTransform = true;
        }
        if (!skipAttr) {
          setter = this[key3 + "Setter"] || this._defaultSetter;
          setter.call(this, val2, key3, element);
        }
      }, this);
      this.afterSetters();
    }
    if (complete) {
      complete.call(this);
    }
    return ret;
  }
  /**
   * Apply a clipping shape to this element.
   *
   * @function Highcharts.SVGElement#clip
   *
   * @param {SVGElement} [clipElem]
   *        The clipping shape. If skipped, the current clip is removed.
   *
   * @return {Highcharts.SVGElement}
   *         Returns the SVG element to allow chaining.
   */
  clip(clipElem) {
    if (clipElem && !clipElem.clipPath) {
      const id = uniqueKey$9() + "-", clipPath = this.renderer.createElement("clipPath").attr({ id }).add(this.renderer.defs);
      extend$1q(clipElem, { clipPath, id, count: 0 });
      clipElem.add(clipPath);
    }
    return this.attr("clip-path", clipElem ? `url(${this.renderer.url}#${clipElem.id})` : "none");
  }
  /**
   * Calculate the coordinates needed for drawing a rectangle crisply and
   * return the calculated attributes.
   *
   * @function Highcharts.SVGElement#crisp
   *
   * @param {Highcharts.RectangleObject} rect
   * Rectangle to crisp.
   *
   * @param {number} [strokeWidth]
   * The stroke width to consider when computing crisp positioning. It can
   * also be set directly on the rect parameter.
   *
   * @return {Highcharts.RectangleObject}
   * The modified rectangle arguments.
   */
  crisp(rect2, strokeWidth) {
    strokeWidth = Math.round(strokeWidth || rect2.strokeWidth || 0);
    const x1 = rect2.x || this.x || 0, y1 = rect2.y || this.y || 0, x2 = (rect2.width || this.width || 0) + x1, y2 = (rect2.height || this.height || 0) + y1, x = crisp$f(x1, strokeWidth), y = crisp$f(y1, strokeWidth), x2Crisp = crisp$f(x2, strokeWidth), y2Crisp = crisp$f(y2, strokeWidth);
    extend$1q(rect2, {
      x,
      y,
      width: x2Crisp - x,
      height: y2Crisp - y
    });
    if (defined$1c(rect2.strokeWidth)) {
      rect2.strokeWidth = strokeWidth;
    }
    return rect2;
  }
  /**
   * Build and apply an SVG gradient out of a common JavaScript configuration
   * object. This function is called from the attribute setters. An event
   * hook is added for supporting other complex color types.
   *
   * @private
   * @function Highcharts.SVGElement#complexColor
   *
   * @param {Highcharts.GradientColorObject|Highcharts.PatternObject} colorOptions
   * The gradient or pattern options structure.
   *
   * @param {string} prop
   * The property to apply, can either be `fill` or `stroke`.
   *
   * @param {Highcharts.SVGDOMElement} elem
   * SVG element to apply the gradient on.
   */
  complexColor(colorOptions, prop, elem) {
    const renderer = this.renderer;
    let colorObject, gradName, gradAttr, radAttr, gradients, stops, stopColor, stopOpacity, radialReference, id, key2 = [], value;
    fireEvent$L(this.renderer, "complexColor", {
      args: arguments
    }, function() {
      if (colorOptions.radialGradient) {
        gradName = "radialGradient";
      } else if (colorOptions.linearGradient) {
        gradName = "linearGradient";
      }
      if (gradName) {
        gradAttr = colorOptions[gradName];
        gradients = renderer.gradients;
        stops = colorOptions.stops;
        radialReference = elem.radialReference;
        if (isArray$p(gradAttr)) {
          colorOptions[gradName] = gradAttr = {
            x1: gradAttr[0],
            y1: gradAttr[1],
            x2: gradAttr[2],
            y2: gradAttr[3],
            gradientUnits: "userSpaceOnUse"
          };
        }
        if (gradName === "radialGradient" && radialReference && !defined$1c(gradAttr.gradientUnits)) {
          radAttr = gradAttr;
          gradAttr = merge$1F(gradAttr, renderer.getRadialAttr(radialReference, radAttr), { gradientUnits: "userSpaceOnUse" });
        }
        objectEach$u(gradAttr, function(value2, n) {
          if (n !== "id") {
            key2.push(n, value2);
          }
        });
        objectEach$u(stops, function(val) {
          key2.push(val);
        });
        key2 = key2.join(",");
        if (gradients[key2]) {
          id = gradients[key2].attr("id");
        } else {
          gradAttr.id = id = uniqueKey$9();
          const gradientObject = gradients[key2] = renderer.createElement(gradName).attr(gradAttr).add(renderer.defs);
          gradientObject.radAttr = radAttr;
          gradientObject.stops = [];
          stops.forEach(function(stop2) {
            if (stop2[1].indexOf("rgba") === 0) {
              colorObject = Color.parse(stop2[1]);
              stopColor = colorObject.get("rgb");
              stopOpacity = colorObject.get("a");
            } else {
              stopColor = stop2[1];
              stopOpacity = 1;
            }
            const stopObject = renderer.createElement("stop").attr({
              offset: stop2[0],
              "stop-color": stopColor,
              "stop-opacity": stopOpacity
            }).add(gradientObject);
            gradientObject.stops.push(stopObject);
          });
        }
        value = "url(" + renderer.url + "#" + id + ")";
        elem.setAttribute(prop, value);
        elem.gradient = key2;
        colorOptions.toString = function() {
          return value;
        };
      }
    });
  }
  /**
   * Set styles for the element. In addition to CSS styles supported by
   * native SVG and HTML elements, there are also some custom made for
   * Highcharts, like `width`, `ellipsis` and `textOverflow` for SVG text
   * elements.
   *
   * @sample highcharts/members/renderer-text-on-chart/
   *         Styled text
   *
   * @function Highcharts.SVGElement#css
   *
   * @param {Highcharts.CSSObject} styles
   *        The new CSS styles.
   *
   * @return {Highcharts.SVGElement}
   *         Return the SVG element for chaining.
   */
  css(styles) {
    const oldStyles = this.styles, newStyles = {}, elem = this.element;
    let textWidth, hasNew = !oldStyles;
    if (oldStyles) {
      objectEach$u(styles, function(value, n) {
        if (oldStyles && oldStyles[n] !== value) {
          newStyles[n] = value;
          hasNew = true;
        }
      });
    }
    if (hasNew) {
      if (oldStyles) {
        styles = extend$1q(oldStyles, newStyles);
      }
      if (styles.width === null || styles.width === "auto") {
        delete this.textWidth;
      } else if (elem.nodeName.toLowerCase() === "text" && styles.width) {
        textWidth = this.textWidth = pInt$6(styles.width);
      }
      extend$1q(this.styles, styles);
      if (textWidth && (!svg$2 && this.renderer.forExport)) {
        delete styles.width;
      }
      const fontSize = isFirefox$3 && styles.fontSize || null;
      if (fontSize && (isNumber$17(fontSize) || /^\d+$/.test(fontSize))) {
        styles.fontSize += "px";
      }
      const stylesToApply = merge$1F(styles);
      if (elem.namespaceURI === this.SVG_NS) {
        ["textOutline", "textOverflow", "whiteSpace", "width"].forEach((key2) => stylesToApply && delete stylesToApply[key2]);
        if (stylesToApply.color) {
          stylesToApply.fill = stylesToApply.color;
          delete stylesToApply.color;
        }
      }
      css$e(elem, stylesToApply);
    }
    if (this.added) {
      if (this.element.nodeName === "text") {
        this.renderer.buildText(this);
      }
      if (styles.textOutline) {
        this.applyTextOutline(styles.textOutline);
      }
    }
    return this;
  }
  /**
   * @private
   * @function Highcharts.SVGElement#dashstyleSetter
   * @param {string} value
   */
  dashstyleSetter(value) {
    let i, strokeWidth = this["stroke-width"];
    if (strokeWidth === "inherit") {
      strokeWidth = 1;
    }
    if (value) {
      value = value.toLowerCase();
      const v = value.replace("shortdashdotdot", "3,1,1,1,1,1,").replace("shortdashdot", "3,1,1,1").replace("shortdot", "1,1,").replace("shortdash", "3,1,").replace("longdash", "8,3,").replace(/dot/g, "1,3,").replace("dash", "4,3,").replace(/,$/, "").split(",");
      i = v.length;
      while (i--) {
        v[i] = "" + pInt$6(v[i]) * pick$1O(strokeWidth, NaN);
      }
      value = v.join(",").replace(/NaN/g, "none");
      this.element.setAttribute("stroke-dasharray", value);
    }
  }
  /**
   * Destroy the element and element wrapper and clear up the DOM and event
   * hooks.
   *
   * @function Highcharts.SVGElement#destroy
   */
  destroy() {
    const wrapper = this, element = wrapper.element || {}, renderer = wrapper.renderer, ownerSVGElement = element.ownerSVGElement;
    let parentToClean = element.nodeName === "SPAN" && wrapper.parentGroup || void 0, grandParent, i;
    element.onclick = element.onmouseout = element.onmouseover = element.onmousemove = element.point = null;
    stop$1(wrapper);
    if (wrapper.clipPath && ownerSVGElement) {
      const clipPath = wrapper.clipPath;
      [].forEach.call(ownerSVGElement.querySelectorAll("[clip-path],[CLIP-PATH]"), function(el) {
        if (el.getAttribute("clip-path").indexOf(clipPath.element.id) > -1) {
          el.removeAttribute("clip-path");
        }
      });
      wrapper.clipPath = clipPath.destroy();
    }
    if (wrapper.stops) {
      for (i = 0; i < wrapper.stops.length; i++) {
        wrapper.stops[i].destroy();
      }
      wrapper.stops.length = 0;
      wrapper.stops = void 0;
    }
    wrapper.safeRemoveChild(element);
    while (parentToClean?.div && parentToClean.div.childNodes.length === 0) {
      grandParent = parentToClean.parentGroup;
      wrapper.safeRemoveChild(parentToClean.div);
      delete parentToClean.div;
      parentToClean = grandParent;
    }
    if (wrapper.alignOptions) {
      erase$b(renderer.alignedObjects, wrapper);
    }
    objectEach$u(wrapper, (val, key2) => {
      if (
        // Destroy child elements of a group
        wrapper[key2]?.parentGroup === wrapper || // Destroy own elements
        ["connector", "foreignObject"].indexOf(key2) !== -1
      ) {
        wrapper[key2]?.destroy?.();
      }
      delete wrapper[key2];
    });
    return;
  }
  /**
   * @private
   * @function Highcharts.SVGElement#dSettter
   * @param {number|string|Highcharts.SVGPathArray} value
   * @param {string} key
   * @param {Highcharts.SVGDOMElement} element
   */
  dSetter(value, key2, element) {
    if (isArray$p(value)) {
      if (typeof value[0] === "string") {
        value = this.renderer.pathToSegments(value);
      }
      this.pathArray = value;
      value = value.reduce((acc, seg, i) => {
        if (!seg?.join) {
          return (seg || "").toString();
        }
        return (i ? acc + " " : "") + seg.join(" ");
      }, "");
    }
    if (/(NaN| {2}|^$)/.test(value)) {
      value = "M 0 0";
    }
    if (this[key2] !== value) {
      element.setAttribute(key2, value);
      this[key2] = value;
    }
  }
  /**
   * @private
   * @function Highcharts.SVGElement#fillSetter
   * @param {Highcharts.ColorType} value
   * @param {string} key
   * @param {Highcharts.SVGDOMElement} element
   */
  fillSetter(value, key2, element) {
    if (typeof value === "string") {
      element.setAttribute(key2, value);
    } else if (value) {
      this.complexColor(value, key2, element);
    }
  }
  /**
   * @private
   * @function Highcharts.SVGElement#hrefSetter
   * @param {Highcharts.ColorType} value
   * @param {string} key
   * @param {Highcharts.SVGDOMElement} element
   */
  hrefSetter(value, key2, element) {
    element.setAttributeNS("http://www.w3.org/1999/xlink", key2, value);
  }
  /**
   * Get the bounding box (width, height, x and y) for the element. Generally
   * used to get rendered text size. Since this is called a lot in charts,
   * the results are cached based on text properties, in order to save DOM
   * traffic. The returned bounding box includes the rotation, so for example
   * a single text line of rotation 90 will report a greater height, and a
   * width corresponding to the line-height.
   *
   * @sample highcharts/members/renderer-on-chart/
   *         Draw a rectangle based on a text's bounding box
   *
   * @function Highcharts.SVGElement#getBBox
   *
   * @param {boolean} [reload]
   *        Skip the cache and get the updated DOM bounding box.
   *
   * @param {number} [rot]
   *        Override the element's rotation. This is internally used on axis
   *        labels with a value of 0 to find out what the bounding box would
   *        be have been if it were not rotated.
   *
   * @return {Highcharts.BBoxObject}
   *         The bounding box with `x`, `y`, `width` and `height` properties.
   */
  getBBox(reload, rot) {
    const wrapper = this, { alignValue, element, renderer, styles, textStr } = wrapper, { cache: cache2, cacheKeys } = renderer, isSVG = element.namespaceURI === wrapper.SVG_NS, rotation = pick$1O(rot, wrapper.rotation, 0), fontSize = renderer.styledMode ? element && SVGElement2.prototype.getStyle.call(element, "font-size") : styles.fontSize;
    let bBox, height, toggleTextShadowShim, cacheKey;
    if (defined$1c(textStr)) {
      cacheKey = textStr.toString();
      if (cacheKey.indexOf("<") === -1) {
        cacheKey = cacheKey.replace(/\d/g, "0");
      }
      cacheKey += [
        "",
        renderer.rootFontSize,
        fontSize,
        rotation,
        wrapper.textWidth,
        // #7874, also useHTML
        alignValue,
        styles.lineClamp,
        styles.textOverflow,
        // #5968
        styles.fontWeight
        // #12163
      ].join(",");
    }
    if (cacheKey && !reload) {
      bBox = cache2[cacheKey];
    }
    if (!bBox || bBox.polygon) {
      if (isSVG || renderer.forExport) {
        try {
          toggleTextShadowShim = this.fakeTS && function(display) {
            const outline = element.querySelector(".highcharts-text-outline");
            if (outline) {
              css$e(outline, { display });
            }
          };
          if (isFunction$4(toggleTextShadowShim)) {
            toggleTextShadowShim("none");
          }
          bBox = element.getBBox ? (
            // SVG: use extend because IE9 is not allowed to change
            // width and height in case of rotation (below)
            extend$1q({}, element.getBBox())
          ) : {
            // HTML elements with `exporting.allowHTML` and
            // legacy IE in export mode
            width: element.offsetWidth,
            height: element.offsetHeight,
            x: 0,
            y: 0
          };
          if (isFunction$4(toggleTextShadowShim)) {
            toggleTextShadowShim("");
          }
        } catch (e2) {
        }
        if (!bBox || bBox.width < 0) {
          bBox = { x: 0, y: 0, width: 0, height: 0 };
        }
      } else {
        bBox = wrapper.htmlGetBBox();
      }
      height = bBox.height;
      if (isSVG) {
        bBox.height = height = {
          "11px,17": 14,
          "13px,20": 16
        }[`${fontSize || ""},${Math.round(height)}`] || height;
      }
      if (rotation) {
        bBox = this.getRotatedBox(bBox, rotation);
      }
      const e = { bBox };
      fireEvent$L(this, "afterGetBBox", e);
      bBox = e.bBox;
    }
    if (cacheKey && (textStr === "" || bBox.height > 0)) {
      while (cacheKeys.length > 250) {
        delete cache2[cacheKeys.shift()];
      }
      if (!cache2[cacheKey]) {
        cacheKeys.push(cacheKey);
      }
      cache2[cacheKey] = bBox;
    }
    return bBox;
  }
  /**
   * Get the rotated box.
   * @private
   */
  getRotatedBox(box, rotation) {
    const { x: boxX, y: boxY, width, height } = box, { alignValue, translateY, rotationOriginX = 0, rotationOriginY = 0 } = this, alignFactor = getAlignFactor$a(alignValue), baseline = Number(this.element.getAttribute("y") || 0) - (translateY ? 0 : boxY), rad = rotation * deg2rad$a, rad90 = (rotation - 90) * deg2rad$a, cosRad = Math.cos(rad), sinRad = Math.sin(rad), wCosRad = width * cosRad, wSinRad = width * sinRad, cosRad90 = Math.cos(rad90), sinRad90 = Math.sin(rad90), [[xOriginCosRad, xOriginSinRad], [yOriginCosRad, yOriginSinRad]] = [
      rotationOriginX,
      rotationOriginY
    ].map((rotOrigin) => [
      rotOrigin - rotOrigin * cosRad,
      rotOrigin * sinRad
    ]), pX = boxX + alignFactor * (width - wCosRad) + xOriginCosRad + yOriginSinRad, pY = boxY + baseline - alignFactor * wSinRad - xOriginSinRad + yOriginCosRad, aX = pX + baseline * cosRad90, bX = aX + wCosRad, cX = bX - height * cosRad90, dX = cX - wCosRad, aY = pY + baseline * sinRad90, bY = aY + wSinRad, cY = bY - height * sinRad90, dY = cY - wSinRad;
    const x = Math.min(aX, bX, cX, dX), y = Math.min(aY, bY, cY, dY), boxWidth = Math.max(aX, bX, cX, dX) - x, boxHeight = Math.max(aY, bY, cY, dY) - y;
    return {
      x,
      y,
      width: boxWidth,
      height: boxHeight,
      polygon: [
        [aX, aY],
        [bX, bY],
        [cX, cY],
        [dX, dY]
      ]
    };
  }
  /**
   * Get the computed style. Only in styled mode.
   *
   * @example
   * chart.series[0].points[0].graphic.getStyle('stroke-width'); // => '1px'
   *
   * @function Highcharts.SVGElement#getStyle
   *
   * @param {string} prop
   *        The property name to check for.
   *
   * @return {string}
   *         The current computed value.
   */
  getStyle(prop) {
    return win$c.getComputedStyle(this.element || this, "").getPropertyValue(prop);
  }
  /**
   * Check if an element has the given class name.
   *
   * @function Highcharts.SVGElement#hasClass
   *
   * @param {string} className
   * The class name to check for.
   *
   * @return {boolean}
   * Whether the class name is found.
   */
  hasClass(className) {
    return ("" + this.attr("class")).split(" ").indexOf(className) !== -1;
  }
  /**
   * Hide the element, similar to setting the `visibility` attribute to
   * `hidden`.
   *
   * @function Highcharts.SVGElement#hide
   *
   * @return {Highcharts.SVGElement}
   *         Returns the SVGElement for chaining.
   */
  hide() {
    return this.attr({ visibility: "hidden" });
  }
  /**
   * @private
   */
  htmlGetBBox() {
    return { height: 0, width: 0, x: 0, y: 0 };
  }
  /**
   * Initialize the SVG element. This function only exists to make the
   * initialization process overridable. It should not be called directly.
   *
   * @function Highcharts.SVGElement#init
   *
   * @param {Highcharts.SVGRenderer} renderer
   * The SVGRenderer instance to initialize to.
   *
   * @param {string} nodeName
   * The SVG node name.
   */
  constructor(renderer, nodeName) {
    this.onEvents = {};
    this.opacity = 1;
    this.SVG_NS = SVG_NS$3;
    this.element = nodeName === "span" || nodeName === "body" ? createElement$c(nodeName) : doc$r.createElementNS(this.SVG_NS, nodeName);
    this.renderer = renderer;
    this.styles = {};
    fireEvent$L(this, "afterInit");
  }
  /**
   * Add an event listener. This is a simple setter that replaces the
   * previous event of the same type added by this function, as opposed to
   * the {@link Highcharts#addEvent} function.
   *
   * @sample highcharts/members/element-on/
   *         A clickable rectangle
   *
   * @function Highcharts.SVGElement#on
   *
   * @param {string} eventType
   * The event type.
   *
   * @param {Function} handler
   * The handler callback.
   *
   * @return {Highcharts.SVGElement}
   * The SVGElement for chaining.
   */
  on(eventType, handler) {
    const { onEvents } = this;
    if (onEvents[eventType]) {
      onEvents[eventType]();
    }
    onEvents[eventType] = addEvent$1v(this.element, eventType, handler);
    return this;
  }
  /**
   * @private
   * @function Highcharts.SVGElement#opacitySetter
   * @param {string} value
   * @param {string} key
   * @param {Highcharts.SVGDOMElement} element
   */
  opacitySetter(value, key2, element) {
    const opacity = Number(Number(value).toFixed(3));
    this.opacity = opacity;
    element.setAttribute(key2, opacity);
  }
  /**
   * Re-align an aligned text or label after setting the text.
   *
   * @private
   * @function Highcharts.SVGElement#reAlign
   *
   */
  reAlign() {
    if (this.alignOptions?.width && this.alignOptions.align !== "left") {
      this.alignOptions.width = this.getBBox().width;
      this.placed = false;
      this.align();
    }
  }
  /**
   * Remove a class name from the element.
   *
   * @function Highcharts.SVGElement#removeClass
   *
   * @param {string|RegExp} className
   *        The class name to remove.
   *
   * @return {Highcharts.SVGElement} Returns the SVG element for chainability.
   */
  removeClass(className) {
    return this.attr("class", ("" + this.attr("class")).replace(isString$g(className) ? new RegExp(`(^| )${className}( |$)`) : (
      // #12064, #13590
      className
    ), " ").replace(/ +/g, " ").trim());
  }
  /**
   *
   * @private
   */
  removeTextOutline() {
    const outline = this.element.querySelector("tspan.highcharts-text-outline");
    if (outline) {
      this.safeRemoveChild(outline);
    }
  }
  /**
   * Removes an element from the DOM.
   *
   * @private
   * @function Highcharts.SVGElement#safeRemoveChild
   *
   * @param {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} element
   * The DOM node to remove.
   */
  safeRemoveChild(element) {
    const parentNode = element.parentNode;
    if (parentNode) {
      parentNode.removeChild(element);
    }
  }
  /**
   * Set the coordinates needed to draw a consistent radial gradient across
   * a shape regardless of positioning inside the chart. Used on pie slices
   * to make all the slices have the same radial reference point.
   *
   * @function Highcharts.SVGElement#setRadialReference
   *
   * @param {Array<number>} coordinates
   * The center reference. The format is `[centerX, centerY, diameter]` in
   * pixels.
   *
   * @return {Highcharts.SVGElement}
   * Returns the SVGElement for chaining.
   */
  setRadialReference(coordinates2) {
    const existingGradient = this.element.gradient && this.renderer.gradients[this.element.gradient] || void 0;
    this.element.radialReference = coordinates2;
    if (existingGradient?.radAttr) {
      existingGradient.animate(this.renderer.getRadialAttr(coordinates2, existingGradient.radAttr));
    }
    return this;
  }
  /**
   * Add a shadow to the element. In styled mode, this method is not used,
   * instead use `defs` and filters.
   *
   * @example
   * renderer.rect(10, 100, 100, 100)
   *     .attr({ fill: 'red' })
   *     .shadow(true);
   *
   * @function Highcharts.SVGElement#shadow
   *
   * @param {boolean|Highcharts.ShadowOptionsObject} [shadowOptions] The
   *        shadow options. If `true`, the default options are applied. If
   *        `false`, the current shadow will be removed.
   *
   * @return {Highcharts.SVGElement} Returns the SVGElement for chaining.
   */
  shadow(shadowOptions) {
    const { renderer } = this, options2 = merge$1F(this.parentGroup?.rotation === 90 ? {
      offsetX: -1,
      offsetY: -1
    } : {}, isObject$l(shadowOptions) ? shadowOptions : {}), id = renderer.shadowDefinition(options2);
    return this.attr({
      filter: shadowOptions ? `url(${renderer.url}#${id})` : "none"
    });
  }
  /**
   * Show the element after it has been hidden.
   *
   * @function Highcharts.SVGElement#show
   *
   * @param {boolean} [inherit=true]
   *        Set the visibility attribute to `inherit` rather than `visible`.
   *        The difference is that an element with `visibility="visible"`
   *        will be visible even if the parent is hidden.
   *
   * @return {Highcharts.SVGElement}
   *         Returns the SVGElement for chaining.
   */
  show(inherit = true) {
    return this.attr({ visibility: inherit ? "inherit" : "visible" });
  }
  /**
   * Set the stroke-width and record it on the SVGElement
   *
   * @private
   * @function Highcharts.SVGElement#strokeSetter
   * @param {number|string|ColorType} value
   * @param {string} key
   * @param {Highcharts.SVGDOMElement} element
   */
  "stroke-widthSetter"(value, key2, element) {
    this[key2] = value;
    element.setAttribute(key2, value);
  }
  /**
   * Get the computed stroke width in pixel values. This is used extensively
   * when drawing shapes to ensure the shapes are rendered crisp and
   * positioned correctly relative to each other. Using
   * `shape-rendering: crispEdges` leaves us less control over positioning,
   * for example when we want to stack columns next to each other, or position
   * things pixel-perfectly within the plot box.
   *
   * The common pattern when placing a shape is:
   * - Create the SVGElement and add it to the DOM. In styled mode, it will
   *   now receive a stroke width from the style sheet. In classic mode we
   *   will add the `stroke-width` attribute.
   * - Read the computed `elem.strokeWidth()`.
   * - Place it based on the stroke width.
   *
   * @function Highcharts.SVGElement#strokeWidth
   *
   * @return {number}
   * The stroke width in pixels. Even if the given stroke width (in CSS or by
   * attributes) is based on `em` or other units, the pixel size is returned.
   */
  strokeWidth() {
    if (!this.renderer.styledMode) {
      return this["stroke-width"] || 0;
    }
    const val = this.getStyle("stroke-width");
    let ret = 0, tempElement;
    if (/px$/.test(val)) {
      ret = pInt$6(val);
    } else if (val !== "") {
      tempElement = doc$r.createElementNS(SVG_NS$3, "rect");
      attr$d(tempElement, {
        width: val,
        "stroke-width": 0
      });
      this.element.parentNode.appendChild(tempElement);
      ret = tempElement.getBBox().width;
      tempElement.parentNode.removeChild(tempElement);
    }
    return ret;
  }
  /**
   * If one of the symbol size affecting parameters are changed,
   * check all the others only once for each call to an element's
   * .attr() method
   *
   * @private
   * @function Highcharts.SVGElement#symbolAttr
   *
   * @param {Highcharts.SVGAttributes} hash
   * The attributes to set.
   */
  symbolAttr(hash2) {
    const wrapper = this;
    SVGElement2.symbolCustomAttribs.forEach(function(key2) {
      wrapper[key2] = pick$1O(hash2[key2], wrapper[key2]);
    });
    wrapper.attr({
      d: wrapper.renderer.symbols[wrapper.symbolName](wrapper.x, wrapper.y, wrapper.width, wrapper.height, wrapper)
    });
  }
  /**
   * @private
   * @function Highcharts.SVGElement#textSetter
   * @param {string} value
   */
  textSetter(value) {
    if (value !== this.textStr) {
      delete this.textPxLength;
      this.textStr = value;
      if (this.added) {
        this.renderer.buildText(this);
      }
      this.reAlign();
    }
  }
  /**
   * @private
   * @function Highcharts.SVGElement#titleSetter
   * @param {string} value
   */
  titleSetter(value) {
    const el = this.element;
    const titleNode = el.getElementsByTagName("title")[0] || doc$r.createElementNS(this.SVG_NS, "title");
    if (el.insertBefore) {
      el.insertBefore(titleNode, el.firstChild);
    } else {
      el.appendChild(titleNode);
    }
    titleNode.textContent = replaceNested$2(
      // Scan #[73]
      pick$1O(value, ""),
      // #3276, #3895
      [/<[^>]*>/g, ""]
    ).replace(/&lt;/g, "<").replace(/&gt;/g, ">");
  }
  /**
   * Bring the element to the front. Alternatively, a new zIndex can be set.
   *
   * @sample highcharts/members/element-tofront/
   *         Click an element to bring it to front
   *
   * @function Highcharts.SVGElement#toFront
   *
   * @return {Highcharts.SVGElement}
   * Returns the SVGElement for chaining.
   */
  toFront() {
    const element = this.element;
    element.parentNode.appendChild(element);
    return this;
  }
  /**
   * Move an object and its children by x and y values.
   *
   * @function Highcharts.SVGElement#translate
   *
   * @param {number} x
   * The x value.
   *
   * @param {number} y
   * The y value.
   *
   * @return {Highcharts.SVGElement}
   * Translated element.
   */
  translate(x, y) {
    return this.attr({
      translateX: x,
      translateY: y
    });
  }
  /**
   * Update the transform attribute based on internal properties. Deals with
   * the custom `translateX`, `translateY`, `rotation`, `scaleX` and `scaleY`
   * attributes and updates the SVG `transform` attribute.
   *
   * @private
   * @function Highcharts.SVGElement#updateTransform
   */
  updateTransform(attrib = "transform") {
    const { element, foreignObject, matrix, padding, rotation = 0, rotationOriginX, rotationOriginY, scaleX, scaleY, text, translateX = 0, translateY = 0 } = this;
    const transform2 = ["translate(" + translateX + "," + translateY + ")"];
    if (defined$1c(matrix)) {
      transform2.push("matrix(" + matrix.join(",") + ")");
    }
    if (rotation) {
      transform2.push("rotate(" + rotation + " " + (rotationOriginX ?? element.getAttribute("x") ?? this.x ?? 0) + " " + (rotationOriginY ?? element.getAttribute("y") ?? this.y ?? 0) + ")");
      if (text?.element.tagName === "SPAN" && !text?.foreignObject) {
        text.attr({
          rotation,
          rotationOriginX: (rotationOriginX || 0) - padding,
          rotationOriginY: (rotationOriginY || 0) - padding
        });
      }
    }
    if (defined$1c(scaleX) || defined$1c(scaleY)) {
      transform2.push("scale(" + pick$1O(scaleX, 1) + " " + pick$1O(scaleY, 1) + ")");
    }
    if (transform2.length && !(text || this).textPath) {
      (foreignObject?.element || element).setAttribute(attrib, transform2.join(" "));
    }
  }
  /**
   * @private
   * @function Highcharts.SVGElement#visibilitySetter
   *
   * @param {string} value
   *
   * @param {string} key
   *
   * @param {Highcharts.SVGDOMElement} element
   *
   */
  visibilitySetter(value, key2, element) {
    if (value === "inherit") {
      element.removeAttribute(key2);
    } else if (this[key2] !== value) {
      element.setAttribute(key2, value);
    }
    this[key2] = value;
  }
  /**
   * @private
   * @function Highcharts.SVGElement#xGetter
   */
  xGetter(key2) {
    if (this.element.nodeName === "circle") {
      if (key2 === "x") {
        key2 = "cx";
      } else if (key2 === "y") {
        key2 = "cy";
      }
    }
    return this._defaultGetter(key2);
  }
  /**
   * @private
   * @function Highcharts.SVGElement#zIndexSetter
   */
  zIndexSetter(value, key2) {
    const renderer = this.renderer, parentGroup = this.parentGroup, parentWrapper = parentGroup || renderer, parentNode = parentWrapper.element || renderer.box, element = this.element, svgParent = parentNode === renderer.box;
    let childNodes, otherElement, otherZIndex, inserted = false, undefinedOtherZIndex, run = this.added, i;
    if (defined$1c(value)) {
      element.setAttribute("data-z-index", value);
      value = +value;
      if (this[key2] === value) {
        run = false;
      }
    } else if (defined$1c(this[key2])) {
      element.removeAttribute("data-z-index");
    }
    this[key2] = value;
    if (run) {
      value = this.zIndex;
      if (value && parentGroup) {
        parentGroup.handleZ = true;
      }
      childNodes = parentNode.childNodes;
      for (i = childNodes.length - 1; i >= 0 && !inserted; i--) {
        otherElement = childNodes[i];
        otherZIndex = otherElement.getAttribute("data-z-index");
        undefinedOtherZIndex = !defined$1c(otherZIndex);
        if (otherElement !== element) {
          if (
            // Negative zIndex versus no zIndex:
            // On all levels except the highest. If the parent is
            // <svg>, then we don't want to put items before <desc>
            // or <defs>
            value < 0 && undefinedOtherZIndex && !svgParent && !i
          ) {
            parentNode.insertBefore(element, childNodes[i]);
            inserted = true;
          } else if (
            // Insert after the first element with a lower zIndex
            pInt$6(otherZIndex) <= value || // If negative zIndex, add this before first undefined
            // zIndex element
            undefinedOtherZIndex && (!defined$1c(value) || value >= 0)
          ) {
            parentNode.insertBefore(element, childNodes[i + 1]);
            inserted = true;
          }
        }
      }
      if (!inserted) {
        parentNode.insertBefore(element, childNodes[svgParent ? 3 : 0]);
        inserted = true;
      }
    }
    return inserted;
  }
};
SVGElement$1.symbolCustomAttribs = [
  "anchorX",
  "anchorY",
  "clockwise",
  "end",
  "height",
  "innerR",
  "r",
  "start",
  "width",
  "x",
  "y"
];
SVGElement$1.prototype.strokeSetter = SVGElement$1.prototype.fillSetter;
SVGElement$1.prototype.yGetter = SVGElement$1.prototype.xGetter;
SVGElement$1.prototype.matrixSetter = SVGElement$1.prototype.rotationOriginXSetter = SVGElement$1.prototype.rotationOriginYSetter = SVGElement$1.prototype.rotationSetter = SVGElement$1.prototype.scaleXSetter = SVGElement$1.prototype.scaleYSetter = SVGElement$1.prototype.translateXSetter = SVGElement$1.prototype.translateYSetter = SVGElement$1.prototype.verticalAlignSetter = function(value, key2) {
  this[key2] = value;
  this.doTransform = true;
};
const { defined: defined$1b, extend: extend$1p, getAlignFactor: getAlignFactor$9, isNumber: isNumber$16, merge: merge$1E, pick: pick$1N, removeEvent: removeEvent$c } = Utilities;
class SVGLabel extends SVGElement$1 {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(renderer, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
    super(renderer, "g");
    this.paddingLeftSetter = this.paddingSetter;
    this.paddingRightSetter = this.paddingSetter;
    this.doUpdate = false;
    this.textStr = str;
    this.x = x;
    this.y = y;
    this.anchorX = anchorX;
    this.anchorY = anchorY;
    this.baseline = baseline;
    this.className = className;
    this.addClass(className === "button" ? "highcharts-no-tooltip" : "highcharts-label");
    if (className) {
      this.addClass("highcharts-" + className);
    }
    this.text = renderer.text(void 0, 0, 0, useHTML).attr({ zIndex: 1 });
    let hasBGImage;
    if (typeof shape === "string") {
      hasBGImage = /^url\((.*?)\)$/.test(shape);
      if (hasBGImage || this.renderer.symbols[shape]) {
        this.symbolKey = shape;
      }
    }
    this.bBox = SVGLabel.emptyBBox;
    this.padding = 3;
    this.baselineOffset = 0;
    this.needsBox = renderer.styledMode || hasBGImage;
    this.deferredAttr = {};
    this.alignFactor = 0;
  }
  /* *
   *
   *  Functions
   *
   * */
  alignSetter(value) {
    const alignFactor = getAlignFactor$9(value);
    this.textAlign = value;
    if (alignFactor !== this.alignFactor) {
      this.alignFactor = alignFactor;
      if (this.bBox && isNumber$16(this.xSetting)) {
        this.attr({ x: this.xSetting });
      }
    }
  }
  anchorXSetter(value, key2) {
    this.anchorX = value;
    this.boxAttr(key2, Math.round(value) - this.getCrispAdjust() - this.xSetting);
  }
  anchorYSetter(value, key2) {
    this.anchorY = value;
    this.boxAttr(key2, value - this.ySetting);
  }
  /*
   * Set a box attribute, or defer it if the box is not yet created
   */
  boxAttr(key2, value) {
    if (this.box) {
      this.box.attr(key2, value);
    } else {
      this.deferredAttr[key2] = value;
    }
  }
  /*
   * Pick up some properties and apply them to the text instead of the
   * wrapper.
   */
  css(styles) {
    if (styles) {
      const textStyles = {};
      styles = merge$1E(styles);
      SVGLabel.textProps.forEach((prop) => {
        if (typeof styles[prop] !== "undefined") {
          textStyles[prop] = styles[prop];
          delete styles[prop];
        }
      });
      this.text.css(textStyles);
      if ("fontSize" in textStyles || "fontWeight" in textStyles) {
        this.updateTextPadding();
      } else if ("width" in textStyles || "textOverflow" in textStyles) {
        this.updateBoxSize();
      }
    }
    return SVGElement$1.prototype.css.call(this, styles);
  }
  /*
   * Destroy and release memory.
   */
  destroy() {
    removeEvent$c(this.element, "mouseenter");
    removeEvent$c(this.element, "mouseleave");
    if (this.text) {
      this.text.destroy();
    }
    if (this.box) {
      this.box = this.box.destroy();
    }
    SVGElement$1.prototype.destroy.call(this);
    return void 0;
  }
  fillSetter(value, key2) {
    if (value) {
      this.needsBox = true;
    }
    this.fill = value;
    this.boxAttr(key2, value);
  }
  /*
   * Return the bounding box of the box, not the group.
   */
  getBBox(reload, rot) {
    if (this.textStr && this.bBox.width === 0 && this.bBox.height === 0) {
      this.updateBoxSize();
    }
    const { padding, height = 0, translateX = 0, translateY = 0, width = 0 } = this, paddingLeft = pick$1N(this.paddingLeft, padding), rotation = rot ?? (this.rotation || 0);
    let bBox = {
      width,
      height,
      x: translateX + this.bBox.x - paddingLeft,
      y: translateY + this.bBox.y - padding + this.baselineOffset
    };
    if (rotation) {
      bBox = this.getRotatedBox(bBox, rotation);
    }
    return bBox;
  }
  getCrispAdjust() {
    return (this.renderer.styledMode && this.box ? this.box.strokeWidth() : this["stroke-width"] ? parseInt(this["stroke-width"], 10) : 0) % 2 / 2;
  }
  heightSetter(value) {
    this.heightSetting = value;
    this.doUpdate = true;
  }
  /**
   * This method is executed in the end of `attr()`, after setting all
   * attributes in the hash. In can be used to efficiently consolidate
   * multiple attributes in one SVG property -- e.g., translate, rotate and
   * scale are merged in one "transform" attribute in the SVG node.
   * Also updating height or width should trigger update of the box size.
   *
   * @private
   * @function Highcharts.SVGLabel#afterSetters
   */
  afterSetters() {
    super.afterSetters();
    if (this.doUpdate) {
      this.updateBoxSize();
      this.doUpdate = false;
    }
  }
  /*
   * After the text element is added, get the desired size of the border
   * box and add it before the text in the DOM.
   */
  onAdd() {
    this.text.add(this);
    this.attr({
      // Alignment is available now  (#3295, 0 not rendered if given
      // as a value)
      text: pick$1N(this.textStr, ""),
      x: this.x || 0,
      y: this.y || 0
    });
    if (this.box && defined$1b(this.anchorX)) {
      this.attr({
        anchorX: this.anchorX,
        anchorY: this.anchorY
      });
    }
  }
  paddingSetter(value, key2) {
    if (!isNumber$16(value)) {
      this[key2] = void 0;
    } else if (value !== this[key2]) {
      this[key2] = value;
      this.updateTextPadding();
    }
  }
  rSetter(value, key2) {
    this.boxAttr(key2, value);
  }
  strokeSetter(value, key2) {
    this.stroke = value;
    this.boxAttr(key2, value);
  }
  "stroke-widthSetter"(value, key2) {
    if (value) {
      this.needsBox = true;
    }
    this["stroke-width"] = value;
    this.boxAttr(key2, value);
  }
  "text-alignSetter"(value) {
    this.textAlign = this["text-align"] = value;
    this.updateTextPadding();
  }
  textSetter(text) {
    if (typeof text !== "undefined") {
      this.text.attr({ text });
    }
    this.updateTextPadding();
    this.reAlign();
  }
  /*
   * This function runs after the label is added to the DOM (when the bounding
   * box is available), and after the text of the label is updated to detect
   * the new bounding box and reflect it in the border box.
   */
  updateBoxSize() {
    const text = this.text, attribs = {}, padding = this.padding, bBox = this.bBox = (!isNumber$16(this.widthSetting) || !isNumber$16(this.heightSetting) || this.textAlign) && defined$1b(text.textStr) ? text.getBBox(void 0, 0) : SVGLabel.emptyBBox;
    let crispAdjust;
    this.width = this.getPaddedWidth();
    this.height = (this.heightSetting || bBox.height || 0) + 2 * padding;
    const metrics = this.renderer.fontMetrics(text);
    this.baselineOffset = padding + Math.min(
      // When applicable, use the font size of the first line (#15707)
      (this.text.firstLineMetrics || metrics).b,
      // When the height is 0, there is no bBox, so go with the font
      // metrics. Highmaps CSS demos.
      bBox.height || Infinity
    );
    if (this.heightSetting) {
      this.baselineOffset += (this.heightSetting - metrics.h) / 2;
    }
    if (this.needsBox && !text.textPath) {
      if (!this.box) {
        const box = this.box = this.symbolKey ? this.renderer.symbol(this.symbolKey) : this.renderer.rect();
        box.addClass(
          // Don't use label className for buttons
          (this.className === "button" ? "" : "highcharts-label-box") + (this.className ? " highcharts-" + this.className + "-box" : "")
        );
        box.add(this);
      }
      crispAdjust = this.getCrispAdjust();
      attribs.x = crispAdjust;
      attribs.y = (this.baseline ? -this.baselineOffset : 0) + crispAdjust;
      attribs.width = Math.round(this.width);
      attribs.height = Math.round(this.height);
      this.box.attr(extend$1p(attribs, this.deferredAttr));
      this.deferredAttr = {};
    }
  }
  /*
   * This function runs after setting text or padding, but only if padding
   * is changed.
   */
  updateTextPadding() {
    const text = this.text, textAlign = text.styles.textAlign || this.textAlign;
    if (!text.textPath) {
      this.updateBoxSize();
      const textY = this.baseline ? 0 : this.baselineOffset, textX = (this.paddingLeft ?? this.padding) + // Compensate for alignment
      getAlignFactor$9(textAlign) * (this.widthSetting ?? this.bBox.width);
      if (textX !== text.x || textY !== text.y) {
        text.attr({
          align: textAlign,
          x: textX
        });
        if (typeof textY !== "undefined") {
          text.attr("y", textY);
        }
      }
      text.x = textX;
      text.y = textY;
    }
  }
  widthSetter(value) {
    this.widthSetting = isNumber$16(value) ? value : void 0;
    this.doUpdate = true;
  }
  getPaddedWidth() {
    const padding = this.padding;
    const paddingLeft = pick$1N(this.paddingLeft, padding);
    const paddingRight = pick$1N(this.paddingRight, padding);
    return (this.widthSetting || this.bBox.width || 0) + paddingLeft + paddingRight;
  }
  xSetter(value) {
    this.x = value;
    if (this.alignFactor) {
      value -= this.alignFactor * this.getPaddedWidth();
      this["forceAnimate:x"] = true;
    }
    this.xSetting = Math.round(value);
    this.attr("translateX", this.xSetting);
  }
  ySetter(value) {
    this.ySetting = this.y = Math.round(value);
    this.attr("translateY", this.ySetting);
  }
}
SVGLabel.emptyBBox = {
  width: 0,
  height: 0,
  x: 0,
  y: 0
};
SVGLabel.textProps = [
  "color",
  "direction",
  "fontFamily",
  "fontSize",
  "fontStyle",
  "fontWeight",
  "lineClamp",
  "lineHeight",
  "textAlign",
  "textDecoration",
  "textOutline",
  "textOverflow",
  "whiteSpace",
  "width"
];
const { defined: defined$1a, isNumber: isNumber$15, pick: pick$1M } = Utilities;
function arc$1(cx, cy, w, h, options2) {
  const arc2 = [];
  if (options2) {
    let start2 = options2.start || 0, end = options2.end || 0;
    const rx = pick$1M(options2.r, w), ry = pick$1M(options2.r, h || w), proximity = 2e-4 / (options2.borderRadius ? 1 : Math.max(rx, 1)), fullCircle = Math.abs(end - start2 - 2 * Math.PI) < proximity;
    if (fullCircle) {
      start2 = Math.PI / 2;
      end = Math.PI * 2.5 - proximity;
    }
    const innerRadius = options2.innerR, open2 = pick$1M(options2.open, fullCircle), cosStart = Math.cos(start2), sinStart = Math.sin(start2), cosEnd = Math.cos(end), sinEnd = Math.sin(end), longArc = pick$1M(options2.longArc, end - start2 - Math.PI < proximity ? 0 : 1);
    let arcSegment = [
      "A",
      // ArcTo
      rx,
      // X radius
      ry,
      // Y radius
      0,
      // Slanting
      longArc,
      // Long or short arc
      pick$1M(options2.clockwise, 1),
      // Clockwise
      cx + rx * cosEnd,
      cy + ry * sinEnd
    ];
    arcSegment.params = { start: start2, end, cx, cy };
    arc2.push([
      "M",
      cx + rx * cosStart,
      cy + ry * sinStart
    ], arcSegment);
    if (defined$1a(innerRadius)) {
      arcSegment = [
        "A",
        // ArcTo
        innerRadius,
        // X radius
        innerRadius,
        // Y radius
        0,
        // Slanting
        longArc,
        // Long or short arc
        // Clockwise - opposite to the outer arc clockwise
        defined$1a(options2.clockwise) ? 1 - options2.clockwise : 0,
        cx + innerRadius * cosStart,
        cy + innerRadius * sinStart
      ];
      arcSegment.params = {
        start: end,
        end: start2,
        cx,
        cy
      };
      arc2.push(open2 ? [
        "M",
        cx + innerRadius * cosEnd,
        cy + innerRadius * sinEnd
      ] : [
        "L",
        cx + innerRadius * cosEnd,
        cy + innerRadius * sinEnd
      ], arcSegment);
    }
    if (!open2) {
      arc2.push(["Z"]);
    }
  }
  return arc2;
}
function callout(x, y, w, h, options2) {
  const arrowLength = 6, halfDistance = 6, r = Math.min(options2?.r || 0, w, h), safeDistance = r + halfDistance, anchorX = options2?.anchorX, anchorY = options2?.anchorY || 0;
  const path = roundedRect$1(x, y, w, h, { r });
  if (!isNumber$15(anchorX)) {
    return path;
  }
  if (anchorX < w && anchorX > 0 && anchorY < h && anchorY > 0) {
    return path;
  }
  if (x + anchorX > w - safeDistance) {
    if (anchorY > y + safeDistance && anchorY < y + h - safeDistance) {
      path.splice(3, 1, ["L", x + w, anchorY - halfDistance], ["L", x + w + arrowLength, anchorY], ["L", x + w, anchorY + halfDistance], ["L", x + w, y + h - r]);
    } else {
      if (anchorX < w) {
        const isTopCorner = anchorY < y + safeDistance, cornerY = isTopCorner ? y : y + h, sliceStart = isTopCorner ? 2 : 5;
        path.splice(sliceStart, 0, ["L", anchorX, anchorY], ["L", x + w - r, cornerY]);
      } else {
        path.splice(3, 1, ["L", x + w, h / 2], ["L", anchorX, anchorY], ["L", x + w, h / 2], ["L", x + w, y + h - r]);
      }
    }
  } else if (x + anchorX < safeDistance) {
    if (anchorY > y + safeDistance && anchorY < y + h - safeDistance) {
      path.splice(7, 1, ["L", x, anchorY + halfDistance], ["L", x - arrowLength, anchorY], ["L", x, anchorY - halfDistance], ["L", x, y + r]);
    } else {
      if (anchorX > 0) {
        const isTopCorner = anchorY < y + safeDistance, cornerY = isTopCorner ? y : y + h, sliceStart = isTopCorner ? 1 : 6;
        path.splice(sliceStart, 0, ["L", anchorX, anchorY], ["L", x + r, cornerY]);
      } else {
        path.splice(7, 1, ["L", x, h / 2], ["L", anchorX, anchorY], ["L", x, h / 2], ["L", x, y + r]);
      }
    }
  } else if (
    // Replace bottom
    anchorY > h && anchorX < w - safeDistance
  ) {
    path.splice(5, 1, ["L", anchorX + halfDistance, y + h], ["L", anchorX, y + h + arrowLength], ["L", anchorX - halfDistance, y + h], ["L", x + r, y + h]);
  } else if (
    // Replace top
    anchorY < 0 && anchorX > safeDistance
  ) {
    path.splice(1, 1, ["L", anchorX - halfDistance, y], ["L", anchorX, y - arrowLength], ["L", anchorX + halfDistance, y], ["L", w - r, y]);
  }
  return path;
}
function circle(x, y, w, h) {
  return arc$1(x + w / 2, y + h / 2, w / 2, h / 2, {
    start: Math.PI * 0.5,
    end: Math.PI * 2.5,
    open: false
  });
}
function diamond(x, y, w, h) {
  return [
    ["M", x + w / 2, y],
    ["L", x + w, y + h / 2],
    ["L", x + w / 2, y + h],
    ["L", x, y + h / 2],
    ["Z"]
  ];
}
function rect(x, y, w, h, options2) {
  if (options2?.r) {
    return roundedRect$1(x, y, w, h, options2);
  }
  return [
    ["M", x, y],
    ["L", x + w, y],
    ["L", x + w, y + h],
    ["L", x, y + h],
    ["Z"]
  ];
}
function roundedRect$1(x, y, w, h, options2) {
  const r = options2?.r || 0;
  return [
    ["M", x + r, y],
    ["L", x + w - r, y],
    // Top side
    ["A", r, r, 0, 0, 1, x + w, y + r],
    // Top-right corner
    ["L", x + w, y + h - r],
    // Right side
    ["A", r, r, 0, 0, 1, x + w - r, y + h],
    // Bottom-right corner
    ["L", x + r, y + h],
    // Bottom side
    ["A", r, r, 0, 0, 1, x, y + h - r],
    // Bottom-left corner
    ["L", x, y + r],
    // Left side
    ["A", r, r, 0, 0, 1, x + r, y],
    ["Z"]
    // Top-left corner
  ];
}
function triangle(x, y, w, h) {
  return [
    ["M", x + w / 2, y],
    ["L", x + w, y + h],
    ["L", x, y + h],
    ["Z"]
  ];
}
function triangleDown(x, y, w, h) {
  return [
    ["M", x, y],
    ["L", x + w, y],
    ["L", x + w / 2, y + h],
    ["Z"]
  ];
}
const Symbols = {
  arc: arc$1,
  callout,
  circle,
  diamond,
  rect,
  roundedRect: roundedRect$1,
  square: rect,
  triangle,
  "triangle-down": triangleDown
};
const { doc: doc$q, SVG_NS: SVG_NS$2, win: win$b } = Highcharts;
const { attr: attr$c, extend: extend$1o, fireEvent: fireEvent$K, isString: isString$f, objectEach: objectEach$t, pick: pick$1L } = Utilities;
const stringWithEllipsis = (text, currentIndex) => text.substring(0, currentIndex) + "…";
class TextBuilder {
  constructor(svgElement) {
    const textStyles = svgElement.styles;
    this.renderer = svgElement.renderer;
    this.svgElement = svgElement;
    this.width = svgElement.textWidth;
    this.textLineHeight = textStyles?.lineHeight;
    this.textOutline = textStyles?.textOutline;
    this.ellipsis = Boolean(textStyles?.textOverflow === "ellipsis");
    this.lineClamp = textStyles?.lineClamp;
    this.noWrap = Boolean(textStyles?.whiteSpace === "nowrap");
  }
  /**
   * Build an SVG representation of the pseudo HTML given in the object's
   * svgElement.
   *
   * @private
   *
   * @return {void}.
   */
  buildSVG() {
    const wrapper = this.svgElement, textNode = wrapper.element, renderer = wrapper.renderer, textStr = pick$1L(wrapper.textStr, "").toString(), hasMarkup = textStr.indexOf("<") !== -1, childNodes = textNode.childNodes, tempParent = !wrapper.added && renderer.box, regexMatchBreaks = /<br.*?>/g, textCache = [
      textStr,
      this.ellipsis,
      this.noWrap,
      this.textLineHeight,
      this.textOutline,
      wrapper.getStyle("font-size"),
      wrapper.styles.lineClamp,
      this.width
    ].join(",");
    if (textCache === wrapper.textCache) {
      return;
    }
    wrapper.textCache = textCache;
    delete wrapper.actualWidth;
    for (let i = childNodes.length; i--; ) {
      textNode.removeChild(childNodes[i]);
    }
    if (!hasMarkup && !this.ellipsis && !this.width && !wrapper.textPath && (textStr.indexOf(" ") === -1 || this.noWrap && !regexMatchBreaks.test(textStr))) {
      textNode.appendChild(doc$q.createTextNode(this.unescapeEntities(textStr)));
    } else if (textStr !== "") {
      if (tempParent) {
        tempParent.appendChild(textNode);
      }
      const ast = new AST(textStr);
      this.modifyTree(ast.nodes);
      ast.addToDOM(textNode);
      this.modifyDOM();
      if (this.ellipsis && (textNode.textContent || "").indexOf("…") !== -1) {
        wrapper.attr(
          "title",
          this.unescapeEntities(wrapper.textStr || "", ["&lt;", "&gt;"])
          // #7179
        );
      }
      if (tempParent) {
        tempParent.removeChild(textNode);
      }
    }
    if (isString$f(this.textOutline) && wrapper.applyTextOutline) {
      wrapper.applyTextOutline(this.textOutline);
    }
  }
  /**
   * Modify the DOM of the generated SVG structure. This function only does
   * operations that cannot be done until the elements are attached to the
   * DOM, like doing layout based on rendered metrics of the added elements.
   *
   * @private
   *
   */
  modifyDOM() {
    const wrapper = this.svgElement;
    const x = attr$c(wrapper.element, "x");
    wrapper.firstLineMetrics = void 0;
    let firstChild;
    while (firstChild = wrapper.element.firstChild) {
      if (/^[\s\u200B]*$/.test(firstChild.textContent || " ")) {
        wrapper.element.removeChild(firstChild);
      } else {
        break;
      }
    }
    [].forEach.call(wrapper.element.querySelectorAll("tspan.highcharts-br"), (br, i) => {
      if (br.nextSibling && br.previousSibling) {
        if (i === 0 && br.previousSibling.nodeType === 1) {
          wrapper.firstLineMetrics = wrapper.renderer.fontMetrics(br.previousSibling);
        }
        attr$c(br, {
          // Since the break is inserted in front of the next
          // line, we need to use the next sibling for the line
          // height
          dy: this.getLineHeight(br.nextSibling),
          x
        });
      }
    });
    const width = this.width || 0;
    if (!width) {
      return;
    }
    const modifyTextNode = (textNode, parentElement) => {
      const text = textNode.textContent || "";
      const words = text.replace(/([^\^])-/g, "$1- ").split(" ");
      const hasWhiteSpace = !this.noWrap && (words.length > 1 || wrapper.element.childNodes.length > 1);
      const dy = this.getLineHeight(parentElement), ellipsisWidth = Math.max(
        0,
        // Subtract the font face to make room for
        // the ellipsis itself
        width - 0.8 * dy
      );
      let lineNo = 0;
      let startAt = wrapper.actualWidth;
      if (hasWhiteSpace) {
        const lines = [];
        const precedingSiblings = [];
        while (parentElement.firstChild && parentElement.firstChild !== textNode) {
          precedingSiblings.push(parentElement.firstChild);
          parentElement.removeChild(parentElement.firstChild);
        }
        while (words.length) {
          if (words.length && !this.noWrap && lineNo > 0) {
            lines.push(textNode.textContent || "");
            textNode.textContent = words.join(" ").replace(/- /g, "-");
          }
          this.truncate(
            textNode,
            void 0,
            words,
            lineNo === 0 ? startAt || 0 : 0,
            width,
            ellipsisWidth,
            // Build the text to test for
            (t, currentIndex) => words.slice(0, currentIndex).join(" ").replace(/- /g, "-")
          );
          startAt = wrapper.actualWidth;
          lineNo++;
          if (this.lineClamp && lineNo >= this.lineClamp) {
            if (words.length) {
              this.truncate(
                textNode,
                textNode.textContent || "",
                void 0,
                0,
                // Target width
                width,
                ellipsisWidth,
                stringWithEllipsis
              );
              textNode.textContent = textNode.textContent?.replace("…", "") + "…";
            }
            break;
          }
        }
        precedingSiblings.forEach((childNode) => {
          parentElement.insertBefore(childNode, textNode);
        });
        lines.forEach((line2) => {
          parentElement.insertBefore(doc$q.createTextNode(line2), textNode);
          const br = doc$q.createElementNS(SVG_NS$2, "tspan");
          br.textContent = "​";
          attr$c(br, { dy, x });
          parentElement.insertBefore(br, textNode);
        });
      } else if (this.ellipsis) {
        if (text) {
          this.truncate(
            textNode,
            text,
            void 0,
            0,
            // Target width
            width,
            ellipsisWidth,
            stringWithEllipsis
          );
        }
      }
    };
    const modifyChildren = ((node) => {
      const childNodes = [].slice.call(node.childNodes);
      childNodes.forEach((childNode) => {
        if (childNode.nodeType === win$b.Node.TEXT_NODE) {
          modifyTextNode(childNode, node);
        } else {
          if (childNode.className.baseVal.indexOf("highcharts-br") !== -1) {
            wrapper.actualWidth = 0;
          }
          modifyChildren(childNode);
        }
      });
    });
    modifyChildren(wrapper.element);
  }
  /**
   * Get the rendered line height of a <text>, <tspan> or pure text node.
   * @private
   * @param {DOMElementType|Text} node The node to check for
   * @return {number} The rendered line height
   */
  getLineHeight(node) {
    const element = node.nodeType === win$b.Node.TEXT_NODE ? node.parentElement : node;
    return this.textLineHeight ? parseInt(this.textLineHeight.toString(), 10) : this.renderer.fontMetrics(element || this.svgElement.element).h;
  }
  /**
   * Transform a pseudo HTML AST node tree into an SVG structure. We do as
   * much heavy lifting as we can here, before doing the final processing in
   * the modifyDOM function. The original data is mutated.
   *
   * @private
   *
   * @param {ASTNode[]} nodes The AST nodes
   *
   */
  modifyTree(nodes) {
    const modifyChild = (node, i) => {
      const { attributes = {}, children, style = {}, tagName } = node, styledMode = this.renderer.styledMode;
      if (tagName === "b" || tagName === "strong") {
        if (styledMode) {
          attributes["class"] = "highcharts-strong";
        } else {
          style.fontWeight = "bold";
        }
      } else if (tagName === "i" || tagName === "em") {
        if (styledMode) {
          attributes["class"] = "highcharts-emphasized";
        } else {
          style.fontStyle = "italic";
        }
      }
      if (style?.color) {
        style.fill = style.color;
      }
      if (tagName === "br") {
        attributes["class"] = "highcharts-br";
        node.textContent = "​";
        const nextNode = nodes[i + 1];
        if (nextNode?.textContent) {
          nextNode.textContent = nextNode.textContent.replace(/^ +/gm, "");
        }
      } else if (tagName === "a" && children && children.some((child) => child.tagName === "#text")) {
        node.children = [{ children, tagName: "tspan" }];
      }
      if (tagName !== "#text" && tagName !== "a") {
        node.tagName = "tspan";
      }
      extend$1o(node, { attributes, style });
      if (children) {
        children.filter((c) => c.tagName !== "#text").forEach(modifyChild);
      }
    };
    nodes.forEach(modifyChild);
    fireEvent$K(this.svgElement, "afterModifyTree", { nodes });
  }
  /*
   * Truncate the text node contents to a given length. Used when the css
   * width is set. If the `textOverflow` is `ellipsis`, the text is truncated
   * character by character to the given length. If not, the text is
   * word-wrapped line by line.
   */
  truncate(textNode, text, words, startAt, width, ellipsisWidth, getString) {
    const svgElement = this.svgElement;
    const { rotation } = svgElement;
    const lengths = [];
    let minIndex = words && !startAt ? 1 : 0;
    let maxIndex = (text || words || "").length;
    let currentIndex = maxIndex;
    let str;
    let actualWidth;
    if (!words) {
      width = ellipsisWidth;
    }
    const getSubStringLength = function(charEnd, concatenatedEnd) {
      const end = concatenatedEnd || charEnd;
      const parentNode = textNode.parentNode;
      if (parentNode && typeof lengths[end] === "undefined") {
        if (parentNode.getSubStringLength) {
          try {
            lengths[end] = startAt + parentNode.getSubStringLength(0, words ? end + 1 : end);
          } catch (e) {
          }
        }
      }
      return lengths[end];
    };
    svgElement.rotation = 0;
    actualWidth = getSubStringLength(textNode.textContent.length);
    if (startAt + actualWidth > width) {
      while (minIndex <= maxIndex) {
        currentIndex = Math.ceil((minIndex + maxIndex) / 2);
        if (words) {
          str = getString(words, currentIndex);
        }
        actualWidth = getSubStringLength(currentIndex, str && str.length - 1);
        if (minIndex === maxIndex) {
          minIndex = maxIndex + 1;
        } else if (actualWidth > width) {
          maxIndex = currentIndex - 1;
        } else {
          minIndex = currentIndex;
        }
      }
      if (maxIndex === 0) {
        textNode.textContent = "";
      } else if (!(text && maxIndex === text.length - 1)) {
        textNode.textContent = str || getString(text || words, currentIndex);
      }
      if (this.ellipsis && actualWidth > width) {
        this.truncate(textNode, textNode.textContent || "", void 0, 0, width, ellipsisWidth, stringWithEllipsis);
      }
    }
    if (words) {
      words.splice(0, currentIndex);
    }
    svgElement.actualWidth = actualWidth;
    svgElement.rotation = rotation;
  }
  /*
   * Un-escape HTML entities based on the public `renderer.escapes` list
   *
   * @private
   *
   * @param {string} inputStr The string to unescape
   * @param {Array<string>} [except] Exceptions
   *
   * @return {string} The processed string
   */
  unescapeEntities(inputStr, except) {
    objectEach$t(this.renderer.escapes, function(value, key2) {
      if (!except || except.indexOf(value) === -1) {
        inputStr = inputStr.toString().replace(new RegExp(value, "g"), key2);
      }
    });
    return inputStr;
  }
}
const { defaultOptions: defaultOptions$l } = DefaultOptions;
const { charts: charts$3, deg2rad: deg2rad$9, doc: doc$p, isFirefox: isFirefox$2, isMS: isMS$1, isWebKit, noop: noop$j, SVG_NS: SVG_NS$1, symbolSizes, win: win$a } = Highcharts;
const { addEvent: addEvent$1u, attr: attr$b, createElement: createElement$b, crisp: crisp$e, css: css$d, defined: defined$19, destroyObjectProperties: destroyObjectProperties$a, extend: extend$1n, isArray: isArray$o, isNumber: isNumber$14, isObject: isObject$k, isString: isString$e, merge: merge$1D, pick: pick$1K, pInt: pInt$5, replaceNested: replaceNested$1, uniqueKey: uniqueKey$8 } = Utilities;
let hasInternalReferenceBug;
class SVGRenderer {
  /**
   * The root `svg` node of the renderer.
   *
   * @name Highcharts.SVGRenderer#box
   * @type {Highcharts.SVGDOMElement}
   */
  /**
   * The wrapper for the root `svg` node of the renderer.
   *
   * @name Highcharts.SVGRenderer#boxWrapper
   * @type {Highcharts.SVGElement}
   */
  /**
   * A pointer to the `defs` node of the root SVG.
   *
   * @name Highcharts.SVGRenderer#defs
   * @type {Highcharts.SVGElement}
   */
  /**
   * Whether the rendered content is intended for export.
   *
   * @name Highcharts.SVGRenderer#forExport
   * @type {boolean | undefined}
   */
  /**
   * Page url used for internal references.
   *
   * @private
   * @name Highcharts.SVGRenderer#url
   * @type {string}
   */
  /**
   * Initialize the SVGRenderer. Overridable initializer function that takes
   * the same parameters as the constructor.
   *
   * @function Highcharts.SVGRenderer#init
   *
   * @param {Highcharts.HTMLDOMElement} container
   * Where to put the SVG in the web page.
   *
   * @param {number} width
   * The width of the SVG.
   *
   * @param {number} height
   * The height of the SVG.
   *
   * @param {Highcharts.CSSObject} [style]
   * The box style, if not in styleMode
   *
   * @param {boolean} [forExport=false]
   * Whether the rendered content is intended for export.
   *
   * @param {boolean} [allowHTML=true]
   * Whether the renderer is allowed to include HTML text, which will be
   * projected on top of the SVG.
   *
   * @param {boolean} [styledMode=false]
   * Whether the renderer belongs to a chart that is in styled mode. If it
   * does, it will avoid setting presentational attributes in some cases, but
   * not when set explicitly through `.attr` and `.css` etc.
   */
  constructor(container, width, height, style, forExport, allowHTML, styledMode) {
    this.x = 0;
    this.y = 0;
    const renderer = this, boxWrapper = renderer.createElement("svg").attr({
      version: "1.1",
      "class": "highcharts-root"
    }), element = boxWrapper.element;
    if (!styledMode) {
      boxWrapper.css(this.getStyle(style || {}));
    }
    container.appendChild(element);
    attr$b(container, "dir", "ltr");
    if (container.innerHTML.indexOf("xmlns") === -1) {
      attr$b(element, "xmlns", this.SVG_NS);
    }
    this.box = element;
    this.boxWrapper = boxWrapper;
    this.alignedObjects = [];
    this.url = this.getReferenceURL();
    const desc = this.createElement("desc").add();
    desc.element.appendChild(doc$p.createTextNode("Created with Highcharts 12.2.0"));
    this.defs = this.createElement("defs").add();
    this.allowHTML = allowHTML;
    this.forExport = forExport;
    this.styledMode = styledMode;
    this.gradients = {};
    this.cache = {};
    this.cacheKeys = [];
    this.imgCount = 0;
    this.rootFontSize = boxWrapper.getStyle("font-size");
    renderer.setSize(width, height, false);
    let subPixelFix, rect2;
    if (isFirefox$2 && container.getBoundingClientRect) {
      subPixelFix = function() {
        css$d(container, { left: 0, top: 0 });
        rect2 = container.getBoundingClientRect();
        css$d(container, {
          left: Math.ceil(rect2.left) - rect2.left + "px",
          top: Math.ceil(rect2.top) - rect2.top + "px"
        });
      };
      subPixelFix();
      renderer.unSubPixelFix = addEvent$1u(win$a, "resize", subPixelFix);
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * General method for adding a definition to the SVG `defs` tag. Can be used
   * for gradients, fills, filters etc. Styled mode only. A hook for adding
   * general definitions to the SVG's defs tag. Definitions can be referenced
   * from the CSS by its `id`. Read more in
   * [gradients, shadows and patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns).
   * Styled mode only.
   *
   * @function Highcharts.SVGRenderer#definition
   *
   * @param {Highcharts.ASTNode} def
   * A serialized form of an SVG definition, including children.
   *
   * @return {Highcharts.SVGElement}
   * The inserted node.
   */
  definition(def) {
    const ast = new AST([def]);
    return ast.addToDOM(this.defs.element);
  }
  /**
   * Get the prefix needed for internal URL references to work in certain
   * cases. Some older browser versions had a bug where internal url
   * references in SVG attributes, on the form `url(#some-id)`, would fail if
   * a base tag was present in the page. There were also issues with
   * `history.pushState` related to this prefix.
   *
   * Related issues: #24, #672, #1070, #5244.
   *
   * The affected browsers are:
   * - Chrome <= 53 (May 2018)
   * - Firefox <= 51 (January 2017)
   * - Safari/Mac <= 12.1 (2018 or 2019)
   * - Safari/iOS <= 13
   *
   * @todo Remove this hack when time has passed. All the affected browsers
   * are evergreens, so it is increasingly unlikely that users are affected by
   * the bug.
   *
   * @return {string}
   * The prefix to use. An empty string for modern browsers.
   */
  getReferenceURL() {
    if ((isFirefox$2 || isWebKit) && doc$p.getElementsByTagName("base").length) {
      if (!defined$19(hasInternalReferenceBug)) {
        const id = uniqueKey$8();
        const ast = new AST([{
          tagName: "svg",
          attributes: {
            width: 8,
            height: 8
          },
          children: [{
            tagName: "defs",
            children: [{
              tagName: "clipPath",
              attributes: {
                id
              },
              children: [{
                tagName: "rect",
                attributes: {
                  width: 4,
                  height: 4
                }
              }]
            }]
          }, {
            tagName: "rect",
            attributes: {
              id: "hitme",
              width: 8,
              height: 8,
              "clip-path": `url(#${id})`,
              fill: "rgba(0,0,0,0.001)"
            }
          }]
        }]);
        const svg2 = ast.addToDOM(doc$p.body);
        css$d(svg2, {
          position: "fixed",
          top: 0,
          left: 0,
          zIndex: 9e5
        });
        const hitElement = doc$p.elementFromPoint(6, 6);
        hasInternalReferenceBug = hitElement?.id === "hitme";
        doc$p.body.removeChild(svg2);
      }
      if (hasInternalReferenceBug) {
        return replaceNested$1(
          win$a.location.href.split("#")[0],
          // Remove hash
          [/<[^>]*>/g, ""],
          // Wing cut HTML
          [/([\('\)])/g, "\\$1"],
          // Escape parantheses and quotes
          [/ /g, "%20"]
          // Replace spaces (needed for Safari only)
        );
      }
    }
    return "";
  }
  /**
   * Get the global style setting for the renderer.
   *
   * @private
   * @function Highcharts.SVGRenderer#getStyle
   *
   * @param {Highcharts.CSSObject} style
   * Style settings.
   *
   * @return {Highcharts.CSSObject}
   * The style settings mixed with defaults.
   */
  getStyle(style) {
    this.style = extend$1n({
      fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif',
      fontSize: "1rem"
    }, style);
    return this.style;
  }
  /**
   * Apply the global style on the renderer, mixed with the default styles.
   *
   * @function Highcharts.SVGRenderer#setStyle
   *
   * @param {Highcharts.CSSObject} style
   * CSS to apply.
   */
  setStyle(style) {
    this.boxWrapper.css(this.getStyle(style));
  }
  /**
   * Detect whether the renderer is hidden. This happens when one of the
   * parent elements has `display: none`. Used internally to detect when we
   * need to render preliminarily in another div to get the text bounding
   * boxes right.
   *
   * @function Highcharts.SVGRenderer#isHidden
   *
   * @return {boolean}
   * True if it is hidden.
   */
  isHidden() {
    return !this.boxWrapper.getBBox().width;
  }
  /**
   * Destroys the renderer and its allocated members.
   *
   * @function Highcharts.SVGRenderer#destroy
   *
   * @return {null}
   * Pass through value.
   */
  destroy() {
    const renderer = this, rendererDefs = renderer.defs;
    renderer.box = null;
    renderer.boxWrapper = renderer.boxWrapper.destroy();
    destroyObjectProperties$a(renderer.gradients || {});
    renderer.gradients = null;
    renderer.defs = rendererDefs.destroy();
    if (renderer.unSubPixelFix) {
      renderer.unSubPixelFix();
    }
    renderer.alignedObjects = null;
    return null;
  }
  /**
   * Create a wrapper for an SVG element. Serves as a factory for
   * {@link SVGElement}, but this function is itself mostly called from
   * primitive factories like {@link SVGRenderer#path}, {@link
   * SVGRenderer#rect} or {@link SVGRenderer#text}.
   *
   * @function Highcharts.SVGRenderer#createElement
   *
   * @param {string} nodeName
   * The node name, for example `rect`, `g` etc.
   *
   * @return {Highcharts.SVGElement}
   * The generated SVGElement.
   */
  createElement(nodeName) {
    return new this.Element(this, nodeName);
  }
  /**
   * Get converted radial gradient attributes according to the radial
   * reference. Used internally from the {@link SVGElement#colorGradient}
   * function.
   *
   * @private
   * @function Highcharts.SVGRenderer#getRadialAttr
   */
  getRadialAttr(radialReference, gradAttr) {
    return {
      cx: radialReference[0] - radialReference[2] / 2 + (gradAttr.cx || 0) * radialReference[2],
      cy: radialReference[1] - radialReference[2] / 2 + (gradAttr.cy || 0) * radialReference[2],
      r: (gradAttr.r || 0) * radialReference[2]
    };
  }
  /**
   * Create a drop shadow definition and return its id
   *
   * @private
   * @function Highcharts.SVGRenderer#shadowDefinition
   *
   * @param {boolean|Highcharts.ShadowOptionsObject} [shadowOptions] The
   *        shadow options. If `true`, the default options are applied
   */
  shadowDefinition(shadowOptions) {
    const id = [
      `highcharts-drop-shadow-${this.chartIndex}`,
      ...Object.keys(shadowOptions).map((key2) => `${key2}-${shadowOptions[key2]}`)
    ].join("-").toLowerCase().replace(/[^a-z\d\-]/g, ""), options2 = merge$1D({
      color: "#000000",
      offsetX: 1,
      offsetY: 1,
      opacity: 0.15,
      width: 5
    }, shadowOptions);
    if (!this.defs.element.querySelector(`#${id}`)) {
      this.definition({
        tagName: "filter",
        attributes: {
          id,
          filterUnits: options2.filterUnits
        },
        children: this.getShadowFilterContent(options2)
      });
    }
    return id;
  }
  /**
   * Get shadow filter content.
   * NOTE! Overridden in es5 module for IE11 compatibility.
   *
   * @private
   * @function Highcharts.SVGRenderer#getShadowFilterContent
   *
   * @param {ShadowOptionsObject} options
   * The shadow options.
   * @return {Array<AST.Node>}
   * The shadow filter content.
   */
  getShadowFilterContent(options2) {
    return [{
      tagName: "feDropShadow",
      attributes: {
        dx: options2.offsetX,
        dy: options2.offsetY,
        "flood-color": options2.color,
        // Tuned and modified to keep a preserve compatibility
        // with the old settings
        "flood-opacity": Math.min(options2.opacity * 5, 1),
        stdDeviation: options2.width / 2
      }
    }];
  }
  /**
   * Parse a simple HTML string into SVG tspans. Called internally when text
   * is set on an SVGElement. The function supports a subset of HTML tags, CSS
   * text features like `width`, `text-overflow`, `white-space`, and also
   * attributes like `href` and `style`.
   *
   * @private
   * @function Highcharts.SVGRenderer#buildText
   *
   * @param {Highcharts.SVGElement} wrapper
   * The parent SVGElement.
   */
  buildText(wrapper) {
    new TextBuilder(wrapper).buildSVG();
  }
  /**
   * Returns white for dark colors and black for bright colors, based on W3C's
   * definition of [Relative luminance](
   * https://www.w3.org/WAI/GL/wiki/Relative_luminance).
   *
   * @function Highcharts.SVGRenderer#getContrast
   *
   * @param {Highcharts.ColorString} color
   * The color to get the contrast for.
   *
   * @return {Highcharts.ColorString}
   * The contrast color, either `#000000` or `#FFFFFF`.
   */
  getContrast(color2) {
    const rgba256 = Color.parse(color2).rgba, channelFunc = " clamp(0,calc(9e9*(0.5 - (0.2126*r + 0.7152*g + 0.0722*b))),1)";
    if (isNumber$14(rgba256[0]) || !Color.useColorMix) {
      const rgba = rgba256.map((b8) => {
        const c = b8 / 255;
        return c <= 0.04 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
      }), l = 0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2];
      return 1.05 / (l + 0.05) > (l + 0.05) / 0.05 ? "#FFFFFF" : "#000000";
    }
    return "color(from " + color2 + " srgb" + channelFunc + channelFunc + channelFunc + ")";
  }
  /**
   * Create a button with preset states. Styles for the button can either be
   * set as arguments, or a general theme for all buttons can be set by the
   * `global.buttonTheme` option.
   *
   * @function Highcharts.SVGRenderer#button
   *
   * @param {string} text
   * The text or HTML to draw.
   *
   * @param {number} x
   * The x position of the button's left side.
   *
   * @param {number} y
   * The y position of the button's top side.
   *
   * @param {Highcharts.EventCallbackFunction<Highcharts.SVGElement>} callback
   * The function to execute on button click or touch.
   *
   * @param {Highcharts.SVGAttributes} [theme]
   * SVG attributes for the normal state.
   *
   * @param {Highcharts.SVGAttributes} [hoverState]
   * SVG attributes for the hover state.
   *
   * @param {Highcharts.SVGAttributes} [selectState]
   * SVG attributes for the pressed state.
   *
   * @param {Highcharts.SVGAttributes} [disabledState]
   * SVG attributes for the disabled state.
   *
   * @param {Highcharts.SymbolKeyValue} [shape=rect]
   * The shape type.
   *
   * @param {boolean} [useHTML=false]
   * Whether to use HTML to render the label.
   *
   * @return {Highcharts.SVGElement}
   * The button element.
   */
  button(text, x, y, callback, theme2 = {}, hoverState, selectState, disabledState, shape, useHTML) {
    const label = this.label(text, x, y, shape, void 0, void 0, useHTML, void 0, "button"), styledMode = this.styledMode, args = arguments;
    let curState = 0;
    theme2 = merge$1D(defaultOptions$l.global.buttonTheme, theme2);
    if (styledMode) {
      delete theme2.fill;
      delete theme2.stroke;
      delete theme2["stroke-width"];
    }
    const states2 = theme2.states || {}, normalStyle = theme2.style || {};
    delete theme2.states;
    delete theme2.style;
    const stateAttribs = [
      AST.filterUserAttributes(theme2)
    ], stateStyles = [normalStyle];
    if (!styledMode) {
      ["hover", "select", "disabled"].forEach((stateName, i) => {
        stateAttribs.push(merge$1D(stateAttribs[0], AST.filterUserAttributes(args[i + 5] || states2[stateName] || {})));
        stateStyles.push(stateAttribs[i + 1].style);
        delete stateAttribs[i + 1].style;
      });
    }
    addEvent$1u(label.element, isMS$1 ? "mouseover" : "mouseenter", function() {
      if (curState !== 3) {
        label.setState(1);
      }
    });
    addEvent$1u(label.element, isMS$1 ? "mouseout" : "mouseleave", function() {
      if (curState !== 3) {
        label.setState(curState);
      }
    });
    label.setState = (state = 0) => {
      if (state !== 1) {
        label.state = curState = state;
      }
      label.removeClass(/highcharts-button-(normal|hover|pressed|disabled)/).addClass("highcharts-button-" + ["normal", "hover", "pressed", "disabled"][state]);
      if (!styledMode) {
        label.attr(stateAttribs[state]);
        const css2 = stateStyles[state];
        if (isObject$k(css2)) {
          label.css(css2);
        }
      }
    };
    label.attr(stateAttribs[0]);
    if (!styledMode) {
      label.css(extend$1n({ cursor: "default" }, normalStyle));
      if (useHTML) {
        label.text.css({ pointerEvents: "none" });
      }
    }
    return label.on("touchstart", (e) => e.stopPropagation()).on("click", function(e) {
      if (curState !== 3) {
        callback?.call(label, e);
      }
    });
  }
  /**
   * Make a straight line crisper by not spilling out to neighbour pixels.
   *
   * @function Highcharts.SVGRenderer#crispLine
   *
   * @param {Highcharts.SVGPathArray} points
   *        The original points on the format `[['M', 0, 0], ['L', 100, 0]]`.
   *
   * @param {number} width
   *        The width of the line.
   *
   * @return {Highcharts.SVGPathArray}
   *         The original points array, but modified to render crisply.
   */
  crispLine(points, width) {
    const [start2, end] = points;
    if (defined$19(start2[1]) && start2[1] === end[1]) {
      start2[1] = end[1] = crisp$e(start2[1], width);
    }
    if (defined$19(start2[2]) && start2[2] === end[2]) {
      start2[2] = end[2] = crisp$e(start2[2], width);
    }
    return points;
  }
  /**
   * Draw a path, wraps the SVG `path` element.
   *
   * @sample highcharts/members/renderer-path-on-chart/
   *         Draw a path in a chart
   * @sample highcharts/members/renderer-path/
   *         Draw a path independent from a chart
   *
   * @example
   * let path = renderer.path(['M', 10, 10, 'L', 30, 30, 'z'])
   *     .attr({ stroke: '#ff00ff' })
   *     .add();
   *
   * @function Highcharts.SVGRenderer#path
   *
   * @param {Highcharts.SVGPathArray} [path]
   * An SVG path definition in array form.
   *
   * @return {Highcharts.SVGElement}
   * The generated wrapper element.
   *
   */
  /**
  * Draw a path, wraps the SVG `path` element.
  *
  * @function Highcharts.SVGRenderer#path
  *
  * @param {Highcharts.SVGAttributes} [attribs]
  * The initial attributes.
  *
  * @return {Highcharts.SVGElement}
  * The generated wrapper element.
  */
  path(path) {
    const attribs = this.styledMode ? {} : {
      fill: "none"
    };
    if (isArray$o(path)) {
      attribs.d = path;
    } else if (isObject$k(path)) {
      extend$1n(attribs, path);
    }
    return this.createElement("path").attr(attribs);
  }
  /**
   * Draw a circle, wraps the SVG `circle` element.
   *
   * @sample highcharts/members/renderer-circle/
   *         Drawing a circle
   *
   * @function Highcharts.SVGRenderer#circle
   *
   * @param {number} [x]
   * The center x position.
   *
   * @param {number} [y]
   * The center y position.
   *
   * @param {number} [r]
   * The radius.
   *
   * @return {Highcharts.SVGElement}
   * The generated wrapper element.
   */
  /**
  * Draw a circle, wraps the SVG `circle` element.
  *
  * @function Highcharts.SVGRenderer#circle
  *
  * @param {Highcharts.SVGAttributes} [attribs]
  * The initial attributes.
  *
  * @return {Highcharts.SVGElement}
  * The generated wrapper element.
  */
  circle(x, y, r) {
    const attribs = isObject$k(x) ? x : typeof x === "undefined" ? {} : { x, y, r }, wrapper = this.createElement("circle");
    wrapper.xSetter = wrapper.ySetter = function(value, key2, element) {
      element.setAttribute("c" + key2, value);
    };
    return wrapper.attr(attribs);
  }
  /**
   * Draw and return an arc.
   *
   * @sample highcharts/members/renderer-arc/
   *         Drawing an arc
   *
   * @function Highcharts.SVGRenderer#arc
   *
   * @param {number} [x=0]
   * Center X position.
   *
   * @param {number} [y=0]
   * Center Y position.
   *
   * @param {number} [r=0]
   * The outer radius' of the arc.
   *
   * @param {number} [innerR=0]
   * Inner radius like used in donut charts.
   *
   * @param {number} [start=0]
   * The starting angle of the arc in radians, where 0 is to the right and
   * `-Math.PI/2` is up.
   *
   * @param {number} [end=0]
   * The ending angle of the arc in radians, where 0 is to the right and
   * `-Math.PI/2` is up.
   *
   * @return {Highcharts.SVGElement}
   * The generated wrapper element.
   */
  /**
  * Draw and return an arc. Overloaded function that takes arguments object.
  *
  * @function Highcharts.SVGRenderer#arc
  *
  * @param {Highcharts.SVGAttributes} attribs
  * Initial SVG attributes.
  *
  * @return {Highcharts.SVGElement}
  * The generated wrapper element.
  */
  arc(x, y, r, innerR, start2, end) {
    let options2;
    if (isObject$k(x)) {
      options2 = x;
      y = options2.y;
      r = options2.r;
      innerR = options2.innerR;
      start2 = options2.start;
      end = options2.end;
      x = options2.x;
    } else {
      options2 = { innerR, start: start2, end };
    }
    const arc2 = this.symbol("arc", x, y, r, r, options2);
    arc2.r = r;
    return arc2;
  }
  /**
   * Draw and return a rectangle.
   *
   * @function Highcharts.SVGRenderer#rect
   *
   * @param {number} [x]
   * Left position.
   *
   * @param {number} [y]
   * Top position.
   *
   * @param {number} [width]
   * Width of the rectangle.
   *
   * @param {number} [height]
   * Height of the rectangle.
   *
   * @param {number} [r]
   * Border corner radius.
   *
   * @param {number} [strokeWidth]
   * A stroke width can be supplied to allow crisp drawing.
   *
   * @return {Highcharts.SVGElement}
   * The generated wrapper element.
   */
  /**
  * Draw and return a rectangle.
  *
  * @sample highcharts/members/renderer-rect-on-chart/
  *         Draw a rectangle in a chart
  * @sample highcharts/members/renderer-rect/
  *         Draw a rectangle independent from a chart
  *
  * @function Highcharts.SVGRenderer#rect
  *
  * @param {Highcharts.SVGAttributes} [attributes]
  * General SVG attributes for the rectangle.
  *
  * @return {Highcharts.SVGElement}
  * The generated wrapper element.
  */
  rect(x, y, width, height, r, strokeWidth) {
    const attribs = isObject$k(x) ? x : typeof x === "undefined" ? {} : {
      x,
      y,
      r,
      width: Math.max(width || 0, 0),
      height: Math.max(height || 0, 0)
    }, wrapper = this.createElement("rect");
    if (!this.styledMode) {
      if (typeof strokeWidth !== "undefined") {
        attribs["stroke-width"] = strokeWidth;
        extend$1n(attribs, wrapper.crisp(attribs));
      }
      attribs.fill = "none";
    }
    wrapper.rSetter = function(value, _key, element) {
      wrapper.r = value;
      attr$b(element, {
        rx: value,
        ry: value
      });
    };
    wrapper.rGetter = function() {
      return wrapper.r || 0;
    };
    return wrapper.attr(attribs);
  }
  /**
   * Draw and return a rectangle with advanced corner rounding options.
   *
   * @function Highcharts.SVGRenderer#roundedRect
   *
   * @param {Highcharts.SVGAttributes} attribs
   *      Attributes
   * @return {Highcharts.SVGElement}
   * The generated wrapper element.
   */
  roundedRect(attribs) {
    return this.symbol("roundedRect").attr(attribs);
  }
  /**
   * Resize the {@link SVGRenderer#box} and re-align all aligned child
   * elements.
   *
   * @sample highcharts/members/renderer-g/
   *         Show and hide grouped objects
   *
   * @function Highcharts.SVGRenderer#setSize
   *
   * @param {number} width
   * The new pixel width.
   *
   * @param {number} height
   * The new pixel height.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animate=true]
   * Whether and how to animate.
   */
  setSize(width, height, animate2) {
    const renderer = this;
    renderer.width = width;
    renderer.height = height;
    renderer.boxWrapper.animate({
      width,
      height
    }, {
      step: function() {
        this.attr({
          viewBox: "0 0 " + this.attr("width") + " " + this.attr("height")
        });
      },
      duration: pick$1K(animate2, true) ? void 0 : 0
    });
    renderer.alignElements();
  }
  /**
   * Create and return an svg group element. Child
   * {@link Highcharts.SVGElement} objects are added to the group by using the
   * group as the first parameter in {@link Highcharts.SVGElement#add|add()}.
   *
   * @function Highcharts.SVGRenderer#g
   *
   * @param {string} [name]
   *        The group will be given a class name of `highcharts-{name}`. This
   *        can be used for styling and scripting.
   *
   * @return {Highcharts.SVGElement}
   *         The generated wrapper element.
   */
  g(name) {
    const elem = this.createElement("g");
    return name ? elem.attr({ "class": "highcharts-" + name }) : elem;
  }
  /**
   * Display an image.
   *
   * @sample highcharts/members/renderer-image-on-chart/
   *         Add an image in a chart
   * @sample highcharts/members/renderer-image/
   *         Add an image independent of a chart
   *
   * @function Highcharts.SVGRenderer#image
   *
   * @param {string} href
   *        The image source.
   *
   * @param {number} [x]
   *        The X position.
   *
   * @param {number} [y]
   *        The Y position.
   *
   * @param {number} [width]
   *        The image width. If omitted, it defaults to the image file width.
   *
   * @param {number} [height]
   *        The image height. If omitted it defaults to the image file
   *        height.
   *
   * @param {Function} [onload]
   *        Event handler for image load.
   *
   * @return {Highcharts.SVGElement}
   *         The generated wrapper element.
   */
  image(href, x, y, width, height, onload) {
    const attribs = { preserveAspectRatio: "none" };
    if (isNumber$14(x)) {
      attribs.x = x;
    }
    if (isNumber$14(y)) {
      attribs.y = y;
    }
    if (isNumber$14(width)) {
      attribs.width = width;
    }
    if (isNumber$14(height)) {
      attribs.height = height;
    }
    const elemWrapper = this.createElement("image").attr(attribs), onDummyLoad = function(e) {
      elemWrapper.attr({ href });
      onload.call(elemWrapper, e);
    };
    if (onload) {
      elemWrapper.attr({
        /* eslint-disable-next-line max-len */
        href: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
      });
      const dummy = new win$a.Image();
      addEvent$1u(dummy, "load", onDummyLoad);
      dummy.src = href;
      if (dummy.complete) {
        onDummyLoad({});
      }
    } else {
      elemWrapper.attr({ href });
    }
    return elemWrapper;
  }
  /**
   * Draw a symbol out of pre-defined shape paths from
   * {@link SVGRenderer#symbols}.
   * It is used in Highcharts for point makers, which cake a `symbol` option,
   * and label and button backgrounds like in the tooltip and stock flags.
   *
   * @function Highcharts.SVGRenderer#symbol
   *
   * @param {string} symbol
   * The symbol name.
   *
   * @param {number} [x]
   * The X coordinate for the top left position.
   *
   * @param {number} [y]
   * The Y coordinate for the top left position.
   *
   * @param {number} [width]
   * The pixel width.
   *
   * @param {number} [height]
   * The pixel height.
   *
   * @param {Highcharts.SymbolOptionsObject} [options]
   * Additional options, depending on the actual symbol drawn.
   *
   * @return {Highcharts.SVGElement}
   * SVG symbol.
   */
  symbol(symbol, x, y, width, height, options2) {
    const ren = this, imageRegex = /^url\((.*?)\)$/, isImage = imageRegex.test(symbol), sym = !isImage && (this.symbols[symbol] ? symbol : "circle"), symbolFn = sym && this.symbols[sym];
    let obj, path, imageSrc, centerImage;
    if (symbolFn) {
      if (typeof x === "number") {
        path = symbolFn.call(this.symbols, x || 0, y || 0, width || 0, height || 0, options2);
      }
      obj = this.path(path);
      if (!ren.styledMode) {
        obj.attr("fill", "none");
      }
      extend$1n(obj, {
        symbolName: sym || void 0,
        x,
        y,
        width,
        height
      });
      if (options2) {
        extend$1n(obj, options2);
      }
    } else if (isImage) {
      imageSrc = symbol.match(imageRegex)[1];
      const img = obj = this.image(imageSrc);
      img.imgwidth = pick$1K(options2?.width, symbolSizes[imageSrc]?.width);
      img.imgheight = pick$1K(options2?.height, symbolSizes[imageSrc]?.height);
      centerImage = (obj2) => obj2.attr({
        width: obj2.width,
        height: obj2.height
      });
      ["width", "height"].forEach((key2) => {
        img[`${key2}Setter`] = function(value, key3) {
          this[key3] = value;
          const { alignByTranslate, element, width: width2, height: height2, imgwidth, imgheight } = this, imgSize = key3 === "width" ? imgwidth : imgheight;
          let scale2 = 1;
          if (options2 && options2.backgroundSize === "within" && width2 && height2 && imgwidth && imgheight) {
            scale2 = Math.min(width2 / imgwidth, height2 / imgheight);
            attr$b(element, {
              width: Math.round(imgwidth * scale2),
              height: Math.round(imgheight * scale2)
            });
          } else if (element && imgSize) {
            element.setAttribute(key3, imgSize);
          }
          if (!alignByTranslate && imgwidth && imgheight) {
            this.translate(((width2 || 0) - imgwidth * scale2) / 2, ((height2 || 0) - imgheight * scale2) / 2);
          }
        };
      });
      if (defined$19(x)) {
        img.attr({
          x,
          y
        });
      }
      img.isImg = true;
      img.symbolUrl = symbol;
      if (defined$19(img.imgwidth) && defined$19(img.imgheight)) {
        centerImage(img);
      } else {
        img.attr({ width: 0, height: 0 });
        createElement$b("img", {
          onload: function() {
            const chart = charts$3[ren.chartIndex];
            if (this.width === 0) {
              css$d(this, {
                position: "absolute",
                top: "-999em"
              });
              doc$p.body.appendChild(this);
            }
            symbolSizes[imageSrc] = {
              width: this.width,
              height: this.height
            };
            img.imgwidth = this.width;
            img.imgheight = this.height;
            if (img.element) {
              centerImage(img);
            }
            if (this.parentNode) {
              this.parentNode.removeChild(this);
            }
            ren.imgCount--;
            if (!ren.imgCount && chart && !chart.hasLoaded) {
              chart.onload();
            }
          },
          src: imageSrc
        });
        this.imgCount++;
      }
    }
    return obj;
  }
  /**
   * Define a clipping rectangle. The clipping rectangle is later applied
   * to {@link SVGElement} objects through the {@link SVGElement#clip}
   * function.
   *
   * This function is deprecated as of v11.2. Instead, use a regular shape
   * (`rect`, `path` etc), and the `SVGElement.clipTo` function.
   *
   * @example
   * let circle = renderer.circle(100, 100, 100)
   *     .attr({ fill: 'red' })
   *     .add();
   * let clipRect = renderer.clipRect(100, 100, 100, 100);
   *
   * // Leave only the lower right quarter visible
   * circle.clip(clipRect);
   *
   * @deprecated
   *
   * @function Highcharts.SVGRenderer#clipRect
   *
   * @param {number} [x]
   *
   * @param {number} [y]
   *
   * @param {number} [width]
   *
   * @param {number} [height]
   *
   * @return {Highcharts.ClipRectElement}
   *         A clipping rectangle.
   */
  clipRect(x, y, width, height) {
    return this.rect(x, y, width, height, 0);
  }
  /**
   * Draw text. The text can contain a subset of HTML, like spans and anchors
   * and some basic text styling of these. For more advanced features like
   * border and background, use {@link Highcharts.SVGRenderer#label} instead.
   * To update the text after render, run `text.attr({ text: 'New text' })`.
   *
   * @sample highcharts/members/renderer-text-on-chart/
   *         Annotate the chart freely
   * @sample highcharts/members/renderer-on-chart/
   *         Annotate with a border and in response to the data
   * @sample highcharts/members/renderer-text/
   *         Formatted text
   *
   * @function Highcharts.SVGRenderer#text
   *
   * @param {string} [str]
   * The text of (subset) HTML to draw.
   *
   * @param {number} [x]
   * The x position of the text's lower left corner.
   *
   * @param {number} [y]
   * The y position of the text's lower left corner.
   *
   * @param {boolean} [useHTML=false]
   * Use HTML to render the text.
   *
   * @return {Highcharts.SVGElement}
   * The text object.
   */
  text(str, x, y, useHTML) {
    const renderer = this, attribs = {};
    if (useHTML && (renderer.allowHTML || !renderer.forExport)) {
      return renderer.html(str, x, y);
    }
    attribs.x = Math.round(x || 0);
    if (y) {
      attribs.y = Math.round(y);
    }
    if (defined$19(str)) {
      attribs.text = str;
    }
    const wrapper = renderer.createElement("text").attr(attribs);
    if (!useHTML || renderer.forExport && !renderer.allowHTML) {
      wrapper.xSetter = function(value, key2, element) {
        const tspans = element.getElementsByTagName("tspan"), parentVal = element.getAttribute(key2);
        for (let i = 0, tspan; i < tspans.length; i++) {
          tspan = tspans[i];
          if (tspan.getAttribute(key2) === parentVal) {
            tspan.setAttribute(key2, value);
          }
        }
        element.setAttribute(key2, value);
      };
    }
    return wrapper;
  }
  /**
   * Utility to return the baseline offset and total line height from the font
   * size.
   *
   * @function Highcharts.SVGRenderer#fontMetrics
   *
   * @param {Highcharts.SVGElement|Highcharts.SVGDOMElement|number} [element]
   *        The element to inspect for a current font size. If a number is
   *        given, it's used as a fall back for direct font size in pixels.
   *
   * @return {Highcharts.FontMetricsObject}
   *         The font metrics.
   */
  fontMetrics(element) {
    const f = pInt$5(SVGElement$1.prototype.getStyle.call(element, "font-size") || 0);
    const h = f < 24 ? f + 3 : Math.round(f * 1.2), b = Math.round(h * 0.8);
    return {
      // Line height
      h,
      // Baseline
      b,
      // Font size
      f
    };
  }
  /**
   * Correct X and Y positioning of a label for rotation (#1764).
   *
   * @private
   * @function Highcharts.SVGRenderer#rotCorr
   */
  rotCorr(baseline, rotation, alterY) {
    let y = baseline;
    if (rotation && alterY) {
      y = Math.max(y * Math.cos(rotation * deg2rad$9), 4);
    }
    return {
      x: -baseline / 3 * Math.sin(rotation * deg2rad$9),
      y
    };
  }
  /**
   * Compatibility function to convert the legacy one-dimensional path array
   * into an array of segments.
   *
   * It is used in maps to parse the `path` option, and in SVGRenderer.dSetter
   * to support legacy paths from demos.
   *
   * @private
   * @function Highcharts.SVGRenderer#pathToSegments
   */
  pathToSegments(path) {
    const ret = [];
    const segment = [];
    const commandLength = {
      A: 8,
      C: 7,
      H: 2,
      L: 3,
      M: 3,
      Q: 5,
      S: 5,
      T: 3,
      V: 2
    };
    for (let i = 0; i < path.length; i++) {
      if (isString$e(segment[0]) && isNumber$14(path[i]) && segment.length === commandLength[segment[0].toUpperCase()]) {
        path.splice(i, 0, segment[0].replace("M", "L").replace("m", "l"));
      }
      if (typeof path[i] === "string") {
        if (segment.length) {
          ret.push(segment.slice(0));
        }
        segment.length = 0;
      }
      segment.push(path[i]);
    }
    ret.push(segment.slice(0));
    return ret;
  }
  /**
   * Draw a label, which is an extended text element with support for border
   * and background. Highcharts creates a `g` element with a text and a `path`
   * or `rect` inside, to make it behave somewhat like a HTML div. Border and
   * background are set through `stroke`, `stroke-width` and `fill` attributes
   * using the {@link Highcharts.SVGElement#attr|attr} method. To update the
   * text after render, run `label.attr({ text: 'New text' })`.
   *
   * @sample highcharts/members/renderer-label-on-chart/
   *         A label on the chart
   *
   * @function Highcharts.SVGRenderer#label
   *
   * @param {string} str
   *        The initial text string or (subset) HTML to render.
   *
   * @param {number} x
   *        The x position of the label's left side.
   *
   * @param {number} [y]
   *        The y position of the label's top side or baseline, depending on
   *        the `baseline` parameter.
   *
   * @param {string} [shape='rect']
   *        The shape of the label's border/background, if any. Defaults to
   *        `rect`. Other possible values are `callout` or other shapes
   *        defined in {@link Highcharts.SVGRenderer#symbols}.
   *
   * @param {number} [anchorX]
   *        In case the `shape` has a pointer, like a flag, this is the
   *        coordinates it should be pinned to.
   *
   * @param {number} [anchorY]
   *        In case the `shape` has a pointer, like a flag, this is the
   *        coordinates it should be pinned to.
   *
   * @param {boolean} [useHTML=false]
   *        Whether to use HTML to render the label.
   *
   * @param {boolean} [baseline=false]
   *        Whether to position the label relative to the text baseline,
   *        like {@link Highcharts.SVGRenderer#text|renderer.text}, or to the
   *        upper border of the rectangle.
   *
   * @param {string} [className]
   *        Class name for the group.
   *
   * @return {Highcharts.SVGElement}
   *         The generated label.
   */
  label(str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
    return new SVGLabel(this, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className);
  }
  /**
   * Re-align all aligned elements.
   *
   * @private
   * @function Highcharts.SVGRenderer#alignElements
   */
  alignElements() {
    this.alignedObjects.forEach((el) => el.align());
  }
}
extend$1n(SVGRenderer.prototype, {
  /**
   * A pointer to the renderer's associated Element class.
   *
   * @name Highcharts.SVGRenderer#Element
   * @type {Highcharts.SVGElement}
   */
  Element: SVGElement$1,
  SVG_NS: SVG_NS$1,
  /**
   * A collection of characters mapped to HTML entities. When `useHTML` on an
   * element is true, these entities will be rendered correctly by HTML. In
   * the SVG pseudo-HTML, they need to be unescaped back to simple characters,
   * so for example `&lt;` will render as `<`.
   *
   * @example
   * // Add support for unescaping quotes
   * Highcharts.SVGRenderer.prototype.escapes['"'] = '&quot;';
   *
   * @name Highcharts.SVGRenderer#escapes
   * @type {Highcharts.Dictionary<string>}
   */
  escapes: {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    "'": "&#39;",
    // eslint-disable-line quotes
    '"': "&quot;"
  },
  /**
   * An extendable collection of functions for defining symbol paths.
   *
   * @name Highcharts.SVGRenderer#symbols
   * @type {Highcharts.SymbolDictionary}
   */
  symbols: Symbols,
  /**
   * Dummy function for plugins, called every time the renderer is updated.
   * Prior to Highcharts 5, this was used for the canvg renderer.
   *
   * @deprecated
   * @function Highcharts.SVGRenderer#draw
   */
  draw: noop$j
});
RendererRegistry$1.registerRendererType("svg", SVGRenderer, true);
const { composed: composed$y, isFirefox: isFirefox$1 } = Highcharts;
const { attr: attr$a, css: css$c, createElement: createElement$a, defined: defined$18, extend: extend$1m, getAlignFactor: getAlignFactor$8, isNumber: isNumber$13, pInt: pInt$4, pushUnique: pushUnique$y } = Utilities;
function commonSetter(value, key2, elem) {
  const style = this.div?.style || elem.style;
  SVGElement$1.prototype[`${key2}Setter`].call(this, value, key2, elem);
  if (style) {
    style[key2] = value;
  }
}
const decorateSVGGroup = (g, container) => {
  if (!g.div) {
    const className = attr$a(g.element, "class"), cssProto = g.css;
    const div = createElement$a(
      "div",
      className ? { className } : void 0,
      {
        // Add HTML specific styles
        position: "absolute",
        left: `${g.translateX || 0}px`,
        top: `${g.translateY || 0}px`,
        // Add pre-existing styles
        ...g.styles,
        // Add g attributes that correspond to CSS
        display: g.display,
        opacity: g.opacity,
        // #5075
        visibility: g.visibility
      },
      // The top group is appended to container
      g.parentGroup?.div || container
    );
    g.classSetter = (value, key2, element) => {
      element.setAttribute("class", value);
      div.className = value;
    };
    g.translateXSetter = g.translateYSetter = (value, key2) => {
      g[key2] = value;
      div.style[key2 === "translateX" ? "left" : "top"] = `${value}px`;
      g.doTransform = true;
    };
    g.opacitySetter = g.visibilitySetter = commonSetter;
    g.css = (styles) => {
      cssProto.call(g, styles);
      if (styles.cursor) {
        div.style.cursor = styles.cursor;
      }
      if (styles.pointerEvents) {
        div.style.pointerEvents = styles.pointerEvents;
      }
      return g;
    };
    g.on = function() {
      SVGElement$1.prototype.on.apply({
        element: div,
        onEvents: g.onEvents
      }, arguments);
      return g;
    };
    g.div = div;
  }
  return g.div;
};
let HTMLElement$1 = class HTMLElement2 extends SVGElement$1 {
  /**
   * Compose
   * @private
   */
  static compose(SVGRendererClass) {
    if (pushUnique$y(composed$y, this.compose)) {
      SVGRendererClass.prototype.html = function(str, x, y) {
        return new HTMLElement2(this, "span").attr({
          text: str,
          x: Math.round(x),
          y: Math.round(y)
        });
      };
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  constructor(renderer, nodeName) {
    super(renderer, nodeName);
    if (HTMLElement2.useForeignObject) {
      this.foreignObject = renderer.createElement("foreignObject").attr({
        zIndex: 2
      });
    } else {
      this.css({
        position: "absolute",
        ...renderer.styledMode ? {} : {
          fontFamily: renderer.style.fontFamily,
          fontSize: renderer.style.fontSize
        }
      });
    }
    this.element.style.whiteSpace = "nowrap";
  }
  /**
   * Get the correction in X and Y positioning as the element is rotated.
   * @private
   */
  getSpanCorrection(width, baseline, alignCorrection) {
    this.xCorr = -width * alignCorrection;
    this.yCorr = -baseline;
  }
  /**
   * Apply CSS to HTML elements. This is used in text within SVG rendering.
   * @private
   */
  css(styles) {
    const { element } = this, isSettingWidth = element.tagName === "SPAN" && styles && "width" in styles, textWidth = isSettingWidth && styles.width;
    let doTransform;
    if (isSettingWidth) {
      delete styles.width;
      this.textWidth = pInt$4(textWidth) || void 0;
      doTransform = true;
    }
    if (styles?.textOverflow === "ellipsis") {
      styles.overflow = "hidden";
      styles.whiteSpace = "nowrap";
    }
    if (styles?.lineClamp) {
      styles.display = "-webkit-box";
      styles.WebkitLineClamp = styles.lineClamp;
      styles.WebkitBoxOrient = "vertical";
      styles.overflow = "hidden";
    }
    if (isNumber$13(Number(styles?.fontSize))) {
      styles.fontSize += "px";
    }
    extend$1m(this.styles, styles);
    css$c(element, styles);
    if (doTransform) {
      this.updateTransform();
    }
    return this;
  }
  /**
   * The useHTML method for calculating the bounding box based on offsets.
   * Called internally from the `SVGElement.getBBox` function and subsequently
   * rotated.
   *
   * @private
   */
  htmlGetBBox() {
    const { element } = this;
    return {
      x: element.offsetLeft,
      y: element.offsetTop,
      width: element.offsetWidth,
      height: element.offsetHeight
    };
  }
  /**
   * Batch update styles and attributes related to transform
   *
   * @private
   */
  updateTransform() {
    if (!this.added) {
      this.alignOnAdd = true;
      return;
    }
    const { element, foreignObject, oldTextWidth, renderer, rotation, rotationOriginX, rotationOriginY, scaleX, scaleY, styles: { display = "inline-block", whiteSpace }, textAlign = "left", textWidth, translateX = 0, translateY = 0, x = 0, y = 0 } = this;
    const getTextPxLength = () => {
      if (this.textPxLength) {
        return this.textPxLength;
      }
      css$c(element, {
        width: "",
        whiteSpace: whiteSpace || "nowrap"
      });
      return element.offsetWidth;
    };
    if (!foreignObject) {
      css$c(element, {
        marginLeft: `${translateX}px`,
        marginTop: `${translateY}px`
      });
    }
    if (element.tagName === "SPAN") {
      const currentTextTransform = [
        rotation,
        textAlign,
        element.innerHTML,
        textWidth,
        this.textAlign
      ].join(","), parentPadding = this.parentGroup?.padding * -1 || 0;
      let baseline;
      if (textWidth !== oldTextWidth) {
        const textPxLength = getTextPxLength(), textWidthNum = textWidth || 0, willOverWrap = element.style.textOverflow === "" && element.style.webkitLineClamp;
        if ((textWidthNum > oldTextWidth || textPxLength > textWidthNum || willOverWrap) && // Only set the width if the text is able to word-wrap,
        // or text-overflow is ellipsis (#9537)
        (/[\-\s\u00AD]/.test(element.textContent || element.innerText) || element.style.textOverflow === "ellipsis")) {
          const usePxWidth = rotation || scaleX || textPxLength > textWidthNum || // Set width to prevent over-wrapping (#22609)
          willOverWrap;
          css$c(element, {
            width: usePxWidth && isNumber$13(textWidth) ? textWidth + "px" : "auto",
            // #16261
            display,
            whiteSpace: whiteSpace || "normal"
            // #3331
          });
          this.oldTextWidth = textWidth;
        }
      }
      if (foreignObject) {
        css$c(element, {
          // Inline block must be set before we can read the offset
          // width
          display: "inline-block",
          verticalAlign: "top"
        });
        foreignObject.attr({
          width: renderer.width,
          height: renderer.height
        });
      }
      if (currentTextTransform !== this.cTT) {
        baseline = renderer.fontMetrics(element).b;
        if (defined$18(rotation) && !foreignObject && (rotation !== (this.oldRotation || 0) || textAlign !== this.oldAlign)) {
          css$c(element, {
            transform: `rotate(${rotation}deg)`,
            transformOrigin: `${parentPadding}% ${parentPadding}px`
          });
        }
        this.getSpanCorrection(
          // Avoid elem.offsetWidth if we can, it affects rendering
          // time heavily (#7656)
          !defined$18(rotation) && !this.textWidth && this.textPxLength || // #7920
          element.offsetWidth,
          baseline,
          getAlignFactor$8(textAlign)
        );
      }
      const { xCorr = 0, yCorr = 0 } = this, rotOriginX = (rotationOriginX ?? x) - xCorr - x - parentPadding, rotOriginY = (rotationOriginY ?? y) - yCorr - y - parentPadding, styles = {
        left: `${x + xCorr}px`,
        top: `${y + yCorr}px`,
        textAlign,
        transformOrigin: `${rotOriginX}px ${rotOriginY}px`
      };
      if (scaleX || scaleY) {
        styles.transform = `scale(${scaleX ?? 1},${scaleY ?? 1})`;
      }
      if (foreignObject) {
        super.updateTransform();
        if (isNumber$13(x) && isNumber$13(y)) {
          foreignObject.attr({
            x: x + xCorr,
            y: y + yCorr,
            width: element.offsetWidth + 3,
            height: element.offsetHeight,
            "transform-origin": element.getAttribute("transform-origin") || "0 0"
          });
          css$c(element, { display, textAlign });
        } else if (isFirefox$1) {
          foreignObject.attr({
            width: 0,
            height: 0
          });
        }
      } else {
        css$c(element, styles);
      }
      this.cTT = currentTextTransform;
      this.oldRotation = rotation;
      this.oldAlign = textAlign;
    }
  }
  /**
   * Add the element to a group wrapper. For HTML elements, a parallel div
   * will be created for each ancenstor SVG `g` element.
   *
   * @private
   */
  add(parentGroup) {
    const { foreignObject, renderer } = this, container = renderer.box.parentNode, parents = [];
    if (foreignObject) {
      foreignObject.add(parentGroup);
      super.add(
        // Create a body inside the foreignObject
        renderer.createElement("body").attr({ xmlns: "http://www.w3.org/1999/xhtml" }).css({
          background: "transparent",
          // 3px is to avoid clipping on the right
          margin: "0 3px 0 0"
          // For export
        }).add(foreignObject)
      );
    } else {
      let div;
      this.parentGroup = parentGroup;
      if (parentGroup) {
        div = parentGroup.div;
        if (!div) {
          let svgGroup = parentGroup;
          while (svgGroup) {
            parents.push(svgGroup);
            svgGroup = svgGroup.parentGroup;
          }
          for (const parentGroup2 of parents.reverse()) {
            div = decorateSVGGroup(parentGroup2, container);
          }
        }
      }
      (div || container).appendChild(this.element);
    }
    this.added = true;
    if (this.alignOnAdd) {
      this.updateTransform();
    }
    return this;
  }
  /**
   * Text setter
   * @private
   */
  textSetter(value) {
    if (value !== this.textStr) {
      delete this.bBox;
      delete this.oldTextWidth;
      AST.setElementHTML(this.element, value ?? "");
      this.textStr = value;
      this.doTransform = true;
    }
  }
  /**
   * Align setter
   *
   * @private
   */
  alignSetter(value) {
    this.alignValue = this.textAlign = value;
    this.doTransform = true;
  }
  /**
   * Various setters which rely on update transform
   * @private
   */
  xSetter(value, key2) {
    this[key2] = value;
    this.doTransform = true;
  }
};
const proto = HTMLElement$1.prototype;
proto.visibilitySetter = proto.opacitySetter = commonSetter;
proto.ySetter = proto.rotationSetter = proto.rotationOriginXSetter = proto.rotationOriginYSetter = proto.xSetter;
var AxisDefaults;
(function(AxisDefaults2) {
  AxisDefaults2.xAxis = {
    /**
     * When using multiple axis, the ticks of two or more opposite axes
     * will automatically be aligned by adding ticks to the axis or axes
     * with the least ticks, as if `tickAmount` were specified.
     *
     * This can be prevented by setting `alignTicks` to false. If the grid
     * lines look messy, it's a good idea to hide them for the secondary
     * axis by setting `gridLineWidth` to 0.
     *
     * If `startOnTick` or `endOnTick` in an Axis options are set to false,
     * then the `alignTicks ` will be disabled for the Axis.
     *
     * Disabled for logarithmic axes.
     *
     * @product   highcharts highstock gantt
     */
    alignTicks: true,
    /**
     * Whether to allow decimals in this axis' ticks. When counting
     * integers, like persons or hits on a web page, decimals should
     * be avoided in the labels. By default, decimals are allowed on small
     * scale axes.
     *
     * @see [minTickInterval](#xAxis.minTickInterval)
     *
     * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-true/
     *         True by default
     * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-false/
     *         False
     *
     * @type      {boolean|undefined}
     * @default   undefined
     * @since     2.0
     */
    allowDecimals: void 0,
    /**
     * When using an alternate grid color, a band is painted across the
     * plot area between every other grid line.
     *
     * @sample {highcharts} highcharts/yaxis/alternategridcolor/
     *         Alternate grid color on the Y axis
     * @sample {highstock} stock/xaxis/alternategridcolor/
     *         Alternate grid color on the Y axis
     *
     * @type      {Highcharts.ColorType}
     * @apioption xAxis.alternateGridColor
     */
    /**
     * An array defining breaks in the axis, the sections defined will be
     * left out and all the points shifted closer to each other.
     *
     * @productdesc {highcharts}
     * Requires that the broken-axis.js module is loaded.
     *
     * @sample {highcharts} highcharts/axisbreak/break-simple/
     *         Simple break
     * @sample {highcharts|highstock} highcharts/axisbreak/break-visualized/
     *         Advanced with callback
     * @sample {highstock} stock/demo/intraday-breaks/
     *         Break on nights and weekends
     *
     * @type      {Array<*>}
     * @since     4.1.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.breaks
     */
    /**
     * A number indicating how much space should be left between the start
     * and the end of the break. The break size is given in axis units,
     * so for instance on a `datetime` axis, a break size of 3600000 would
     * indicate the equivalent of an hour.
     *
     * @type      {number}
     * @default   0
     * @since     4.1.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.breaks.breakSize
     */
    /**
     * The axis value where the break starts. On datetime axes, this may be
     * a date string.
     *
     * @type      {number|string}
     * @since     4.1.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.breaks.from
     */
    /**
     * Defines an interval after which the break appears again. By default
     * the breaks do not repeat.
     *
     * @type      {number}
     * @default   0
     * @since     4.1.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.breaks.repeat
     */
    /**
     * The axis value where the break ends. On datetime axes, this may be
     * a date string.
     *
     * @type      {number|string}
     * @since     4.1.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.breaks.to
     */
    /**
     * If categories are present for the xAxis, names are used instead of
     * numbers for that axis.
     *
     * Since Highcharts 3.0, categories can also
     * be extracted by giving each point a [name](#series.data) and setting
     * axis [type](#xAxis.type) to `category`. However, if you have multiple
     * series, best practice remains defining the `categories` array.
     *
     * Example: `categories: ['Apples', 'Bananas', 'Oranges']`
     *
     * @sample {highcharts} highcharts/demo/line-labels/
     *         With
     * @sample {highcharts} highcharts/xaxis/categories/
     *         Without
     *
     * @type      {Array<string>}
     * @product   highcharts gantt
     * @apioption xAxis.categories
     */
    /**
     * The highest allowed value for automatically computed axis extremes.
     *
     * @see [floor](#xAxis.floor)
     *
     * @sample {highcharts|highstock} highcharts/yaxis/floor-ceiling/
     *         Floor and ceiling
     *
     * @type       {number}
     * @since      4.0
     * @product    highcharts highstock gantt
     * @apioption  xAxis.ceiling
     */
    /**
     * A class name that opens for styling the axis by CSS, especially in
     * Highcharts styled mode. The class name is applied to group elements
     * for the grid, axis elements and labels.
     *
     * @sample {highcharts|highstock|highmaps} highcharts/css/axis/
     *         Multiple axes with separate styling
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption xAxis.className
     */
    /**
     * Configure a crosshair that follows either the mouse pointer or the
     * hovered point.
     *
     * In styled mode, the crosshairs are styled in the
     * `.highcharts-crosshair`, `.highcharts-crosshair-thin` or
     * `.highcharts-xaxis-category` classes.
     *
     * @productdesc {highstock}
     * In Highcharts stock, by default, the crosshair is enabled on the
     * X axis and disabled on the Y axis.
     *
     * @sample {highcharts} highcharts/xaxis/crosshair-both/
     *         Crosshair on both axes
     * @sample {highstock} stock/xaxis/crosshairs-xy/
     *         Crosshair on both axes, with y axis label
     * @sample {highmaps} highcharts/xaxis/crosshair-both/
     *         Crosshair on both axes
     *
     * @declare   Highcharts.AxisCrosshairOptions
     * @type      {boolean|*}
     * @default   false
     * @since     4.1
     * @apioption xAxis.crosshair
     */
    /**
     * The value on a perpendicular axis where this axis should cross. This
     * is typically used on mathematical plots where the axes cross at 0.
     * When `crossing` is set, space will not be reserved at the sides of
     * the chart for axis labels and title, so those may be clipped. In this
     * case it is better to place the axes without the `crossing` option.
     *
     * @type      {number}
     * @sample    highcharts/xaxis/crossing
     *            Function plot with axes crossing at 0
     * @since 11.0.1
     * @apioption xAxis.crossing
     */
    /**
     * A class name for the crosshair, especially as a hook for styling.
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption xAxis.crosshair.className
     */
    /**
     * The color of the crosshair. Defaults to `#cccccc` for numeric and
     * datetime axes, and `rgba(204,214,235,0.25)` for category axes, where
     * the crosshair by default highlights the whole category.
     *
     * @sample {highcharts|highstock|highmaps} highcharts/xaxis/crosshair-customized/
     *         Customized crosshairs
     *
     * @type      {Highcharts.ColorType}
     * @default   #cccccc
     * @since     4.1
     * @apioption xAxis.crosshair.color
     */
    /**
     * The dash style for the crosshair. See
     * [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
     * for possible values.
     *
     * @sample {highcharts|highmaps} highcharts/xaxis/crosshair-dotted/
     *         Dotted crosshair
     * @sample {highstock} stock/xaxis/crosshair-dashed/
     *         Dashed X axis crosshair
     *
     * @type      {Highcharts.DashStyleValue}
     * @default   Solid
     * @since     4.1
     * @apioption xAxis.crosshair.dashStyle
     */
    /**
     * A label on the axis next to the crosshair.
     *
     * In styled mode, the label is styled with the
     * `.highcharts-crosshair-label` class.
     *
     * @sample {highstock} stock/xaxis/crosshair-label/
     *         Crosshair labels
     * @sample {highstock} highcharts/css/crosshair-label/
     *         Style mode
     *
     * @declare   Highcharts.AxisCrosshairLabelOptions
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label
     */
    /**
     * Alignment of the label compared to the axis. Defaults to `"left"` for
     * right-side axes, `"right"` for left-side axes and `"center"` for
     * horizontal axes.
     *
     * @type      {Highcharts.AlignValue}
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.align
     */
    /**
     * The background color for the label. Defaults to the related series
     * color, or `#666666` if that is not available.
     *
     * @type      {Highcharts.ColorType}
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.backgroundColor
     */
    /**
     * The border color for the crosshair label
     *
     * @type      {Highcharts.ColorType}
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.borderColor
     */
    /**
     * The border corner radius of the crosshair label.
     *
     * @type      {number}
     * @default   3
     * @since     2.1.10
     * @product   highstock
     * @apioption xAxis.crosshair.label.borderRadius
     */
    /**
     * The border width for the crosshair label.
     *
     * @type      {number}
     * @default   0
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.borderWidth
     */
    /**
     * Flag to enable crosshair's label.
     *
     * @sample {highstock} stock/xaxis/crosshairs-xy/
     *         Enabled label for yAxis' crosshair
     *
     * @type      {boolean}
     * @default   false
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.enabled
     */
    /**
     * A format string for the crosshair label. Defaults to `{value}` for
     * numeric axes and `{value:%b %d, %Y}` for datetime axes.
     *
     * @type      {string}
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.format
     */
    /**
     * Formatter function for the label text.
     *
     * @type      {Highcharts.XAxisCrosshairLabelFormatterCallbackFunction}
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.formatter
     */
    /**
     * Padding inside the crosshair label.
     *
     * @type      {number}
     * @default   8
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.padding
     */
    /**
     * The shape to use for the label box.
     *
     * @type      {string}
     * @default   callout
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.shape
     */
    /**
     * Text styles for the crosshair label.
     *
     * @type      {Highcharts.CSSObject}
     * @default   {"color": "white", "fontWeight": "normal", "fontSize": "11px", "textAlign": "center"}
     * @since     2.1
     * @product   highstock
     * @apioption xAxis.crosshair.label.style
     */
    /**
     * Whether the crosshair should snap to the point or follow the pointer
     * independent of points.
     *
     * @sample {highcharts|highstock} highcharts/xaxis/crosshair-snap-false/
     *         True by default
     * @sample {highmaps} maps/demo/latlon-advanced/
     *         Snap is false
     *
     * @type      {boolean}
     * @default   true
     * @since     4.1
     * @apioption xAxis.crosshair.snap
     */
    /**
     * The pixel width of the crosshair. Defaults to 1 for numeric or
     * datetime axes, and for one category width for category axes.
     *
     * @sample {highcharts} highcharts/xaxis/crosshair-customized/
     *         Customized crosshairs
     * @sample {highstock} highcharts/xaxis/crosshair-customized/
     *         Customized crosshairs
     * @sample {highmaps} highcharts/xaxis/crosshair-customized/
     *         Customized crosshairs
     *
     * @type      {number}
     * @default   1
     * @since     4.1
     * @apioption xAxis.crosshair.width
     */
    /**
     * The Z index of the crosshair. Higher Z indices allow drawing the
     * crosshair on top of the series or behind the grid lines.
     *
     * @type      {number}
     * @default   2
     * @since     4.1
     * @apioption xAxis.crosshair.zIndex
     */
    /**
     * Whether to pan axis. If `chart.panning` is enabled, the option
     * allows to disable panning on an individual axis.
     */
    panningEnabled: true,
    /**
     * The Z index for the axis group.
     *
     * @see [axis.gridZIndex](#xAxis.gridZIndex)
     * @see [axis.labels.zIndex](#xAxis.labels.zIndex)
     */
    zIndex: 2,
    /**
     * Whether to zoom axis. If `chart.zoomType` is set, the option allows
     * to disable zooming on an individual axis.
     *
     * @sample {highcharts} highcharts/xaxis/zoomenabled/
     *         Zoom enabled is false
     */
    zoomEnabled: true,
    /**
     * For a datetime axis, the scale will automatically adjust to the
     * appropriate unit. This member gives the default string
     * representations used for each unit. For intermediate values,
     * different units may be used, for example the `day` unit can be used
     * on midnight and `hour` unit be used for intermediate values on the
     * same axis.
     *
     * For an overview of the string or object configuration, see
     * [dateFormat](/class-reference/Highcharts.Time#dateFormat).
     *
     * Defaults to:
     * ```js
     * {
     *     millisecond: '%[HMSL]',
     *     second: '%[HMS]',
     *     minute: '%[HM]',
     *     hour: '%[HM]',
     *     day: '%[eb]',
     *     week: '%[eb]',
     *     month: '%[bY]',
     *     year: '%Y'
     * }
     * ```
     *
     * @sample {highcharts} highcharts/xaxis/datetimelabelformats-object/
     *         Object day format on X axis
     * @sample {highcharts} highcharts/xaxis/datetimelabelformats/
     *         String day format on X axis
     * @sample {highstock} stock/xaxis/datetimelabelformats/
     *         More information in x axis labels
     *
     * @declare Highcharts.AxisDateTimeLabelFormatsOptions
     * @product highcharts highstock gantt
     */
    dateTimeLabelFormats: {
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      millisecond: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.millisecond.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.millisecond.main
         */
        main: "%[HMSL]",
        range: false
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      second: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.second.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.second.main
         */
        main: "%[HMS]",
        range: false
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      minute: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.minute.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.minute.main
         */
        main: "%[HM]",
        range: false
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      hour: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.hour.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.hour.main
         */
        main: "%[HM]",
        range: false
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      day: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.day.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.day.main
         */
        main: "%[eb]"
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      week: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.week.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.week.main
         */
        main: "%[eb]"
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      month: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.month.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.month.main
         */
        main: "%[bY]"
      },
      /**
       * @declare Highcharts.AxisDateTimeLabelFormatsOptionsObject
       * @type {string|*}
       */
      year: {
        /**
         * @type {Array<string|Highcharts.DateTimeFormatOptions>}
         * @default undefined
         * @apioption xAxis.dateTimeLabelFormats.year.list
         */
        /**
         * @type {string|Highcharts.DateTimeFormatOptions}
         * @apioption xAxis.dateTimeLabelFormats.year.main
         */
        main: "%Y"
      }
    },
    /**
     * Whether to force the axis to end on a tick. Use this option with
     * the `maxPadding` option to control the axis end.
     *
     * @productdesc {highstock}
     * In Highcharts Stock, `endOnTick` is always `false` when the navigator
     * is enabled, to prevent jumpy scrolling. With disabled navigator
     * enabling `endOnTick` may lead to extending the xAxis to show the last
     * tick, therefore range selector buttons may not have an active state
     * if the axis gets extended.
     *
     * @sample {highcharts} highcharts/yaxis/endontick/
     *         True by default
     * @sample {highcharts} highcharts/yaxis/endontick-false/
     *         False
     * @sample {highstock} stock/demo/basic-line/
     *         True by default
     * @sample {highstock} stock/xaxis/endontick/
     *         False
     *
     * @since 1.2.0
     */
    endOnTick: false,
    /**
     * Event handlers for the axis.
     *
     * @type      {*}
     * @apioption xAxis.events
     */
    /**
     * An event fired after the breaks have rendered.
     *
     * @see [breaks](#xAxis.breaks)
     *
     * @sample {highcharts} highcharts/axisbreak/break-event/
     *         AfterBreak Event
     *
     * @type      {Highcharts.AxisEventCallbackFunction}
     * @since     4.1.0
     * @product   highcharts gantt
     * @apioption xAxis.events.afterBreaks
     */
    /**
     * As opposed to the `setExtremes` event, this event fires after the
     * final min and max values are computed and corrected for `minRange`.
     *
     * Fires when the minimum and maximum is set for the axis, either by
     * calling the `.setExtremes()` method or by selecting an area in the
     * chart. One parameter, `event`, is passed to the function, containing
     * common event information.
     *
     * The new user set minimum and maximum values can be found by
     * `event.min` and `event.max`. These reflect the axis minimum and
     * maximum in axis values. The actual data extremes are found in
     * `event.dataMin` and `event.dataMax`.
     *
     * @type      {Highcharts.AxisSetExtremesEventCallbackFunction}
     * @since     2.3
     * @context   Highcharts.Axis
     * @apioption xAxis.events.afterSetExtremes
     */
    /**
     * An event fired when a break from this axis occurs on a point.
     *
     * @see [breaks](#xAxis.breaks)
     *
     * @sample {highcharts} highcharts/axisbreak/break-visualized/
     *         Visualization of a Break
     *
     * @type      {Highcharts.AxisPointBreakEventCallbackFunction}
     * @since     4.1.0
     * @product   highcharts gantt
     * @context   Highcharts.Axis
     * @apioption xAxis.events.pointBreak
     */
    /**
     * An event fired when a point falls inside a break from this axis.
     *
     * @type      {Highcharts.AxisPointBreakEventCallbackFunction}
     * @product   highcharts highstock gantt
     * @context   Highcharts.Axis
     * @apioption xAxis.events.pointInBreak
     */
    /**
     * An event fired when a point is outside a break after zoom.
     *
     * @type      {Highcharts.AxisPointBreakEventCallbackFunction}
     * @product   highcharts highstock gantt
     * @context   Highcharts.Axis
     * @apioption xAxis.events.pointBreakOut
     */
    /**
     * Fires when the minimum and maximum is set for the axis, either by
     * calling the `.setExtremes()` method or by selecting an area in the
     * chart. One parameter, `event`, is passed to the function,
     * containing common event information.
     *
     * The new user set minimum and maximum values can be found by
     * `event.min` and `event.max`. These reflect the axis minimum and
     * maximum in data values. When an axis is zoomed all the way out from
     * the "Reset zoom" button, `event.min` and `event.max` are null, and
     * the new extremes are set based on `this.dataMin` and `this.dataMax`.
     *
     * @sample {highstock} stock/xaxis/events-setextremes/
     *         Log new extremes on x axis
     *
     * @type      {Highcharts.AxisSetExtremesEventCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Axis
     * @apioption xAxis.events.setExtremes
     */
    /**
     * The lowest allowed value for automatically computed axis extremes.
     *
     * @see [ceiling](#yAxis.ceiling)
     *
     * @sample {highcharts} highcharts/yaxis/floor-ceiling/
     *         Floor and ceiling
     * @sample {highstock} stock/demo/lazy-loading/
     *         Prevent negative stock price on Y axis
     *
     * @type      {number}
     * @since     4.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.floor
     */
    /**
     * The dash or dot style of the grid lines. For possible values, see
     * [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
     *
     * @sample {highcharts} highcharts/yaxis/gridlinedashstyle/
     *         Long dashes
     * @sample {highstock} stock/xaxis/gridlinedashstyle/
     *         Long dashes
     *
     * @type      {Highcharts.DashStyleValue}
     * @since     1.2
     */
    gridLineDashStyle: "Solid",
    /**
     * The Z index of the grid lines.
     *
     * @sample {highcharts|highstock} highcharts/xaxis/gridzindex/
     *         A Z index of 4 renders the grid above the graph
     *
     * @product   highcharts highstock gantt
     *
     * @see [axis.zIndex](#xAxis.zIndex)
     * @see [axis.labels.zIndex](#xAxis.labels.zIndex)
     */
    gridZIndex: 1,
    /**
     * An id for the axis. This can be used after render time to get
     * a pointer to the axis object through `chart.get()`.
     *
     * @sample {highcharts} highcharts/xaxis/id/
     *         Get the object
     * @sample {highstock} stock/xaxis/id/
     *         Get the object
     *
     * @type      {string}
     * @since     1.2.0
     * @apioption xAxis.id
     */
    /**
     * The axis labels show the number or category for each tick.
     *
     * Since v8.0.0: Labels are animated in categorized x-axis with
     * updating data if `tickInterval` and `step` is set to 1.
     *
     * @productdesc {highmaps}
     * X and Y axis labels are by default disabled in Highmaps, but the
     * functionality is inherited from Highcharts and used on `colorAxis`,
     * and can be enabled on X and Y axes too.
     */
    labels: {
      /**
       * What part of the string the given position is anchored to.
       * If `left`, the left side of the string is at the axis position.
       * Can be one of `"left"`, `"center"` or `"right"`. Defaults to
       * an intelligent guess based on which side of the chart the axis
       * is on and the rotation of the label.
       *
       * @see [reserveSpace](#xAxis.labels.reserveSpace)
       *
       * @sample {highcharts} highcharts/xaxis/labels-align-left/
       *         Left
       * @sample {highcharts} highcharts/xaxis/labels-align-right/
       *         Right
       * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/
       *         Left-aligned labels on a vertical category axis
       *
       * @type      {Highcharts.AlignValue}
       * @apioption xAxis.labels.align
       */
      /**
       * Whether to allow the axis labels to overlap. When false,
       * overlapping labels are hidden.
       *
       * @sample {highcharts} highcharts/xaxis/labels-allowoverlap-true/
       *         X axis labels overlap enabled
       *
       * @type      {boolean}
       * @default   false
       * @apioption xAxis.labels.allowOverlap
       */
      /**
       * For horizontal axes, the allowed degrees of label rotation
       * to prevent overlapping labels. If there is enough space,
       * labels are not rotated. As the chart gets narrower, it
       * will start rotating the labels -45 degrees, then remove
       * every second label and try again with rotations 0 and -45 etc.
       * Set it to `undefined` to disable rotation, which will
       * cause the labels to word-wrap if possible. Defaults to `[-45]``
       * on bottom and top axes, `undefined` on left and right axes.
       *
       * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-default/
       *         Default auto rotation of 0 or -45
       * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-0-90/
       *         Custom graded auto rotation
       *
       * @type      {Array<number>}
       * @default   undefined
       * @since     4.1.0
       * @product   highcharts highstock gantt
       * @apioption xAxis.labels.autoRotation
       */
      /**
       * When each category width is more than this many pixels, we don't
       * apply auto rotation. Instead, we lay out the axis label with word
       * wrap. A lower limit makes sense when the label contains multiple
       * short words that don't extend the available horizontal space for
       * each label.
       *
       * @sample {highcharts} highcharts/xaxis/labels-autorotationlimit/
       *         Lower limit
       *
       * @since     4.1.5
       * @product   highcharts gantt
       */
      autoRotationLimit: 80,
      /**
       * The label's pixel distance from the perimeter of the plot area.
       * On cartesian charts, this is overridden if the `labels.y` setting
       * is set.
       *
       * @sample {highcharts} highcharts/yaxis/labels-distance/
       *         Polar chart, labels centered under the arc
       *
       * @type      {number}
       * @product   highcharts gantt
       */
      distance: 15,
      /**
       * Enable or disable the axis labels.
       *
       * @sample {highcharts} highcharts/xaxis/labels-enabled/
       *         X axis labels disabled
       * @sample {highstock} stock/xaxis/labels-enabled/
       *         X axis labels disabled
       *
       */
      enabled: true,
      /**
       * A format string for the axis label. The context is available as
       * format string variables. For example, you can use `{text}` to
       * insert the default formatted text. The recommended way of adding
       * units for the label is using `text`, for example `{text} km`.
       *
       * To add custom numeric or datetime formatting, use `{value}` with
       * formatting, for example `{value:.1f}` or `{value:%Y-%m-%d}`.
       *
       * See
       * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
       * for more examples of formatting.
       *
       * The default value is not specified due to the dynamic
       * nature of the default implementation.
       *
       * @sample {highcharts|highstock} highcharts/yaxis/labels-format/
       *         Add units to Y axis label
       * @sample {highcharts} highcharts/xaxis/labels-format-linked/
       *         Linked category names
       * @sample {highcharts} highcharts/xaxis/labels-format-custom/
       *         Custom number format
       *
       * @type      {string}
       * @since     3.0
       * @apioption xAxis.labels.format
       */
      /**
       * Callback JavaScript function to format the label. The value
       * is given by `this.value`. Additional properties for `this` are
       * `axis`, `chart`, `isFirst`, `isLast` and `text` which holds the
       * value of the default formatter.
       *
       * Defaults to a built in function returning a formatted string
       * depending on whether the axis is `category`, `datetime`,
       * `numeric` or other.
       *
       * @sample {highcharts} highcharts/xaxis/labels-formatter-linked/
       *         Linked category names
       * @sample {highcharts} highcharts/xaxis/labels-formatter-extended/
       *         Modified numeric labels
       * @sample {highstock} stock/xaxis/labels-formatter/
       *         Added units on Y axis
       *
       * @type      {Highcharts.AxisLabelsFormatterCallbackFunction}
       * @apioption xAxis.labels.formatter
       */
      /**
       * The number of pixels to indent the labels per level in a treegrid
       * axis.
       *
       * @sample gantt/treegrid-axis/demo
       *         Indentation 10px by default.
       * @sample gantt/treegrid-axis/indentation-0px
       *         Indentation set to 0px.
       *
       * @product gantt
       */
      indentation: 10,
      /**
       * Horizontal axis only. When `staggerLines` is not set,
       * `maxStaggerLines` defines how many lines the axis is allowed to
       * add to automatically avoid overlapping X labels. Set to `1` to
       * disable overlap detection.
       *
       * @deprecated
       * @type      {number}
       * @default   5
       * @since     1.3.3
       * @apioption xAxis.labels.maxStaggerLines
       */
      /**
       * How to handle overflowing labels on horizontal axis. If set to
       * `"allow"`, it will not be aligned at all. By default it
       * `"justify"` labels inside the chart area. If there is room to
       * move it, it will be aligned to the edge, else it will be removed.
       *
       * @since      2.2.5
       * @validvalue ["allow", "justify"]
       */
      overflow: "justify",
      /**
       * The pixel padding for axis labels, to ensure white space between
       * them. Defaults to 4 for horizontal axes, 1 for vertical.
       *
       * @type      {number}
       * @default   undefined
       * @product   highcharts gantt
       * @apioption xAxis.labels.padding
       */
      /**
       * Whether to reserve space for the labels. By default, space is
       * reserved for the labels in these cases:
       *
       * * On all horizontal axes.
       * * On vertical axes if `label.align` is `right` on a left-side
       * axis or `left` on a right-side axis.
       * * On vertical axes if `label.align` is `center`.
       *
       * This can be turned off when for example the labels are rendered
       * inside the plot area instead of outside.
       *
       * @see [labels.align](#xAxis.labels.align)
       *
       * @sample {highcharts} highcharts/xaxis/labels-reservespace/
       *         No reserved space, labels inside plot
       * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/
       *         Left-aligned labels on a vertical category axis
       *
       * @type      {boolean}
       * @since     4.1.10
       * @product   highcharts highstock gantt
       * @apioption xAxis.labels.reserveSpace
       */
      reserveSpace: void 0,
      /**
       * Rotation of the labels in degrees. When `undefined`, the
       * `autoRotation` option takes precedence.
       *
       * @sample {highcharts} highcharts/xaxis/labels-rotation/
       *         X axis labels rotated 90°
       *
       * @type      {number}
       * @default   0
       * @apioption xAxis.labels.rotation
       */
      rotation: void 0,
      /**
       * Horizontal axes only. The number of lines to spread the labels
       * over to make room or tighter labels. 0 disables staggering.
       *
       * @sample {highcharts} highcharts/xaxis/labels-staggerlines/
       *         Show labels over two lines
       * @sample {highstock} stock/xaxis/labels-staggerlines/
       *         Show labels over two lines
       *
       * @since     2.1
       */
      staggerLines: 0,
      /**
       * To show only every _n_'th label on the axis, set the step to _n_.
       * Setting the step to 2 shows every other label.
       *
       * By default, when 0, the step is calculated automatically to avoid
       * overlap. To prevent this, set it to 1\. This usually only
       * happens on a category axis, and is often a sign that you have
       * chosen the wrong axis type.
       *
       * Read more at
       * [Axis docs](https://www.highcharts.com/docs/chart-concepts/axes)
       * => What axis should I use?
       *
       * @sample {highcharts} highcharts/xaxis/labels-step/
       *         Showing only every other axis label on a categorized
       *         x-axis
       * @sample {highcharts} highcharts/xaxis/labels-step-auto/
       *         Auto steps on a category axis
       *
       * @since     2.1
       */
      step: 0,
      /**
       * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
       * to render the labels.
       */
      useHTML: false,
      /**
       * The x position offset of all labels relative to the tick
       * positions on the axis. Overrides the `labels.distance` option.
       *
       * @type      {number}
       * @apioption xAxis.labels.x
       */
      /**
       * The y position offset of all labels relative to the tick
       * positions on the axis. Overrides the `labels.distance` option.
       *
       * @sample {highcharts} highcharts/xaxis/labels-x/
       *         X axis labels placed on grid lines
       *
       * @type      {number}
       * @apioption xAxis.labels.y
       */
      /**
       * The Z index for the axis labels.
       *
       * @see [axis.zIndex](#xAxis.zIndex)
       * @see [axis.gridZIndex](#xAxis.gridZIndex)
       */
      zIndex: 7,
      /**
       * CSS styles for the label. Use `lineClamp` to control wrapping of
       * category labels. Use `textOverflow: 'none'` to prevent ellipsis
       * (dots).
       *
       * In styled mode, the labels are styled with the
       * `.highcharts-axis-labels` class.
       *
       * @sample {highcharts} highcharts/xaxis/labels-style/
       *         Red X axis labels
       *
       * @type      {Highcharts.CSSObject}
       */
      style: {
        /** @internal */
        color: "#333333",
        /** @internal */
        cursor: "default",
        /**
         * @type {number|string}
         */
        fontSize: "0.8em",
        /** @internal */
        textOverflow: "ellipsis"
      }
    },
    /**
     * The left position as the horizontal axis. If it's a number, it is
     * interpreted as pixel position relative to the chart.
     *
     * Since Highcharts v5.0.13: If it's a percentage string, it is
     * interpreted as percentages of the plot width, offset from plot area
     * left.
     *
     * @sample {highcharts} highcharts/xaxis/axis-position-properties
     *         Different axis position properties
     *
     * @type      {number|string}
     * @product   highcharts highstock
     * @apioption xAxis.left
     */
    /**
     * The top position as the vertical axis. If it's a number, it is
     * interpreted as pixel position relative to the chart.
     *
     * Since Highcharts 2: If it's a percentage string, it is interpreted
     * as percentages of the plot height, offset from plot area top.
     *
     * @sample {highcharts} highcharts/xaxis/axis-position-properties
     *         Different axis position properties
     *
     * @type      {number|string}
     * @product   highcharts highstock
     * @apioption xAxis.top
     */
    /**
     * Index of another axis that this axis is linked to. When an axis is
     * linked to a master axis, it will take the same extremes as
     * the master, but as assigned by min or max or by setExtremes.
     * It can be used to show additional info, or to ease reading the
     * chart by duplicating the scales.
     *
     * @sample {highcharts} highcharts/xaxis/linkedto/
     *         Different string formats of the same date
     * @sample {highcharts} highcharts/yaxis/linkedto/
     *         Y values on both sides
     *
     * @type      {number}
     * @since     2.0.2
     * @product   highcharts highstock gantt
     * @apioption xAxis.linkedTo
     */
    /**
     * The maximum value of the axis. If `undefined`, the max value is
     * automatically calculated.
     *
     * If a datetime string is passed, it is parsed into epoch time
     * according to the time zone given in [time.timezone](#time.timezone).
     *
     * If the [endOnTick](#yAxis.endOnTick) option is true, the `max` value
     * might be rounded up.
     *
     * If a [tickAmount](#yAxis.tickAmount) is set, the axis may be extended
     * beyond the set max in order to reach the given number of ticks. The
     * same may happen in a chart with multiple axes, determined by [chart.
     * alignTicks](#chart), where a `tickAmount` is applied internally.
     *
     * @sample {highcharts} highcharts/yaxis/max-200/
     *         Y axis max of 200
     * @sample {highcharts} highcharts/yaxis/max-logarithmic/
     *         Y axis max on logarithmic axis
     * @sample {highstock} stock/xaxis/min-max/
     *         Fixed min and max on X axis
     *
     * @type      {number|string|null}
     * @apioption xAxis.max
     */
    /**
     * Padding of the max value relative to the length of the axis. A
     * padding of 0.05 will make a 100px axis 5px longer. This is useful
     * when you don't want the highest data value to appear on the edge
     * of the plot area. When the axis' `max` option is set or a max extreme
     * is set using `axis.setExtremes()`, the maxPadding will be ignored.
     *
     * @productdesc {highstock}
     * For an [ordinal](#xAxis.ordinal) axis, `minPadding` and `maxPadding`
     * are ignored. Use [overscroll](#xAxis.overscroll) instead.
     *
     * @sample {highcharts} highcharts/yaxis/maxpadding/
     *         Max padding of 0.25 on y axis
     * @sample {highstock} stock/xaxis/minpadding-maxpadding/
     *         Greater min- and maxPadding
     * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
     *         Add some padding
     *
     * @default   {highcharts} 0.01
     * @default   {highstock|highmaps} 0
     * @since     1.2.0
     */
    maxPadding: 0.01,
    /**
     * Deprecated. Use `minRange` instead.
     *
     * @deprecated
     * @type      {number}
     * @product   highcharts highstock
     * @apioption xAxis.maxZoom
     */
    /**
     * The minimum value of the axis. If `undefined`, the min value is
     * automatically calculated.
     *
     * If a datetime string is passed, it is parsed into epoch time
     * according to the time zone given in [time.timezone](#time.timezone).
     *
     * If the [startOnTick](#yAxis.startOnTick) option is true (default),
     * the `min` value might be rounded down.
     *
     * The automatically calculated minimum value is also affected by
     * [floor](#yAxis.floor), [softMin](#yAxis.softMin),
     * [minPadding](#yAxis.minPadding), [minRange](#yAxis.minRange)
     * as well as [series.threshold](#plotOptions.series.threshold)
     * and [series.softThreshold](#plotOptions.series.softThreshold).
     *
     * @sample {highcharts} highcharts/yaxis/min-startontick-false/
     *         -50 with startOnTick to false
     * @sample {highcharts} highcharts/yaxis/min-startontick-true/
     *         -50 with startOnTick true by default
     * @sample {highstock} stock/xaxis/min-max/
     *         Set min and max on X axis
     *
     * @type      {number|string|null}
     * @apioption xAxis.min
     */
    /**
     * The dash or dot style of the minor grid lines. For possible values,
     * see [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
     *
     * @sample {highcharts} highcharts/yaxis/minorgridlinedashstyle/
     *         Long dashes on minor grid lines
     * @sample {highstock} stock/xaxis/minorgridlinedashstyle/
     *         Long dashes on minor grid lines
     *
     * @type      {Highcharts.DashStyleValue}
     * @since     1.2
     */
    minorGridLineDashStyle: "Solid",
    /**
     * Specific tick interval in axis units for the minor ticks. On a linear
     * axis, if `"auto"`, the minor tick interval is calculated as a fifth
     * of the tickInterval. If `undefined`, minor ticks are not shown.
     *
     * On logarithmic axes, the unit is the power of the value. For example,
     * setting the minorTickInterval to 1 puts one tick on each of 0.1, 1,
     * 10, 100 etc. Setting the minorTickInterval to 0.1 produces 9 ticks
     * between 1 and 10, 10 and 100 etc.
     *
     * If user settings dictate minor ticks to become too dense, they don't
     * make sense, and will be ignored to prevent performance problems.
     *
     * @sample {highcharts} highcharts/yaxis/minortickinterval-null/
     *         Undefined by default
     * @sample {highcharts} highcharts/yaxis/minortickinterval-5/ 5 units
     * @sample {highcharts} highcharts/yaxis/minortickinterval-log-auto/
     *         "auto"
     * @sample {highcharts} highcharts/yaxis/minortickinterval-log/ 0.1
     * @sample {highstock} stock/demo/basic-line/ Null by default
     * @sample {highstock} stock/xaxis/minortickinterval-auto/ "auto"
     *
     * @type      {number|'auto'}
     * @apioption xAxis.minorTickInterval
     */
    /**
     * The pixel length of the minor tick marks.
     *
     * @sample {highcharts} highcharts/yaxis/minorticklength/
     *         10px on Y axis
     * @sample {highstock} stock/xaxis/minorticks/
     *         10px on Y axis
     */
    minorTickLength: 2,
    /**
     * The position of the minor tick marks relative to the axis line.
     *  Can be one of `inside` and `outside`.
     *
     * @sample {highcharts} highcharts/yaxis/minortickposition-outside/
     *         Outside by default
     * @sample {highcharts} highcharts/yaxis/minortickposition-inside/
     *         Inside
     * @sample {highstock} stock/xaxis/minorticks/
     *         Inside
     *
     * @validvalue ["inside", "outside"]
     */
    minorTickPosition: "outside",
    /**
     * Enable or disable minor ticks. The interval between the minor ticks
     * can be controlled either by the
     * [minorTicksPerMajor](#xAxis.minorTicksPerMajor) setting, or as an
     * absolute [minorTickInterval](#xAxis.minorTickInterval) value.
     *
     * On a logarithmic axis, minor ticks are laid out based on a best
     * guess, attempting to enter an approximate number of minor ticks
     * between each major tick based on
     * [minorTicksPerMajor](#xAxis.minorTicksPerMajor).
     *
     * Prior to v6.0.0, ticks were enabled in auto layout by setting
     * `minorTickInterval` to `"auto"`.
     *
     * @productdesc {highcharts} On axes using
     * [categories](#xAxis.categories), minor ticks are not supported.
     *
     * @sample {highcharts} highcharts/yaxis/minorticks-true/ Enabled on
     *         linear Y axis
     *
     * @type      {boolean}
     * @default   false
     * @since     6.0.0
     * @apioption xAxis.minorTicks
     */
    /**
     * The number of minor ticks per major tick. Works for `linear`,
     * `logarithmic` and `datetime` axes.
     *
     * @sample {highcharts} highcharts/yaxis/minortickspermajor/
     *         2 minor ticks per major tick on Y axis
     *
     * @since  11.0.0
     *
     * @type {number}
     */
    minorTicksPerMajor: 5,
    /**
     * The pixel width of the minor tick mark.
     *
     * @sample {highcharts} highcharts/yaxis/minortickwidth/
     *         3px width
     * @sample {highstock} stock/xaxis/minorticks/
     *         1px width
     *
     * @type      {number}
     * @default   0
     * @apioption xAxis.minorTickWidth
     */
    /**
     * Padding of the min value relative to the length of the axis. A
     * padding of 0.05 will make a 100px axis 5px longer. This is useful
     * when you don't want the lowest data value to appear on the edge
     * of the plot area. When the axis' `min` option is set or a min extreme
     * is set using `axis.setExtremes()`, the minPadding will be ignored.
     *
     * @productdesc {highstock}
     * For an [ordinal](#xAxis.ordinal) axis, `minPadding` and `maxPadding`
     * are ignored. Use [overscroll](#xAxis.overscroll) instead.
     *
     * @sample {highcharts} highcharts/yaxis/minpadding/
     *         Min padding of 0.2
     * @sample {highstock} stock/xaxis/minpadding-maxpadding/
     *         Greater min- and maxPadding
     * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/
     *         Add some padding
     *
     * @default    {highcharts} 0.01
     * @default    {highstock|highmaps} 0
     * @since      1.2.0
     * @product    highcharts highstock gantt
     */
    minPadding: 0.01,
    /**
     * The minimum range to display on this axis. The entire axis will not
     * be allowed to span over a smaller interval than this. For example,
     * for a datetime axis the main unit is milliseconds. If minRange is
     * set to 3600000, you can't zoom in more than to one hour.
     *
     * The default minRange for the x axis is five times the smallest
     * interval between any of the data points.
     *
     * On a logarithmic axis, the unit for the minimum range is the power.
     * So a minRange of 1 means that the axis can be zoomed to 10-100,
     * 100-1000, 1000-10000 etc.
     *
     * **Note**: The `minPadding`, `maxPadding`, `startOnTick` and
     * `endOnTick` settings also affect how the extremes of the axis
     * are computed.
     *
     * @sample {highcharts} highcharts/xaxis/minrange/
     *         Minimum range of 5
     * @sample {highstock} stock/xaxis/minrange/
     *         Max zoom of 6 months overrides user selections
     *
     * @type      {number}
     * @apioption xAxis.minRange
     */
    /**
     * The minimum tick interval allowed in axis values. For example on
     * zooming in on an axis with daily data, this can be used to prevent
     * the axis from showing hours. Defaults to the closest distance between
     * two points on the axis.
     *
     * @type      {number}
     * @since     2.3.0
     * @apioption xAxis.minTickInterval
     */
    /**
     * The distance in pixels from the plot area to the axis line.
     * A positive offset moves the axis with it's line, labels and ticks
     * away from the plot area. This is typically used when two or more
     * axes are displayed on the same side of the plot. With multiple
     * axes the offset is dynamically adjusted to avoid collision, this
     * can be overridden by setting offset explicitly.
     *
     * @sample {highcharts} highcharts/yaxis/offset/
     *         Y axis offset of 70
     * @sample {highcharts} highcharts/yaxis/offset-centered/
     *         Axes positioned in the center of the plot
     * @sample {highstock} stock/xaxis/offset/
     *         Y axis offset by 70 px
     *
     * @type {number}
     */
    offset: void 0,
    /**
     * Whether to display the axis on the opposite side of the normal. The
     * normal is on the left side for vertical axes and bottom for
     * horizontal, so the opposite sides will be right and top respectively.
     * This is typically used with dual or multiple axes.
     *
     * @sample {highcharts} highcharts/yaxis/opposite/
     *         Secondary Y axis opposite
     * @sample {highstock} stock/xaxis/opposite/
     *         Y axis on left side
     *
     * @default   {highcharts|highstock|highmaps} false
     * @default   {gantt} true
     * @type      Boolean
     * @apioption xAxis.opposite
     */
    /**
     * In an ordinal axis, the points are equally spaced in the chart
     * regardless of the actual time or x distance between them. This means
     * that missing data periods (e.g. nights or weekends for a stock chart)
     * will not take up space in the chart.
     * Having `ordinal: false` will show any gaps created by the `gapSize`
     * setting proportionate to their duration.
     *
     * In stock charts the X axis is ordinal by default, unless
     * the boost module is used and at least one of the series' data length
     * exceeds the [boostThreshold](#series.line.boostThreshold).
     *
     * For an ordinal axis, `minPadding` and `maxPadding` are ignored. Use
     * [overscroll](#xAxis.overscroll) instead.
     *
     * @sample {highstock} stock/xaxis/ordinal-true/
     *         True by default
     * @sample {highstock} stock/xaxis/ordinal-false/
     *         False
     *
     * @see [overscroll](#xAxis.overscroll)
     *
     * @type      {boolean}
     * @default   true
     * @since     1.1
     * @product   highstock
     * @apioption xAxis.ordinal
     */
    /**
     * Additional range on the right side of the xAxis. Works similar to
     * `xAxis.maxPadding`, but the value is set in terms of axis values,
     * percentage or pixels.
     *
     * If it's a number, it is interpreted as axis values, which in a
     * datetime axis equals milliseconds.
     *
     * If it's a percentage string, is interpreted as percentages of axis
     * length. An overscroll of 50% will make a 100px axis 50px longer.
     *
     * If it's a pixel string, it is interpreted as a fixed pixel value, but
     * limited to 90% of the axis length.
     *
     * @sample {highstock} stock/xaxis/overscroll/ One minute overscroll
     *         with live data
     * @sample {highstock} stock/xaxis/overscroll-percent/ Overscroll set in
     *         percentage
     * @sample {highstock} stock/xaxis/overscroll-pixel/ Overscroll set in
     *         pixels
     *
     * @type      {number | string}
     * @default   0
     * @since     6.0.0
     * @product   highstock
     * @apioption xAxis.overscroll
     */
    /**
     * Refers to the index in the [panes](#panes) array. Used for circular
     * gauges and polar charts. When the option is not set then first pane
     * will be used.
     *
     * @sample highcharts/demo/gauge-vu-meter
     *         Two gauges with different center
     *
     * @type      {number}
     * @product   highcharts
     * @apioption xAxis.pane
     */
    /**
     * The zoomed range to display when only defining one or none of `min`
     * or `max`. For example, to show the latest month, a range of one month
     * can be set.
     *
     * @sample {highstock} stock/xaxis/range/
     *         Setting a zoomed range when the rangeSelector is disabled
     *
     * @type      {number}
     * @product   highstock
     * @apioption xAxis.range
     */
    /**
     * Whether to reverse the axis so that the highest number is closest
     * to the origin. If the chart is inverted, the x axis is reversed by
     * default.
     *
     * @sample {highcharts} highcharts/yaxis/reversed/
     *         Reversed Y axis
     * @sample {highstock} stock/xaxis/reversed/
     *         Reversed Y axis
     *
     * @type      {boolean}
     * @default   undefined
     * @apioption xAxis.reversed
     */
    reversed: void 0,
    /**
     * This option determines how stacks should be ordered within a group.
     * For example reversed xAxis also reverses stacks, so first series
     * comes last in a group. To keep order like for non-reversed xAxis
     * enable this option.
     *
     * @sample {highcharts} highcharts/xaxis/reversedstacks/
     *         Reversed stacks comparison
     * @sample {highstock} highcharts/xaxis/reversedstacks/
     *         Reversed stacks comparison
     *
     * @since     6.1.1
     * @product   highcharts highstock
     */
    reversedStacks: false,
    /**
     * An optional scrollbar to display on the X axis in response to
     * limiting the minimum and maximum of the axis values.
     *
     * In styled mode, all the presentational options for the scrollbar are
     * replaced by the classes `.highcharts-scrollbar-thumb`,
     * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
     * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
     *
     * @sample {highstock} stock/yaxis/heatmap-scrollbars/
     *         Heatmap with both scrollbars
     *
     * @extends   scrollbar
     * @since     4.2.6
     * @product   highstock
     * @apioption xAxis.scrollbar
     */
    /**
     * Whether to show the axis line and title when the axis has no data.
     *
     * @sample {highcharts} highcharts/yaxis/showempty/
     *         When clicking the legend to hide series, one axis preserves
     *         line and title, the other doesn't
     * @sample {highstock} highcharts/yaxis/showempty/
     *         When clicking the legend to hide series, one axis preserves
     *         line and title, the other doesn't
     *
     * @since     1.1
     */
    showEmpty: true,
    /**
     * Whether to show the first tick label.
     *
     * @sample {highcharts} highcharts/xaxis/showfirstlabel-false/
     *         Set to false on X axis
     * @sample {highstock} stock/xaxis/showfirstlabel/
     *         Labels below plot lines on Y axis
     */
    showFirstLabel: true,
    /**
     * Whether to show the last tick label. Defaults to `true` on cartesian
     * charts, and `false` on polar charts.
     *
     * @sample {highcharts} highcharts/xaxis/showlastlabel-true/
     *         Set to true on X axis
     * @sample {highstock} stock/xaxis/showfirstlabel/
     *         Labels below plot lines on Y axis
     *
     * @type    {boolean}
     * @default undefined
     * @product highcharts highstock gantt
     */
    showLastLabel: true,
    /**
     * A soft maximum for the axis. If the series data maximum is less than
     * this, the axis will stay at this maximum, but if the series data
     * maximum is higher, the axis will flex to show all data.
     *
     * @sample highcharts/yaxis/softmin-softmax/
     *         Soft min and max
     *
     * @type      {number}
     * @since     5.0.1
     * @product   highcharts highstock gantt
     * @apioption xAxis.softMax
     */
    /**
     * A soft minimum for the axis. If the series data minimum is greater
     * than this, the axis will stay at this minimum, but if the series
     * data minimum is lower, the axis will flex to show all data.
     *
     * @sample highcharts/yaxis/softmin-softmax/
     *         Soft min and max
     *
     * @type      {number}
     * @since     5.0.1
     * @product   highcharts highstock gantt
     * @apioption xAxis.softMin
     */
    /**
     * For datetime axes, this decides where to put the tick between weeks.
     *  0 = Sunday, 1 = Monday.
     *
     * @sample {highcharts} highcharts/xaxis/startofweek-monday/
     *         Monday by default
     * @sample {highcharts} highcharts/xaxis/startofweek-sunday/
     *         Sunday
     * @sample {highstock} stock/xaxis/startofweek-1
     *         Monday by default
     * @sample {highstock} stock/xaxis/startofweek-0
     *         Sunday
     *
     * @product highcharts highstock gantt
     */
    startOfWeek: 1,
    /**
     * Whether to force the axis to start on a tick. Use this option with
     * the `minPadding` option to control the axis start.
     *
     * @productdesc {highstock}
     * In Highcharts Stock, `startOnTick` is always `false` when
     * the navigator is enabled, to prevent jumpy scrolling.
     *
     * @sample {highcharts} highcharts/xaxis/startontick-false/
     *         False by default
     * @sample {highcharts} highcharts/xaxis/startontick-true/
     *         True
     *
     * @since 1.2.0
     */
    startOnTick: false,
    /**
     * The amount of ticks to draw on the axis. This opens up for aligning
     * the ticks of multiple charts or panes within a chart. This option
     * overrides the `tickPixelInterval` option.
     *
     * This option only has an effect on linear axes. Datetime, logarithmic
     * or category axes are not affected.
     *
     * @sample {highcharts} highcharts/yaxis/tickamount/
     *         8 ticks on Y axis
     * @sample {highstock} highcharts/yaxis/tickamount/
     *         8 ticks on Y axis
     *
     * @type      {number}
     * @since     4.1.0
     * @product   highcharts highstock gantt
     * @apioption xAxis.tickAmount
     */
    /**
     * The interval of the tick marks in axis units. When `undefined`, the
     * tick interval is computed to approximately follow the
     * [tickPixelInterval](#xAxis.tickPixelInterval) on linear and datetime
     * axes. On categorized axes, a `undefined` tickInterval will default to
     * 1, one category. Note that datetime axes are based on milliseconds,
     * so for example an interval of one day is expressed as
     * `24 * 3600 * 1000`.
     *
     * On logarithmic axes, the tickInterval is based on powers, so a
     * tickInterval of 1 means one tick on each of 0.1, 1, 10, 100 etc. A
     * tickInterval of 2 means a tick of 0.1, 10, 1000 etc. A tickInterval
     * of 0.2 puts a tick on 0.1, 0.2, 0.4, 0.6, 0.8, 1, 2, 4, 6, 8, 10, 20,
     * 40 etc.
     *
     *
     * If the tickInterval is too dense for labels to be drawn, Highcharts
     * may remove ticks.
     *
     * If the chart has multiple axes, the [alignTicks](#chart.alignTicks)
     * option may interfere with the `tickInterval` setting.
     *
     * @see [tickPixelInterval](#xAxis.tickPixelInterval)
     * @see [tickPositions](#xAxis.tickPositions)
     * @see [tickPositioner](#xAxis.tickPositioner)
     *
     * @sample {highcharts} highcharts/xaxis/tickinterval-5/
     *         Tick interval of 5 on a linear axis
     * @sample {highstock} stock/xaxis/tickinterval/
     *         Tick interval of 0.01 on Y axis
     *
     * @type      {number}
     * @apioption xAxis.tickInterval
     */
    /**
     * The pixel length of the main tick marks.
     *
     * @sample {highcharts} highcharts/xaxis/ticklength/
     *         20 px tick length on the X axis
     * @sample {highstock} stock/xaxis/ticks/
     *         Formatted ticks on X axis
     */
    tickLength: 10,
    /**
     * If tickInterval is `null` this option sets the approximate pixel
     * interval of the tick marks. Not applicable to categorized axis.
     *
     * The tick interval is also influenced by the [minTickInterval](
     * #xAxis.minTickInterval) option, that, by default prevents ticks from
     * being denser than the data points.
     *
     * @see [tickInterval](#xAxis.tickInterval)
     * @see [tickPositioner](#xAxis.tickPositioner)
     * @see [tickPositions](#xAxis.tickPositions)
     *
     * @sample {highcharts} highcharts/xaxis/tickpixelinterval-50/
     *         50 px on X axis
     * @sample {highstock} stock/xaxis/tickpixelinterval/
     *         200 px on X axis
     */
    tickPixelInterval: 100,
    /**
     * For categorized axes only. If `on` the tick mark is placed in the
     * center of the category, if `between` the tick mark is placed between
     * categories. The default is `between` if the `tickInterval` is 1, else
     * `on`. In order to render tick marks on a category axis it is necessary
     * to provide a [tickWidth](#xAxis.tickWidth).
     *
     * @sample {highcharts} highcharts/xaxis/tickmarkplacement-between/
     *         "between" by default
     * @sample {highcharts} highcharts/xaxis/tickmarkplacement-on/
     *         "on"
     *
     * @product    highcharts gantt
     * @validvalue ["on", "between"]
     */
    tickmarkPlacement: "between",
    /**
     * The position of the major tick marks relative to the axis line.
     * Can be one of `inside` and `outside`.
     *
     * @sample {highcharts} highcharts/xaxis/tickposition-outside/
     *         "outside" by default
     * @sample {highcharts} highcharts/xaxis/tickposition-inside/
     *         "inside"
     * @sample {highstock} stock/xaxis/ticks/
     *         Formatted ticks on X axis
     *
     * @validvalue ["inside", "outside"]
     */
    tickPosition: "outside",
    /**
     * A callback function returning array defining where the ticks are
     * laid out on the axis. This overrides the default behaviour of
     * [tickPixelInterval](#xAxis.tickPixelInterval) and [tickInterval](
     * #xAxis.tickInterval). The automatic tick positions are accessible
     * through `this.tickPositions` and can be modified by the callback.
     *
     * @see [tickPositions](#xAxis.tickPositions)
     *
     * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/
     *         Demo of tickPositions and tickPositioner
     * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/
     *         Demo of tickPositions and tickPositioner
     *
     * @type      {Highcharts.AxisTickPositionerCallbackFunction}
     * @apioption xAxis.tickPositioner
     */
    /**
     * An array defining where the ticks are laid out on the axis. This
     * overrides the default behaviour of [tickPixelInterval](
     * #xAxis.tickPixelInterval) and [tickInterval](#xAxis.tickInterval).
     *
     * @see [tickPositioner](#xAxis.tickPositioner)
     *
     * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/
     *         Demo of tickPositions and tickPositioner
     * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/
     *         Demo of tickPositions and tickPositioner
     *
     * @type      {Array<number>}
     * @apioption xAxis.tickPositions
     */
    /**
     * The pixel width of the major tick marks. Defaults to 0 on category
     * axes, otherwise 1.
     *
     * In styled mode, the stroke width is given in the `.highcharts-tick`
     * class, but in order for the element to be generated on category axes,
     * the option must be explicitly set to 1.
     *
     * @sample {highcharts} highcharts/xaxis/tickwidth/
     *         10 px width
     * @sample {highcharts} highcharts/css/axis-grid/
     *         Styled mode
     * @sample {highstock} stock/xaxis/ticks/
     *         Formatted ticks on X axis
     * @sample {highstock} highcharts/css/axis-grid/
     *         Styled mode
     *
     * @type      {undefined|number}
     * @default   {highstock} 1
     * @default   {highmaps} 0
     * @apioption xAxis.tickWidth
     */
    /**
     * The axis title, showing next to the axis line.
     *
     * @productdesc {highmaps}
     * In Highmaps, the axis is hidden by default, but adding an axis title
     * is still possible. X axis and Y axis titles will appear at the bottom
     * and left by default.
     */
    title: {
      /**
       * Alignment of the title relative to the axis values. Possible
       * values are "low", "middle" or "high".
       *
       * @sample {highcharts} highcharts/xaxis/title-align-low/
       *         "low"
       * @sample {highcharts} highcharts/xaxis/title-align-center/
       *         "middle" by default
       * @sample {highcharts} highcharts/xaxis/title-align-high/
       *         "high"
       * @sample {highcharts} highcharts/yaxis/title-offset/
       *         Place the Y axis title on top of the axis
       * @sample {highstock} stock/xaxis/title-align/
       *         Aligned to "high" value
       *
       * @type {Highcharts.AxisTitleAlignValue}
       */
      align: "middle",
      /**
       * Deprecated. Set the `text` to `undefined` to disable the title.
       *
       * @deprecated
       * @type      {boolean}
       * @product   highcharts
       * @apioption xAxis.title.enabled
       */
      /**
       * The pixel distance between the axis labels or line and the title.
       * Defaults to 0 for horizontal axes, 10 for vertical
       *
       * @sample {highcharts} highcharts/xaxis/title-margin/
       *         Y axis title margin of 60
       *
       * @type      {number}
       * @apioption xAxis.title.margin
       */
      /**
       * The distance of the axis title from the axis line. By default,
       * this distance is computed from the offset width of the labels,
       * the labels' distance from the axis and the title's margin.
       * However when the offset option is set, it overrides all this.
       *
       * @sample {highcharts} highcharts/yaxis/title-offset/
       *         Place the axis title on top of the axis
       * @sample {highstock} highcharts/yaxis/title-offset/
       *         Place the axis title on top of the Y axis
       *
       * @type      {number}
       * @since     2.2.0
       * @apioption xAxis.title.offset
       */
      /**
       * Whether to reserve space for the title when laying out the axis.
       *
       * @type      {boolean}
       * @default   true
       * @since     5.0.11
       * @product   highcharts highstock gantt
       * @apioption xAxis.title.reserveSpace
       */
      /**
       * The rotation of the text in degrees. 0 is horizontal, 270 is
       * vertical reading from bottom to top. Defaults to 0 for horizontal
       * axes, 270 for left-side axes and 90 for right-side axes.
       *
       * @sample    {highcharts} highcharts/yaxis/title-offset/
       *            Horizontal
       *
       * @type      {number}
       * @default   undefined
       * @apioption xAxis.title.rotation
       */
      /**
       * The actual text of the axis title. It can contain basic HTML tags
       * like `b`, `i` and `span` with style.
       *
       * @sample {highcharts} highcharts/xaxis/title-text/
       *         Custom HTML
       * @sample {highstock} stock/xaxis/title-text/
       *         Titles for both axes
       *
       * @type      {string|null}
       * @apioption xAxis.title.text
       */
      /**
       * Alignment of the text, can be `"left"`, `"right"` or `"center"`.
       * Default alignment depends on the
       * [title.align](xAxis.title.align):
       *
       * Horizontal axes:
       * - for `align` = `"low"`, `textAlign` is set to `left`
       * - for `align` = `"middle"`, `textAlign` is set to `center`
       * - for `align` = `"high"`, `textAlign` is set to `right`
       *
       * Vertical axes:
       * - for `align` = `"low"` and `opposite` = `true`, `textAlign` is
       *   set to `right`
       * - for `align` = `"low"` and `opposite` = `false`, `textAlign` is
       *   set to `left`
       * - for `align` = `"middle"`, `textAlign` is set to `center`
       * - for `align` = `"high"` and `opposite` = `true` `textAlign` is
       *   set to `left`
       * - for `align` = `"high"` and `opposite` = `false` `textAlign` is
       *   set to `right`
       *
       * @type      {Highcharts.AlignValue}
       * @apioption xAxis.title.textAlign
       */
      /**
       * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
       * to render the axis title.
       *
       * @product   highcharts highstock gantt
       */
      useHTML: false,
      /**
       * Horizontal pixel offset of the title position.
       *
       * @since     4.1.6
       * @product   highcharts highstock gantt
       */
      x: 0,
      /**
       * Vertical pixel offset of the title position.
       *
       * @product   highcharts highstock gantt
       */
      y: 0,
      /**
       * CSS styles for the title. If the title text is longer than the
       * axis length, it will wrap to multiple lines by default. This can
       * be customized by setting the `lineClamp` property, by setting a
       * specific `width` or by setting `whiteSpace: 'nowrap'`.
       *
       * In styled mode, the stroke width is given in the
       * `.highcharts-axis-title` class.
       *
       * @sample {highcharts} highcharts/xaxis/title-style/
       *         Red
       * @sample {highcharts} highcharts/css/axis/
       *         Styled mode
       *
       * @type    {Highcharts.CSSObject}
       */
      style: {
        /** @internal */
        color: "#666666",
        /**
         * @type {number|string}
         */
        fontSize: "0.8em"
      }
    },
    /**
     * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`
     * or `category`. In a datetime axis, the numbers are given in
     * milliseconds, and tick marks are placed on appropriate values like
     * full hours or days. In a category axis, the
     * [point names](#series.line.data.name) of the chart's series are used
     * for categories, if not a [categories](#xAxis.categories) array is
     * defined.
     *
     * @sample {highcharts} highcharts/xaxis/type-linear/
     *         Linear
     * @sample {highcharts} highcharts/yaxis/type-log/
     *         Logarithmic
     * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/
     *         Logarithmic with minor grid lines
     * @sample {highcharts} highcharts/xaxis/type-log-both/
     *         Logarithmic on two axes
     * @sample {highcharts} highcharts/yaxis/type-log-negative/
     *         Logarithmic with extension to emulate negative values
     *
     * @type    {Highcharts.AxisTypeValue}
     * @default linear
     * @product highcharts gantt
     * @apioption xAxis.type
     */
    /**
     * If there are multiple axes on the same side of the chart, the pixel
     * margin between the axes. Defaults to 0 on vertical axes, 15 on
     * horizontal axes.
     *
     * @type      {number}
     * @since     7.0.3
     * @apioption xAxis.margin
     */
    /**
     * Applies only when the axis `type` is `category`. When `uniqueNames`
     * is true, points are placed on the X axis according to their names.
     * If the same point name is repeated in the same or another series,
     * the point is placed on the same X position as other points of the
     * same name. When `uniqueNames` is false, the points are laid out in
     * increasing X positions regardless of their names, and the X axis
     * category will take the name of the last point in each position.
     *
     * @sample {highcharts} highcharts/xaxis/uniquenames-true/
     *         True by default
     * @sample {highcharts} highcharts/xaxis/uniquenames-false/
     *         False
     *
     * @since     4.2.7
     * @product   highcharts gantt
     * @type      {boolean}
     * @default   true
     * @apioption xAxis.uniqueNames
     */
    /**
     * Datetime axis only. An array determining what time intervals the
     * ticks are allowed to fall on. Each array item is an array where the
     * first value is the time unit and the second value another array of
     * allowed multiples.
     *
     * Defaults to:
     * ```js
     * units: [[
     *     'millisecond', // unit name
     *     [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
     * ], [
     *     'second',
     *     [1, 2, 5, 10, 15, 30]
     * ], [
     *     'minute',
     *     [1, 2, 5, 10, 15, 30]
     * ], [
     *     'hour',
     *     [1, 2, 3, 4, 6, 8, 12]
     * ], [
     *     'day',
     *     [1, 2]
     * ], [
     *     'week',
     *     [1, 2]
     * ], [
     *     'month',
     *     [1, 2, 3, 4, 6]
     * ], [
     *     'year',
     *     null
     * ]]
     * ```
     *
     * @sample {highcharts} highcharts/xaxis/units/
     *         Axis units demonstrated
     *
     * @type      {Array<Array<string,(Array<number>|null)>>}
     * @product   highcharts highstock gantt
     * @apioption xAxis.units
     */
    /**
     * Whether axis, including axis title, line, ticks and labels, should
     * be visible.
     *
     * @since     4.1.9
     * @product   highcharts highstock gantt
     */
    visible: true,
    /**
     * Color of the minor, secondary grid lines.
     *
     * In styled mode, the stroke width is given in the
     * `.highcharts-minor-grid-line` class.
     *
     * @sample {highcharts} highcharts/yaxis/minorgridlinecolor/
     *         Bright grey lines from Y axis
     * @sample {highcharts|highstock} highcharts/css/axis-grid/
     *         Styled mode
     * @sample {highstock} stock/xaxis/minorgridlinecolor/
     *         Bright grey lines from Y axis
     *
     * @type    {Highcharts.ColorType}
     * @default #f2f2f2
     */
    minorGridLineColor: "#f2f2f2",
    /**
     * Width of the minor, secondary grid lines.
     *
     * In styled mode, the stroke width is given in the
     * `.highcharts-grid-line` class.
     *
     * @sample {highcharts} highcharts/yaxis/minorgridlinewidth/
     *         2px lines from Y axis
     * @sample {highcharts|highstock} highcharts/css/axis-grid/
     *         Styled mode
     * @sample {highstock} stock/xaxis/minorgridlinewidth/
     *         2px lines from Y axis
     */
    minorGridLineWidth: 1,
    /**
     * Color for the minor tick marks.
     *
     * @sample {highcharts} highcharts/yaxis/minortickcolor/
     *         Black tick marks on Y axis
     * @sample {highstock} stock/xaxis/minorticks/
     *         Black tick marks on Y axis
     *
     * @type    {Highcharts.ColorType}
     * @default #999999
     */
    minorTickColor: "#999999",
    /**
     * The color of the line marking the axis itself.
     *
     * In styled mode, the line stroke is given in the
     * `.highcharts-axis-line` or `.highcharts-xaxis-line` class.
     *
     * @sample {highcharts} highcharts/yaxis/linecolor/
     *         A red line on Y axis
     * @sample {highcharts|highstock} highcharts/css/axis/
     *         Axes in styled mode
     * @sample {highstock} stock/xaxis/linecolor/
     *         A red line on X axis
     *
     * @type    {Highcharts.ColorType}
     */
    lineColor: "#333333",
    /**
     * The width of the line marking the axis itself.
     *
     * In styled mode, the stroke width is given in the
     * `.highcharts-axis-line` or `.highcharts-xaxis-line` class.
     *
     * @sample {highcharts} highcharts/yaxis/linecolor/
     *         A 1px line on Y axis
     * @sample {highcharts|highstock} highcharts/css/axis/
     *         Axes in styled mode
     * @sample {highstock} stock/xaxis/linewidth/
     *         A 2px line on X axis
     *
     * @default {highcharts|highstock} 1
     * @default {highmaps} 0
     */
    lineWidth: 1,
    /**
     * Color of the grid lines extending the ticks across the plot area.
     *
     * In styled mode, the stroke is given in the `.highcharts-grid-line`
     * class.
     *
     * @productdesc {highmaps}
     * In Highmaps, the grid lines are hidden by default.
     *
     * @sample {highcharts} highcharts/yaxis/gridlinecolor/
     *         Green lines
     * @sample {highcharts|highstock} highcharts/css/axis-grid/
     *         Styled mode
     * @sample {highstock} stock/xaxis/gridlinecolor/
     *         Green lines
     *
     * @type    {Highcharts.ColorType}
     * @default #e6e6e6
     */
    gridLineColor: "#e6e6e6",
    /**
     * The width of the grid lines extending the ticks across the plot area.
     * Defaults to 1 on the Y axis and 0 on the X axis, except for 3d
     * charts.
     *
     * In styled mode, the stroke width is given in the
     * `.highcharts-grid-line` class.
     *
     * @sample {highcharts} highcharts/yaxis/gridlinewidth/
     *         2px lines
     * @sample {highcharts|highstock} highcharts/css/axis-grid/
     *         Styled mode
     * @sample {highstock} stock/xaxis/gridlinewidth/
     *         2px lines
     *
     * @type      {number}
     * @apioption xAxis.gridLineWidth
     */
    gridLineWidth: void 0,
    /**
     * The height as the vertical axis. If it's a number, it is
     * interpreted as pixels.
     *
     * Since Highcharts 2: If it's a percentage string, it is interpreted
     * as percentages of the total plot height.
     *
     * @sample {highcharts} highcharts/xaxis/axis-position-properties
     *         Different axis position properties
     *
     * @type      {number|string}
     * @product   highcharts highstock
     * @apioption xAxis.height
     */
    /**
     * The width as the horizontal axis. If it's a number, it is interpreted
     * as pixels.
     *
     * Since Highcharts v5.0.13: If it's a percentage string, it is
     * interpreted as percentages of the total plot width.
     *
     * @sample {highcharts} highcharts/xaxis/axis-position-properties
     *         Different axis position properties
     *
     * @type      {number|string}
     * @product   highcharts highstock
     * @apioption xAxis.width
     */
    /**
     * Color for the main tick marks.
     *
     * In styled mode, the stroke is given in the `.highcharts-tick`
     * class.
     *
     * @sample {highcharts} highcharts/xaxis/tickcolor/
     *         Red ticks on X axis
     * @sample {highcharts|highstock} highcharts/css/axis-grid/
     *         Styled mode
     * @sample {highstock} stock/xaxis/ticks/
     *         Formatted ticks on X axis
     *
     * @type    {Highcharts.ColorType}
     */
    tickColor: "#333333"
    /* Palette.neutralColor80 */
    // `tickWidth: 1`
  };
  AxisDefaults2.yAxis = {
    /**
     * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`,
     * `category` or `treegrid`. Defaults to `treegrid` for Gantt charts,
     * `linear` for other chart types.
     *
     * In a datetime axis, the numbers are given in milliseconds, and tick
     * marks are placed on appropriate values, like full hours or days. In a
     * category or treegrid axis, the [point names](#series.line.data.name)
     * of the chart's series are used for categories, if a
     * [categories](#xAxis.categories) array is not defined.
     *
     * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/
     *         Logarithmic with minor grid lines
     * @sample {highcharts} highcharts/yaxis/type-log-negative/
     *         Logarithmic with extension to emulate negative values
     * @sample {gantt} gantt/treegrid-axis/demo
     *         Treegrid axis
     *
     * @type      {Highcharts.AxisTypeValue}
     * @default   {highcharts} linear
     * @default   {gantt} treegrid
     * @product   highcharts gantt
     * @apioption yAxis.type
     */
    /**
     * The height of the Y axis. If it's a number, it is interpreted as
     * pixels.
     *
     * Since Highcharts 2: If it's a percentage string, it is interpreted as
     * percentages of the total plot height.
     *
     * @see [yAxis.top](#yAxis.top)
     *
     * @sample {highstock} stock/demo/candlestick-and-volume/
     *         Percentage height panes
     *
     * @type      {number|string}
     * @product   highcharts highstock
     * @apioption yAxis.height
     */
    /**
     * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color
     * to represent the maximum value of the Y axis.
     *
     * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/
     *         Min and max colors
     *
     * @type      {Highcharts.ColorType}
     * @default   #003399
     * @since     4.0
     * @product   highcharts
     * @apioption yAxis.maxColor
     */
    /**
     * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color
     * to represent the minimum value of the Y axis.
     *
     * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/
     *         Min and max color
     *
     * @type      {Highcharts.ColorType}
     * @default   #e6ebf5
     * @since     4.0
     * @product   highcharts
     * @apioption yAxis.minColor
     */
    /**
     * Whether to reverse the axis so that the highest number is closest
     * to the origin.
     *
     * @sample {highcharts} highcharts/yaxis/reversed/
     *         Reversed Y axis
     * @sample {highstock} stock/xaxis/reversed/
     *         Reversed Y axis
     *
     * @type      {boolean}
     * @default   {highcharts} false
     * @default   {highstock} false
     * @default   {highmaps} true
     * @default   {gantt} true
     * @apioption yAxis.reversed
     */
    /**
     * If `true`, the first series in a stack will be drawn on top in a
     * positive, non-reversed Y axis. If `false`, the first series is in
     * the base of the stack.
     *
     * @sample {highcharts} highcharts/yaxis/reversedstacks-false/
     *         Non-reversed stacks
     * @sample {highstock} highcharts/yaxis/reversedstacks-false/
     *         Non-reversed stacks
     *
     * @type      {boolean}
     * @default   true
     * @since     3.0.10
     * @product   highcharts highstock
     * @apioption yAxis.reversedStacks
     */
    reversedStacks: true,
    /**
     * Solid gauge series only. Color stops for the solid gauge. Use this
     * in cases where a linear gradient between a `minColor` and `maxColor`
     * is not sufficient. The stops is an array of tuples, where the first
     * item is a float between 0 and 1 assigning the relative position in
     * the gradient, and the second item is the color.
     *
     * For solid gauges, the Y axis also inherits the concept of
     * [data classes](https://api.highcharts.com/highmaps#colorAxis.dataClasses)
     * from the Highmaps color axis.
     *
     * @sample {highcharts} highcharts/demo/gauge-solid/
     *         Gauge with stops
     *
     * @see [minColor](#yAxis.minColor)
     * @see [maxColor](#yAxis.maxColor)
     *
     * @type      {Array<Array<number,Highcharts.ColorType>>}
     * @since     4.0
     * @product   highcharts
     * @apioption yAxis.stops
     */
    /**
     * The pixel width of the major tick marks.
     *
     * @sample {highcharts} highcharts/xaxis/tickwidth/ 10 px width
     * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis
     *
     * @type      {number}
     * @default   0
     * @product   highcharts highstock gantt
     * @apioption yAxis.tickWidth
     */
    /**
     * Whether to force the axis to end on a tick. Use this option with
     * the `maxPadding` option to control the axis end.
     *
     * This option is always disabled, when panning type is
     * either `y` or `xy`.
     *
     * @see [type](#chart.panning.type)
     *
     *
     * @sample {highcharts} highcharts/yaxis/endontick/
     *         True by default
     * @sample {highcharts} highcharts/yaxis/endontick-false/
     *         False
     * @sample {highstock} stock/demo/basic-line/
     *         True by default
     * @sample {highstock} stock/xaxis/endontick/
     *         False for Y axis
     *
     * @since 1.2.0
     */
    endOnTick: true,
    /**
     * Padding of the max value relative to the length of the axis. A
     * padding of 0.05 will make a 100px axis 5px longer. This is useful
     * when you don't want the highest data value to appear on the edge
     * of the plot area. When the axis' `max` option is set or a max extreme
     * is set using `axis.setExtremes()`, the maxPadding will be ignored.
     *
     * Also the `softThreshold` option takes precedence over `maxPadding`,
     * so if the data is tangent to the threshold, `maxPadding` may not
     * apply unless `softThreshold` is set to false.
     *
     * @sample {highcharts} highcharts/yaxis/maxpadding-02/
     *         Max padding of 0.2
     * @sample {highstock} stock/xaxis/minpadding-maxpadding/
     *         Greater min- and maxPadding
     *
     * @since   1.2.0
     * @product highcharts highstock gantt
     */
    maxPadding: 0.05,
    /**
     * Padding of the min value relative to the length of the axis. A
     * padding of 0.05 will make a 100px axis 5px longer. This is useful
     * when you don't want the lowest data value to appear on the edge
     * of the plot area. When the axis' `min` option is set or a max extreme
     * is set using `axis.setExtremes()`, the maxPadding will be ignored.
     *
     * Also the `softThreshold` option takes precedence over `minPadding`,
     * so if the data is tangent to the threshold, `minPadding` may not
     * apply unless `softThreshold` is set to false.
     *
     * @sample {highcharts} highcharts/yaxis/minpadding/
     *         Min padding of 0.2
     * @sample {highstock} stock/xaxis/minpadding-maxpadding/
     *         Greater min- and maxPadding
     *
     * @since   1.2.0
     * @product highcharts highstock gantt
     */
    minPadding: 0.05,
    /**
     * @productdesc {highstock}
     * In Highcharts Stock 1.x, the Y axis was placed
     * on the left side by default.
     *
     * @sample {highcharts} highcharts/yaxis/opposite/
     *         Secondary Y axis opposite
     * @sample {highstock} stock/xaxis/opposite/
     *         Y axis on left side
     *
     * @type      {boolean}
     * @default   {highstock} true
     * @default   {highcharts} false
     * @product   highstock highcharts gantt
     * @apioption yAxis.opposite
     */
    /**
     * @see [tickInterval](#xAxis.tickInterval)
     * @see [tickPositioner](#xAxis.tickPositioner)
     * @see [tickPositions](#xAxis.tickPositions)
     */
    tickPixelInterval: 72,
    /**
     * Whether to show the last tick label.
     *
     * @productdesc {highcharts|gantt}
     * Defaults to `true` on cartesian charts, and `false` on polar charts.
     *
     * @productdesc {highstock}
     * Defaults to `true` for categorized yAxis and `false` for other types
     * of yAxis.
     *
     * @default undefined
     */
    showLastLabel: true,
    /**
     * @extends xAxis.labels
     */
    labels: {
      /**
       * The label's pixel distance from the perimeter of the plot area.
       * On cartesian charts, this is overridden if the `labels.y` setting
       * is set.
       *
       * On polar charts, if it's a percentage string, it is interpreted
       * the same as [series.radius](#plotOptions.gauge.radius), so the
       * label can be aligned under the gauge's shape.
       *
       * @sample {highcharts} highcharts/yaxis/labels-distance/
       *         Polar chart, labels centered under the arc
       *
       * @type      {number|string}
       * @product   highcharts
       * @apioption yAxis.labels.distance
       */
      /**
       * The y position offset of all labels relative to the tick
       * positions on the axis. For polar and radial axis consider the use
       * of the [distance](#yAxis.labels.distance) option.
       *
       * @sample {highcharts} highcharts/xaxis/labels-x/
       *         Y axis labels placed on grid lines
       *
       * @type      {number}
       * @default   {highcharts} 3
       * @default   {highstock} -2
       * @default   {highmaps} 3
       * @apioption yAxis.labels.y
       */
      /**
       * What part of the string the given position is anchored to. Can
       * be one of `"left"`, `"center"` or `"right"`. The exact position
       * also depends on the `labels.x` setting.
       *
       * Angular gauges and solid gauges defaults to `"center"`.
       * Solid gauges with two labels have additional option `"auto"`
       * for automatic horizontal and vertical alignment.
       *
       * @sample {highcharts} highcharts/yaxis/labels-align-left/
       *         Left
       * @sample {highcharts} highcharts/series-solidgauge/labels-auto-aligned/
       *         Solid gauge labels auto aligned
       *
       * @type       {Highcharts.AlignValue}
       * @default    {highstock} right
       * @apioption  yAxis.labels.align
       */
      /**
       * The x position offset of all labels relative to the tick
       * positions on the axis. Defaults to -15 for left axis, 15 for
       * right axis.
       *
       * @sample {highcharts} highcharts/xaxis/labels-x/
       *         Y axis labels placed on grid lines
       *
       * @type {number}
       */
      x: void 0
    },
    /**
     * @sample {highcharts} highcharts/yaxis/max-200/
     *         Y axis max of 200
     * @sample {highcharts} highcharts/yaxis/max-logarithmic/
     *         Y axis max on logarithmic axis
     * @sample {highstock} stock/yaxis/min-max/
     *         Fixed min and max on Y axis
     *
     * @apioption yAxis.max
     */
    /**
     * @sample {highcharts} highcharts/yaxis/min-startontick-false/
     *         -50 with startOnTick to false
     * @sample {highcharts} highcharts/yaxis/min-startontick-true/
     *         -50 with startOnTick true by default
     * @sample {highstock} stock/yaxis/min-max/
     *         Fixed min and max on Y axis
     *
     * @apioption yAxis.min
     */
    /**
     * An optional scrollbar to display on the Y axis in response to
     * limiting the minimum an maximum of the axis values.
     *
     * In styled mode, all the presentational options for the scrollbar
     * are replaced by the classes `.highcharts-scrollbar-thumb`,
     * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`,
     * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`.
     *
     * @sample {highstock} stock/yaxis/scrollbar/
     *         Scrollbar on the Y axis
     *
     * @extends   scrollbar
     * @since     4.2.6
     * @product   highstock
     * @excluding height
     * @apioption yAxis.scrollbar
     */
    /**
     * Enable the scrollbar on the Y axis.
     *
     * @sample {highstock} stock/yaxis/scrollbar/
     *         Enabled on Y axis
     *
     * @type      {boolean}
     * @default   false
     * @since     4.2.6
     * @product   highstock
     * @apioption yAxis.scrollbar.enabled
     */
    /**
     * Pixel margin between the scrollbar and the axis elements.
     *
     * @type      {number}
     * @default   10
     * @since     4.2.6
     * @product   highstock
     * @apioption yAxis.scrollbar.margin
     */
    /* eslint-disable @highcharts/highcharts/doclet-apioption-last */
    /**
     * Defines the position of the scrollbar. By default, it is positioned
     * on the opposite of the main axis (right side of the chart).
     * However, in the case of RTL languages could be set to `false`
     * which positions the scrollbar on the left.
     *
     * Works only for vertical axes.
     * This means yAxis in a non-inverted chart and xAxis in the inverted.
     *
     * @sample stock/yaxis/scrollbar-opposite/
     *         A scrollbar not on the opposite side
     *
     * @type      {boolean}
     * @default   true
     * @since 9.3.0
     *
     * @apioption yAxis.scrollbar.opposite
     * @apioption xAxis.scrollbar.opposite
     *
     */
    /* eslint-enable @highcharts/highcharts/doclet-apioption-last */
    /**
     * Whether to show the scrollbar when it is fully zoomed out at max
     * range. Setting it to `false` on the Y axis makes the scrollbar stay
     * hidden until the user zooms in, like common in browsers.
     *
     * @type      {boolean}
     * @default   true
     * @since     4.2.6
     * @product   highstock
     * @apioption yAxis.scrollbar.showFull
     */
    /**
     * The width of a vertical scrollbar or height of a horizontal
     * scrollbar. Defaults to 20 on touch devices.
     *
     * @type      {number}
     * @default   14
     * @since     4.2.6
     * @product   highstock
     * @apioption yAxis.scrollbar.size
     */
    /**
     * Z index of the scrollbar elements.
     *
     * @type      {number}
     * @default   3
     * @since     4.2.6
     * @product   highstock
     * @apioption yAxis.scrollbar.zIndex
     */
    /**
     * A soft maximum for the axis. If the series data maximum is less
     * than this, the axis will stay at this maximum, but if the series
     * data maximum is higher, the axis will flex to show all data.
     *
     * **Note**: The [series.softThreshold](
     * #plotOptions.series.softThreshold) option takes precedence over this
     * option.
     *
     * @sample highcharts/yaxis/softmin-softmax/
     *         Soft min and max
     *
     * @type      {number}
     * @since     5.0.1
     * @product   highcharts highstock gantt
     * @apioption yAxis.softMax
     */
    /**
     * A soft minimum for the axis. If the series data minimum is greater
     * than this, the axis will stay at this minimum, but if the series
     * data minimum is lower, the axis will flex to show all data.
     *
     * **Note**: The [series.softThreshold](
     * #plotOptions.series.softThreshold) option takes precedence over this
     * option.
     *
     * @sample highcharts/yaxis/softmin-softmax/
     *         Soft min and max
     *
     * @type      {number}
     * @since     5.0.1
     * @product   highcharts highstock gantt
     * @apioption yAxis.softMin
     */
    /**
     * Defines the horizontal alignment of the stack total label. Can be one
     * of `"left"`, `"center"` or `"right"`. The default value is calculated
     * at runtime and depends on orientation and whether the stack is
     * positive or negative.
     *
     * @sample {highcharts} highcharts/yaxis/stacklabels-align-left/
     *         Aligned to the left
     * @sample {highcharts} highcharts/yaxis/stacklabels-align-center/
     *         Aligned in center
     * @sample {highcharts} highcharts/yaxis/stacklabels-align-right/
     *         Aligned to the right
     *
     * @type      {Highcharts.AlignValue}
     * @since     2.1.5
     * @product   highcharts
     * @apioption yAxis.stackLabels.align
     */
    /**
     * A format string for the data label. Available variables are the same
     * as for `formatter`.
     *
     * @type      {string}
     * @default   {total}
     * @since     3.0.2
     * @product   highcharts highstock
     * @apioption yAxis.stackLabels.format
     */
    /**
     * Rotation of the labels in degrees.
     *
     * @sample {highcharts} highcharts/yaxis/stacklabels-rotation/
     *         Labels rotated 45°
     *
     * @type      {number}
     * @default   0
     * @since     2.1.5
     * @product   highcharts
     * @apioption yAxis.stackLabels.rotation
     */
    /**
     * The text alignment for the label. While `align` determines where the
     * texts anchor point is placed with regards to the stack, `textAlign`
     * determines how the text is aligned against its anchor point. Possible
     * values are `"left"`, `"center"` and `"right"`. The default value is
     * calculated at runtime and depends on orientation and whether the
     * stack is positive or negative.
     *
     * @sample {highcharts} highcharts/yaxis/stacklabels-textalign-left/
     *         Label in center position but text-aligned left
     *
     * @type      {Highcharts.AlignValue}
     * @since     2.1.5
     * @product   highcharts
     * @apioption yAxis.stackLabels.textAlign
     */
    /**
     * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the labels.
     *
     * @type      {boolean}
     * @default   false
     * @since     3.0
     * @product   highcharts highstock
     * @apioption yAxis.stackLabels.useHTML
     */
    /**
     * Defines the vertical alignment of the stack total label. Can be one
     * of `"top"`, `"middle"` or `"bottom"`. The default value is calculated
     * at runtime and depends on orientation and whether the stack is
     * positive or negative.
     *
     * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-top/
     *         Vertically aligned top
     * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-middle/
     *         Vertically aligned middle
     * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-bottom/
     *         Vertically aligned bottom
     *
     * @type      {Highcharts.VerticalAlignValue}
     * @since     2.1.5
     * @product   highcharts
     * @apioption yAxis.stackLabels.verticalAlign
     */
    /**
     * The x position offset of the label relative to the left of the
     * stacked bar. The default value is calculated at runtime and depends
     * on orientation and whether the stack is positive or negative.
     *
     * @sample {highcharts} highcharts/yaxis/stacklabels-x/
     *         Stack total labels with x offset
     *
     * @type      {number}
     * @since     2.1.5
     * @product   highcharts
     * @apioption yAxis.stackLabels.x
     */
    /**
     * The y position offset of the label relative to the tick position
     * on the axis. The default value is calculated at runtime and depends
     * on orientation and whether the stack is positive or negative.
     *
     * @sample {highcharts} highcharts/yaxis/stacklabels-y/
     *         Stack total labels with y offset
     *
     * @type      {number}
     * @since     2.1.5
     * @product   highcharts
     * @apioption yAxis.stackLabels.y
     */
    /**
     * Whether to force the axis to start on a tick. Use this option with
     * the `maxPadding` option to control the axis start.
     *
     * This option is always disabled, when panning type is
     * either `y` or `xy`.
     *
     * @see [type](#chart.panning.type)
     *
     * @sample {highcharts} highcharts/xaxis/startontick-false/
     *         False by default
     * @sample {highcharts} highcharts/xaxis/startontick-true/
     *         True
     * @sample {highstock} stock/xaxis/endontick/
     *         False for Y axis
     *
     * @since   1.2.0
     * @product highcharts highstock gantt
     */
    startOnTick: true,
    title: {
      /**
       * The pixel distance between the axis labels and the title.
       * Positive values are outside the axis line, negative are inside.
       *
       * @sample {highcharts} highcharts/xaxis/title-margin/
       *         Y axis title margin of 60
       *
       * @type      {number}
       * @default   40
       * @apioption yAxis.title.margin
       */
      /**
       * The actual text of the axis title. Horizontal texts can contain
       * HTML, but rotated texts are painted using vector techniques and
       * must be clean text. The Y axis title is disabled by setting the
       * `text` option to `undefined`. The default value is overriden by
       * the `lang.yAxisTitle` language option.
       *
       * @sample {highcharts} highcharts/xaxis/title-text/
       *         Custom HTML
       *
       * @type    {string|undefined}
       * @default {highcharts} Values
       * @default {highstock} undefined
       * @product highcharts highstock gantt
       */
    },
    /**
     * The top position of the Y axis. If it's a number, it is interpreted
     * as pixel position relative to the chart.
     *
     * Since Highcharts 2: If it's a percentage string, it is interpreted as
     * percentages of the plot height, offset from plot area top.
     *
     * @see [yAxis.height](#yAxis.height)
     *
     * @sample {highstock} stock/demo/candlestick-and-volume/
     *         Percentage height panes
     *
     * @type      {number|string}
     * @product   highcharts highstock
     * @apioption yAxis.top
     */
    /**
     * The stack labels show the total value for each bar in a stacked
     * column or bar chart. The label will be placed on top of positive
     * columns and below negative columns. In case of an inverted column
     * chart or a bar chart the label is placed to the right of positive
     * bars and to the left of negative bars.
     *
     * @product highcharts
     */
    stackLabels: {
      /**
       * Enable or disable the initial animation when a series is
       * displayed for the `stackLabels`. The animation can also be set as
       * a configuration object. Please note that this option only
       * applies to the initial animation.
       * For other animations, see [chart.animation](#chart.animation)
       * and the animation parameter under the API methods.
       * The following properties are supported:
       *
       * - `defer`: The animation delay time in milliseconds.
       *
       * @sample {highcharts} highcharts/plotoptions/animation-defer/
       *          Animation defer settings
       * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
       * @since 8.2.0
       * @apioption yAxis.stackLabels.animation
       */
      animation: {},
      /**
       * The animation delay time in milliseconds.
       * Set to `0` renders stackLabel immediately.
       * As `undefined` inherits defer time from the [series.animation.defer](#plotOptions.series.animation.defer).
       *
       * @type      {number}
       * @since 8.2.0
       * @apioption yAxis.stackLabels.animation.defer
       */
      /**
       * Allow the stack labels to overlap.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-allowoverlap-false/
       *         Default false
       *
       * @since   5.0.13
       * @product highcharts
       */
      allowOverlap: false,
      /**
       * The background color or gradient for the stack label.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-box/
       *          Stack labels box options
       * @type      {Highcharts.ColorType}
       * @since 8.1.0
       * @apioption yAxis.stackLabels.backgroundColor
       */
      /**
       * The border color for the stack label. Defaults to `undefined`.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-box/
       *          Stack labels box options
       * @type      {Highcharts.ColorType}
       * @since 8.1.0
       * @apioption yAxis.stackLabels.borderColor
       */
      /**
       * The border radius in pixels for the stack label.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-box/
       *          Stack labels box options
       * @type      {number}
       * @default   0
       * @since 8.1.0
       * @apioption yAxis.stackLabels.borderRadius
       */
      /**
       * The border width in pixels for the stack label.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-box/
       *          Stack labels box options
       * @type      {number}
       * @default   0
       * @since 8.1.0
       * @apioption yAxis.stackLabels.borderWidth
       */
      /**
       * Enable or disable the stack total labels.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-enabled/
       *         Enabled stack total labels
       * @sample {highcharts} highcharts/yaxis/stacklabels-enabled-waterfall/
       *         Enabled stack labels in waterfall chart
       *
       * @since   2.1.5
       * @product highcharts
       */
      enabled: false,
      /**
       * Whether to hide stack labels that are outside the plot area.
       * By default, the stack label is moved
       * inside the plot area according to the
       * [overflow](/highcharts/#yAxis/stackLabels/overflow)
       * option.
       *
       * @type  {boolean}
       * @since 7.1.3
       */
      crop: true,
      /**
       * How to handle stack total labels that flow outside the plot area.
       * The default is set to `"justify"`,
       * which aligns them inside the plot area.
       * For columns and bars, this means it will be moved inside the bar.
       * To display stack labels outside the plot area,
       * set `crop` to `false` and `overflow` to `"allow"`.
       *
       * @sample highcharts/yaxis/stacklabels-overflow/
       *         Stack labels flows outside the plot area.
       *
       * @type  {Highcharts.DataLabelsOverflowValue}
       * @since 7.1.3
       */
      overflow: "justify",
      /* eslint-disable valid-jsdoc */
      /**
       * Callback JavaScript function to format the label. The value is
       * given by `this.total`.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-formatter/
       *         Added units to stack total value
       *
       * @type    {Highcharts.FormatterCallbackFunction<Highcharts.StackItemObject>}
       * @since   2.1.5
       * @product highcharts
       */
      formatter: function() {
        const { numberFormatter } = this.axis.chart;
        return numberFormatter(this.total || 0, -1);
      },
      /**
       * CSS styles for the label.
       *
       * In styled mode, the styles are set in the
       * `.highcharts-stack-label` class.
       *
       * @sample {highcharts} highcharts/yaxis/stacklabels-style/
       *         Red stack total labels
       *
       * @type    {Highcharts.CSSObject}
       * @since   2.1.5
       * @product highcharts
       */
      style: {
        /** @internal */
        color: "#000000",
        /**
         * @type {number|string}
         */
        fontSize: "0.7em",
        /** @internal */
        fontWeight: "bold",
        /** @internal */
        textOutline: "1px contrast"
      }
    },
    gridLineWidth: 1,
    lineWidth: 0
  };
})(AxisDefaults || (AxisDefaults = {}));
const AxisDefaults$1 = AxisDefaults;
const { addEvent: addEvent$1t, isFunction: isFunction$3, objectEach: objectEach$s, removeEvent: removeEvent$b } = Utilities;
var Foundation;
(function(Foundation2) {
  function registerEventOptions2(component, options2) {
    component.eventOptions = component.eventOptions || {};
    objectEach$s(options2.events, function(event, eventType) {
      if (component.eventOptions[eventType] !== event) {
        if (component.eventOptions[eventType]) {
          removeEvent$b(component, eventType, component.eventOptions[eventType]);
          delete component.eventOptions[eventType];
        }
        if (isFunction$3(event)) {
          component.eventOptions[eventType] = event;
          addEvent$1t(component, eventType, event, {
            order: 0
            // #14080 fire those events as firsts
          });
        }
      }
    });
  }
  Foundation2.registerEventOptions = registerEventOptions2;
})(Foundation || (Foundation = {}));
const Foundation$1 = Foundation;
const { deg2rad: deg2rad$8 } = Highcharts;
const { clamp: clamp$m, correctFloat: correctFloat$f, defined: defined$17, destroyObjectProperties: destroyObjectProperties$9, extend: extend$1l, fireEvent: fireEvent$J, getAlignFactor: getAlignFactor$7, isNumber: isNumber$12, merge: merge$1C, objectEach: objectEach$r, pick: pick$1J } = Utilities;
class Tick {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(axis, pos, type, noLabel, parameters) {
    this.isNew = true;
    this.isNewLabel = true;
    this.axis = axis;
    this.pos = pos;
    this.type = type || "";
    this.parameters = parameters || {};
    this.tickmarkOffset = this.parameters.tickmarkOffset;
    this.options = this.parameters.options;
    fireEvent$J(this, "init");
    if (!type && !noLabel) {
      this.addLabel();
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Write the tick label.
   *
   * @private
   * @function Highcharts.Tick#addLabel
   */
  addLabel() {
    const tick = this, axis = tick.axis, options2 = axis.options, chart = axis.chart, categories = axis.categories, log = axis.logarithmic, names2 = axis.names, pos = tick.pos, labelOptions = pick$1J(tick.options?.labels, options2.labels), tickPositions = axis.tickPositions, isFirst = pos === tickPositions[0], isLast = pos === tickPositions[tickPositions.length - 1], animateLabels = (!labelOptions.step || labelOptions.step === 1) && axis.tickInterval === 1, tickPositionInfo = tickPositions.info;
    let label = tick.label, dateTimeLabelFormat, dateTimeLabelFormats, i;
    let value = this.parameters.category || (categories ? pick$1J(categories[pos], names2[pos], pos) : pos);
    if (log && isNumber$12(value)) {
      value = correctFloat$f(log.lin2log(value));
    }
    if (axis.dateTime) {
      if (tickPositionInfo) {
        dateTimeLabelFormats = chart.time.resolveDTLFormat(options2.dateTimeLabelFormats[!options2.grid && tickPositionInfo.higherRanks[pos] || tickPositionInfo.unitName]);
        dateTimeLabelFormat = dateTimeLabelFormats.main;
      } else if (isNumber$12(value)) {
        dateTimeLabelFormat = axis.dateTime.getXDateFormat(value, options2.dateTimeLabelFormats || {});
      }
    }
    tick.isFirst = isFirst;
    tick.isLast = isLast;
    const ctx = {
      axis,
      chart,
      dateTimeLabelFormat,
      isFirst,
      isLast,
      pos,
      tick,
      tickPositionInfo,
      value
    };
    fireEvent$J(this, "labelFormat", ctx);
    const labelFormatter = (ctx2) => {
      if (labelOptions.formatter) {
        return labelOptions.formatter.call(ctx2, ctx2);
      }
      if (labelOptions.format) {
        ctx2.text = axis.defaultLabelFormatter.call(ctx2);
        return Templating.format(labelOptions.format, ctx2, chart);
      }
      return axis.defaultLabelFormatter.call(ctx2);
    };
    const str = labelFormatter.call(ctx, ctx);
    const list = dateTimeLabelFormats?.list;
    if (list) {
      tick.shortenLabel = function() {
        for (i = 0; i < list.length; i++) {
          extend$1l(ctx, { dateTimeLabelFormat: list[i] });
          label.attr({
            text: labelFormatter.call(ctx, ctx)
          });
          if (label.getBBox().width < axis.getSlotWidth(tick) - 2 * (labelOptions.padding || 0)) {
            return;
          }
        }
        label.attr({
          text: ""
        });
      };
    } else {
      tick.shortenLabel = void 0;
    }
    if (animateLabels && axis._addedPlotLB) {
      tick.moveLabel(str, labelOptions);
    }
    if (!defined$17(label) && !tick.movedLabel) {
      tick.label = label = tick.createLabel(str, labelOptions);
      tick.rotation = 0;
    } else if (label && label.textStr !== str && !animateLabels) {
      if (label.textWidth && !labelOptions.style.width && !label.styles.width) {
        label.css({ width: null });
      }
      label.attr({ text: str });
      label.textPxLength = label.getBBox().width;
    }
  }
  /**
   * Render and return the label of the tick.
   *
   * @private
   * @function Highcharts.Tick#createLabel
   */
  createLabel(str, labelOptions, xy) {
    const axis = this.axis, { renderer, styledMode } = axis.chart, whiteSpace = labelOptions.style.whiteSpace, label = defined$17(str) && labelOptions.enabled ? renderer.text(str, xy?.x, xy?.y, labelOptions.useHTML).add(axis.labelGroup) : void 0;
    if (label) {
      if (!styledMode) {
        label.css(merge$1C(labelOptions.style));
      }
      label.textPxLength = label.getBBox().width;
      if (!styledMode && whiteSpace) {
        label.css({ whiteSpace });
      }
    }
    return label;
  }
  /**
   * Destructor for the tick prototype
   *
   * @private
   * @function Highcharts.Tick#destroy
   */
  destroy() {
    destroyObjectProperties$9(this, this.axis);
  }
  /**
   * Gets the x and y positions for ticks in terms of pixels.
   *
   * @private
   * @function Highcharts.Tick#getPosition
   *
   * @param {boolean} horiz
   * Whether the tick is on an horizontal axis or not.
   *
   * @param {number} tickPos
   * Position of the tick.
   *
   * @param {number} tickmarkOffset
   * Tickmark offset for all ticks.
   *
   * @param {boolean} [old]
   * Whether the axis has changed or not.
   *
   * @return {Highcharts.PositionObject}
   * The tick position.
   *
   * @emits Highcharts.Tick#event:afterGetPosition
   */
  getPosition(horiz, tickPos, tickmarkOffset, old) {
    const axis = this.axis, chart = axis.chart, cHeight = old && chart.oldChartHeight || chart.chartHeight, pos = {
      x: horiz ? correctFloat$f(axis.translate(tickPos + tickmarkOffset, void 0, void 0, old) + axis.transB) : axis.left + axis.offset + (axis.opposite ? (old && chart.oldChartWidth || chart.chartWidth) - axis.right - axis.left : 0),
      y: horiz ? cHeight - axis.bottom + axis.offset - (axis.opposite ? axis.height : 0) : correctFloat$f(cHeight - axis.translate(tickPos + tickmarkOffset, void 0, void 0, old) - axis.transB)
    };
    pos.y = clamp$m(pos.y, -1e9, 1e9);
    fireEvent$J(this, "afterGetPosition", { pos });
    return pos;
  }
  /**
   * Get the x, y position of the tick label
   * @private
   */
  getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
    const axis = this.axis, transA = axis.transA, reversed = (
      // #7911
      axis.isLinked && axis.linkedParent ? axis.linkedParent.reversed : axis.reversed
    ), staggerLines = axis.staggerLines, rotCorr = axis.tickRotCorr || { x: 0, y: 0 }, labelOffsetCorrection = !horiz && !axis.reserveSpaceDefault ? -axis.labelOffset * (axis.labelAlign === "center" ? 0.5 : 1) : 0, distance = labelOptions.distance, pos = {};
    let yOffset, line2;
    if (axis.side === 0) {
      yOffset = label.rotation ? -distance : -label.getBBox().height;
    } else if (axis.side === 2) {
      yOffset = rotCorr.y + distance;
    } else {
      yOffset = Math.cos(label.rotation * deg2rad$8) * (rotCorr.y - label.getBBox(false, 0).height / 2);
    }
    if (defined$17(labelOptions.y)) {
      yOffset = axis.side === 0 && axis.horiz ? labelOptions.y + yOffset : labelOptions.y;
    }
    x = x + pick$1J(labelOptions.x, [0, 1, 0, -1][axis.side] * distance) + labelOffsetCorrection + rotCorr.x - (tickmarkOffset && horiz ? tickmarkOffset * transA * (reversed ? -1 : 1) : 0);
    y = y + yOffset - (tickmarkOffset && !horiz ? tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
    if (staggerLines) {
      line2 = index / (step || 1) % staggerLines;
      if (axis.opposite) {
        line2 = staggerLines - line2 - 1;
      }
      y += line2 * (axis.labelOffset / staggerLines);
    }
    pos.x = x;
    pos.y = Math.round(y);
    fireEvent$J(this, "afterGetLabelPosition", { pos, tickmarkOffset, index });
    return pos;
  }
  /**
   * Get the offset height or width of the label
   *
   * @private
   * @function Highcharts.Tick#getLabelSize
   */
  getLabelSize() {
    return this.label ? this.label.getBBox()[this.axis.horiz ? "height" : "width"] : 0;
  }
  /**
   * Extendible method to return the path of the marker
   * @private
   */
  getMarkPath(x, y, tickLength, tickWidth, horiz = false, renderer) {
    return renderer.crispLine([[
      "M",
      x,
      y
    ], [
      "L",
      x + (horiz ? 0 : -tickLength),
      y + (horiz ? tickLength : 0)
    ]], tickWidth);
  }
  /**
   * Handle the label overflow by adjusting the labels to the left and right
   * edge, or hide them if they collide into the neighbour label.
   *
   * @private
   * @function Highcharts.Tick#handleOverflow
   */
  handleOverflow(xy) {
    const tick = this, axis = this.axis, labelOptions = axis.options.labels, pxPos = xy.x, chartWidth = axis.chart.chartWidth, spacing = axis.chart.spacing, leftBound = pick$1J(axis.labelLeft, Math.min(axis.pos, spacing[3])), rightBound = pick$1J(axis.labelRight, Math.max(!axis.isRadial ? axis.pos + axis.len : 0, chartWidth - spacing[1])), label = this.label, rotation = this.rotation, factor = getAlignFactor$7(axis.labelAlign || label.attr("align")), labelWidth = label.getBBox().width, slotWidth = axis.getSlotWidth(tick), xCorrection = factor, css2 = {};
    let modifiedSlotWidth = slotWidth, goRight = 1, leftPos, rightPos, textWidth;
    if (!rotation && labelOptions.overflow === "justify") {
      leftPos = pxPos - factor * labelWidth;
      rightPos = pxPos + (1 - factor) * labelWidth;
      if (leftPos < leftBound) {
        modifiedSlotWidth = xy.x + modifiedSlotWidth * (1 - factor) - leftBound;
      } else if (rightPos > rightBound) {
        modifiedSlotWidth = rightBound - xy.x + modifiedSlotWidth * factor;
        goRight = -1;
      }
      modifiedSlotWidth = Math.min(slotWidth, modifiedSlotWidth);
      if (modifiedSlotWidth < slotWidth && axis.labelAlign === "center") {
        xy.x += goRight * (slotWidth - modifiedSlotWidth - xCorrection * (slotWidth - Math.min(labelWidth, modifiedSlotWidth)));
      }
      if (labelWidth > modifiedSlotWidth || axis.autoRotation && label?.styles?.width) {
        textWidth = modifiedSlotWidth;
      }
    } else if (rotation < 0 && pxPos - factor * labelWidth < leftBound) {
      textWidth = Math.round(pxPos / Math.cos(rotation * deg2rad$8) - leftBound);
    } else if (rotation > 0 && pxPos + factor * labelWidth > rightBound) {
      textWidth = Math.round((chartWidth - pxPos) / Math.cos(rotation * deg2rad$8));
    }
    if (textWidth && label) {
      if (tick.shortenLabel) {
        tick.shortenLabel();
      } else {
        label.css(extend$1l(css2, {
          width: Math.floor(textWidth) + "px",
          lineClamp: axis.isRadial ? 0 : 1
        }));
      }
    }
  }
  /**
   * Try to replace the label if the same one already exists.
   *
   * @private
   * @function Highcharts.Tick#moveLabel
   */
  moveLabel(str, labelOptions) {
    const tick = this, label = tick.label, axis = tick.axis;
    let moved = false, labelPos;
    if (label && label.textStr === str) {
      tick.movedLabel = label;
      moved = true;
      delete tick.label;
    } else {
      objectEach$r(axis.ticks, function(currentTick) {
        if (!moved && !currentTick.isNew && currentTick !== tick && currentTick.label && currentTick.label.textStr === str) {
          tick.movedLabel = currentTick.label;
          moved = true;
          currentTick.labelPos = tick.movedLabel.xy;
          delete currentTick.label;
        }
      });
    }
    if (!moved && (tick.labelPos || label)) {
      labelPos = tick.labelPos || label.xy;
      tick.movedLabel = tick.createLabel(str, labelOptions, labelPos);
      if (tick.movedLabel) {
        tick.movedLabel.attr({ opacity: 0 });
      }
    }
  }
  /**
   * Put everything in place
   *
   * @private
   * @param {number} index
   *
   * @param {boolean} [old]
   * Use old coordinates to prepare an animation into new position
   *
   * @param {number} [opacity]
   */
  render(index, old, opacity) {
    const tick = this, axis = tick.axis, horiz = axis.horiz, pos = tick.pos, tickmarkOffset = pick$1J(tick.tickmarkOffset, axis.tickmarkOffset), xy = tick.getPosition(horiz, pos, tickmarkOffset, old), x = xy.x, y = xy.y, axisStart = axis.pos, axisEnd = axisStart + axis.len, pxPos = horiz ? x : y;
    const labelOpacity = pick$1J(
      opacity,
      tick.label?.newOpacity,
      // #15528
      1
    );
    if (!axis.chart.polar && (correctFloat$f(pxPos) < axisStart || pxPos > axisEnd)) {
      opacity = 0;
    }
    opacity ?? (opacity = 1);
    this.isActive = true;
    this.renderGridLine(old, opacity);
    this.renderMark(xy, opacity);
    this.renderLabel(xy, old, labelOpacity, index);
    tick.isNew = false;
    fireEvent$J(this, "afterRender");
  }
  /**
   * Renders the gridLine.
   *
   * @private
   * @function Highcharts.Tick#renderGridLine
   * @param {boolean} old  Whether or not the tick is old
   * @param {number} opacity  The opacity of the grid line
   */
  renderGridLine(old, opacity) {
    const tick = this, axis = tick.axis, options2 = axis.options, attribs = {}, pos = tick.pos, type = tick.type, tickmarkOffset = pick$1J(tick.tickmarkOffset, axis.tickmarkOffset), renderer = axis.chart.renderer;
    let gridLine = tick.gridLine, gridLinePath, gridLineWidth = options2.gridLineWidth, gridLineColor = options2.gridLineColor, dashStyle = options2.gridLineDashStyle;
    if (tick.type === "minor") {
      gridLineWidth = options2.minorGridLineWidth;
      gridLineColor = options2.minorGridLineColor;
      dashStyle = options2.minorGridLineDashStyle;
    }
    if (!gridLine) {
      if (!axis.chart.styledMode) {
        attribs.stroke = gridLineColor;
        attribs["stroke-width"] = gridLineWidth || 0;
        attribs.dashstyle = dashStyle;
      }
      if (!type) {
        attribs.zIndex = 1;
      }
      if (old) {
        opacity = 0;
      }
      tick.gridLine = gridLine = renderer.path().attr(attribs).addClass("highcharts-" + (type ? type + "-" : "") + "grid-line").add(axis.gridGroup);
    }
    if (gridLine) {
      gridLinePath = axis.getPlotLinePath({
        value: pos + tickmarkOffset,
        lineWidth: gridLine.strokeWidth(),
        force: "pass",
        old,
        acrossPanes: false
        // #18025
      });
      if (gridLinePath) {
        gridLine[old || tick.isNew ? "attr" : "animate"]({
          d: gridLinePath,
          opacity
        });
      }
    }
  }
  /**
   * Renders the tick mark.
   *
   * @private
   * @function Highcharts.Tick#renderMark
   * @param {Highcharts.PositionObject} xy  The position vector of the mark
   * @param {number} opacity  The opacity of the mark
   */
  renderMark(xy, opacity) {
    const tick = this, axis = tick.axis, options2 = axis.options, renderer = axis.chart.renderer, type = tick.type, tickSize = axis.tickSize(type ? type + "Tick" : "tick"), x = xy.x, y = xy.y, tickWidth = pick$1J(options2[type !== "minor" ? "tickWidth" : "minorTickWidth"], !type && axis.isXAxis ? 1 : 0), tickColor = options2[type !== "minor" ? "tickColor" : "minorTickColor"];
    let mark = tick.mark;
    const isNewMark = !mark;
    if (tickSize) {
      if (axis.opposite) {
        tickSize[0] = -tickSize[0];
      }
      if (!mark) {
        tick.mark = mark = renderer.path().addClass("highcharts-" + (type ? type + "-" : "") + "tick").add(axis.axisGroup);
        if (!axis.chart.styledMode) {
          mark.attr({
            stroke: tickColor,
            "stroke-width": tickWidth
          });
        }
      }
      mark[isNewMark ? "attr" : "animate"]({
        d: tick.getMarkPath(x, y, tickSize[0], mark.strokeWidth(), axis.horiz, renderer),
        opacity
      });
    }
  }
  /**
   * Renders the tick label.
   * Note: The label should already be created in init(), so it should only
   * have to be moved into place.
   *
   * @private
   * @function Highcharts.Tick#renderLabel
   * @param {Highcharts.PositionObject} xy  The position vector of the label
   * @param {boolean} old  Whether or not the tick is old
   * @param {number} opacity  The opacity of the label
   * @param {number} index  The index of the tick
   */
  renderLabel(xy, old, opacity, index) {
    const tick = this, axis = tick.axis, horiz = axis.horiz, options2 = axis.options, label = tick.label, labelOptions = options2.labels, step = labelOptions.step, tickmarkOffset = pick$1J(tick.tickmarkOffset, axis.tickmarkOffset), x = xy.x, y = xy.y;
    let show = true;
    if (label && isNumber$12(x)) {
      label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
      if (tick.isFirst && !tick.isLast && !options2.showFirstLabel || tick.isLast && !tick.isFirst && !options2.showLastLabel) {
        show = false;
      } else if (horiz && !labelOptions.step && !labelOptions.rotation && !old && opacity !== 0) {
        tick.handleOverflow(xy);
      }
      if (step && index % step) {
        show = false;
      }
      if (show && isNumber$12(xy.y)) {
        xy.opacity = opacity;
        label[tick.isNewLabel ? "attr" : "animate"](xy).show(true);
        tick.isNewLabel = false;
      } else {
        label.hide();
        tick.isNewLabel = true;
      }
    }
  }
  /**
   * Replace labels with the moved ones to perform animation. Additionally
   * destroy unused labels.
   *
   * @private
   * @function Highcharts.Tick#replaceMovedLabel
   */
  replaceMovedLabel() {
    const tick = this, label = tick.label, axis = tick.axis;
    if (label && !tick.isNew) {
      label.animate({ opacity: 0 }, void 0, label.destroy);
      delete tick.label;
    }
    axis.isDirty = true;
    tick.label = tick.movedLabel;
    delete tick.movedLabel;
  }
}
const { animObject: animObject$e } = animationExports;
const { xAxis, yAxis } = AxisDefaults$1;
const { defaultOptions: defaultOptions$k } = DefaultOptions;
const { registerEventOptions: registerEventOptions$3 } = Foundation$1;
const { deg2rad: deg2rad$7 } = Highcharts;
const { arrayMax: arrayMax$a, arrayMin: arrayMin$8, clamp: clamp$l, correctFloat: correctFloat$e, defined: defined$16, destroyObjectProperties: destroyObjectProperties$8, erase: erase$a, error: error$8, extend: extend$1k, fireEvent: fireEvent$I, getClosestDistance: getClosestDistance$1, insertItem: insertItem$1, isArray: isArray$n, isNumber: isNumber$11, isString: isString$d, merge: merge$1B, normalizeTickInterval: normalizeTickInterval$2, objectEach: objectEach$q, pick: pick$1I, relativeLength: relativeLength$h, removeEvent: removeEvent$a, splat: splat$k, syncTimeout: syncTimeout$a } = Utilities;
const getNormalizedTickInterval = (axis, tickInterval) => normalizeTickInterval$2(tickInterval, void 0, void 0, pick$1I(
  axis.options.allowDecimals,
  // If the tick interval is greater than 0.5, avoid decimals, as
  // linear axes are often used to render discrete values (#3363). If
  // a tick amount is set, allow decimals by default, as it increases
  // the chances for a good fit.
  tickInterval < 0.5 || axis.tickAmount !== void 0
), !!axis.tickAmount);
extend$1k(defaultOptions$k, { xAxis, yAxis: merge$1B(xAxis, yAxis) });
class Axis {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(chart, userOptions, coll) {
    this.init(chart, userOptions, coll);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Overrideable function to initialize the axis.
   *
   * @see {@link Axis}
   *
   * @function Highcharts.Axis#init
   *
   * @param {Highcharts.Chart} chart
   * The Chart instance to apply the axis on.
   *
   * @param {AxisOptions} userOptions
   * Axis options.
   *
   * @emits Highcharts.Axis#event:afterInit
   * @emits Highcharts.Axis#event:init
   */
  init(chart, userOptions, coll = this.coll) {
    const isXAxis = coll === "xAxis", axis = this, horiz = axis.isZAxis || (chart.inverted ? !isXAxis : isXAxis);
    axis.chart = chart;
    axis.horiz = horiz;
    axis.isXAxis = isXAxis;
    axis.coll = coll;
    fireEvent$I(this, "init", { userOptions });
    axis.opposite = pick$1I(userOptions.opposite, axis.opposite);
    axis.side = pick$1I(
      userOptions.side,
      axis.side,
      horiz ? axis.opposite ? 0 : 2 : (
        // Top : bottom
        axis.opposite ? 1 : 3
      )
      // Right : left
    );
    axis.setOptions(userOptions);
    const options2 = axis.options, labelsOptions = options2.labels;
    axis.type ?? (axis.type = options2.type || "linear");
    axis.uniqueNames ?? (axis.uniqueNames = options2.uniqueNames ?? true);
    fireEvent$I(axis, "afterSetType");
    axis.userOptions = userOptions;
    axis.minPixelPadding = 0;
    axis.reversed = pick$1I(options2.reversed, axis.reversed);
    axis.visible = options2.visible;
    axis.zoomEnabled = options2.zoomEnabled;
    axis.hasNames = this.type === "category" || options2.categories === true;
    axis.categories = isArray$n(options2.categories) && options2.categories || (axis.hasNames ? [] : void 0);
    if (!axis.names) {
      axis.names = [];
      axis.names.keys = {};
    }
    axis.plotLinesAndBandsGroups = {};
    axis.positiveValuesOnly = !!axis.logarithmic;
    axis.isLinked = defined$16(options2.linkedTo);
    axis.ticks = {};
    axis.labelEdge = [];
    axis.minorTicks = {};
    axis.plotLinesAndBands = [];
    axis.alternateBands = {};
    axis.len ?? (axis.len = 0);
    axis.minRange = axis.userMinRange = options2.minRange || options2.maxZoom;
    axis.range = options2.range;
    axis.offset = options2.offset || 0;
    axis.max = void 0;
    axis.min = void 0;
    const crosshair = pick$1I(options2.crosshair, splat$k(chart.options.tooltip.crosshairs)[isXAxis ? 0 : 1]);
    axis.crosshair = crosshair === true ? {} : crosshair;
    if (chart.axes.indexOf(axis) === -1) {
      if (isXAxis) {
        chart.axes.splice(chart.xAxis.length, 0, axis);
      } else {
        chart.axes.push(axis);
      }
      insertItem$1(this, chart[this.coll]);
    }
    chart.orderItems(axis.coll);
    axis.series = axis.series || [];
    if (chart.inverted && !axis.isZAxis && isXAxis && !defined$16(axis.reversed)) {
      axis.reversed = true;
    }
    axis.labelRotation = isNumber$11(labelsOptions.rotation) ? labelsOptions.rotation : void 0;
    registerEventOptions$3(axis, options2);
    fireEvent$I(this, "afterInit");
  }
  /**
   * Merge and set options.
   *
   * @private
   * @function Highcharts.Axis#setOptions
   *
   * @param {Highcharts.AxisOptions} userOptions
   * Axis options.
   *
   * @emits Highcharts.Axis#event:afterSetOptions
   */
  setOptions(userOptions) {
    const sideSpecific = this.horiz ? (
      // Top and bottom axis defaults
      {
        labels: {
          autoRotation: [-45],
          padding: 3
        },
        margin: 15
      }
    ) : (
      // Left and right axis, title rotated 90 or 270 degrees
      // respectively
      {
        labels: {
          padding: 1
        },
        title: {
          rotation: 90 * this.side
        }
      }
    );
    this.options = merge$1B(
      sideSpecific,
      // Merge in the default title for y-axis, which changes with
      // language settings
      this.coll === "yAxis" ? {
        title: {
          text: this.chart.options.lang.yAxisTitle
        }
      } : {},
      defaultOptions$k[this.coll],
      userOptions
    );
    fireEvent$I(this, "afterSetOptions", { userOptions });
  }
  /**
   * The default label formatter. The context is a special config object for
   * the label. In apps, use the
   * [labels.formatter](https://api.highcharts.com/highcharts/xAxis.labels.formatter)
   * instead, except when a modification is needed.
   *
   * @function Highcharts.Axis#defaultLabelFormatter
   *
   * @param {Highcharts.AxisLabelsFormatterContextObject} this
   * Formatter context of axis label.
   *
   * @param {Highcharts.AxisLabelsFormatterContextObject} [ctx]
   * Formatter context of axis label.
   *
   * @return {string}
   * The formatted label content.
   */
  defaultLabelFormatter() {
    const axis = this.axis, chart = this.chart, { numberFormatter } = chart, value = isNumber$11(this.value) ? this.value : NaN, time = axis.chart.time, categories = axis.categories, dateTimeLabelFormat = this.dateTimeLabelFormat, lang2 = defaultOptions$k.lang, numericSymbols = lang2.numericSymbols, numSymMagnitude = lang2.numericSymbolMagnitude || 1e3, numericSymbolDetector = axis.logarithmic ? Math.abs(value) : axis.tickInterval;
    let i = numericSymbols?.length, multi, ret;
    if (categories) {
      ret = `${this.value}`;
    } else if (dateTimeLabelFormat) {
      ret = time.dateFormat(dateTimeLabelFormat, value, true);
    } else if (i && numericSymbols && numericSymbolDetector >= 1e3) {
      while (i-- && typeof ret === "undefined") {
        multi = Math.pow(numSymMagnitude, i + 1);
        if (
          // Only accept a numeric symbol when the distance is more
          // than a full unit. So for example if the symbol is k, we
          // don't accept numbers like 0.5k.
          numericSymbolDetector >= multi && // Accept one decimal before the symbol. Accepts 0.5k but
          // not 0.25k. How does this work with the previous?
          value * 10 % multi === 0 && numericSymbols[i] !== null && value !== 0
        ) {
          ret = numberFormatter(value / multi, -1) + numericSymbols[i];
        }
      }
    }
    if (typeof ret === "undefined") {
      if (Math.abs(value) >= 1e4) {
        ret = numberFormatter(value, -1);
      } else {
        ret = numberFormatter(value, -1, void 0, "");
      }
    }
    return ret;
  }
  /**
   * Get the minimum and maximum for the series of each axis. The function
   * analyzes the axis series and updates `this.dataMin` and `this.dataMax`.
   *
   * @private
   * @function Highcharts.Axis#getSeriesExtremes
   *
   * @emits Highcharts.Axis#event:afterGetSeriesExtremes
   * @emits Highcharts.Axis#event:getSeriesExtremes
   */
  getSeriesExtremes() {
    const axis = this;
    let xExtremes;
    fireEvent$I(this, "getSeriesExtremes", null, function() {
      axis.hasVisibleSeries = false;
      axis.dataMin = axis.dataMax = axis.threshold = void 0;
      axis.softThreshold = !axis.isXAxis;
      axis.series.forEach((series) => {
        if (series.reserveSpace()) {
          const seriesOptions = series.options;
          let xData, threshold = seriesOptions.threshold, seriesDataMin, seriesDataMax;
          axis.hasVisibleSeries = true;
          if (axis.positiveValuesOnly && (threshold || 0) <= 0) {
            threshold = void 0;
          }
          if (axis.isXAxis) {
            xData = series.getColumn("x");
            if (xData.length) {
              xData = axis.logarithmic ? xData.filter((x) => x > 0) : xData;
              xExtremes = series.getXExtremes(xData);
              seriesDataMin = xExtremes.min;
              seriesDataMax = xExtremes.max;
              if (!isNumber$11(seriesDataMin) && // #5010:
              !(seriesDataMin instanceof Date)) {
                xData = xData.filter(isNumber$11);
                xExtremes = series.getXExtremes(xData);
                seriesDataMin = xExtremes.min;
                seriesDataMax = xExtremes.max;
              }
              if (xData.length) {
                axis.dataMin = Math.min(pick$1I(axis.dataMin, seriesDataMin), seriesDataMin);
                axis.dataMax = Math.max(pick$1I(axis.dataMax, seriesDataMax), seriesDataMax);
              }
            }
          } else {
            const dataExtremes = series.applyExtremes();
            if (isNumber$11(dataExtremes.dataMin)) {
              seriesDataMin = dataExtremes.dataMin;
              axis.dataMin = Math.min(pick$1I(axis.dataMin, seriesDataMin), seriesDataMin);
            }
            if (isNumber$11(dataExtremes.dataMax)) {
              seriesDataMax = dataExtremes.dataMax;
              axis.dataMax = Math.max(pick$1I(axis.dataMax, seriesDataMax), seriesDataMax);
            }
            if (defined$16(threshold)) {
              axis.threshold = threshold;
            }
            if (!seriesOptions.softThreshold || axis.positiveValuesOnly) {
              axis.softThreshold = false;
            }
          }
        }
      });
    });
    fireEvent$I(this, "afterGetSeriesExtremes");
  }
  /**
   * Translate from axis value to pixel position on the chart, or back. Use
   * the `toPixels` and `toValue` functions in applications.
   *
   * @private
   * @function Highcharts.Axis#translate
   */
  translate(val, backwards, cvsCoord, old, handleLog, pointPlacement) {
    const axis = this.linkedParent || this, localMin = old && axis.old ? axis.old.min : axis.min;
    if (!isNumber$11(localMin)) {
      return NaN;
    }
    const minPixelPadding = axis.minPixelPadding, doPostTranslate = (axis.isOrdinal || axis.brokenAxis?.hasBreaks || axis.logarithmic && handleLog) && axis.lin2val;
    let sign2 = 1, cvsOffset = 0, localA = old && axis.old ? axis.old.transA : axis.transA, returnValue = 0;
    if (!localA) {
      localA = axis.transA;
    }
    if (cvsCoord) {
      sign2 *= -1;
      cvsOffset = axis.len;
    }
    if (axis.reversed) {
      sign2 *= -1;
      cvsOffset -= sign2 * (axis.sector || axis.len);
    }
    if (backwards) {
      val = val * sign2 + cvsOffset;
      val -= minPixelPadding;
      returnValue = val / localA + localMin;
      if (doPostTranslate) {
        returnValue = axis.lin2val(returnValue);
      }
    } else {
      if (doPostTranslate) {
        val = axis.val2lin(val);
      }
      const value = sign2 * (val - localMin) * localA;
      returnValue = value + cvsOffset + sign2 * minPixelPadding + (isNumber$11(pointPlacement) ? localA * pointPlacement : 0);
      if (!axis.isRadial) {
        returnValue = correctFloat$e(returnValue);
      }
    }
    return returnValue;
  }
  /**
   * Translate a value in terms of axis units into pixels within the chart.
   *
   * @function Highcharts.Axis#toPixels
   *
   * @param {number|string} value
   * A value in terms of axis units. For datetime axes, a timestamp or
   * date/time string is accepted.
   *
   * @param {boolean} [paneCoordinates=false]
   * Whether to return the pixel coordinate relative to the chart or just the
   * axis/pane itself.
   *
   * @return {number}
   * Pixel position of the value on the chart or axis.
   */
  toPixels(value, paneCoordinates) {
    return this.translate(this.chart?.time.parse(value) ?? NaN, false, !this.horiz, void 0, true) + (paneCoordinates ? 0 : this.pos);
  }
  /**
   * Translate a pixel position along the axis to a value in terms of axis
   * units.
   *
   * @function Highcharts.Axis#toValue
   *
   * @param {number} pixel
   * The pixel value coordinate.
   *
   * @param {boolean} [paneCoordinates=false]
   * Whether the input pixel is relative to the chart or just the axis/pane
   * itself.
   *
   * @return {number}
   * The axis value.
   */
  toValue(pixel, paneCoordinates) {
    return this.translate(pixel - (paneCoordinates ? 0 : this.pos), true, !this.horiz, void 0, true);
  }
  /**
   * Create the path for a plot line that goes from the given value on
   * this axis, across the plot to the opposite side. Also used internally for
   * grid lines and crosshairs.
   *
   * @function Highcharts.Axis#getPlotLinePath
   *
   * @param {Highcharts.AxisPlotLinePathOptionsObject} options
   * Options for the path.
   *
   * @return {Highcharts.SVGPathArray|null}
   * The SVG path definition for the plot line.
   */
  getPlotLinePath(options2) {
    const axis = this, chart = axis.chart, axisLeft = axis.left, axisTop = axis.top, old = options2.old, value = options2.value, lineWidth = options2.lineWidth, cHeight = old && chart.oldChartHeight || chart.chartHeight, cWidth = old && chart.oldChartWidth || chart.chartWidth, transB = axis.transB;
    let translatedValue = options2.translatedValue, force = options2.force, x1, y1, x2, y2, skip;
    function between(x, a, b) {
      if (force !== "pass" && (x < a || x > b)) {
        if (force) {
          x = clamp$l(x, a, b);
        } else {
          skip = true;
        }
      }
      return x;
    }
    const evt = {
      value,
      lineWidth,
      old,
      force,
      acrossPanes: options2.acrossPanes,
      translatedValue
    };
    fireEvent$I(this, "getPlotLinePath", evt, function(e) {
      translatedValue = pick$1I(translatedValue, axis.translate(value, void 0, void 0, old));
      translatedValue = clamp$l(translatedValue, -1e9, 1e9);
      x1 = x2 = translatedValue + transB;
      y1 = y2 = cHeight - translatedValue - transB;
      if (!isNumber$11(translatedValue)) {
        skip = true;
        force = false;
      } else if (axis.horiz) {
        y1 = axisTop;
        y2 = cHeight - axis.bottom + (axis.options.isInternal ? 0 : chart.scrollablePixelsY || 0);
        x1 = x2 = between(x1, axisLeft, axisLeft + axis.width);
      } else {
        x1 = axisLeft;
        x2 = cWidth - axis.right + (chart.scrollablePixelsX || 0);
        y1 = y2 = between(y1, axisTop, axisTop + axis.height);
      }
      e.path = skip && !force ? void 0 : chart.renderer.crispLine([["M", x1, y1], ["L", x2, y2]], lineWidth || 1);
    });
    return evt.path;
  }
  /**
   * Internal function to get the tick positions of a linear axis to round
   * values like whole tens or every five.
   *
   * @function Highcharts.Axis#getLinearTickPositions
   *
   * @param {number} tickInterval
   * The normalized tick interval.
   *
   * @param {number} min
   * Axis minimum.
   *
   * @param {number} max
   * Axis maximum.
   *
   * @return {Array<number>}
   * An array of axis values where ticks should be placed.
   */
  getLinearTickPositions(tickInterval, min2, max2) {
    const roundedMin = correctFloat$e(Math.floor(min2 / tickInterval) * tickInterval), roundedMax = correctFloat$e(Math.ceil(max2 / tickInterval) * tickInterval), tickPositions = [];
    let pos, lastPos, precision;
    if (correctFloat$e(roundedMin + tickInterval) === roundedMin) {
      precision = 20;
    }
    if (this.single) {
      return [min2];
    }
    pos = roundedMin;
    while (pos <= roundedMax) {
      tickPositions.push(pos);
      pos = correctFloat$e(pos + tickInterval, precision);
      if (pos === lastPos) {
        break;
      }
      lastPos = pos;
    }
    return tickPositions;
  }
  /**
   * Resolve the new minorTicks/minorTickInterval options into the legacy
   * loosely typed minorTickInterval option.
   *
   * @function Highcharts.Axis#getMinorTickInterval
   *
   * @return {number|"auto"|null}
   * Legacy option
   */
  getMinorTickInterval() {
    const { minorTicks, minorTickInterval } = this.options;
    if (minorTicks === true) {
      return pick$1I(minorTickInterval, "auto");
    }
    if (minorTicks === false) {
      return;
    }
    return minorTickInterval;
  }
  /**
   * Internal function to return the minor tick positions. For logarithmic
   * axes, the same logic as for major ticks is reused.
   *
   * @function Highcharts.Axis#getMinorTickPositions
   *
   * @return {Array<number>}
   * An array of axis values where ticks should be placed.
   */
  getMinorTickPositions() {
    const axis = this, options2 = axis.options, tickPositions = axis.tickPositions, minorTickInterval = axis.minorTickInterval, pointRangePadding = axis.pointRangePadding || 0, min2 = (axis.min || 0) - pointRangePadding, max2 = (axis.max || 0) + pointRangePadding, range2 = axis.brokenAxis?.hasBreaks ? axis.brokenAxis.unitLength : max2 - min2;
    let minorTickPositions = [], pos;
    if (range2 && range2 / minorTickInterval < axis.len / 3) {
      const logarithmic = axis.logarithmic;
      if (logarithmic) {
        this.paddedTicks.forEach(function(_pos, i, paddedTicks) {
          if (i) {
            minorTickPositions.push.apply(minorTickPositions, logarithmic.getLogTickPositions(minorTickInterval, paddedTicks[i - 1], paddedTicks[i], true));
          }
        });
      } else if (axis.dateTime && this.getMinorTickInterval() === "auto") {
        minorTickPositions = minorTickPositions.concat(axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(minorTickInterval), min2, max2, options2.startOfWeek));
      } else {
        for (pos = min2 + (tickPositions[0] - min2) % minorTickInterval; pos <= max2; pos += minorTickInterval) {
          if (pos === minorTickPositions[0]) {
            break;
          }
          minorTickPositions.push(pos);
        }
      }
    }
    if (minorTickPositions.length !== 0) {
      axis.trimTicks(minorTickPositions);
    }
    return minorTickPositions;
  }
  /**
   * Adjust the min and max for the minimum range. Keep in mind that the
   * series data is not yet processed, so we don't have information on data
   * cropping and grouping, or updated `axis.pointRange` or
   * `series.pointRange`. The data can't be processed until we have finally
   * established min and max.
   *
   * @private
   * @function Highcharts.Axis#adjustForMinRange
   */
  adjustForMinRange() {
    const axis = this, options2 = axis.options, logarithmic = axis.logarithmic, time = axis.chart.time;
    let { max: max2, min: min2, minRange } = axis, zoomOffset, spaceAvailable, closestDataRange, minArgs, maxArgs;
    if (axis.isXAxis && typeof minRange === "undefined" && !logarithmic) {
      if (defined$16(options2.min) || defined$16(options2.max) || defined$16(options2.floor) || defined$16(options2.ceiling)) {
        minRange = null;
      } else {
        closestDataRange = getClosestDistance$1(axis.series.map((s) => {
          const xData = s.getColumn("x");
          return s.xIncrement ? xData.slice(0, 2) : xData;
        })) || 0;
        minRange = Math.min(closestDataRange * 5, axis.dataMax - axis.dataMin);
      }
    }
    if (isNumber$11(max2) && isNumber$11(min2) && isNumber$11(minRange) && max2 - min2 < minRange) {
      spaceAvailable = axis.dataMax - axis.dataMin >= minRange;
      zoomOffset = (minRange - max2 + min2) / 2;
      minArgs = [
        min2 - zoomOffset,
        time.parse(options2.min) ?? min2 - zoomOffset
      ];
      if (spaceAvailable) {
        minArgs[2] = logarithmic ? logarithmic.log2lin(axis.dataMin) : axis.dataMin;
      }
      min2 = arrayMax$a(minArgs);
      maxArgs = [
        min2 + minRange,
        time.parse(options2.max) ?? min2 + minRange
      ];
      if (spaceAvailable) {
        maxArgs[2] = logarithmic ? logarithmic.log2lin(axis.dataMax) : axis.dataMax;
      }
      max2 = arrayMin$8(maxArgs);
      if (max2 - min2 < minRange) {
        minArgs[0] = max2 - minRange;
        minArgs[1] = time.parse(options2.min) ?? max2 - minRange;
        min2 = arrayMax$a(minArgs);
      }
    }
    axis.minRange = minRange;
    axis.min = min2;
    axis.max = max2;
  }
  /**
   * Find the closestPointRange across all series, including the single data
   * series.
   *
   * @private
   * @function Highcharts.Axis#getClosest
   */
  getClosest() {
    let closestSingleDistance, closestDistance;
    if (this.categories) {
      closestDistance = 1;
    } else {
      const singleXs = [];
      this.series.forEach(function(series) {
        const seriesClosest = series.closestPointRange, xData = series.getColumn("x");
        if (xData.length === 1) {
          singleXs.push(xData[0]);
        } else if (series.sorted && defined$16(seriesClosest) && series.reserveSpace()) {
          closestDistance = defined$16(closestDistance) ? Math.min(closestDistance, seriesClosest) : seriesClosest;
        }
      });
      if (singleXs.length) {
        singleXs.sort((a, b) => a - b);
        closestSingleDistance = getClosestDistance$1([singleXs]);
      }
    }
    if (closestSingleDistance && closestDistance) {
      return Math.min(closestSingleDistance, closestDistance);
    }
    return closestSingleDistance || closestDistance;
  }
  /**
   * When a point name is given and no x, search for the name in the existing
   * categories, or if categories aren't provided, search names or create a
   * new category (#2522).
   *
   * @private
   * @function Highcharts.Axis#nameToX
   *
   * @param {Highcharts.Point} point
   * The point to inspect.
   *
   * @return {number}
   * The X value that the point is given.
   */
  nameToX(point) {
    const explicitCategories = isArray$n(this.options.categories), names2 = explicitCategories ? this.categories : this.names;
    let nameX = point.options.x, x;
    point.series.requireSorting = false;
    if (!defined$16(nameX)) {
      nameX = this.uniqueNames && names2 ? explicitCategories ? names2.indexOf(point.name) : pick$1I(names2.keys[point.name], -1) : point.series.autoIncrement();
    }
    if (nameX === -1) {
      if (!explicitCategories && names2) {
        x = names2.length;
      }
    } else if (isNumber$11(nameX)) {
      x = nameX;
    }
    if (typeof x !== "undefined") {
      this.names[x] = point.name;
      this.names.keys[point.name] = x;
    } else if (point.x) {
      x = point.x;
    }
    return x;
  }
  /**
   * When changes have been done to series data, update the axis.names.
   *
   * @private
   * @function Highcharts.Axis#updateNames
   */
  updateNames() {
    const axis = this, names2 = this.names, i = names2.length;
    if (i > 0) {
      Object.keys(names2.keys).forEach(function(key2) {
        delete names2.keys[key2];
      });
      names2.length = 0;
      this.minRange = this.userMinRange;
      (this.series || []).forEach((series) => {
        series.xIncrement = null;
        if (!series.points || series.isDirtyData) {
          axis.max = Math.max(axis.max || 0, series.dataTable.rowCount - 1);
          series.processData();
          series.generatePoints();
        }
        const xData = series.getColumn("x").slice();
        series.data.forEach((point, i2) => {
          let x = xData[i2];
          if (point?.options && typeof point.name !== "undefined") {
            x = axis.nameToX(point);
            if (typeof x !== "undefined" && x !== point.x) {
              xData[i2] = point.x = x;
            }
          }
        });
        series.dataTable.setColumn("x", xData);
      });
    }
  }
  /**
   * Update translation information.
   *
   * @private
   * @function Highcharts.Axis#setAxisTranslation
   *
   * @emits Highcharts.Axis#event:afterSetAxisTranslation
   */
  setAxisTranslation() {
    const axis = this, range2 = axis.max - axis.min, linkedParent = axis.linkedParent, hasCategories = !!axis.categories, isXAxis = axis.isXAxis;
    let pointRange = axis.axisPointRange || 0, closestPointRange, minPointOffset = 0, pointRangePadding = 0, ordinalCorrection, transA = axis.transA;
    if (isXAxis || hasCategories || pointRange) {
      closestPointRange = axis.getClosest();
      if (linkedParent) {
        minPointOffset = linkedParent.minPointOffset;
        pointRangePadding = linkedParent.pointRangePadding;
      } else {
        axis.series.forEach(function(series) {
          const seriesPointRange = hasCategories ? 1 : isXAxis ? pick$1I(series.options.pointRange, closestPointRange, 0) : axis.axisPointRange || 0, pointPlacement = series.options.pointPlacement;
          pointRange = Math.max(pointRange, seriesPointRange);
          if (!axis.single || hasCategories) {
            const isPointPlacementAxis = series.is("xrange") ? !isXAxis : isXAxis;
            minPointOffset = Math.max(minPointOffset, isPointPlacementAxis && isString$d(pointPlacement) ? 0 : seriesPointRange / 2);
            pointRangePadding = Math.max(pointRangePadding, isPointPlacementAxis && pointPlacement === "on" ? 0 : seriesPointRange);
          }
        });
      }
      ordinalCorrection = axis.ordinal?.slope && closestPointRange ? axis.ordinal.slope / closestPointRange : 1;
      axis.minPointOffset = minPointOffset = minPointOffset * ordinalCorrection;
      axis.pointRangePadding = pointRangePadding = pointRangePadding * ordinalCorrection;
      axis.pointRange = Math.min(pointRange, axis.single && hasCategories ? 1 : range2);
      if (isXAxis) {
        axis.closestPointRange = closestPointRange;
      }
    }
    axis.translationSlope = axis.transA = transA = axis.staticScale || axis.len / (range2 + pointRangePadding || 1);
    axis.transB = axis.horiz ? axis.left : axis.bottom;
    axis.minPixelPadding = transA * minPointOffset;
    fireEvent$I(this, "afterSetAxisTranslation");
  }
  /**
   * @private
   * @function Highcharts.Axis#minFromRange
   */
  minFromRange() {
    const { max: max2, min: min2 } = this;
    return isNumber$11(max2) && isNumber$11(min2) && max2 - min2 || void 0;
  }
  /**
   * Set the tick positions to round values and optionally extend the extremes
   * to the nearest tick.
   *
   * @private
   * @function Highcharts.Axis#setTickInterval
   *
   * @param {boolean} secondPass
   * TO-DO: parameter description
   *
   * @emits Highcharts.Axis#event:foundExtremes
   */
  setTickInterval(secondPass) {
    const axis = this, { categories, chart, dataMax, dataMin, dateTime, isXAxis, logarithmic, options: options2, softThreshold } = axis, time = chart.time, threshold = isNumber$11(axis.threshold) ? axis.threshold : void 0, minRange = axis.minRange || 0, { ceiling, floor: floor2, linkedTo, softMax, softMin } = options2, linkedParent = isNumber$11(linkedTo) && chart[axis.coll]?.[linkedTo], tickPixelIntervalOption = options2.tickPixelInterval;
    let maxPadding = options2.maxPadding, minPadding = options2.minPadding, range2 = 0, linkedParentExtremes, tickIntervalOption = isNumber$11(options2.tickInterval) && options2.tickInterval >= 0 ? options2.tickInterval : void 0, thresholdMin, thresholdMax, hardMin, hardMax;
    if (!dateTime && !categories && !linkedParent) {
      this.getTickAmount();
    }
    hardMin = pick$1I(axis.userMin, time.parse(options2.min));
    hardMax = pick$1I(axis.userMax, time.parse(options2.max));
    if (linkedParent) {
      axis.linkedParent = linkedParent;
      linkedParentExtremes = linkedParent.getExtremes();
      axis.min = pick$1I(linkedParentExtremes.min, linkedParentExtremes.dataMin);
      axis.max = pick$1I(linkedParentExtremes.max, linkedParentExtremes.dataMax);
      if (this.type !== linkedParent.type) {
        error$8(11, true, chart);
      }
    } else {
      if (softThreshold && defined$16(threshold) && isNumber$11(dataMax) && isNumber$11(dataMin)) {
        if (dataMin >= threshold) {
          thresholdMin = threshold;
          minPadding = 0;
        } else if (dataMax <= threshold) {
          thresholdMax = threshold;
          maxPadding = 0;
        }
      }
      axis.min = pick$1I(hardMin, thresholdMin, dataMin);
      axis.max = pick$1I(hardMax, thresholdMax, dataMax);
    }
    if (isNumber$11(axis.max) && isNumber$11(axis.min)) {
      if (logarithmic) {
        if (axis.positiveValuesOnly && !secondPass && Math.min(axis.min, pick$1I(dataMin, axis.min)) <= 0) {
          error$8(10, true, chart);
        }
        axis.min = correctFloat$e(logarithmic.log2lin(axis.min), 16);
        axis.max = correctFloat$e(logarithmic.log2lin(axis.max), 16);
      }
      if (axis.range && isNumber$11(dataMin)) {
        axis.userMin = axis.min = hardMin = Math.max(dataMin, axis.minFromRange() || 0);
        axis.userMax = hardMax = axis.max;
        axis.range = void 0;
      }
    }
    fireEvent$I(axis, "foundExtremes");
    axis.adjustForMinRange();
    if (isNumber$11(axis.min) && isNumber$11(axis.max)) {
      if (!isNumber$11(axis.userMin) && isNumber$11(softMin) && softMin < axis.min) {
        axis.min = hardMin = softMin;
      }
      if (!isNumber$11(axis.userMax) && isNumber$11(softMax) && softMax > axis.max) {
        axis.max = hardMax = softMax;
      }
      if (!categories && !axis.axisPointRange && !axis.stacking?.usePercentage && !linkedParent) {
        range2 = axis.max - axis.min;
        if (range2) {
          if (!defined$16(hardMin) && minPadding) {
            axis.min -= range2 * minPadding;
          }
          if (!defined$16(hardMax) && maxPadding) {
            axis.max += range2 * maxPadding;
          }
        }
      }
      if (!isNumber$11(axis.userMin) && isNumber$11(floor2)) {
        axis.min = Math.max(axis.min, floor2);
      }
      if (!isNumber$11(axis.userMax) && isNumber$11(ceiling)) {
        axis.max = Math.min(axis.max, ceiling);
      }
      if (softThreshold && isNumber$11(dataMin) && isNumber$11(dataMax)) {
        const numThreshold = threshold || 0;
        if (!defined$16(hardMin) && axis.min < numThreshold && dataMin >= numThreshold) {
          axis.min = options2.minRange ? Math.min(numThreshold, axis.max - minRange) : numThreshold;
        } else if (!defined$16(hardMax) && axis.max > numThreshold && dataMax <= numThreshold) {
          axis.max = options2.minRange ? Math.max(numThreshold, axis.min + minRange) : numThreshold;
        }
      }
      if (!chart.polar && axis.min > axis.max) {
        if (defined$16(options2.min)) {
          axis.max = axis.min;
        } else if (defined$16(options2.max)) {
          axis.min = axis.max;
        }
      }
      range2 = axis.max - axis.min;
    }
    if (axis.min === axis.max || !isNumber$11(axis.min) || !isNumber$11(axis.max)) {
      axis.tickInterval = 1;
    } else if (linkedParent && !tickIntervalOption && tickPixelIntervalOption === linkedParent.options.tickPixelInterval) {
      axis.tickInterval = tickIntervalOption = linkedParent.tickInterval;
    } else {
      axis.tickInterval = pick$1I(
        tickIntervalOption,
        this.tickAmount ? range2 / Math.max(this.tickAmount - 1, 1) : void 0,
        // For categorized axis, 1 is default, for linear axis use
        // tickPix
        categories ? 1 : (
          // Don't let it be more than the data range
          range2 * tickPixelIntervalOption / Math.max(axis.len, tickPixelIntervalOption)
        )
      );
    }
    if (isXAxis && !secondPass) {
      const hasExtremesChanged = axis.min !== axis.old?.min || axis.max !== axis.old?.max;
      axis.series.forEach(function(series) {
        series.forceCrop = series.forceCropping?.();
        series.processData(hasExtremesChanged);
      });
      fireEvent$I(this, "postProcessData", { hasExtremesChanged });
    }
    axis.setAxisTranslation();
    fireEvent$I(this, "initialAxisTranslation");
    if (axis.pointRange && !tickIntervalOption) {
      axis.tickInterval = Math.max(axis.pointRange, axis.tickInterval);
    }
    const minTickInterval = pick$1I(
      options2.minTickInterval,
      // In datetime axes, don't go below the data interval, except when
      // there are scatter-like series involved (#13369).
      dateTime && !axis.series.some((s) => !s.sorted) ? axis.closestPointRange : 0
    );
    if (!tickIntervalOption && minTickInterval && axis.tickInterval < minTickInterval) {
      axis.tickInterval = minTickInterval;
    }
    if (!dateTime && !logarithmic && !tickIntervalOption) {
      axis.tickInterval = getNormalizedTickInterval(axis, axis.tickInterval);
    }
    if (!this.tickAmount) {
      axis.tickInterval = axis.unsquish();
    }
    this.setTickPositions();
  }
  /**
   * Now we have computed the normalized tickInterval, get the tick positions.
   *
   * @private
   * @function Highcharts.Axis#setTickPositions
   *
   * @emits Highcharts.Axis#event:afterSetTickPositions
   */
  setTickPositions() {
    const axis = this, options2 = this.options, tickPositionsOption = options2.tickPositions, tickPositioner = options2.tickPositioner, minorTickIntervalOption = this.getMinorTickInterval(), allowEndOnTick = !this.isPanning, startOnTick = allowEndOnTick && options2.startOnTick, endOnTick = allowEndOnTick && options2.endOnTick;
    let tickPositions = [], tickPositionerResult;
    this.tickmarkOffset = this.categories && options2.tickmarkPlacement === "between" && this.tickInterval === 1 ? 0.5 : 0;
    this.single = this.min === this.max && defined$16(this.min) && !this.tickAmount && // Data is on integer (#6563)
    (this.min % 1 === 0 || // Between integers and decimals are not allowed (#6274)
    options2.allowDecimals !== false);
    if (tickPositionsOption) {
      tickPositions = tickPositionsOption.slice();
    } else if (isNumber$11(this.min) && isNumber$11(this.max)) {
      if (!axis.ordinal?.positions && (this.max - this.min) / this.tickInterval > Math.max(2 * this.len, 200)) {
        tickPositions = [this.min, this.max];
        error$8(19, false, this.chart);
      } else if (axis.dateTime) {
        tickPositions = axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(this.tickInterval, options2.units), this.min, this.max, options2.startOfWeek, axis.ordinal?.positions, this.closestPointRange, true);
      } else if (axis.logarithmic) {
        tickPositions = axis.logarithmic.getLogTickPositions(this.tickInterval, this.min, this.max);
      } else {
        const startingTickInterval = this.tickInterval;
        let adjustedTickInterval = startingTickInterval;
        while (adjustedTickInterval <= startingTickInterval * 2) {
          tickPositions = this.getLinearTickPositions(this.tickInterval, this.min, this.max);
          if (this.tickAmount && tickPositions.length > this.tickAmount) {
            this.tickInterval = getNormalizedTickInterval(this, adjustedTickInterval *= 1.1);
          } else {
            break;
          }
        }
      }
      if (tickPositions.length > this.len) {
        tickPositions = [
          tickPositions[0],
          tickPositions[tickPositions.length - 1]
        ];
        if (tickPositions[0] === tickPositions[1]) {
          tickPositions.length = 1;
        }
      }
      if (tickPositioner) {
        this.tickPositions = tickPositions;
        tickPositionerResult = tickPositioner.apply(axis, [this.min, this.max]);
        if (tickPositionerResult) {
          tickPositions = tickPositionerResult;
        }
      }
    }
    this.tickPositions = tickPositions;
    this.minorTickInterval = minorTickIntervalOption === "auto" && this.tickInterval ? this.tickInterval / options2.minorTicksPerMajor : minorTickIntervalOption;
    this.paddedTicks = tickPositions.slice(0);
    this.trimTicks(tickPositions, startOnTick, endOnTick);
    if (!this.isLinked && isNumber$11(this.min) && isNumber$11(this.max)) {
      if (this.single && tickPositions.length < 2 && !this.categories && !this.series.some((s) => s.is("heatmap") && s.options.pointPlacement === "between")) {
        this.min -= 0.5;
        this.max += 0.5;
      }
      if (!tickPositionsOption && !tickPositionerResult) {
        this.adjustTickAmount();
      }
    }
    fireEvent$I(this, "afterSetTickPositions");
  }
  /**
   * Handle startOnTick and endOnTick by either adapting to padding min/max or
   * rounded min/max. Also handle single data points.
   *
   * @private
   * @function Highcharts.Axis#trimTicks
   *
   * @param {Array<number>} tickPositions
   * TO-DO: parameter description
   *
   * @param {boolean} [startOnTick]
   * TO-DO: parameter description
   *
   * @param {boolean} [endOnTick]
   * TO-DO: parameter description
   */
  trimTicks(tickPositions, startOnTick, endOnTick) {
    const roundedMin = tickPositions[0], roundedMax = tickPositions[tickPositions.length - 1], minPointOffset = !this.isOrdinal && this.minPointOffset || 0;
    fireEvent$I(this, "trimTicks");
    if (!this.isLinked || // Linked non-grid axes should trim ticks, #21743.
    // Grid axis has custom handling of ticks.
    !this.grid) {
      if (startOnTick && roundedMin !== -Infinity) {
        this.min = roundedMin;
      } else {
        while (this.min - minPointOffset > tickPositions[0]) {
          tickPositions.shift();
        }
      }
      if (endOnTick) {
        this.max = roundedMax;
      } else {
        while (this.max + minPointOffset < tickPositions[tickPositions.length - 1]) {
          tickPositions.pop();
        }
      }
      if (tickPositions.length === 0 && defined$16(roundedMin) && !this.options.tickPositions) {
        tickPositions.push((roundedMax + roundedMin) / 2);
      }
    }
  }
  /**
   * Check if there are multiple axes in the same pane.
   *
   * @private
   * @function Highcharts.Axis#alignToOthers
   *
   * @return {boolean|undefined}
   * True if there are other axes.
   */
  alignToOthers() {
    const axis = this, chart = axis.chart, alignedAxes = [this], options2 = axis.options, chartOptions = chart.options.chart, alignThresholds = this.coll === "yAxis" && chartOptions.alignThresholds, thresholdAlignments = [];
    let hasOther;
    axis.thresholdAlignment = void 0;
    if (
      // Only if alignTicks or alignThresholds is true
      (chartOptions.alignTicks !== false && options2.alignTicks || alignThresholds) && // Disabled when startOnTick or endOnTick are false (#7604)
      options2.startOnTick !== false && options2.endOnTick !== false && // Don't try to align ticks on a log axis, they are not evenly
      // spaced (#6021)
      !axis.logarithmic
    ) {
      const getKey = (axis2) => {
        const { horiz, options: options3 } = axis2;
        return [
          horiz ? options3.left : options3.top,
          options3.width,
          options3.height,
          options3.pane
        ].join(",");
      };
      const thisKey = getKey(this);
      chart[this.coll].forEach(function(otherAxis) {
        const { series } = otherAxis;
        if (
          // #4442
          series.length && series.some((s) => s.visible) && otherAxis !== axis && getKey(otherAxis) === thisKey
        ) {
          hasOther = true;
          alignedAxes.push(otherAxis);
        }
      });
    }
    if (hasOther && alignThresholds) {
      alignedAxes.forEach((otherAxis) => {
        const threshAlign = otherAxis.getThresholdAlignment(axis);
        if (isNumber$11(threshAlign)) {
          thresholdAlignments.push(threshAlign);
        }
      });
      const thresholdAlignment = thresholdAlignments.length > 1 ? thresholdAlignments.reduce((sum2, n) => sum2 += n, 0) / thresholdAlignments.length : void 0;
      alignedAxes.forEach((axis2) => {
        axis2.thresholdAlignment = thresholdAlignment;
      });
    }
    return hasOther;
  }
  /**
   * Where the axis wants its threshold, from 0 which is on `axis.min`, to 1 which
   * is on `axis.max`.
   *
   * @private
   * @function Highcharts.Axis#getThresholdAlignment
   */
  getThresholdAlignment(callerAxis) {
    if (!isNumber$11(this.dataMin) || this !== callerAxis && this.series.some((s) => s.isDirty || s.isDirtyData)) {
      this.getSeriesExtremes();
    }
    if (isNumber$11(this.threshold)) {
      let thresholdAlignment = clamp$l((this.threshold - (this.dataMin || 0)) / ((this.dataMax || 0) - (this.dataMin || 0)), 0, 1);
      if (this.options.reversed) {
        thresholdAlignment = 1 - thresholdAlignment;
      }
      return thresholdAlignment;
    }
  }
  /**
   * Find the max ticks of either the x and y axis collection, and record it
   * in `this.tickAmount`.
   *
   * @private
   * @function Highcharts.Axis#getTickAmount
   */
  getTickAmount() {
    const axis = this, options2 = this.options, tickPixelInterval = options2.tickPixelInterval;
    let tickAmount = options2.tickAmount;
    if (!defined$16(options2.tickInterval) && !tickAmount && this.len < tickPixelInterval && !this.isRadial && !axis.logarithmic && options2.startOnTick && options2.endOnTick) {
      tickAmount = 2;
    }
    if (!tickAmount && this.alignToOthers()) {
      tickAmount = Math.ceil(this.len / tickPixelInterval) + 1;
    }
    if (tickAmount < 4) {
      this.finalTickAmt = tickAmount;
      tickAmount = 5;
    }
    this.tickAmount = tickAmount;
  }
  /**
   * When using multiple axes, adjust the number of ticks to match the highest
   * number of ticks in that group.
   *
   * @private
   * @function Highcharts.Axis#adjustTickAmount
   */
  adjustTickAmount() {
    const axis = this, { finalTickAmt, max: max2, min: min2, options: options2, tickPositions, tickAmount, thresholdAlignment } = axis, currentTickAmount = tickPositions?.length, threshold = pick$1I(axis.threshold, axis.softThreshold ? 0 : null);
    let len, i, tickInterval = axis.tickInterval, thresholdTickIndex;
    const append = () => tickPositions.push(correctFloat$e(tickPositions[tickPositions.length - 1] + tickInterval)), prepend = () => tickPositions.unshift(correctFloat$e(tickPositions[0] - tickInterval));
    if (isNumber$11(thresholdAlignment)) {
      thresholdTickIndex = thresholdAlignment < 0.5 ? Math.ceil(thresholdAlignment * (tickAmount - 1)) : Math.floor(thresholdAlignment * (tickAmount - 1));
      if (options2.reversed) {
        thresholdTickIndex = tickAmount - 1 - thresholdTickIndex;
      }
    }
    if (axis.hasData() && isNumber$11(min2) && isNumber$11(max2)) {
      const adjustExtremes2 = () => {
        axis.transA *= (currentTickAmount - 1) / (tickAmount - 1);
        axis.min = options2.startOnTick ? tickPositions[0] : Math.min(min2, tickPositions[0]);
        axis.max = options2.endOnTick ? tickPositions[tickPositions.length - 1] : Math.max(max2, tickPositions[tickPositions.length - 1]);
      };
      if (isNumber$11(thresholdTickIndex) && isNumber$11(axis.threshold)) {
        while (tickPositions[thresholdTickIndex] !== threshold || tickPositions.length !== tickAmount || tickPositions[0] > min2 || tickPositions[tickPositions.length - 1] < max2) {
          tickPositions.length = 0;
          tickPositions.push(axis.threshold);
          while (tickPositions.length < tickAmount) {
            if (
              // Start by prepending positions until the threshold
              // is at the required index...
              tickPositions[thresholdTickIndex] === void 0 || tickPositions[thresholdTickIndex] > axis.threshold
            ) {
              prepend();
            } else {
              append();
            }
          }
          if (tickInterval > axis.tickInterval * 8) {
            break;
          }
          tickInterval *= 2;
        }
        adjustExtremes2();
      } else if (currentTickAmount < tickAmount) {
        while (tickPositions.length < tickAmount) {
          if (tickPositions.length % 2 || min2 === threshold) {
            append();
          } else {
            prepend();
          }
        }
        adjustExtremes2();
      }
      if (defined$16(finalTickAmt)) {
        i = len = tickPositions.length;
        while (i--) {
          if (
            // Remove every other tick
            finalTickAmt === 3 && i % 2 === 1 || // Remove all but first and last
            finalTickAmt <= 2 && i > 0 && i < len - 1
          ) {
            tickPositions.splice(i, 1);
          }
        }
        axis.finalTickAmt = void 0;
      }
    }
  }
  /**
   * Set the scale based on data min and max, user set min and max or options.
   *
   * @private
   * @function Highcharts.Axis#setScale
   *
   * @emits Highcharts.Axis#event:afterSetScale
   */
  setScale() {
    const axis = this, { coll, stacking } = axis;
    let isDirtyData = false, isXAxisDirty = false;
    axis.series.forEach((series) => {
      isDirtyData = isDirtyData || series.isDirtyData || series.isDirty;
      isXAxisDirty = isXAxisDirty || series.xAxis?.isDirty || false;
    });
    axis.setAxisSize();
    const isDirtyAxisLength = axis.len !== axis.old?.len;
    if (isDirtyAxisLength || isDirtyData || isXAxisDirty || axis.isLinked || axis.forceRedraw || axis.userMin !== axis.old?.userMin || axis.userMax !== axis.old?.userMax || axis.alignToOthers()) {
      if (stacking && coll === "yAxis") {
        stacking.buildStacks();
      }
      axis.forceRedraw = false;
      if (!axis.userMinRange) {
        axis.minRange = void 0;
      }
      axis.getSeriesExtremes();
      axis.setTickInterval();
      if (stacking && coll === "xAxis") {
        stacking.buildStacks();
      }
      if (!axis.isDirty) {
        axis.isDirty = isDirtyAxisLength || axis.min !== axis.old?.min || axis.max !== axis.old?.max;
      }
    } else if (stacking) {
      stacking.cleanStacks();
    }
    if (isDirtyData) {
      delete axis.allExtremes;
    }
    fireEvent$I(this, "afterSetScale");
  }
  /**
   * Set the minimum and maximum of the axes after render time. If the
   * `startOnTick` and `endOnTick` options are true, the minimum and maximum
   * values are rounded off to the nearest tick. To prevent this, these
   * options can be set to false before calling setExtremes. Also, setExtremes
   * will not allow a range lower than the `minRange` option, which by default
   * is the range of five points.
   *
   * @sample highcharts/members/axis-setextremes/
   *         Set extremes from a button
   * @sample highcharts/members/axis-setextremes-datetime/
   *         Set extremes on a datetime axis
   * @sample highcharts/members/axis-setextremes-off-ticks/
   *         Set extremes off ticks
   * @sample stock/members/axis-setextremes/
   *         Set extremes in Highcharts Stock
   *
   * @function Highcharts.Axis#setExtremes
   *
   * @param {number|string} [newMin]
   * The new minimum value. For datetime axes, date strings are accepted.
   *
   * @param {number|string} [newMax]
   * The new maximum value. For datetime axes, date strings are accepted.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart or wait for an explicit call to
   * {@link Highcharts.Chart#redraw}
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
   * Enable or modify animations.
   *
   * @param {*} [eventArguments]
   * Arguments to be accessed in event handler.
   *
   * @emits Highcharts.Axis#event:setExtremes
   */
  setExtremes(min2, max2, redraw = true, animation, eventArguments) {
    const chart = this.chart;
    this.series.forEach((serie) => {
      delete serie.kdTree;
    });
    min2 = chart.time.parse(min2);
    max2 = chart.time.parse(max2);
    eventArguments = extend$1k(eventArguments, { min: min2, max: max2 });
    fireEvent$I(this, "setExtremes", eventArguments, (e) => {
      this.userMin = e.min;
      this.userMax = e.max;
      this.eventArgs = e;
      if (redraw) {
        chart.redraw(animation);
      }
    });
  }
  /**
   * Update the axis metrics.
   *
   * @private
   * @function Highcharts.Axis#setAxisSize
   */
  setAxisSize() {
    const chart = this.chart, options2 = this.options, offsets = options2.offsets || [0, 0, 0, 0], horiz = this.horiz, width = this.width = Math.round(relativeLength$h(pick$1I(options2.width, chart.plotWidth - offsets[3] + offsets[1]), chart.plotWidth)), height = this.height = Math.round(relativeLength$h(pick$1I(options2.height, chart.plotHeight - offsets[0] + offsets[2]), chart.plotHeight)), top = this.top = Math.round(relativeLength$h(pick$1I(options2.top, chart.plotTop + offsets[0]), chart.plotHeight, chart.plotTop)), left = this.left = Math.round(relativeLength$h(pick$1I(options2.left, chart.plotLeft + offsets[3]), chart.plotWidth, chart.plotLeft));
    this.bottom = chart.chartHeight - height - top;
    this.right = chart.chartWidth - width - left;
    this.len = Math.max(horiz ? width : height, 0);
    this.pos = horiz ? left : top;
  }
  /**
   * Get the current extremes for the axis.
   *
   * @sample highcharts/members/axis-getextremes/
   *         Report extremes by click on a button
   *
   * @function Highcharts.Axis#getExtremes
   *
   * @return {Highcharts.ExtremesObject}
   * An object containing extremes information.
   */
  getExtremes() {
    const axis = this, log = axis.logarithmic;
    return {
      min: log ? correctFloat$e(log.lin2log(axis.min)) : axis.min,
      max: log ? correctFloat$e(log.lin2log(axis.max)) : axis.max,
      dataMin: axis.dataMin,
      dataMax: axis.dataMax,
      userMin: axis.userMin,
      userMax: axis.userMax
    };
  }
  /**
   * Get the zero plane either based on zero or on the min or max value.
   * Used in bar and area plots.
   *
   * @function Highcharts.Axis#getThreshold
   *
   * @param {number} threshold
   * The threshold in axis values.
   *
   * @return {number}
   * The translated threshold position in terms of pixels, and corrected to
   * stay within the axis bounds.
   */
  getThreshold(threshold) {
    const axis = this, log = axis.logarithmic, realMin = log ? log.lin2log(axis.min) : axis.min, realMax = log ? log.lin2log(axis.max) : axis.max;
    if (threshold === null || threshold === -Infinity) {
      threshold = realMin;
    } else if (threshold === Infinity) {
      threshold = realMax;
    } else if (realMin > threshold) {
      threshold = realMin;
    } else if (realMax < threshold) {
      threshold = realMax;
    }
    return axis.translate(threshold, 0, 1, 0, 1);
  }
  /**
   * Compute auto alignment for the axis label based on which side the axis is
   * on and the given rotation for the label.
   *
   * @private
   * @function Highcharts.Axis#autoLabelAlign
   *
   * @param {number} rotation
   * The rotation in degrees as set by either the `rotation` or `autoRotation`
   * options.
   *
   * @return {Highcharts.AlignValue}
   * Can be `"center"`, `"left"` or `"right"`.
   */
  autoLabelAlign(rotation) {
    const angle = (pick$1I(rotation, 0) - this.side * 90 + 720) % 360, evt = { align: "center" };
    fireEvent$I(this, "autoLabelAlign", evt, function(e) {
      if (angle > 15 && angle < 165) {
        e.align = "right";
      } else if (angle > 195 && angle < 345) {
        e.align = "left";
      }
    });
    return evt.align;
  }
  /**
   * Get the tick length and width for the axis based on axis options.
   *
   * @private
   * @function Highcharts.Axis#tickSize
   *
   * @param {string} [prefix]
   * 'tick' or 'minorTick'
   *
   * @return {Array<number,number>|undefined}
   * An array of tickLength and tickWidth
   */
  tickSize(prefix) {
    const options2 = this.options, tickWidth = pick$1I(
      options2[prefix === "tick" ? "tickWidth" : "minorTickWidth"],
      // Default to 1 on linear and datetime X axes
      prefix === "tick" && this.isXAxis && !this.categories ? 1 : 0
    );
    let tickLength = options2[prefix === "tick" ? "tickLength" : "minorTickLength"], tickSize;
    if (tickWidth && tickLength) {
      if (options2[prefix + "Position"] === "inside") {
        tickLength = -tickLength;
      }
      tickSize = [tickLength, tickWidth];
    }
    const e = { tickSize };
    fireEvent$I(this, "afterTickSize", e);
    return e.tickSize;
  }
  /**
   * Return the size of the labels.
   *
   * @private
   * @function Highcharts.Axis#labelMetrics
   */
  labelMetrics() {
    const renderer = this.chart.renderer, ticks = this.ticks, tick = ticks[Object.keys(ticks)[0]] || {};
    return this.chart.renderer.fontMetrics(tick.label || tick.movedLabel || renderer.box);
  }
  /**
   * Prevent the ticks from getting so close we can't draw the labels. On a
   * horizontal axis, this is handled by rotating the labels, removing ticks
   * and adding ellipsis. On a vertical axis remove ticks and add ellipsis.
   *
   * @private
   * @function Highcharts.Axis#unsquish
   */
  unsquish() {
    const labelOptions = this.options.labels, padding = labelOptions.padding || 0, horiz = this.horiz, tickInterval = this.tickInterval, slotSize = this.len / (((this.categories ? 1 : 0) + this.max - this.min) / tickInterval), rotationOption = labelOptions.rotation, lineHeight = correctFloat$e(this.labelMetrics().h * 0.8), range2 = Math.max(this.max - this.min, 0), getStep = function(spaceNeeded) {
      let step = (spaceNeeded + 2 * padding) / (slotSize || 1);
      step = step > 1 ? Math.ceil(step) : 1;
      if (step * tickInterval > range2 && spaceNeeded !== Infinity && slotSize !== Infinity && range2) {
        step = Math.ceil(range2 / tickInterval);
      }
      return correctFloat$e(step * tickInterval);
    };
    let newTickInterval = tickInterval, rotation, bestScore = Number.MAX_VALUE, autoRotation;
    if (horiz) {
      if (!labelOptions.staggerLines) {
        if (isNumber$11(rotationOption)) {
          autoRotation = [rotationOption];
        } else if (slotSize < labelOptions.autoRotationLimit) {
          autoRotation = labelOptions.autoRotation;
        }
      }
      if (autoRotation) {
        let step, score;
        for (const rot of autoRotation) {
          if (rot === rotationOption || rot && rot >= -90 && rot <= 90) {
            step = getStep(Math.abs(lineHeight / Math.sin(deg2rad$7 * rot)));
            score = step + Math.abs(rot / 360);
            if (score < bestScore) {
              bestScore = score;
              rotation = rot;
              newTickInterval = step;
            }
          }
        }
      }
    } else {
      newTickInterval = getStep(lineHeight * 0.75);
    }
    this.autoRotation = autoRotation;
    this.labelRotation = pick$1I(rotation, isNumber$11(rotationOption) ? rotationOption : 0);
    return labelOptions.step ? tickInterval : newTickInterval;
  }
  /**
   * Get the general slot width for labels/categories on this axis. This may
   * change between the pre-render (from Axis.getOffset) and the final tick
   * rendering and placement.
   *
   * @private
   * @function Highcharts.Axis#getSlotWidth
   *
   * @param {Highcharts.Tick} [tick] Optionally, calculate the slot width
   * basing on tick label. It is used in highcharts-3d module, where the slots
   * has different widths depending on perspective angles.
   *
   * @return {number}
   * The pixel width allocated to each axis label.
   */
  getSlotWidth(tick) {
    const chart = this.chart, horiz = this.horiz, labelOptions = this.options.labels, slotCount = Math.max(this.tickPositions.length - (this.categories ? 0 : 1), 1), marginLeft = chart.margin[3];
    if (tick && isNumber$11(tick.slotWidth)) {
      return tick.slotWidth;
    }
    if (horiz && labelOptions.step < 2 && !this.isRadial) {
      if (labelOptions.rotation) {
        return 0;
      }
      return (this.staggerLines || 1) * this.len / slotCount;
    }
    if (!horiz) {
      const cssWidth = labelOptions.style.width;
      if (cssWidth !== void 0) {
        return parseInt(String(cssWidth), 10);
      }
      if (marginLeft) {
        return marginLeft - chart.spacing[3];
      }
    }
    return chart.chartWidth * 0.33;
  }
  /**
   * Render the axis labels and determine whether ellipsis or rotation need to
   * be applied.
   *
   * @private
   * @function Highcharts.Axis#renderUnsquish
   */
  renderUnsquish() {
    const chart = this.chart, renderer = chart.renderer, tickPositions = this.tickPositions, ticks = this.ticks, labelOptions = this.options.labels, labelStyleOptions = labelOptions.style, horiz = this.horiz, slotWidth = this.getSlotWidth(), innerWidth = Math.max(1, Math.round(slotWidth - (horiz ? 2 * (labelOptions.padding || 0) : labelOptions.distance || 0))), attr2 = {}, labelMetrics = this.labelMetrics(), lineClampOption = labelStyleOptions.lineClamp;
    let commonWidth, lineClamp = lineClampOption ?? (Math.floor(this.len / (tickPositions.length * labelMetrics.h)) || 1), maxLabelLength = 0;
    if (!isString$d(labelOptions.rotation)) {
      attr2.rotation = labelOptions.rotation || 0;
    }
    tickPositions.forEach(function(tickPosition) {
      const tick = ticks[tickPosition];
      if (tick.movedLabel) {
        tick.replaceMovedLabel();
      }
      const textPxLength = tick.label?.textPxLength || 0;
      if (textPxLength > maxLabelLength) {
        maxLabelLength = textPxLength;
      }
    });
    this.maxLabelLength = maxLabelLength;
    if (this.autoRotation) {
      if (maxLabelLength > innerWidth && maxLabelLength > labelMetrics.h) {
        attr2.rotation = this.labelRotation;
      } else {
        this.labelRotation = 0;
      }
    } else if (slotWidth) {
      commonWidth = innerWidth;
    }
    if (attr2.rotation) {
      commonWidth = maxLabelLength > chart.chartHeight * 0.5 ? chart.chartHeight * 0.33 : maxLabelLength;
      if (!lineClampOption) {
        lineClamp = 1;
      }
    }
    this.labelAlign = labelOptions.align || this.autoLabelAlign(this.labelRotation);
    if (this.labelAlign) {
      attr2.align = this.labelAlign;
    }
    tickPositions.forEach(function(pos) {
      const tick = ticks[pos], label = tick?.label, widthOption = labelStyleOptions.width, css2 = {};
      if (label) {
        label.attr(attr2);
        if (tick.shortenLabel) {
          tick.shortenLabel();
        } else if (commonWidth && !widthOption && // Setting width in this case messes with the bounding box
        // (#7975)
        labelStyleOptions.whiteSpace !== "nowrap" && // Speed optimizing, #7656
        (commonWidth < (label.textPxLength || 0) || // Resetting CSS, #4928
        label.element.tagName === "SPAN")) {
          label.css(extend$1k(css2, {
            width: `${commonWidth}px`,
            lineClamp
          }));
        } else if (label.styles.width && !css2.width && !widthOption) {
          label.css({ width: "auto" });
        }
        tick.rotation = attr2.rotation;
      }
    }, this);
    this.tickRotCorr = renderer.rotCorr(labelMetrics.b, this.labelRotation || 0, this.side !== 0);
  }
  /**
   * Return true if the axis has associated data.
   *
   * @function Highcharts.Axis#hasData
   *
   * @return {boolean}
   * True if the axis has associated visible series and those series have
   * either valid data points or explicit `min` and `max` settings.
   */
  hasData() {
    return this.series.some(function(s) {
      return s.hasData();
    }) || this.options.showEmpty && defined$16(this.min) && defined$16(this.max);
  }
  /**
   * Adds the title defined in axis.options.title.
   *
   * @function Highcharts.Axis#addTitle
   *
   * @param {boolean} [display]
   * Whether or not to display the title.
   */
  addTitle(display) {
    const axis = this, renderer = axis.chart.renderer, horiz = axis.horiz, opposite = axis.opposite, options2 = axis.options, axisTitleOptions = options2.title, styledMode = axis.chart.styledMode;
    let textAlign;
    if (!axis.axisTitle) {
      textAlign = axisTitleOptions.textAlign;
      if (!textAlign) {
        textAlign = (horiz ? {
          low: "left",
          middle: "center",
          high: "right"
        } : {
          low: opposite ? "right" : "left",
          middle: "center",
          high: opposite ? "left" : "right"
        })[axisTitleOptions.align];
      }
      axis.axisTitle = renderer.text(axisTitleOptions.text || "", 0, 0, axisTitleOptions.useHTML).attr({
        zIndex: 7,
        rotation: axisTitleOptions.rotation || 0,
        align: textAlign
      }).addClass("highcharts-axis-title");
      if (!styledMode) {
        axis.axisTitle.css(merge$1B(axisTitleOptions.style));
      }
      axis.axisTitle.add(axis.axisGroup);
      axis.axisTitle.isNew = true;
    }
    if (!styledMode && !axisTitleOptions.style.width && !axis.isRadial) {
      axis.axisTitle.css({
        width: axis.len + "px"
      });
    }
    axis.axisTitle[display ? "show" : "hide"](display);
  }
  /**
   * Generates a tick for initial positioning.
   *
   * @private
   * @function Highcharts.Axis#generateTick
   *
   * @param {number} pos
   * The tick position in axis values.
   *
   * @param {number} [i]
   * The index of the tick in {@link Axis.tickPositions}.
   */
  generateTick(pos) {
    const axis = this, ticks = axis.ticks;
    if (!ticks[pos]) {
      ticks[pos] = new Tick(axis, pos);
    } else {
      ticks[pos].addLabel();
    }
  }
  /**
   * Create the axisGroup and gridGroup elements on first iteration.
   *
   * @private
   * @function Highcharts.Axis#getOffset
   *
   * @emits Highcharts.Axis#event:afterGetOffset
   */
  createGroups() {
    const {
      axisParent,
      // Used in color axis
      chart,
      coll,
      options: options2
    } = this, renderer = chart.renderer;
    const createGroup = (name, suffix, zIndex) => renderer.g(name).attr({ zIndex }).addClass(`highcharts-${coll.toLowerCase()}${suffix} ` + (this.isRadial ? `highcharts-radial-axis${suffix} ` : "") + (options2.className || "")).add(axisParent);
    if (!this.axisGroup) {
      this.gridGroup = createGroup("grid", "-grid", options2.gridZIndex);
      this.axisGroup = createGroup("axis", "", options2.zIndex);
      this.labelGroup = createGroup("axis-labels", "-labels", options2.labels.zIndex);
    }
  }
  /**
   * Render the tick labels to a preliminary position to get their sizes
   *
   * @private
   * @function Highcharts.Axis#getOffset
   *
   * @emits Highcharts.Axis#event:afterGetOffset
   */
  getOffset() {
    const axis = this, { chart, horiz, options: options2, side, ticks, tickPositions, coll } = axis, invertedSide = chart.inverted && !axis.isZAxis ? [1, 0, 3, 2][side] : side, hasData = axis.hasData(), axisTitleOptions = options2.title, labelOptions = options2.labels, hasCrossing = isNumber$11(options2.crossing), axisOffset = chart.axisOffset, clipOffset = chart.clipOffset, directionFactor = [-1, 1, 1, -1][side];
    let showAxis, titleOffset = 0, titleOffsetOption, titleMargin = 0, labelOffset = 0, labelOffsetPadded, lineHeightCorrection;
    axis.showAxis = showAxis = hasData || options2.showEmpty;
    axis.staggerLines = axis.horiz && labelOptions.staggerLines || void 0;
    axis.createGroups();
    if (hasData || axis.isLinked) {
      tickPositions.forEach(function(pos) {
        axis.generateTick(pos);
      });
      axis.renderUnsquish();
      axis.reserveSpaceDefault = side === 0 || side === 2 || { 1: "left", 3: "right" }[side] === axis.labelAlign;
      if (pick$1I(labelOptions.reserveSpace, hasCrossing ? false : null, axis.labelAlign === "center" ? true : null, axis.reserveSpaceDefault)) {
        tickPositions.forEach(function(pos) {
          labelOffset = Math.max(ticks[pos].getLabelSize(), labelOffset);
        });
      }
      if (axis.staggerLines) {
        labelOffset *= axis.staggerLines;
      }
      axis.labelOffset = labelOffset * (axis.opposite ? -1 : 1);
    } else {
      objectEach$q(ticks, function(tick, n) {
        tick.destroy();
        delete ticks[n];
      });
    }
    if (axisTitleOptions?.text && axisTitleOptions.enabled !== false) {
      axis.addTitle(showAxis);
      if (showAxis && !hasCrossing && axisTitleOptions.reserveSpace !== false) {
        axis.titleOffset = titleOffset = axis.axisTitle.getBBox()[horiz ? "height" : "width"];
        titleOffsetOption = axisTitleOptions.offset;
        titleMargin = defined$16(titleOffsetOption) ? 0 : pick$1I(axisTitleOptions.margin, horiz ? 5 : 10);
      }
    }
    axis.renderLine();
    axis.offset = directionFactor * pick$1I(options2.offset, axisOffset[side] ? axisOffset[side] + (options2.margin || 0) : 0);
    axis.tickRotCorr = axis.tickRotCorr || { x: 0, y: 0 };
    if (side === 0) {
      lineHeightCorrection = -axis.labelMetrics().h;
    } else if (side === 2) {
      lineHeightCorrection = axis.tickRotCorr.y;
    } else {
      lineHeightCorrection = 0;
    }
    labelOffsetPadded = Math.abs(labelOffset) + titleMargin;
    if (labelOffset) {
      labelOffsetPadded -= lineHeightCorrection;
      labelOffsetPadded += directionFactor * (horiz ? pick$1I(labelOptions.y, axis.tickRotCorr.y + directionFactor * labelOptions.distance) : pick$1I(labelOptions.x, directionFactor * labelOptions.distance));
    }
    axis.axisTitleMargin = pick$1I(titleOffsetOption, labelOffsetPadded);
    if (axis.getMaxLabelDimensions) {
      axis.maxLabelDimensions = axis.getMaxLabelDimensions(ticks, tickPositions);
    }
    if (coll !== "colorAxis" && clipOffset) {
      const tickSize = this.tickSize("tick");
      axisOffset[side] = Math.max(
        axisOffset[side],
        (axis.axisTitleMargin || 0) + titleOffset + directionFactor * axis.offset,
        labelOffsetPadded,
        // #3027
        tickPositions?.length && tickSize ? tickSize[0] + directionFactor * axis.offset : 0
        // #4866
      );
      const clip = !axis.axisLine || options2.offset ? 0 : (
        // #4308, #4371
        axis.axisLine.strokeWidth() / 2
      );
      clipOffset[invertedSide] = Math.max(clipOffset[invertedSide], clip);
    }
    fireEvent$I(this, "afterGetOffset");
  }
  /**
   * Internal function to get the path for the axis line. Extended for polar
   * charts.
   *
   * @function Highcharts.Axis#getLinePath
   *
   * @param {number} lineWidth
   * The line width in pixels.
   *
   * @return {Highcharts.SVGPathArray}
   * The SVG path definition in array form.
   */
  getLinePath(lineWidth) {
    const chart = this.chart, opposite = this.opposite, offset2 = this.offset, horiz = this.horiz, lineLeft = this.left + (opposite ? this.width : 0) + offset2, lineTop = chart.chartHeight - this.bottom - (opposite ? this.height : 0) + offset2;
    if (opposite) {
      lineWidth *= -1;
    }
    return chart.renderer.crispLine([
      [
        "M",
        horiz ? this.left : lineLeft,
        horiz ? lineTop : this.top
      ],
      [
        "L",
        horiz ? chart.chartWidth - this.right : lineLeft,
        horiz ? lineTop : chart.chartHeight - this.bottom
      ]
    ], lineWidth);
  }
  /**
   * Render the axis line. Called internally when rendering and redrawing the
   * axis.
   *
   * @function Highcharts.Axis#renderLine
   */
  renderLine() {
    if (!this.axisLine) {
      this.axisLine = this.chart.renderer.path().addClass("highcharts-axis-line").add(this.axisGroup);
      if (!this.chart.styledMode) {
        this.axisLine.attr({
          stroke: this.options.lineColor,
          "stroke-width": this.options.lineWidth,
          zIndex: 7
        });
      }
    }
  }
  /**
   * Position the axis title.
   *
   * @private
   * @function Highcharts.Axis#getTitlePosition
   *
   * @return {Highcharts.PositionObject}
   * X and Y positions for the title.
   */
  getTitlePosition(axisTitle) {
    const horiz = this.horiz, axisLeft = this.left, axisTop = this.top, axisLength = this.len, axisTitleOptions = this.options.title, margin = horiz ? axisLeft : axisTop, opposite = this.opposite, offset2 = this.offset, xOption = axisTitleOptions.x, yOption = axisTitleOptions.y, fontMetrics = this.chart.renderer.fontMetrics(axisTitle), textHeightOvershoot = axisTitle ? Math.max(axisTitle.getBBox(false, 0).height - fontMetrics.h - 1, 0) : 0, alongAxis = {
      low: margin + (horiz ? 0 : axisLength),
      middle: margin + axisLength / 2,
      high: margin + (horiz ? axisLength : 0)
    }[axisTitleOptions.align], offAxis = (horiz ? axisTop + this.height : axisLeft) + (horiz ? 1 : -1) * // Horizontal axis reverses the margin
    (opposite ? -1 : 1) * // So does opposite axes
    (this.axisTitleMargin || 0) + [
      -textHeightOvershoot,
      // Top
      textHeightOvershoot,
      // Right
      fontMetrics.f,
      // Bottom
      -textHeightOvershoot
      // Left
    ][this.side], titlePosition = {
      x: horiz ? alongAxis + xOption : offAxis + (opposite ? this.width : 0) + offset2 + xOption,
      y: horiz ? offAxis + yOption - (opposite ? this.height : 0) + offset2 : alongAxis + yOption
    };
    fireEvent$I(this, "afterGetTitlePosition", { titlePosition });
    return titlePosition;
  }
  /**
   * Render a minor tick into the given position. If a minor tick already
   * exists in this position, move it.
   *
   * @function Highcharts.Axis#renderMinorTick
   *
   * @param {number} pos
   * The position in axis values.
   *
   * @param {boolean} slideIn
   * Whether the tick should animate in from last computed position
   */
  renderMinorTick(pos, slideIn) {
    const axis = this;
    const minorTicks = axis.minorTicks;
    if (!minorTicks[pos]) {
      minorTicks[pos] = new Tick(axis, pos, "minor");
    }
    if (slideIn && minorTicks[pos].isNew) {
      minorTicks[pos].render(null, true);
    }
    minorTicks[pos].render(null, false, 1);
  }
  /**
   * Render a major tick into the given position. If a tick already exists
   * in this position, move it.
   *
   * @function Highcharts.Axis#renderTick
   *
   * @param {number} pos
   * The position in axis values.
   *
   * @param {number} i
   * The tick index.
   *
   * @param {boolean} slideIn
   * Whether the tick should animate in from last computed position
   */
  renderTick(pos, i, slideIn) {
    const axis = this, isLinked = axis.isLinked, ticks = axis.ticks;
    if (!isLinked || pos >= axis.min && pos <= axis.max || axis.grid?.isColumn) {
      if (!ticks[pos]) {
        ticks[pos] = new Tick(axis, pos);
      }
      if (slideIn && ticks[pos].isNew) {
        ticks[pos].render(i, true, -1);
      }
      ticks[pos].render(i);
    }
  }
  /**
   * Render the axis.
   *
   * @private
   * @function Highcharts.Axis#render
   *
   * @emits Highcharts.Axis#event:afterRender
   */
  render() {
    const axis = this, chart = axis.chart, log = axis.logarithmic, renderer = chart.renderer, options2 = axis.options, isLinked = axis.isLinked, tickPositions = axis.tickPositions, axisTitle = axis.axisTitle, ticks = axis.ticks, minorTicks = axis.minorTicks, alternateBands = axis.alternateBands, stackLabelOptions = options2.stackLabels, alternateGridColor = options2.alternateGridColor, crossing = options2.crossing, tickmarkOffset = axis.tickmarkOffset, axisLine = axis.axisLine, showAxis = axis.showAxis, animation = animObject$e(renderer.globalAnimation);
    let from, to;
    axis.labelEdge.length = 0;
    axis.overlap = false;
    [ticks, minorTicks, alternateBands].forEach(function(coll) {
      objectEach$q(coll, function(tick) {
        tick.isActive = false;
      });
    });
    if (isNumber$11(crossing)) {
      const otherAxis = this.isXAxis ? chart.yAxis[0] : chart.xAxis[0], directionFactor = [1, -1, -1, 1][this.side];
      if (otherAxis) {
        let px = otherAxis.toPixels(crossing, true);
        if (axis.horiz) {
          px = otherAxis.len - px;
        }
        axis.offset = directionFactor * px;
      }
    }
    if (axis.hasData() || isLinked) {
      const slideInTicks = axis.chart.hasRendered && axis.old && isNumber$11(axis.old.min);
      if (axis.minorTickInterval && !axis.categories) {
        axis.getMinorTickPositions().forEach(function(pos) {
          axis.renderMinorTick(pos, slideInTicks);
        });
      }
      if (tickPositions.length) {
        tickPositions.forEach(function(pos, i) {
          axis.renderTick(pos, i, slideInTicks);
        });
        if (tickmarkOffset && (axis.min === 0 || axis.single)) {
          if (!ticks[-1]) {
            ticks[-1] = new Tick(axis, -1, null, true);
          }
          ticks[-1].render(-1);
        }
      }
      if (alternateGridColor) {
        tickPositions.forEach(function(pos, i) {
          to = typeof tickPositions[i + 1] !== "undefined" ? tickPositions[i + 1] + tickmarkOffset : axis.max - tickmarkOffset;
          if (i % 2 === 0 && pos < axis.max && to <= axis.max + (chart.polar ? -tickmarkOffset : tickmarkOffset)) {
            if (!alternateBands[pos]) {
              alternateBands[pos] = new Highcharts.PlotLineOrBand(axis, {});
            }
            from = pos + tickmarkOffset;
            alternateBands[pos].options = {
              from: log ? log.lin2log(from) : from,
              to: log ? log.lin2log(to) : to,
              color: alternateGridColor,
              className: "highcharts-alternate-grid"
            };
            alternateBands[pos].render();
            alternateBands[pos].isActive = true;
          }
        });
      }
      if (!axis._addedPlotLB) {
        axis._addedPlotLB = true;
        (options2.plotLines || []).concat(options2.plotBands || []).forEach(function(plotLineOptions) {
          axis.addPlotBandOrLine(plotLineOptions);
        });
      }
    }
    [ticks, minorTicks, alternateBands].forEach(function(coll) {
      const forDestruction = [], delay = animation.duration, destroyInactiveItems = function() {
        let i = forDestruction.length;
        while (i--) {
          if (coll[forDestruction[i]] && !coll[forDestruction[i]].isActive) {
            coll[forDestruction[i]].destroy();
            delete coll[forDestruction[i]];
          }
        }
      };
      objectEach$q(coll, function(tick, pos) {
        if (!tick.isActive) {
          tick.render(pos, false, 0);
          tick.isActive = false;
          forDestruction.push(pos);
        }
      });
      syncTimeout$a(destroyInactiveItems, coll === alternateBands || !chart.hasRendered || !delay ? 0 : delay);
    });
    if (axisLine) {
      axisLine[axisLine.isPlaced ? "animate" : "attr"]({
        d: this.getLinePath(axisLine.strokeWidth())
      });
      axisLine.isPlaced = true;
      axisLine[showAxis ? "show" : "hide"](showAxis);
    }
    if (axisTitle && showAxis) {
      axisTitle[axisTitle.isNew ? "attr" : "animate"](axis.getTitlePosition(axisTitle));
      axisTitle.isNew = false;
    }
    if (stackLabelOptions?.enabled && axis.stacking) {
      axis.stacking.renderStackTotals();
    }
    axis.old = {
      len: axis.len,
      max: axis.max,
      min: axis.min,
      transA: axis.transA,
      userMax: axis.userMax,
      userMin: axis.userMin
    };
    axis.isDirty = false;
    fireEvent$I(this, "afterRender");
  }
  /**
   * Redraw the axis to reflect changes in the data or axis extremes. Called
   * internally from Highcharts.Chart#redraw.
   *
   * @private
   * @function Highcharts.Axis#redraw
   */
  redraw() {
    if (this.visible) {
      this.render();
      this.plotLinesAndBands.forEach(function(plotLine) {
        plotLine.render();
      });
    }
    this.series.forEach(function(series) {
      series.isDirty = true;
    });
  }
  /**
   * Returns an array of axis properties, that should be untouched during
   * reinitialization.
   *
   * @private
   * @function Highcharts.Axis#getKeepProps
   */
  getKeepProps() {
    return this.keepProps || Axis.keepProps;
  }
  /**
   * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint
   * to fully remove the axis.
   *
   * @private
   * @function Highcharts.Axis#destroy
   *
   * @param {boolean} [keepEvents]
   * Whether to preserve events, used internally in Axis.update.
   */
  destroy(keepEvents) {
    const axis = this, plotLinesAndBands = axis.plotLinesAndBands, eventOptions = this.eventOptions;
    fireEvent$I(this, "destroy", { keepEvents });
    if (!keepEvents) {
      removeEvent$a(axis);
    }
    [axis.ticks, axis.minorTicks, axis.alternateBands].forEach(function(coll) {
      destroyObjectProperties$8(coll);
    });
    if (plotLinesAndBands) {
      let i = plotLinesAndBands.length;
      while (i--) {
        plotLinesAndBands[i].destroy();
      }
    }
    [
      "axisLine",
      "axisTitle",
      "axisGroup",
      "gridGroup",
      "labelGroup",
      "cross",
      "scrollbar"
    ].forEach(function(prop) {
      if (axis[prop]) {
        axis[prop] = axis[prop].destroy();
      }
    });
    for (const plotGroup in axis.plotLinesAndBandsGroups) {
      axis.plotLinesAndBandsGroups[plotGroup] = axis.plotLinesAndBandsGroups[plotGroup].destroy();
    }
    objectEach$q(axis, function(val, key2) {
      if (axis.getKeepProps().indexOf(key2) === -1) {
        delete axis[key2];
      }
    });
    this.eventOptions = eventOptions;
  }
  /**
   * Internal function to draw a crosshair.
   *
   * @function Highcharts.Axis#drawCrosshair
   *
   * @param {Highcharts.PointerEventObject} [e]
   * The event arguments from the modified pointer event, extended with
   * `chartX` and `chartY`
   *
   * @param {Highcharts.Point} [point]
   * The Point object if the crosshair snaps to points.
   *
   * @emits Highcharts.Axis#event:afterDrawCrosshair
   * @emits Highcharts.Axis#event:drawCrosshair
   */
  drawCrosshair(e, point) {
    const options2 = this.crosshair, snap2 = options2?.snap ?? true, chart = this.chart;
    let path, pos, categorized, graphic = this.cross, crossOptions;
    fireEvent$I(this, "drawCrosshair", { e, point });
    if (!e) {
      e = this.cross?.e;
    }
    if (
      // Disabled in options
      !options2 || // Snap
      (defined$16(point) || !snap2) === false
    ) {
      this.hideCrosshair();
    } else {
      if (!snap2) {
        pos = e && (this.horiz ? e.chartX - this.pos : this.len - e.chartY + this.pos);
      } else if (defined$16(point)) {
        pos = pick$1I(this.coll !== "colorAxis" ? point.crosshairPos : (
          // 3D axis extension
          null
        ), this.isXAxis ? point.plotX : this.len - point.plotY);
      }
      if (defined$16(pos)) {
        crossOptions = {
          // Value, only used on radial
          value: point && (this.isXAxis ? point.x : pick$1I(point.stackY, point.y)),
          translatedValue: pos
        };
        if (chart.polar) {
          extend$1k(crossOptions, {
            isCrosshair: true,
            chartX: e?.chartX,
            chartY: e?.chartY,
            point
          });
        }
        path = this.getPlotLinePath(crossOptions) || null;
      }
      if (!defined$16(path)) {
        this.hideCrosshair();
        return;
      }
      categorized = this.categories && !this.isRadial;
      if (!graphic) {
        this.cross = graphic = chart.renderer.path().addClass("highcharts-crosshair highcharts-crosshair-" + (categorized ? "category " : "thin ") + (options2.className || "")).attr({
          zIndex: pick$1I(options2.zIndex, 2)
        }).add();
        if (!chart.styledMode) {
          graphic.attr({
            stroke: options2.color || (categorized ? Color.parse(
              "#ccd3ff"
              /* Palette.highlightColor20 */
            ).setOpacity(0.25).get() : "#cccccc"),
            "stroke-width": pick$1I(options2.width, 1)
          }).css({
            "pointer-events": "none"
          });
          if (options2.dashStyle) {
            graphic.attr({
              dashstyle: options2.dashStyle
            });
          }
        }
      }
      graphic.show().attr({
        d: path
      });
      if (categorized && !options2.width) {
        graphic.attr({
          "stroke-width": this.transA
        });
      }
      this.cross.e = e;
    }
    fireEvent$I(this, "afterDrawCrosshair", { e, point });
  }
  /**
   * Hide the crosshair if visible.
   *
   * @function Highcharts.Axis#hideCrosshair
   */
  hideCrosshair() {
    if (this.cross) {
      this.cross.hide();
    }
    fireEvent$I(this, "afterHideCrosshair");
  }
  /**
   * Update an axis object with a new set of options. The options are merged
   * with the existing options, so only new or altered options need to be
   * specified.
   *
   * @sample highcharts/members/axis-update/
   *         Axis update demo
   *
   * @function Highcharts.Axis#update
   *
   * @param {Highcharts.AxisOptions} options
   * The new options that will be merged in with existing options on the axis.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart after the axis is altered. If doing more
   * operations on the chart, it is a good idea to set redraw to false and
   * call {@link Chart#redraw} after.
   */
  update(options2, redraw) {
    const chart = this.chart;
    options2 = merge$1B(this.userOptions, options2);
    this.destroy(true);
    this.init(chart, options2);
    chart.isDirtyBox = true;
    if (pick$1I(redraw, true)) {
      chart.redraw();
    }
  }
  /**
   * Remove the axis from the chart.
   *
   * @sample highcharts/members/chart-addaxis/
   *         Add and remove axes
   *
   * @function Highcharts.Axis#remove
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart following the remove.
   */
  remove(redraw) {
    const chart = this.chart, coll = this.coll, axisSeries = this.series;
    let i = axisSeries.length;
    while (i--) {
      if (axisSeries[i]) {
        axisSeries[i].remove(false);
      }
    }
    erase$a(chart.axes, this);
    erase$a(chart[coll] || [], this);
    chart.orderItems(coll);
    this.destroy();
    chart.isDirtyBox = true;
    if (pick$1I(redraw, true)) {
      chart.redraw();
    }
  }
  /**
   * Update the axis title by options after render time.
   *
   * @sample highcharts/members/axis-settitle/
   *         Set a new Y axis title
   *
   * @function Highcharts.Axis#setTitle
   *
   * @param {Highcharts.AxisTitleOptions} titleOptions
   * The additional title options.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart after setting the title.
   */
  setTitle(titleOptions, redraw) {
    this.update({ title: titleOptions }, redraw);
  }
  /**
   * Set new axis categories and optionally redraw.
   *
   * @sample highcharts/members/axis-setcategories/
   *         Set categories by click on a button
   *
   * @function Highcharts.Axis#setCategories
   *
   * @param {Array<string>} categories
   * The new categories.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart.
   */
  setCategories(categories, redraw) {
    this.update({ categories }, redraw);
  }
}
Axis.keepProps = [
  "coll",
  "extKey",
  "hcEvents",
  "len",
  "names",
  "series",
  "userMax",
  "userMin"
];
const { addEvent: addEvent$1s, getMagnitude, normalizeTickInterval: normalizeTickInterval$1, timeUnits: timeUnits$2 } = Utilities;
var DateTimeAxis;
(function(DateTimeAxis2) {
  function compose2(AxisClass) {
    if (!AxisClass.keepProps.includes("dateTime")) {
      AxisClass.keepProps.push("dateTime");
      const axisProto = AxisClass.prototype;
      axisProto.getTimeTicks = getTimeTicks;
      addEvent$1s(AxisClass, "afterSetType", onAfterSetType);
    }
    return AxisClass;
  }
  DateTimeAxis2.compose = compose2;
  function getTimeTicks() {
    return this.chart.time.getTimeTicks.apply(this.chart.time, arguments);
  }
  function onAfterSetType() {
    if (this.type !== "datetime") {
      this.dateTime = void 0;
      return;
    }
    if (!this.dateTime) {
      this.dateTime = new Additions(this);
    }
  }
  class Additions {
    /* *
     *
     *  Constructors
     *
     * */
    constructor(axis) {
      this.axis = axis;
    }
    /* *
     *
     *  Functions
     *
     * */
    /**
     * Get a normalized tick interval for dates. Returns a configuration
     * object with unit range (interval), count and name. Used to prepare
     * data for `getTimeTicks`. Previously this logic was part of
     * getTimeTicks, but as `getTimeTicks` now runs of segments in stock
     * charts, the normalizing logic was extracted in order to prevent it
     * for running over again for each segment having the same interval.
     * #662, #697.
     * @private
     */
    normalizeTimeTickInterval(tickInterval, unitsOption) {
      const units2 = unitsOption || [[
        // Unit name
        "millisecond",
        // Allowed multiples
        [1, 2, 5, 10, 20, 25, 50, 100, 200, 500]
      ], [
        "second",
        [1, 2, 5, 10, 15, 30]
      ], [
        "minute",
        [1, 2, 5, 10, 15, 30]
      ], [
        "hour",
        [1, 2, 3, 4, 6, 8, 12]
      ], [
        "day",
        [1, 2]
      ], [
        "week",
        [1, 2]
      ], [
        "month",
        [1, 2, 3, 4, 6]
      ], [
        "year",
        null
      ]];
      let unit = units2[units2.length - 1], interval = timeUnits$2[unit[0]], multiples = unit[1], i;
      for (i = 0; i < units2.length; i++) {
        unit = units2[i];
        interval = timeUnits$2[unit[0]];
        multiples = unit[1];
        if (units2[i + 1]) {
          const lessThan = (interval * multiples[multiples.length - 1] + timeUnits$2[units2[i + 1][0]]) / 2;
          if (tickInterval <= lessThan) {
            break;
          }
        }
      }
      if (interval === timeUnits$2.year && tickInterval < 5 * interval) {
        multiples = [1, 2, 5];
      }
      const count = normalizeTickInterval$1(tickInterval / interval, multiples, unit[0] === "year" ? (
        // #1913, #2360
        Math.max(getMagnitude(tickInterval / interval), 1)
      ) : 1);
      return {
        unitRange: interval,
        count,
        unitName: unit[0]
      };
    }
    /**
     * Get the best date format for a specific X value based on the closest
     * point range on the axis.
     *
     * @private
     */
    getXDateFormat(x, dateTimeLabelFormats) {
      const { axis } = this, time = axis.chart.time;
      return axis.closestPointRange ? time.getDateFormat(axis.closestPointRange, x, axis.options.startOfWeek, dateTimeLabelFormats) || // #2546, 2581
      time.resolveDTLFormat(dateTimeLabelFormats.year).main : time.resolveDTLFormat(dateTimeLabelFormats.day).main;
    }
  }
  DateTimeAxis2.Additions = Additions;
})(DateTimeAxis || (DateTimeAxis = {}));
const DateTimeAxis$1 = DateTimeAxis;
const { addEvent: addEvent$1r, normalizeTickInterval, pick: pick$1H } = Utilities;
var LogarithmicAxis;
(function(LogarithmicAxis2) {
  function compose2(AxisClass) {
    if (!AxisClass.keepProps.includes("logarithmic")) {
      AxisClass.keepProps.push("logarithmic");
      addEvent$1r(AxisClass, "afterSetType", onAfterSetType);
      addEvent$1r(AxisClass, "afterInit", onAfterInit2);
    }
    return AxisClass;
  }
  LogarithmicAxis2.compose = compose2;
  function onAfterSetType() {
    if (this.type !== "logarithmic") {
      this.logarithmic = void 0;
    } else {
      this.logarithmic ?? (this.logarithmic = new Additions(this));
    }
  }
  function onAfterInit2() {
    const axis = this;
    const log = axis.logarithmic;
    if (log) {
      axis.lin2val = function(num) {
        return log.lin2log(num);
      };
      axis.val2lin = function(num) {
        return log.log2lin(num);
      };
    }
  }
  class Additions {
    /* *
    *
    *  Constructors
    *
    * */
    constructor(axis) {
      this.axis = axis;
    }
    /* *
    *
    *  Functions
    *
    * */
    /**
     * Set the tick positions of a logarithmic axis.
     */
    getLogTickPositions(interval, min2, max2, minor) {
      const log = this;
      const axis = log.axis;
      const axisLength = axis.len;
      const options2 = axis.options;
      let positions = [];
      if (!minor) {
        log.minorAutoInterval = void 0;
      }
      if (interval >= 0.5) {
        interval = Math.round(interval);
        positions = axis.getLinearTickPositions(interval, min2, max2);
      } else if (interval >= 0.08) {
        const roundedMin = Math.floor(min2);
        let intermediate, i, j, len, pos, lastPos, break2;
        if (interval > 0.3) {
          intermediate = [1, 2, 4];
        } else if (interval > 0.15) {
          intermediate = [1, 2, 4, 6, 8];
        } else {
          intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
        }
        for (i = roundedMin; i < max2 + 1 && !break2; i++) {
          len = intermediate.length;
          for (j = 0; j < len && !break2; j++) {
            pos = log.log2lin(log.lin2log(i) * intermediate[j]);
            if (pos > min2 && (!minor || lastPos <= max2) && typeof lastPos !== "undefined") {
              positions.push(lastPos);
            }
            if (lastPos > max2) {
              break2 = true;
            }
            lastPos = pos;
          }
        }
      } else {
        const realMin = log.lin2log(min2), realMax = log.lin2log(max2), tickIntervalOption = minor ? axis.getMinorTickInterval() : options2.tickInterval, filteredTickIntervalOption = tickIntervalOption === "auto" ? null : tickIntervalOption, tickPixelIntervalOption = options2.tickPixelInterval / (minor ? 5 : 1), totalPixelLength = minor ? axisLength / axis.tickPositions.length : axisLength;
        interval = pick$1H(filteredTickIntervalOption, log.minorAutoInterval, (realMax - realMin) * tickPixelIntervalOption / (totalPixelLength || 1));
        interval = normalizeTickInterval(interval);
        positions = axis.getLinearTickPositions(interval, realMin, realMax).map(log.log2lin);
        if (!minor) {
          log.minorAutoInterval = interval / 5;
        }
      }
      if (!minor) {
        axis.tickInterval = interval;
      }
      return positions;
    }
    lin2log(num) {
      return Math.pow(10, num);
    }
    log2lin(num) {
      return Math.log(num) / Math.LN10;
    }
  }
  LogarithmicAxis2.Additions = Additions;
})(LogarithmicAxis || (LogarithmicAxis = {}));
const LogarithmicAxis$1 = LogarithmicAxis;
const { erase: erase$9, extend: extend$1j, isNumber: isNumber$10 } = Utilities;
var PlotLineOrBandAxis;
(function(PlotLineOrBandAxis2) {
  let PlotLineOrBandClass;
  function addPlotBand(options2) {
    return this.addPlotBandOrLine(options2, "plotBands");
  }
  function addPlotBandOrLine(options2, coll) {
    const userOptions = this.userOptions;
    let obj = new PlotLineOrBandClass(this, options2);
    if (this.visible) {
      obj = obj.render();
    }
    if (obj) {
      if (!this._addedPlotLB) {
        this._addedPlotLB = true;
        (userOptions.plotLines || []).concat(userOptions.plotBands || []).forEach((plotLineOptions) => {
          this.addPlotBandOrLine(plotLineOptions);
        });
      }
      if (coll) {
        const updatedOptions = userOptions[coll] || [];
        updatedOptions.push(options2);
        userOptions[coll] = updatedOptions;
      }
      this.plotLinesAndBands.push(obj);
    }
    return obj;
  }
  function addPlotLine(options2) {
    return this.addPlotBandOrLine(options2, "plotLines");
  }
  function compose2(PlotLineOrBandType, AxisClass) {
    const axisProto = AxisClass.prototype;
    if (!axisProto.addPlotBand) {
      PlotLineOrBandClass = PlotLineOrBandType;
      extend$1j(axisProto, {
        addPlotBand,
        addPlotLine,
        addPlotBandOrLine,
        getPlotBandPath,
        removePlotBand,
        removePlotLine,
        removePlotBandOrLine
      });
    }
    return AxisClass;
  }
  PlotLineOrBandAxis2.compose = compose2;
  function getPlotBandPath(from, to, options2) {
    options2 = options2 || this.options;
    const toPath = this.getPlotLinePath({
      value: to,
      force: true,
      acrossPanes: options2.acrossPanes
    }), result = [], horiz = this.horiz, outside = !isNumber$10(this.min) || !isNumber$10(this.max) || from < this.min && to < this.min || from > this.max && to > this.max, path = this.getPlotLinePath({
      value: from,
      force: true,
      acrossPanes: options2.acrossPanes
    });
    let i, plus = 1, isFlat;
    if (path && toPath) {
      if (outside) {
        isFlat = path.toString() === toPath.toString();
        plus = 0;
      }
      for (i = 0; i < path.length; i += 2) {
        const pathStart = path[i], pathEnd = path[i + 1], toPathStart = toPath[i], toPathEnd = toPath[i + 1];
        if ((pathStart[0] === "M" || pathStart[0] === "L") && (pathEnd[0] === "M" || pathEnd[0] === "L") && (toPathStart[0] === "M" || toPathStart[0] === "L") && (toPathEnd[0] === "M" || toPathEnd[0] === "L")) {
          if (horiz && toPathStart[1] === pathStart[1]) {
            toPathStart[1] += plus;
            toPathEnd[1] += plus;
          } else if (!horiz && toPathStart[2] === pathStart[2]) {
            toPathStart[2] += plus;
            toPathEnd[2] += plus;
          }
          result.push(["M", pathStart[1], pathStart[2]], ["L", pathEnd[1], pathEnd[2]], ["L", toPathEnd[1], toPathEnd[2]], ["L", toPathStart[1], toPathStart[2]], ["Z"]);
        }
        result.isFlat = isFlat;
      }
    }
    return result;
  }
  function removePlotBand(id) {
    this.removePlotBandOrLine(id);
  }
  function removePlotBandOrLine(id) {
    const plotLinesAndBands = this.plotLinesAndBands, options2 = this.options, userOptions = this.userOptions;
    if (plotLinesAndBands) {
      let i = plotLinesAndBands.length;
      while (i--) {
        if (plotLinesAndBands[i].id === id) {
          plotLinesAndBands[i].destroy();
        }
      }
      [
        options2.plotLines || [],
        userOptions.plotLines || [],
        options2.plotBands || [],
        userOptions.plotBands || []
      ].forEach(function(arr) {
        i = arr.length;
        while (i--) {
          if (arr[i]?.id === id) {
            erase$9(arr, arr[i]);
          }
        }
      });
    }
  }
  function removePlotLine(id) {
    this.removePlotBandOrLine(id);
  }
})(PlotLineOrBandAxis || (PlotLineOrBandAxis = {}));
const PlotLineOrBandAxis$1 = PlotLineOrBandAxis;
const { addEvent: addEvent$1q, arrayMax: arrayMax$9, arrayMin: arrayMin$7, defined: defined$15, destroyObjectProperties: destroyObjectProperties$7, erase: erase$8, fireEvent: fireEvent$H, merge: merge$1A, objectEach: objectEach$p, pick: pick$1G } = Utilities;
class PlotLineOrBand {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(ChartClass, AxisClass) {
    addEvent$1q(ChartClass, "afterInit", function() {
      this.labelCollectors.push(() => {
        const labels = [];
        for (const axis of this.axes) {
          for (const { label, options: options2 } of axis.plotLinesAndBands) {
            if (label && !options2?.label?.allowOverlap) {
              labels.push(label);
            }
          }
        }
        return labels;
      });
    });
    return PlotLineOrBandAxis$1.compose(PlotLineOrBand, AxisClass);
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(axis, options2) {
    this.axis = axis;
    this.options = options2;
    this.id = options2.id;
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable no-invalid-this, valid-jsdoc */
  /**
   * Render the plot line or plot band. If it is already existing,
   * move it.
   * @private
   * @function Highcharts.PlotLineOrBand#render
   */
  render() {
    fireEvent$H(this, "render");
    const { axis, options: options2 } = this, { horiz, logarithmic } = axis, { color: color2, events, zIndex = 0 } = options2, { renderer, time } = axis.chart, groupAttribs = {}, to = time.parse(options2.to), from = time.parse(options2.from), value = time.parse(options2.value), borderWidth = options2.borderWidth;
    let optionsLabel = options2.label, { label, svgElem } = this, path = [], group2;
    const isBand = defined$15(from) && defined$15(to), isLine = defined$15(value), isNew = !svgElem, attribs = {
      "class": "highcharts-plot-" + (isBand ? "band " : "line ") + (options2.className || "")
    };
    let groupName = isBand ? "bands" : "lines";
    if (!axis.chart.styledMode) {
      if (isLine) {
        attribs.stroke = color2 || "#999999";
        attribs["stroke-width"] = pick$1G(options2.width, 1);
        if (options2.dashStyle) {
          attribs.dashstyle = options2.dashStyle;
        }
      } else if (isBand) {
        attribs.fill = color2 || "#e6e9ff";
        if (borderWidth) {
          attribs.stroke = options2.borderColor;
          attribs["stroke-width"] = borderWidth;
        }
      }
    }
    groupAttribs.zIndex = zIndex;
    groupName += "-" + zIndex;
    group2 = axis.plotLinesAndBandsGroups[groupName];
    if (!group2) {
      axis.plotLinesAndBandsGroups[groupName] = group2 = renderer.g("plot-" + groupName).attr(groupAttribs).add();
    }
    if (!svgElem) {
      this.svgElem = svgElem = renderer.path().attr(attribs).add(group2);
    }
    if (defined$15(value)) {
      path = axis.getPlotLinePath({
        value: logarithmic?.log2lin(value) ?? value,
        lineWidth: svgElem.strokeWidth(),
        acrossPanes: options2.acrossPanes
      });
    } else if (defined$15(from) && defined$15(to)) {
      path = axis.getPlotBandPath(logarithmic?.log2lin(from) ?? from, logarithmic?.log2lin(to) ?? to, options2);
    } else {
      return;
    }
    if (!this.eventsAdded && events) {
      objectEach$p(events, (event, eventType) => {
        svgElem?.on(eventType, (e) => {
          events[eventType].apply(this, [e]);
        });
      });
      this.eventsAdded = true;
    }
    if ((isNew || !svgElem.d) && path?.length) {
      svgElem.attr({ d: path });
    } else if (svgElem) {
      if (path) {
        svgElem.show();
        svgElem.animate({ d: path });
      } else if (svgElem.d) {
        svgElem.hide();
        if (label) {
          this.label = label = label.destroy();
        }
      }
    }
    if (optionsLabel && (defined$15(optionsLabel.text) || defined$15(optionsLabel.formatter)) && path?.length && axis.width > 0 && axis.height > 0 && !path.isFlat) {
      optionsLabel = merge$1A({
        align: horiz && isBand ? "center" : void 0,
        x: horiz ? !isBand && 4 : 10,
        verticalAlign: !horiz && isBand ? "middle" : void 0,
        y: horiz ? isBand ? 16 : 10 : isBand ? 6 : -4,
        rotation: horiz && !isBand ? 90 : 0,
        ...isBand ? { inside: true } : {}
      }, optionsLabel);
      this.renderLabel(optionsLabel, path, isBand, zIndex);
    } else if (label) {
      label.hide();
    }
    return this;
  }
  /**
   * Render and align label for plot line or band.
   * @private
   * @function Highcharts.PlotLineOrBand#renderLabel
   */
  renderLabel(optionsLabel, path, isBand, zIndex) {
    const plotLine = this, axis = plotLine.axis, renderer = axis.chart.renderer, inside = optionsLabel.inside;
    let label = plotLine.label;
    if (!label) {
      plotLine.label = label = renderer.text(this.getLabelText(optionsLabel), 0, 0, optionsLabel.useHTML).attr({
        align: optionsLabel.textAlign || optionsLabel.align,
        rotation: optionsLabel.rotation,
        "class": "highcharts-plot-" + (isBand ? "band" : "line") + "-label " + (optionsLabel.className || ""),
        zIndex
      });
      if (!axis.chart.styledMode) {
        label.css(merge$1A({
          fontSize: "0.8em",
          textOverflow: isBand && !inside ? "" : "ellipsis"
        }, optionsLabel.style));
      }
      label.add();
    }
    const xBounds = path.xBounds || [path[0][1], path[1][1], isBand ? path[2][1] : path[0][1]], yBounds = path.yBounds || [path[0][2], path[1][2], isBand ? path[2][2] : path[0][2]], x = arrayMin$7(xBounds), y = arrayMin$7(yBounds), bBoxWidth = arrayMax$9(xBounds) - x;
    label.align(optionsLabel, false, {
      x,
      y,
      width: bBoxWidth,
      height: arrayMax$9(yBounds) - y
    });
    label.alignAttr.y -= renderer.fontMetrics(label).b;
    if (!label.alignValue || label.alignValue === "left" || defined$15(inside)) {
      label.css({
        width: (optionsLabel.style?.width || (!isBand || !inside ? label.rotation === 90 ? axis.height - (label.alignAttr.y - axis.top) : (optionsLabel.clip ? axis.width : axis.chart.chartWidth) - (label.alignAttr.x - axis.left) : bBoxWidth)) + "px"
      });
    }
    label.show(true);
  }
  /**
   * Get label's text content.
   * @private
   * @function Highcharts.PlotLineOrBand#getLabelText
   */
  getLabelText(optionsLabel) {
    return defined$15(optionsLabel.formatter) ? optionsLabel.formatter.call(this) : optionsLabel.text;
  }
  /**
   * Remove the plot line or band.
   *
   * @function Highcharts.PlotLineOrBand#destroy
   */
  destroy() {
    erase$8(this.axis.plotLinesAndBands, this);
    delete this.axis;
    destroyObjectProperties$7(this);
  }
}
const { animObject: animObject$d } = animationExports;
const { format: format$g } = Templating;
const { composed: composed$x, dateFormats: dateFormats$2, doc: doc$o, isSafari } = Highcharts;
const { distribute: distribute$3 } = R$1;
const { addEvent: addEvent$1p, clamp: clamp$k, css: css$b, discardElement: discardElement$5, extend: extend$1i, fireEvent: fireEvent$G, getAlignFactor: getAlignFactor$6, isArray: isArray$m, isNumber: isNumber$$, isObject: isObject$j, isString: isString$c, merge: merge$1z, pick: pick$1F, pushUnique: pushUnique$x, splat: splat$j, syncTimeout: syncTimeout$9 } = Utilities;
class Tooltip {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(chart, options2, pointer) {
    this.allowShared = true;
    this.crosshairs = [];
    this.distance = 0;
    this.isHidden = true;
    this.isSticky = false;
    this.options = {};
    this.outside = false;
    this.chart = chart;
    this.init(chart, options2);
    this.pointer = pointer;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Build the body (lines) of the tooltip by iterating over the items and
   * returning one entry for each item, abstracting this functionality allows
   * to easily overwrite and extend it.
   *
   * @private
   * @function Highcharts.Tooltip#bodyFormatter
   */
  bodyFormatter(points) {
    return points.map((point) => {
      const tooltipOptions = point.series.tooltipOptions, formatPrefix = point.formatPrefix || "point";
      return (tooltipOptions[formatPrefix + "Formatter"] || point.tooltipFormatter).call(point, tooltipOptions[formatPrefix + "Format"] || "");
    });
  }
  /**
   * Destroy the single tooltips in a split tooltip.
   * If the tooltip is active then it is not destroyed, unless forced to.
   *
   * @private
   * @function Highcharts.Tooltip#cleanSplit
   *
   * @param {boolean} [force]
   * Force destroy all tooltips.
   */
  cleanSplit(force) {
    this.chart.series.forEach(function(series) {
      const tt = series?.tt;
      if (tt) {
        if (!tt.isActive || force) {
          series.tt = tt.destroy();
        } else {
          tt.isActive = false;
        }
      }
    });
  }
  /**
   * In case no user defined formatter is given, this will be used. Note that
   * the context here is an object holding point, series, x, y etc.
   *
   * @function Highcharts.Tooltip#defaultFormatter
   *
   * @param {Highcharts.Tooltip} tooltip
   *
   * @return {string|Array<string>}
   * Returns a string (single tooltip and shared)
   * or an array of strings (split tooltip)
   */
  defaultFormatter(tooltip) {
    const hoverPoints = this.points || splat$j(this);
    let s;
    s = [tooltip.headerFooterFormatter(hoverPoints[0])];
    s = s.concat(tooltip.bodyFormatter(hoverPoints));
    s.push(tooltip.headerFooterFormatter(hoverPoints[0], true));
    return s;
  }
  /**
   * Removes and destroys the tooltip and its elements.
   *
   * @function Highcharts.Tooltip#destroy
   */
  destroy() {
    if (this.label) {
      this.label = this.label.destroy();
    }
    if (this.split) {
      this.cleanSplit(true);
      if (this.tt) {
        this.tt = this.tt.destroy();
      }
    }
    if (this.renderer) {
      this.renderer = this.renderer.destroy();
      discardElement$5(this.container);
    }
    Utilities.clearTimeout(this.hideTimer);
  }
  /**
   * Extendable method to get the anchor position of the tooltip
   * from a point or set of points
   *
   * @private
   * @function Highcharts.Tooltip#getAnchor
   */
  getAnchor(points, mouseEvent) {
    const { chart, pointer } = this, inverted = chart.inverted, plotTop = chart.plotTop, plotLeft = chart.plotLeft;
    let ret;
    points = splat$j(points);
    if (points[0].series?.yAxis && !points[0].series.yAxis.options.reversedStacks) {
      points = points.slice().reverse();
    }
    if (this.followPointer && mouseEvent) {
      if (typeof mouseEvent.chartX === "undefined") {
        mouseEvent = pointer.normalize(mouseEvent);
      }
      ret = [
        mouseEvent.chartX - plotLeft,
        mouseEvent.chartY - plotTop
      ];
    } else if (points[0].tooltipPos) {
      ret = points[0].tooltipPos;
    } else {
      let chartX = 0, chartY = 0;
      points.forEach(function(point) {
        const pos = point.pos(true);
        if (pos) {
          chartX += pos[0];
          chartY += pos[1];
        }
      });
      chartX /= points.length;
      chartY /= points.length;
      if (this.shared && points.length > 1 && mouseEvent) {
        if (inverted) {
          chartX = mouseEvent.chartX;
        } else {
          chartY = mouseEvent.chartY;
        }
      }
      ret = [chartX - plotLeft, chartY - plotTop];
    }
    return ret.map(Math.round);
  }
  /**
   * Get the CSS class names for the tooltip's label. Styles the label
   * by `colorIndex` or user-defined CSS.
   *
   * @function Highcharts.Tooltip#getClassName
   *
   * @return {string}
   *         The class names.
   */
  getClassName(point, isSplit, isHeader) {
    const options2 = this.options, series = point.series, seriesOptions = series.options;
    return [
      options2.className,
      "highcharts-label",
      isHeader && "highcharts-tooltip-header",
      isSplit ? "highcharts-tooltip-box" : "highcharts-tooltip",
      !isHeader && "highcharts-color-" + pick$1F(point.colorIndex, series.colorIndex),
      seriesOptions?.className
    ].filter(isString$c).join(" ");
  }
  /**
   * Creates the Tooltip label element if it does not exist, then returns it.
   *
   * @function Highcharts.Tooltip#getLabel
   *
   * @return {Highcharts.SVGElement}
   * Tooltip label
   */
  getLabel({ anchorX, anchorY } = { anchorX: 0, anchorY: 0 }) {
    const tooltip = this, styledMode = this.chart.styledMode, options2 = this.options, doSplit = this.split && this.allowShared;
    let container = this.container, renderer = this.chart.renderer;
    if (this.label) {
      const wasSplit = !this.label.hasClass("highcharts-label");
      if (!doSplit && wasSplit || doSplit && !wasSplit) {
        this.destroy();
      }
    }
    if (!this.label) {
      if (this.outside) {
        const chart = this.chart, chartStyle = chart.options.chart.style, Renderer = RendererRegistry$1.getRendererType();
        this.container = container = Highcharts.doc.createElement("div");
        container.className = "highcharts-tooltip-container " + (chart.renderTo.className.match(/(highcharts[a-zA-Z0-9-]+)\s?/gm) || [].join(" "));
        css$b(container, {
          position: "absolute",
          top: "1px",
          pointerEvents: "none",
          zIndex: Math.max(this.options.style.zIndex || 0, (chartStyle?.zIndex || 0) + 3)
        });
        this.renderer = renderer = new Renderer(container, 0, 0, chartStyle, void 0, void 0, renderer.styledMode);
      }
      if (doSplit) {
        this.label = renderer.g("tooltip");
      } else {
        this.label = renderer.label("", anchorX, anchorY, options2.shape || "callout", void 0, void 0, options2.useHTML, void 0, "tooltip").attr({
          padding: options2.padding,
          r: options2.borderRadius
        });
        if (!styledMode) {
          this.label.attr({
            fill: options2.backgroundColor,
            "stroke-width": options2.borderWidth || 0
          }).css(options2.style).css({
            pointerEvents: options2.style.pointerEvents || (this.shouldStickOnContact() ? "auto" : "none")
          });
        }
      }
      if (tooltip.outside) {
        const label = this.label;
        [label.xSetter, label.ySetter].forEach((setter, i) => {
          label[i ? "ySetter" : "xSetter"] = (value) => {
            setter.call(label, tooltip.distance);
            label[i ? "y" : "x"] = value;
            if (container) {
              container.style[i ? "top" : "left"] = `${value}px`;
            }
          };
        });
      }
      this.label.attr({ zIndex: 8 }).shadow(options2.shadow ?? !options2.fixed).add();
    }
    if (container && !container.parentElement) {
      Highcharts.doc.body.appendChild(container);
    }
    return this.label;
  }
  /**
   * Get the total area available area to place the tooltip
   *
   * @private
   */
  getPlayingField() {
    const { body, documentElement } = doc$o, { chart, distance, outside } = this;
    return {
      width: outside ? (
        // Subtract distance to prevent scrollbars
        Math.max(body.scrollWidth, documentElement.scrollWidth, body.offsetWidth, documentElement.offsetWidth, documentElement.clientWidth) - 2 * distance - 2
      ) : chart.chartWidth,
      height: outside ? Math.max(body.scrollHeight, documentElement.scrollHeight, body.offsetHeight, documentElement.offsetHeight, documentElement.clientHeight) : chart.chartHeight
    };
  }
  /**
   * Place the tooltip in a chart without spilling over and not covering the
   * point itself.
   *
   * @function Highcharts.Tooltip#getPosition
   *
   * @param {number} boxWidth
   *        Width of the tooltip box.
   *
   * @param {number} boxHeight
   *        Height of the tooltip box.
   *
   * @param {Highcharts.Point} point
   *        Tooltip related point.
   *
   * @return {Highcharts.PositionObject}
   *         Recommended position of the tooltip.
   */
  getPosition(boxWidth, boxHeight, point) {
    const { distance, chart, outside, pointer } = this, { inverted, plotLeft, plotTop, polar } = chart, { plotX = 0, plotY = 0 } = point, ret = {}, h = inverted && point.h || 0, { height: outerHeight, width: outerWidth } = this.getPlayingField(), chartPosition = pointer.getChartPosition(), scaleX = (val) => val * chartPosition.scaleX, scaleY = (val) => val * chartPosition.scaleY, buildDimensionArray = (dim) => {
      const isX = dim === "x";
      return [
        dim,
        // Dimension - x or y
        isX ? outerWidth : outerHeight,
        isX ? boxWidth : boxHeight
      ].concat(outside ? [
        // If we are using tooltip.outside, we need to scale the
        // position to match scaling of the container in case there
        // is a transform/zoom on the container. #11329
        isX ? scaleX(boxWidth) : scaleY(boxHeight),
        isX ? chartPosition.left - distance + scaleX(plotX + plotLeft) : chartPosition.top - distance + scaleY(plotY + plotTop),
        0,
        isX ? outerWidth : outerHeight
      ] : [
        // Not outside, no scaling is needed
        isX ? boxWidth : boxHeight,
        isX ? plotX + plotLeft : plotY + plotTop,
        isX ? plotLeft : plotTop,
        isX ? plotLeft + chart.plotWidth : plotTop + chart.plotHeight
      ]);
    };
    let first = buildDimensionArray("y"), second = buildDimensionArray("x"), swapped;
    let flipped = !!point.negative;
    if (!polar && chart.hoverSeries?.yAxis?.reversed) {
      flipped = !flipped;
    }
    const preferFarSide = !this.followPointer && pick$1F(point.ttBelow, polar ? false : !inverted === flipped), firstDimension = function(dim, outerSize, innerSize, scaledInnerSize, point2, min2, max2) {
      const scaledDist = outside ? dim === "y" ? scaleY(distance) : scaleX(distance) : distance, scaleDiff = (innerSize - scaledInnerSize) / 2, roomLeft = scaledInnerSize < point2 - distance, roomRight = point2 + distance + scaledInnerSize < outerSize, alignedLeft = point2 - scaledDist - innerSize + scaleDiff, alignedRight = point2 + scaledDist - scaleDiff;
      if (preferFarSide && roomRight) {
        ret[dim] = alignedRight;
      } else if (!preferFarSide && roomLeft) {
        ret[dim] = alignedLeft;
      } else if (roomLeft) {
        ret[dim] = Math.min(max2 - scaledInnerSize, alignedLeft - h < 0 ? alignedLeft : alignedLeft - h);
      } else if (roomRight) {
        ret[dim] = Math.max(min2, alignedRight + h + innerSize > outerSize ? alignedRight : alignedRight + h);
      } else {
        ret[dim] = 0;
        return false;
      }
    }, secondDimension = function(dim, outerSize, innerSize, scaledInnerSize, point2) {
      if (point2 < distance || point2 > outerSize - distance) {
        return false;
      }
      if (point2 < innerSize / 2) {
        ret[dim] = 1;
      } else if (point2 > outerSize - scaledInnerSize / 2) {
        ret[dim] = outerSize - scaledInnerSize - 2;
      } else {
        ret[dim] = point2 - innerSize / 2;
      }
    }, swap2 = function(count) {
      [first, second] = [second, first];
      swapped = count;
    }, run = () => {
      if (firstDimension.apply(0, first) !== false) {
        if (secondDimension.apply(0, second) === false && !swapped) {
          swap2(true);
          run();
        }
      } else if (!swapped) {
        swap2(true);
        run();
      } else {
        ret.x = ret.y = 0;
      }
    };
    if (inverted && !polar || this.len > 1) {
      swap2();
    }
    run();
    return ret;
  }
  /**
   * Place the tooltip when `position.fixed` is true. This is called both for
   * single tooltips, and for partial tooltips when `split`.
   *
   * @private
   */
  getFixedPosition(boxWidth, boxHeight, point) {
    const series = point.series, { chart, options: options2, split } = this, position = options2.position, relativeToOption = position.relativeTo, noPane = options2.shared || series?.yAxis?.isRadial && (relativeToOption === "pane" || !relativeToOption), relativeTo = noPane ? "plotBox" : relativeToOption, bounds = relativeTo === "chart" ? chart.renderer : chart[relativeTo] || chart.getClipBox(series, true);
    return {
      x: bounds.x + (bounds.width - boxWidth) * getAlignFactor$6(position.align) + position.x,
      y: bounds.y + (bounds.height - boxHeight) * getAlignFactor$6(position.verticalAlign) + (!split && position.y || 0)
    };
  }
  /**
   * Hides the tooltip with a fade out animation.
   *
   * @function Highcharts.Tooltip#hide
   *
   * @param {number} [delay]
   *        The fade out in milliseconds. If no value is provided the value
   *        of the tooltip.hideDelay option is used. A value of 0 disables
   *        the fade out animation.
   */
  hide(delay) {
    const tooltip = this;
    Utilities.clearTimeout(this.hideTimer);
    delay = pick$1F(delay, this.options.hideDelay);
    if (!this.isHidden) {
      this.hideTimer = syncTimeout$9(function() {
        const label = tooltip.getLabel();
        tooltip.getLabel().animate({
          opacity: 0
        }, {
          duration: delay ? 150 : delay,
          complete: () => {
            label.hide();
            if (tooltip.container) {
              tooltip.container.remove();
            }
          }
        });
        tooltip.isHidden = true;
      }, delay);
    }
  }
  /**
   * Initialize tooltip.
   *
   * @private
   * @function Highcharts.Tooltip#init
   *
   * @param {Highcharts.Chart} chart
   *        The chart instance.
   *
   * @param {Highcharts.TooltipOptions} options
   *        Tooltip options.
   */
  init(chart, options2) {
    this.chart = chart;
    this.options = options2;
    this.crosshairs = [];
    this.isHidden = true;
    this.split = options2.split && !chart.inverted && !chart.polar;
    this.shared = options2.shared || this.split;
    this.outside = pick$1F(options2.outside, Boolean(chart.scrollablePixelsX || chart.scrollablePixelsY));
  }
  shouldStickOnContact(pointerEvent) {
    return !!(!this.followPointer && this.options.stickOnContact && (!pointerEvent || this.pointer.inClass(pointerEvent.target, "highcharts-tooltip")));
  }
  /**
   * Moves the tooltip with a soft animation to a new position.
   *
   * @private
   * @function Highcharts.Tooltip#move
   *
   * @param {number} x
   *
   * @param {number} y
   *
   * @param {number} anchorX
   *
   * @param {number} anchorY
   */
  move(x, y, anchorX, anchorY) {
    const { followPointer, options: options2 } = this, animation = animObject$d(!followPointer && !this.isHidden && !options2.fixed && options2.animation), skipAnchor = followPointer || (this.len || 0) > 1, attr2 = { x, y };
    if (!skipAnchor) {
      attr2.anchorX = anchorX;
      attr2.anchorY = anchorY;
    } else {
      attr2.anchorX = attr2.anchorY = NaN;
    }
    animation.step = () => this.drawTracker();
    this.getLabel().animate(attr2, animation);
  }
  /**
   * Refresh the tooltip's text and position.
   *
   * @function Highcharts.Tooltip#refresh
   *
   * @param {Highcharts.Point|Array<Highcharts.Point>} pointOrPoints
   *        Either a point or an array of points.
   *
   * @param {Highcharts.PointerEventObject} [mouseEvent]
   *        Mouse event, that is responsible for the refresh and should be
   *        used for the tooltip update.
   */
  refresh(pointOrPoints, mouseEvent) {
    const tooltip = this, { chart, options: options2, pointer, shared: shared2 } = this, points = splat$j(pointOrPoints), point = points[0], formatString = options2.format, formatter = options2.formatter || tooltip.defaultFormatter, styledMode = chart.styledMode;
    let wasShared = tooltip.allowShared;
    if (!options2.enabled || !point.series) {
      return;
    }
    Utilities.clearTimeout(this.hideTimer);
    tooltip.allowShared = !(!isArray$m(pointOrPoints) && pointOrPoints.series && pointOrPoints.series.noSharedTooltip);
    wasShared = wasShared && !tooltip.allowShared;
    tooltip.followPointer = !tooltip.split && point.series.tooltipOptions.followPointer;
    const anchor = tooltip.getAnchor(pointOrPoints, mouseEvent), x = anchor[0], y = anchor[1];
    if (shared2 && tooltip.allowShared) {
      pointer.applyInactiveState(points);
      points.forEach((item) => item.setState("hover"));
      point.points = points;
    }
    this.len = points.length;
    const text = isString$c(formatString) ? format$g(formatString, point, chart) : formatter.call(point, tooltip);
    point.points = void 0;
    const currentSeries = point.series;
    this.distance = pick$1F(currentSeries.tooltipOptions.distance, 16);
    if (text === false) {
      this.hide();
    } else {
      if (tooltip.split && tooltip.allowShared) {
        this.renderSplit(text, points);
      } else {
        let checkX = x;
        let checkY = y;
        if (mouseEvent && pointer.isDirectTouch) {
          checkX = mouseEvent.chartX - chart.plotLeft;
          checkY = mouseEvent.chartY - chart.plotTop;
        }
        if (chart.polar || currentSeries.options.clip === false || points.some((p) => (
          // #16004
          pointer.isDirectTouch || // ##17929
          p.series.shouldShowTooltip(checkX, checkY)
        ))) {
          const label = tooltip.getLabel(wasShared && tooltip.tt || {});
          if (!options2.style.width || styledMode) {
            label.css({
              width: (this.outside ? this.getPlayingField() : chart.spacingBox).width + "px"
            });
          }
          label.attr({
            // Add class before the label BBox calculation (#21035)
            "class": tooltip.getClassName(point),
            text: text && text.join ? text.join("") : text
          });
          if (this.outside) {
            label.attr({
              x: clamp$k(label.x || 0, 0, this.getPlayingField().width - (label.width || 0) - 1)
            });
          }
          if (!styledMode) {
            label.attr({
              stroke: options2.borderColor || point.color || currentSeries.color || "#666666"
            });
          }
          tooltip.updatePosition({
            plotX: x,
            plotY: y,
            negative: point.negative,
            ttBelow: point.ttBelow,
            series: currentSeries,
            h: anchor[2] || 0
          });
        } else {
          tooltip.hide();
          return;
        }
      }
      if (tooltip.isHidden && tooltip.label) {
        tooltip.label.attr({
          opacity: 1
        }).show();
      }
      tooltip.isHidden = false;
    }
    fireEvent$G(this, "refresh");
  }
  /**
   * Render the split tooltip. Loops over each point's text and adds
   * a label next to the point, then uses the distribute function to
   * find best non-overlapping positions.
   *
   * @private
   * @function Highcharts.Tooltip#renderSplit
   *
   * @param {string|Array<(boolean|string)>} labels
   *
   * @param {Array<Highcharts.Point>} points
   */
  renderSplit(labels, points) {
    const tooltip = this;
    const { chart, chart: { chartWidth, chartHeight, plotHeight, plotLeft, plotTop, scrollablePixelsY = 0, scrollablePixelsX, styledMode }, distance, options: options2, options: { fixed, position, positioner }, pointer } = tooltip;
    const { scrollLeft = 0, scrollTop = 0 } = chart.scrollablePlotArea?.scrollingContainer || {};
    const bounds = tooltip.outside && typeof scrollablePixelsX !== "number" ? doc$o.documentElement.getBoundingClientRect() : {
      left: scrollLeft,
      right: scrollLeft + chartWidth
    };
    const tooltipLabel = tooltip.getLabel();
    const ren = this.renderer || chart.renderer;
    const headerTop = Boolean(chart.xAxis[0]?.opposite);
    const { left: chartLeft, top: chartTop } = pointer.getChartPosition();
    const hasFixedPosition = positioner || fixed;
    let distributionBoxTop = plotTop + scrollTop;
    let headerHeight = 0;
    let adjustedPlotHeight = plotHeight - scrollablePixelsY;
    function getAnchor(point) {
      const { isHeader, plotX = 0, plotY = 0, series } = point;
      let anchorX;
      let anchorY;
      if (isHeader) {
        anchorX = Math.max(plotLeft + plotX, plotLeft);
        anchorY = plotTop + plotHeight / 2;
      } else {
        const { xAxis: xAxis2, yAxis: yAxis2 } = series;
        anchorX = xAxis2.pos + clamp$k(plotX, -distance, xAxis2.len + distance);
        if (series.shouldShowTooltip(0, yAxis2.pos - plotTop + plotY, {
          ignoreX: true
        })) {
          anchorY = yAxis2.pos + plotY;
        }
      }
      anchorX = clamp$k(anchorX, bounds.left - distance, bounds.right + distance);
      return { anchorX, anchorY };
    }
    const defaultPositioner = function(boxWidth, boxHeight, point, anchor = [0, 0], alignedLeft = true) {
      let x, y;
      if (point.isHeader) {
        y = headerTop ? 0 : adjustedPlotHeight;
        x = clamp$k(anchor[0] - boxWidth / 2, bounds.left, bounds.right - boxWidth - (tooltip.outside ? chartLeft : 0));
      } else if (fixed && point) {
        const pos = tooltip.getFixedPosition(boxWidth, boxHeight, point);
        x = pos.x;
        y = pos.y - distributionBoxTop;
      } else {
        y = anchor[1] - distributionBoxTop;
        x = alignedLeft ? anchor[0] - boxWidth - distance : anchor[0] + distance;
        x = clamp$k(x, alignedLeft ? x : bounds.left, bounds.right);
      }
      return { x, y };
    };
    function updatePartialTooltip(partialTooltip, point, str) {
      let tt = partialTooltip;
      const { isHeader, series } = point, ttOptions = series.tooltipOptions || options2;
      if (!tt) {
        const attribs = {
          padding: ttOptions.padding,
          r: ttOptions.borderRadius
        };
        if (!styledMode) {
          attribs.fill = ttOptions.backgroundColor;
          attribs["stroke-width"] = ttOptions.borderWidth ?? (fixed && !isHeader ? 0 : 1);
        }
        tt = ren.label("", 0, 0, ttOptions[isHeader ? "headerShape" : "shape"] || (fixed && !isHeader ? "rect" : "callout"), void 0, void 0, ttOptions.useHTML).addClass(tooltip.getClassName(point, true, isHeader)).attr(attribs).add(tooltipLabel);
      }
      tt.isActive = true;
      tt.attr({
        text: str
      });
      if (!styledMode) {
        tt.css(ttOptions.style).attr({
          stroke: ttOptions.borderColor || point.color || series.color || "#333333"
        });
      }
      return tt;
    }
    if (isString$c(labels)) {
      labels = [false, labels];
    }
    let boxes = labels.slice(0, points.length + 1).reduce(function(boxes2, str, i) {
      if (str !== false && str !== "") {
        const point = points[i - 1] || {
          // Item 0 is the header. Instead of this, we could also
          // use the crosshair label
          isHeader: true,
          plotX: points[0].plotX,
          plotY: plotHeight,
          series: {}
        };
        const isHeader = point.isHeader;
        const owner = isHeader ? tooltip : point.series;
        const tt = owner.tt = updatePartialTooltip(owner.tt, point, str.toString());
        const bBox = tt.getBBox();
        const boxWidth = bBox.width + tt.strokeWidth();
        if (isHeader) {
          headerHeight = bBox.height;
          adjustedPlotHeight += headerHeight;
          if (headerTop) {
            distributionBoxTop -= headerHeight;
          }
        }
        const { anchorX, anchorY } = getAnchor(point);
        if (typeof anchorY === "number") {
          const size = bBox.height + 1, boxPosition = (positioner || defaultPositioner).call(tooltip, boxWidth, size, point, [anchorX, anchorY]);
          boxes2.push({
            // 0-align to the top, 1-align to the bottom
            align: hasFixedPosition ? 0 : void 0,
            anchorX,
            anchorY,
            boxWidth,
            point,
            rank: pick$1F(boxPosition.rank, isHeader ? 1 : 0),
            size,
            target: boxPosition.y,
            tt,
            x: boxPosition.x
          });
        } else {
          tt.isActive = false;
        }
      }
      return boxes2;
    }, []);
    if (!hasFixedPosition && boxes.some((box) => {
      const { outside: outside2 } = tooltip;
      const boxStart = (outside2 ? chartLeft : 0) + box.anchorX;
      if (boxStart < bounds.left && boxStart + box.boxWidth < bounds.right) {
        return true;
      }
      return boxStart < chartLeft - bounds.left + box.boxWidth && bounds.right - boxStart > boxStart;
    })) {
      boxes = boxes.map((box) => {
        const { x, y } = defaultPositioner.call(this, box.boxWidth, box.size, box.point, [box.anchorX, box.anchorY], false);
        return extend$1i(box, {
          target: y,
          x
        });
      });
    }
    tooltip.cleanSplit();
    distribute$3(boxes, adjustedPlotHeight);
    const boxExtremes = {
      left: chartLeft,
      right: chartLeft
    };
    boxes.forEach(function(box) {
      const { x, boxWidth, isHeader } = box;
      if (!isHeader) {
        if (tooltip.outside && chartLeft + x < boxExtremes.left) {
          boxExtremes.left = chartLeft + x;
        }
        if (!isHeader && tooltip.outside && boxExtremes.left + boxWidth > boxExtremes.right) {
          boxExtremes.right = chartLeft + x;
        }
      }
    });
    boxes.forEach(function(box) {
      const { x, anchorX, anchorY, pos, point: { isHeader } } = box;
      const attributes = {
        visibility: typeof pos === "undefined" ? "hidden" : "inherit",
        x,
        /* NOTE: y should equal pos to be consistent with !split
         * tooltip, but is currently relative to plotTop. Is left as is
         * to avoid breaking change. Remove distributionBoxTop to make
         * it consistent.
         */
        y: (pos || 0) + distributionBoxTop + (fixed && position.y || 0),
        anchorX,
        anchorY
      };
      if (tooltip.outside && x < anchorX) {
        const offset2 = chartLeft - boxExtremes.left;
        if (offset2 > 0) {
          if (!isHeader) {
            attributes.x = x + offset2;
            attributes.anchorX = anchorX + offset2;
          }
          if (isHeader) {
            attributes.x = (boxExtremes.right - boxExtremes.left) / 2;
            attributes.anchorX = anchorX + offset2;
          }
        }
      }
      box.tt.attr(attributes);
    });
    const { container, outside, renderer } = tooltip;
    if (outside && container && renderer) {
      const { width, height, x, y } = tooltipLabel.getBBox();
      renderer.setSize(width + x, height + y, false);
      container.style.left = boxExtremes.left + "px";
      container.style.top = chartTop + "px";
    }
    if (isSafari) {
      tooltipLabel.attr({
        // Force a redraw of the whole group by chaining the opacity
        // slightly
        opacity: tooltipLabel.opacity === 1 ? 0.999 : 1
      });
    }
  }
  /**
   * If the `stickOnContact` option is active, this will add a tracker shape.
   *
   * @private
   * @function Highcharts.Tooltip#drawTracker
   */
  drawTracker() {
    const tooltip = this;
    if (!this.shouldStickOnContact()) {
      if (tooltip.tracker) {
        tooltip.tracker = tooltip.tracker.destroy();
      }
      return;
    }
    const chart = tooltip.chart;
    const label = tooltip.label;
    const points = tooltip.shared ? chart.hoverPoints : chart.hoverPoint;
    if (!label || !points) {
      return;
    }
    const box = {
      x: 0,
      y: 0,
      width: 0,
      height: 0
    };
    const anchorPos = this.getAnchor(points);
    const labelBBox = label.getBBox();
    anchorPos[0] += chart.plotLeft - (label.translateX || 0);
    anchorPos[1] += chart.plotTop - (label.translateY || 0);
    box.x = Math.min(0, anchorPos[0]);
    box.y = Math.min(0, anchorPos[1]);
    box.width = anchorPos[0] < 0 ? Math.max(Math.abs(anchorPos[0]), labelBBox.width - anchorPos[0]) : Math.max(Math.abs(anchorPos[0]), labelBBox.width);
    box.height = anchorPos[1] < 0 ? Math.max(Math.abs(anchorPos[1]), labelBBox.height - Math.abs(anchorPos[1])) : Math.max(Math.abs(anchorPos[1]), labelBBox.height);
    if (tooltip.tracker) {
      tooltip.tracker.attr(box);
    } else {
      tooltip.tracker = label.renderer.rect(box).addClass("highcharts-tracker").add(label);
      if (!chart.styledMode) {
        tooltip.tracker.attr({
          fill: "rgba(0,0,0,0)"
        });
      }
    }
  }
  /**
   * @private
   */
  styledModeFormat(formatString) {
    return formatString.replace('style="font-size: 0.8em"', 'class="highcharts-header"').replace(/style="color:{(point|series)\.color}"/g, 'class="highcharts-color-{$1.colorIndex} {series.options.className} {point.options.className}"');
  }
  /**
   * Format the footer/header of the tooltip
   * #3397: abstraction to enable formatting of footer and header
   *
   * @private
   * @function Highcharts.Tooltip#headerFooterFormatter
   */
  headerFooterFormatter(point, isFooter) {
    const series = point.series, tooltipOptions = series.tooltipOptions, xAxis2 = series.xAxis, dateTime = xAxis2?.dateTime, e = {
      isFooter,
      point
    };
    let xDateFormat = tooltipOptions.xDateFormat || "", formatString = tooltipOptions[isFooter ? "footerFormat" : "headerFormat"];
    fireEvent$G(this, "headerFormatter", e, function(e2) {
      if (dateTime && !xDateFormat && isNumber$$(point.key)) {
        xDateFormat = dateTime.getXDateFormat(point.key, tooltipOptions.dateTimeLabelFormats);
      }
      if (dateTime && xDateFormat) {
        if (isObject$j(xDateFormat)) {
          const format2 = xDateFormat;
          dateFormats$2[0] = (timestamp) => series.chart.time.dateFormat(format2, timestamp);
          xDateFormat = "%0";
        }
        (point.tooltipDateKeys || ["key"]).forEach((key2) => {
          formatString = formatString.replace(new RegExp("point\\." + key2 + "([ \\)}])"), `(point.${key2}:${xDateFormat})$1`);
        });
      }
      if (series.chart.styledMode) {
        formatString = this.styledModeFormat(formatString);
      }
      e2.text = format$g(formatString, point, this.chart);
    });
    return e.text || "";
  }
  /**
   * Updates the tooltip with the provided tooltip options.
   *
   * @function Highcharts.Tooltip#update
   *
   * @param {Highcharts.TooltipOptions} options
   *        The tooltip options to update.
   */
  update(options2) {
    this.destroy();
    this.init(this.chart, merge$1z(true, this.options, options2));
  }
  /**
   * Find the new position and perform the move
   *
   * @private
   * @function Highcharts.Tooltip#updatePosition
   *
   * @param {Highcharts.Point} point
   */
  updatePosition(point) {
    const { chart, container, distance, options: options2, pointer, renderer } = this, label = this.getLabel(), { height = 0, width = 0 } = label, { fixed, positioner } = options2, { left, top, scaleX, scaleY } = pointer.getChartPosition(), pos = (positioner || fixed && this.getFixedPosition || this.getPosition).call(this, width, height, point), doc2 = Highcharts.doc;
    let anchorX = (point.plotX || 0) + chart.plotLeft, anchorY = (point.plotY || 0) + chart.plotTop, pad2;
    if (renderer && container) {
      if (positioner || fixed) {
        const { scrollLeft = 0, scrollTop = 0 } = chart.scrollablePlotArea?.scrollingContainer || {};
        pos.x += scrollLeft + left - distance;
        pos.y += scrollTop + top - distance;
      }
      pad2 = (options2.borderWidth || 0) + 2 * distance + 2;
      renderer.setSize(
        // Clamp width to keep tooltip in viewport (#21698)
        // and subtract one since tooltip container has 'left: 1px;'
        clamp$k(width + pad2, 0, doc2.documentElement.clientWidth) - 1,
        height + pad2,
        false
      );
      if (scaleX !== 1 || scaleY !== 1) {
        css$b(container, {
          transform: `scale(${scaleX}, ${scaleY})`
        });
        anchorX *= scaleX;
        anchorY *= scaleY;
      }
      anchorX += left - pos.x;
      anchorY += top - pos.y;
    }
    this.move(
      Math.round(pos.x),
      Math.round(pos.y || 0),
      // Can be undefined (#3977)
      anchorX,
      anchorY
    );
  }
}
(function(Tooltip2) {
  function compose2(PointerClass) {
    if (pushUnique$x(composed$x, "Core.Tooltip")) {
      addEvent$1p(PointerClass, "afterInit", function() {
        const chart = this.chart;
        if (chart.options.tooltip) {
          chart.tooltip = new Tooltip2(chart, chart.options.tooltip, this);
        }
      });
    }
  }
  Tooltip2.compose = compose2;
})(Tooltip || (Tooltip = {}));
const Tooltip$1 = Tooltip;
const { animObject: animObject$c } = animationExports;
const { defaultOptions: defaultOptions$j } = DefaultOptions;
const { format: format$f } = Templating;
const { addEvent: addEvent$1o, crisp: crisp$d, erase: erase$7, extend: extend$1h, fireEvent: fireEvent$F, getNestedProperty: getNestedProperty$2, isArray: isArray$l, isFunction: isFunction$2, isNumber: isNumber$_, isObject: isObject$i, merge: merge$1y, pick: pick$1E, syncTimeout: syncTimeout$8, removeEvent: removeEvent$9, uniqueKey: uniqueKey$7 } = Utilities;
let Point$3 = class Point2 {
  /**
   * For categorized axes this property holds the category name for the
   * point. For other axes it holds the X value.
   *
   * @name Highcharts.Point#category
   * @type {number|string}
   */
  /**
   * The name of the point. The name can be given as the first position of the
   * point configuration array, or as a `name` property in the configuration:
   *
   * @example
   * // Array config
   * data: [
   *     ['John', 1],
   *     ['Jane', 2]
   * ]
   *
   * // Object config
   * data: [{
   *        name: 'John',
   *        y: 1
   * }, {
   *     name: 'Jane',
   *     y: 2
   * }]
   *
   * @name Highcharts.Point#name
   * @type {string}
   */
  /**
   * The point's name if it is defined, or its category in case of a category,
   * otherwise the x value. Convenient for tooltip and data label formatting.
   *
   * @name Highcharts.Point#key
   * @type {number|string}
   */
  /**
   * The point's options as applied in the initial configuration, or
   * extended through `Point.update`.
   *
   * In TypeScript you have to extend `PointOptionsObject` via an
   * additional interface to allow custom data options:
   *
   * ```
   * declare interface PointOptionsObject {
   *     customProperty: string;
   * }
   * ```
   *
   * @name Highcharts.Point#options
   * @type {Highcharts.PointOptionsObject}
   */
  /**
   * The percentage for points in a stacked series, pies or gauges.
   *
   * @name Highcharts.Point#percentage
   * @type {number|undefined}
   */
  /**
   * Array of all hovered points when using shared tooltips.
   *
   * @name Highcharts.Point#points
   * @type {Array<Highcharts.Point>|undefined}
   */
  /**
   * The series object associated with the point.
   *
   * @name Highcharts.Point#series
   * @type {Highcharts.Series}
   */
  /**
   * The attributes of the rendered SVG shape like in `column` or `pie`
   * series.
   *
   * @readonly
   * @name Highcharts.Point#shapeArgs
   * @type {Readonly<Highcharts.SVGAttributes>|undefined}
   */
  /**
   * The total of values in either a stack for stacked series, or a pie in a
   * pie series.
   *
   * @name Highcharts.Point#total
   * @type {number|undefined}
   */
  /**
   * For certain series types, like pie charts, where individual points can
   * be shown or hidden.
   *
   * @name Highcharts.Point#visible
   * @type {boolean}
   * @default true
   */
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Animate SVG elements associated with the point.
   *
   * @private
   * @function Highcharts.Point#animateBeforeDestroy
   */
  animateBeforeDestroy() {
    const point = this, animateParams = { x: point.startXPos, opacity: 0 }, graphicalProps = point.getGraphicalProps();
    graphicalProps.singular.forEach(function(prop) {
      const isDataLabel = prop === "dataLabel";
      point[prop] = point[prop].animate(isDataLabel ? {
        x: point[prop].startXPos,
        y: point[prop].startYPos,
        opacity: 0
      } : animateParams);
    });
    graphicalProps.plural.forEach(function(plural) {
      point[plural].forEach(function(item) {
        if (item.element) {
          item.animate(extend$1h({ x: point.startXPos }, item.startYPos ? {
            x: item.startXPos,
            y: item.startYPos
          } : {}));
        }
      });
    });
  }
  /**
   * Apply the options containing the x and y data and possible some extra
   * properties. Called on point init or from point.update.
   *
   * @private
   * @function Highcharts.Point#applyOptions
   *
   * @param {Highcharts.PointOptionsType} options
   *        The point options as defined in series.data.
   *
   * @param {number} [x]
   *        Optionally, the x value.
   *
   * @return {Highcharts.Point}
   *         The Point instance.
   */
  applyOptions(options2, x) {
    const point = this, series = point.series, pointValKey = series.options.pointValKey || series.pointValKey;
    options2 = Point2.prototype.optionsToObject.call(this, options2);
    extend$1h(point, options2);
    point.options = point.options ? extend$1h(point.options, options2) : options2;
    if (options2.group) {
      delete point.group;
    }
    if (options2.dataLabels) {
      delete point.dataLabels;
    }
    if (pointValKey) {
      point.y = Point2.prototype.getNestedProperty.call(point, pointValKey);
    }
    if (point.selected) {
      point.state = "select";
    }
    if ("name" in point && typeof x === "undefined" && series.xAxis && series.xAxis.hasNames) {
      point.x = series.xAxis.nameToX(point);
    }
    if (typeof point.x === "undefined" && series) {
      point.x = x ?? series.autoIncrement();
    } else if (isNumber$_(options2.x) && series.options.relativeXValue) {
      point.x = series.autoIncrement(options2.x);
    } else if (typeof point.x === "string") {
      x ?? (x = series.chart.time.parse(point.x));
      if (isNumber$_(x)) {
        point.x = x;
      }
    }
    point.isNull = this.isValid && !this.isValid();
    point.formatPrefix = point.isNull ? "null" : "point";
    return point;
  }
  /**
   * Destroy a point to clear memory. Its reference still stays in
   * `series.data`.
   *
   * @private
   * @function Highcharts.Point#destroy
   */
  destroy() {
    if (!this.destroyed) {
      const point = this, series = point.series, chart = series.chart, dataSorting = series.options.dataSorting, hoverPoints = chart.hoverPoints, globalAnimation = point.series.chart.renderer.globalAnimation, animation = animObject$c(globalAnimation);
      const destroyPoint = () => {
        if (point.graphic || point.graphics || point.dataLabel || point.dataLabels) {
          removeEvent$9(point);
          point.destroyElements();
        }
        for (const prop in point) {
          delete point[prop];
        }
      };
      if (point.legendItem) {
        chart.legend.destroyItem(point);
      }
      if (hoverPoints) {
        point.setState();
        erase$7(hoverPoints, point);
        if (!hoverPoints.length) {
          chart.hoverPoints = null;
        }
      }
      if (point === chart.hoverPoint) {
        point.onMouseOut();
      }
      if (!dataSorting?.enabled) {
        destroyPoint();
      } else {
        this.animateBeforeDestroy();
        syncTimeout$8(destroyPoint, animation.duration);
      }
      chart.pointCount--;
    }
    this.destroyed = true;
  }
  /**
   * Destroy SVG elements associated with the point.
   *
   * @private
   * @function Highcharts.Point#destroyElements
   * @param {Highcharts.Dictionary<number>} [kinds]
   */
  destroyElements(kinds) {
    const point = this, props = point.getGraphicalProps(kinds);
    props.singular.forEach(function(prop) {
      point[prop] = point[prop].destroy();
    });
    props.plural.forEach(function(plural) {
      point[plural].forEach(function(item) {
        if (item?.element) {
          item.destroy();
        }
      });
      delete point[plural];
    });
  }
  /**
   * Fire an event on the Point object.
   *
   * @private
   * @function Highcharts.Point#firePointEvent
   *
   * @param {string} eventType
   *        Type of the event.
   *
   * @param {Highcharts.Dictionary<any>|Event} [eventArgs]
   *        Additional event arguments.
   *
   * @param {Highcharts.EventCallbackFunction<Highcharts.Point>|Function} [defaultFunction]
   *        Default event handler.
   *
   * @emits Highcharts.Point#event:*
   */
  firePointEvent(eventType, eventArgs, defaultFunction) {
    const point = this, series = this.series, seriesOptions = series.options;
    point.manageEvent(eventType);
    if (eventType === "click" && seriesOptions.allowPointSelect) {
      defaultFunction = function(event) {
        if (!point.destroyed && point.select) {
          point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
        }
      };
    }
    fireEvent$F(point, eventType, eventArgs, defaultFunction);
  }
  /**
   * Get the CSS class names for individual points. Used internally where the
   * returned value is set on every point.
   *
   * @function Highcharts.Point#getClassName
   *
   * @return {string}
   *         The class names.
   */
  getClassName() {
    const point = this;
    return "highcharts-point" + (point.selected ? " highcharts-point-select" : "") + (point.negative ? " highcharts-negative" : "") + (point.isNull ? " highcharts-null-point" : "") + (typeof point.colorIndex !== "undefined" ? " highcharts-color-" + point.colorIndex : "") + (point.options.className ? " " + point.options.className : "") + (point.zone?.className ? " " + point.zone.className.replace("highcharts-negative", "") : "");
  }
  /**
   * Get props of all existing graphical point elements.
   *
   * @private
   * @function Highcharts.Point#getGraphicalProps
   */
  getGraphicalProps(kinds) {
    const point = this, props = [], graphicalProps = { singular: [], plural: [] };
    let prop, i;
    kinds = kinds || { graphic: 1, dataLabel: 1 };
    if (kinds.graphic) {
      props.push(
        "graphic",
        "connector"
        // Used by dumbbell
      );
    }
    if (kinds.dataLabel) {
      props.push("dataLabel", "dataLabelPath", "dataLabelUpper");
    }
    i = props.length;
    while (i--) {
      prop = props[i];
      if (point[prop]) {
        graphicalProps.singular.push(prop);
      }
    }
    [
      "graphic",
      "dataLabel"
    ].forEach(function(prop2) {
      const plural = prop2 + "s";
      if (kinds[prop2] && point[plural]) {
        graphicalProps.plural.push(plural);
      }
    });
    return graphicalProps;
  }
  /**
   * Returns the value of the point property for a given value.
   * @private
   */
  getNestedProperty(key2) {
    if (!key2) {
      return;
    }
    if (key2.indexOf("custom.") === 0) {
      return getNestedProperty$2(key2, this.options);
    }
    return this[key2];
  }
  /**
   * In a series with `zones`, return the zone that the point belongs to.
   *
   * @function Highcharts.Point#getZone
   *
   * @return {Highcharts.SeriesZonesOptionsObject}
   *         The zone item.
   */
  getZone() {
    const series = this.series, zones = series.zones, zoneAxis = series.zoneAxis || "y";
    let zone, i = 0;
    zone = zones[i];
    while (this[zoneAxis] >= zone.value) {
      zone = zones[++i];
    }
    if (!this.nonZonedColor) {
      this.nonZonedColor = this.color;
    }
    if (zone?.color && !this.options.color) {
      this.color = zone.color;
    } else {
      this.color = this.nonZonedColor;
    }
    return zone;
  }
  /**
   * Utility to check if point has new shape type. Used in column series and
   * all others that are based on column series.
   * @private
   */
  hasNewShapeType() {
    const point = this;
    const oldShapeType = point.graphic && (point.graphic.symbolName || point.graphic.element.nodeName);
    return oldShapeType !== this.shapeType;
  }
  /**
   * Initialize the point. Called internally based on the `series.data`
   * option.
   *
   * @function Highcharts.Point#init
   *
   * @param {Highcharts.Series} series
   *        The series object containing this point.
   *
   * @param {Highcharts.PointOptionsType} options
   *        The data in either number, array or object format.
   *
   * @param {number} [x]
   *        Optionally, the X value of the point.
   *
   * @return {Highcharts.Point}
   *         The Point instance.
   *
   * @emits Highcharts.Point#event:afterInit
   */
  constructor(series, options2, x) {
    this.formatPrefix = "point";
    this.visible = true;
    this.point = this;
    this.series = series;
    this.applyOptions(options2, x);
    this.id ?? (this.id = uniqueKey$7());
    this.resolveColor();
    this.dataLabelOnNull ?? (this.dataLabelOnNull = series.options.nullInteraction);
    series.chart.pointCount++;
    fireEvent$F(this, "afterInit");
  }
  /**
   * Determine if point is valid.
   * @private
   * @function Highcharts.Point#isValid
   */
  isValid() {
    return (isNumber$_(this.x) || this.x instanceof Date) && isNumber$_(this.y);
  }
  /**
   * Transform number or array configs into objects. Also called for object
   * configs. Used internally to unify the different configuration formats for
   * points. For example, a simple number `10` in a line series will be
   * transformed to `{ y: 10 }`, and an array config like `[1, 10]` in a
   * scatter series will be transformed to `{ x: 1, y: 10 }`.
   *
   * @function Highcharts.Point#optionsToObject
   *
   * @param {Highcharts.PointOptionsType} options
   * Series data options.
   *
   * @return {Highcharts.Dictionary<*>}
   * Transformed point options.
   */
  optionsToObject(options2) {
    const series = this.series, keys = series.options.keys, pointArrayMap = keys || series.pointArrayMap || ["y"], valueCount = pointArrayMap.length;
    let ret = {}, firstItemType, i = 0, j = 0;
    if (isNumber$_(options2) || options2 === null) {
      ret[pointArrayMap[0]] = options2;
    } else if (isArray$l(options2)) {
      if (!keys && options2.length > valueCount) {
        firstItemType = typeof options2[0];
        if (firstItemType === "string") {
          if (series.xAxis?.dateTime) {
            ret.x = series.chart.time.parse(options2[0]);
          } else {
            ret.name = options2[0];
          }
        } else if (firstItemType === "number") {
          ret.x = options2[0];
        }
        i++;
      }
      while (j < valueCount) {
        if (!keys || typeof options2[i] !== "undefined") {
          if (pointArrayMap[j].indexOf(".") > 0) {
            Point2.prototype.setNestedProperty(ret, options2[i], pointArrayMap[j]);
          } else {
            ret[pointArrayMap[j]] = options2[i];
          }
        }
        i++;
        j++;
      }
    } else if (typeof options2 === "object") {
      ret = options2;
      if (options2.dataLabels) {
        series.hasDataLabels = () => true;
      }
      if (options2.marker) {
        series._hasPointMarkers = true;
      }
    }
    return ret;
  }
  /**
   * Get the pixel position of the point relative to the plot area.
   * @function Highcharts.Point#pos
   *
   * @sample highcharts/point/position
   *         Get point's position in pixels.
   *
   * @param {boolean} chartCoordinates
   * If true, the returned position is relative to the full chart area.
   * If false, it is relative to the plot area determined by the axes.
   *
   * @param {number|undefined} plotY
   * A custom plot y position to be computed. Used internally for some
   * series types that have multiple `y` positions, like area range (low
   * and high values).
   *
   * @return {Array<number>|undefined}
   * Coordinates of the point if the point exists.
   */
  pos(chartCoordinates, plotY = this.plotY) {
    if (!this.destroyed) {
      const { plotX, series } = this, { chart, xAxis: xAxis2, yAxis: yAxis2 } = series;
      let posX = 0, posY = 0;
      if (isNumber$_(plotX) && isNumber$_(plotY)) {
        if (chartCoordinates) {
          posX = xAxis2 ? xAxis2.pos : chart.plotLeft;
          posY = yAxis2 ? yAxis2.pos : chart.plotTop;
        }
        return chart.inverted && xAxis2 && yAxis2 ? [yAxis2.len - plotY + posY, xAxis2.len - plotX + posX] : [plotX + posX, plotY + posY];
      }
    }
  }
  /**
   * @private
   * @function Highcharts.Point#resolveColor
   */
  resolveColor() {
    const series = this.series, optionsChart = series.chart.options.chart, styledMode = series.chart.styledMode;
    let color2, colors, colorCount = optionsChart.colorCount, colorIndex;
    delete this.nonZonedColor;
    if (series.options.colorByPoint) {
      if (!styledMode) {
        colors = series.options.colors || series.chart.options.colors;
        color2 = colors[series.colorCounter];
        colorCount = colors.length;
      }
      colorIndex = series.colorCounter;
      series.colorCounter++;
      if (series.colorCounter === colorCount) {
        series.colorCounter = 0;
      }
    } else {
      if (!styledMode) {
        color2 = series.color;
      }
      colorIndex = series.colorIndex;
    }
    this.colorIndex = pick$1E(this.options.colorIndex, colorIndex);
    this.color = pick$1E(this.options.color, color2);
  }
  /**
   * Set a value in an object, on the property defined by key. The key
   * supports nested properties using dot notation. The function modifies the
   * input object and does not make a copy.
   *
   * @function Highcharts.Point#setNestedProperty<T>
   *
   * @param {T} object
   *        The object to set the value on.
   *
   * @param {*} value
   *        The value to set.
   *
   * @param {string} key
   *        Key to the property to set.
   *
   * @return {T}
   *         The modified object.
   */
  setNestedProperty(object, value, key2) {
    const nestedKeys = key2.split(".");
    nestedKeys.reduce(function(result, key3, i, arr) {
      const isLastKey = arr.length - 1 === i;
      result[key3] = isLastKey ? value : isObject$i(result[key3], true) ? result[key3] : {};
      return result[key3];
    }, object);
    return object;
  }
  shouldDraw() {
    return !this.isNull;
  }
  /**
   * Extendable method for formatting each point's tooltip line.
   *
   * @function Highcharts.Point#tooltipFormatter
   *
   * @param {string} pointFormat
   *        The point format.
   *
   * @return {string}
   *         A string to be concatenated in to the common tooltip text.
   */
  tooltipFormatter(pointFormat) {
    const { chart, pointArrayMap = ["y"], tooltipOptions } = this.series, { valueDecimals = "", valuePrefix = "", valueSuffix = "" } = tooltipOptions;
    if (chart.styledMode) {
      pointFormat = chart.tooltip?.styledModeFormat(pointFormat) || pointFormat;
    }
    pointArrayMap.forEach((key2) => {
      key2 = "{point." + key2;
      if (valuePrefix || valueSuffix) {
        pointFormat = pointFormat.replace(RegExp(key2 + "}", "g"), valuePrefix + key2 + "}" + valueSuffix);
      }
      pointFormat = pointFormat.replace(RegExp(key2 + "}", "g"), key2 + ":,." + valueDecimals + "f}");
    });
    return format$f(pointFormat, this, chart);
  }
  /**
   * Update point with new options (typically x/y data) and optionally redraw
   * the series.
   *
   * @sample highcharts/members/point-update-column/
   *         Update column value
   * @sample highcharts/members/point-update-pie/
   *         Update pie slice
   * @sample maps/members/point-update/
   *         Update map area value in Highmaps
   *
   * @function Highcharts.Point#update
   *
   * @param {Highcharts.PointOptionsType} options
   *        The point options. Point options are handled as described under
   *        the `series.type.data` item for each series type. For example
   *        for a line series, if options is a single number, the point will
   *        be given that number as the marin y value. If it is an array, it
   *        will be interpreted as x and y values respectively. If it is an
   *        object, advanced options are applied.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after the point is updated. If doing
   *        more operations on the chart, it is best practice to set
   *        `redraw` to false and call `chart.redraw()` after.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
   *        Whether to apply animation, and optionally animation
   *        configuration.
   *
   * @emits Highcharts.Point#event:update
   */
  update(options2, redraw, animation, runEvent) {
    const point = this, series = point.series, graphic = point.graphic, chart = series.chart, seriesOptions = series.options;
    let i;
    redraw = pick$1E(redraw, true);
    function update() {
      point.applyOptions(options2);
      const hasMockGraphic = graphic && point.hasMockGraphic;
      const shouldDestroyGraphic = point.y === null ? !hasMockGraphic : hasMockGraphic;
      if (graphic && shouldDestroyGraphic) {
        point.graphic = graphic.destroy();
        delete point.hasMockGraphic;
      }
      if (isObject$i(options2, true)) {
        if (graphic?.element) {
          if (options2 && options2.marker && typeof options2.marker.symbol !== "undefined") {
            point.graphic = graphic.destroy();
          }
        }
        if (options2?.dataLabels && point.dataLabel) {
          point.dataLabel = point.dataLabel.destroy();
        }
      }
      i = point.index;
      const row = {};
      for (const key2 of series.dataColumnKeys()) {
        row[key2] = point[key2];
      }
      series.dataTable.setRow(row, i);
      seriesOptions.data[i] = isObject$i(seriesOptions.data[i], true) || isObject$i(options2, true) ? point.options : pick$1E(options2, seriesOptions.data[i]);
      series.isDirty = series.isDirtyData = true;
      if (!series.fixedBox && series.hasCartesianSeries) {
        chart.isDirtyBox = true;
      }
      if (seriesOptions.legendType === "point") {
        chart.isDirtyLegend = true;
      }
      if (redraw) {
        chart.redraw(animation);
      }
    }
    if (runEvent === false) {
      update();
    } else {
      point.firePointEvent("update", { options: options2 }, update);
    }
  }
  /**
   * Remove a point and optionally redraw the series and if necessary the axes
   *
   * @sample highcharts/plotoptions/series-point-events-remove/
   *         Remove point and confirm
   * @sample highcharts/members/point-remove/
   *         Remove pie slice
   * @sample maps/members/point-remove/
   *         Remove selected points in Highmaps
   *
   * @function Highcharts.Point#remove
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart or wait for an explicit call. When
   *        doing more operations on the chart, for example running
   *        `point.remove()` in a loop, it is best practice to set `redraw`
   *        to false and call `chart.redraw()` after.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=false]
   *        Whether to apply animation, and optionally animation
   *        configuration.
   */
  remove(redraw, animation) {
    this.series.removePoint(this.series.data.indexOf(this), redraw, animation);
  }
  /**
   * Toggle the selection status of a point.
   *
   * @see Highcharts.Chart#getSelectedPoints
   *
   * @sample highcharts/members/point-select/
   *         Select a point from a button
   * @sample highcharts/members/point-select-lasso/
   *         Lasso selection
   * @sample highcharts/chart/events-selection-points/
   *         Rectangle selection
   * @sample maps/series/data-id/
   *         Select a point in Highmaps
   *
   * @function Highcharts.Point#select
   *
   * @param {boolean} [selected]
   * When `true`, the point is selected. When `false`, the point is
   * unselected. When `null` or `undefined`, the selection state is toggled.
   *
   * @param {boolean} [accumulate=false]
   * When `true`, the selection is added to other selected points.
   * When `false`, other selected points are deselected. Internally in
   * Highcharts, when
   * [allowPointSelect](https://api.highcharts.com/highcharts/plotOptions.series.allowPointSelect)
   * is `true`, selected points are accumulated on Control, Shift or Cmd
   * clicking the point.
   *
   * @emits Highcharts.Point#event:select
   * @emits Highcharts.Point#event:unselect
   */
  select(selected, accumulate) {
    const point = this, series = point.series, chart = series.chart;
    selected = pick$1E(selected, !point.selected);
    this.selectedStaging = selected;
    point.firePointEvent(selected ? "select" : "unselect", { accumulate }, function() {
      point.selected = point.options.selected = selected;
      series.options.data[series.data.indexOf(point)] = point.options;
      point.setState(selected && "select");
      if (!accumulate) {
        chart.getSelectedPoints().forEach(function(loopPoint) {
          const loopSeries = loopPoint.series;
          if (loopPoint.selected && loopPoint !== point) {
            loopPoint.selected = loopPoint.options.selected = false;
            loopSeries.options.data[loopSeries.data.indexOf(loopPoint)] = loopPoint.options;
            loopPoint.setState(chart.hoverPoints && loopSeries.options.inactiveOtherPoints ? "inactive" : "");
            loopPoint.firePointEvent("unselect");
          }
        });
      }
    });
    delete this.selectedStaging;
  }
  /**
   * Runs on mouse over the point. Called internally from mouse and touch
   * events.
   *
   * @function Highcharts.Point#onMouseOver
   *
   * @param {Highcharts.PointerEventObject} [e]
   *        The event arguments.
   */
  onMouseOver(e) {
    const point = this, series = point.series, { inverted, pointer } = series.chart;
    if (pointer) {
      e = e ? pointer.normalize(e) : (
        // In cases where onMouseOver is called directly without an
        // event
        pointer.getChartCoordinatesFromPoint(point, inverted)
      );
      pointer.runPointActions(e, point);
    }
  }
  /**
   * Runs on mouse out from the point. Called internally from mouse and touch
   * events.
   *
   * @function Highcharts.Point#onMouseOut
   * @emits Highcharts.Point#event:mouseOut
   */
  onMouseOut() {
    const point = this, chart = point.series.chart;
    point.firePointEvent("mouseOut");
    if (!point.series.options.inactiveOtherPoints) {
      (chart.hoverPoints || []).forEach(function(p) {
        p.setState();
      });
    }
    chart.hoverPoints = chart.hoverPoint = null;
  }
  /**
   * Manage specific event from the series' and point's options. Only do it on
   * demand, to save processing time on hovering.
   *
   * @private
   * @function Highcharts.Point#importEvents
   */
  manageEvent(eventType) {
    const point = this, options2 = merge$1y(point.series.options.point, point.options), userEvent = options2.events?.[eventType];
    if (isFunction$2(userEvent) && (!point.hcEvents?.[eventType] || // Some HC modules, like marker-clusters, draggable-poins etc.
    // use events in their logic, so we need to be sure, that
    // callback function is different
    point.hcEvents?.[eventType]?.map((el) => el.fn).indexOf(userEvent) === -1)) {
      point.importedUserEvent?.();
      point.importedUserEvent = addEvent$1o(point, eventType, userEvent);
      if (point.hcEvents) {
        point.hcEvents[eventType].userEvent = true;
      }
    } else if (point.importedUserEvent && !userEvent && point.hcEvents?.[eventType] && point.hcEvents?.[eventType].userEvent) {
      removeEvent$9(point, eventType);
      delete point.hcEvents[eventType];
      if (!Object.keys(point.hcEvents)) {
        delete point.importedUserEvent;
      }
    }
  }
  /**
   * Set the point's state.
   *
   * @function Highcharts.Point#setState
   *
   * @param {Highcharts.PointStateValue|""} [state]
   *        The new state, can be one of `'hover'`, `'select'`, `'inactive'`,
   *        or `''` (an empty string), `'normal'` or `undefined` to set to
   *        normal state.
   * @param {boolean} [move]
   *        State for animation.
   *
   * @emits Highcharts.Point#event:afterSetState
   */
  setState(state, move) {
    const point = this, series = point.series, previousState = point.state, stateOptions = series.options.states[state || "normal"] || {}, markerOptions = defaultOptions$j.plotOptions[series.type].marker && series.options.marker, normalDisabled = markerOptions && markerOptions.enabled === false, markerStateOptions = markerOptions?.states?.[state || "normal"] || {}, stateDisabled = markerStateOptions.enabled === false, pointMarker = point.marker || {}, chart = series.chart, hasMarkers = markerOptions && series.markerAttribs;
    let halo = series.halo, markerAttribs, pointAttribs, pointAttribsAnimation, stateMarkerGraphic = series.stateMarkerGraphic, newSymbol;
    state = state || "";
    if (
      // Already has this state
      state === point.state && !move || // Selected points don't respond to hover
      point.selected && state !== "select" || // Series' state options is disabled
      stateOptions.enabled === false || // General point marker's state options is disabled
      state && (stateDisabled || normalDisabled && markerStateOptions.enabled === false) || // Individual point marker's state options is disabled
      state && pointMarker.states && pointMarker.states[state] && pointMarker.states[state].enabled === false
    ) {
      return;
    }
    point.state = state;
    if (hasMarkers) {
      markerAttribs = series.markerAttribs(point, state);
    }
    if (point.graphic && !point.hasMockGraphic) {
      if (previousState) {
        point.graphic.removeClass("highcharts-point-" + previousState);
      }
      if (state) {
        point.graphic.addClass("highcharts-point-" + state);
      }
      if (!chart.styledMode) {
        pointAttribs = series.pointAttribs(point, state);
        pointAttribsAnimation = pick$1E(chart.options.chart.animation, stateOptions.animation);
        const opacity = pointAttribs.opacity;
        if (series.options.inactiveOtherPoints && isNumber$_(opacity)) {
          (point.dataLabels || []).forEach(function(label) {
            if (label && !label.hasClass("highcharts-data-label-hidden")) {
              label.animate({ opacity }, pointAttribsAnimation);
              if (label.connector) {
                label.connector.animate({ opacity }, pointAttribsAnimation);
              }
            }
          });
        }
        point.graphic.animate(pointAttribs, pointAttribsAnimation);
      }
      if (markerAttribs) {
        point.graphic.animate(markerAttribs, pick$1E(
          // Turn off globally:
          chart.options.chart.animation,
          markerStateOptions.animation,
          markerOptions.animation
        ));
      }
      if (stateMarkerGraphic) {
        stateMarkerGraphic.hide();
      }
    } else {
      if (state && markerStateOptions) {
        newSymbol = pointMarker.symbol || series.symbol;
        if (stateMarkerGraphic && stateMarkerGraphic.currentSymbol !== newSymbol) {
          stateMarkerGraphic = stateMarkerGraphic.destroy();
        }
        if (markerAttribs) {
          if (!stateMarkerGraphic) {
            if (newSymbol) {
              series.stateMarkerGraphic = stateMarkerGraphic = chart.renderer.symbol(newSymbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height, merge$1y(markerOptions, markerStateOptions)).add(series.markerGroup);
              stateMarkerGraphic.currentSymbol = newSymbol;
            }
          } else {
            stateMarkerGraphic[move ? "animate" : "attr"]({
              x: markerAttribs.x,
              y: markerAttribs.y
            });
          }
        }
        if (!chart.styledMode && stateMarkerGraphic && point.state !== "inactive") {
          stateMarkerGraphic.attr(series.pointAttribs(point, state));
        }
      }
      if (stateMarkerGraphic) {
        stateMarkerGraphic[state && point.isInside ? "show" : "hide"]();
        stateMarkerGraphic.element.point = point;
        stateMarkerGraphic.addClass(point.getClassName(), true);
      }
    }
    const haloOptions = stateOptions.halo;
    const markerGraphic = point.graphic || stateMarkerGraphic;
    const markerVisibility = markerGraphic?.visibility || "inherit";
    if (haloOptions?.size && markerGraphic && markerVisibility !== "hidden" && !point.isCluster) {
      if (!halo) {
        series.halo = halo = chart.renderer.path().add(markerGraphic.parentGroup);
      }
      halo.show()[move ? "animate" : "attr"]({
        d: point.haloPath(haloOptions.size)
      });
      halo.attr({
        "class": "highcharts-halo highcharts-color-" + pick$1E(point.colorIndex, series.colorIndex) + (point.className ? " " + point.className : ""),
        "visibility": markerVisibility,
        "zIndex": -1
        // #4929, #8276
      });
      halo.point = point;
      if (!chart.styledMode) {
        halo.attr(extend$1h({
          "fill": point.color || series.color,
          "fill-opacity": haloOptions.opacity
        }, AST.filterUserAttributes(haloOptions.attributes || {})));
      }
    } else if (halo?.point?.haloPath && !halo.point.destroyed) {
      halo.animate(
        { d: halo.point.haloPath(0) },
        null,
        // Hide after unhovering. The `complete` callback runs in the
        // halo's context (#7681).
        halo.hide
      );
    }
    fireEvent$F(point, "afterSetState", { state });
  }
  /**
   * Get the path definition for the halo, which is usually a shadow-like
   * circle around the currently hovered point.
   *
   * @function Highcharts.Point#haloPath
   *
   * @param {number} size
   *        The radius of the circular halo.
   *
   * @return {Highcharts.SVGPathArray}
   *         The path definition.
   */
  haloPath(size) {
    const pos = this.pos();
    return pos ? this.series.chart.renderer.symbols.circle(crisp$d(pos[0], 1) - size, pos[1] - size, size * 2, size * 2) : [];
  }
};
const { parse: color$b } = Color;
const { charts: charts$2, composed: composed$w, isTouchDevice: isTouchDevice$5 } = Highcharts;
const { addEvent: addEvent$1n, attr: attr$9, css: css$a, extend: extend$1g, find: find$i, fireEvent: fireEvent$E, isNumber: isNumber$Z, isObject: isObject$h, objectEach: objectEach$o, offset, pick: pick$1D, pushUnique: pushUnique$w, splat: splat$i } = Utilities;
class Pointer {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Set inactive state to all series that are not currently hovered,
   * or, if `inactiveOtherPoints` is set to true, set inactive state to
   * all points within that series.
   *
   * @private
   * @function Highcharts.Pointer#applyInactiveState
   *
   * @param {Array<Highcharts.Point>} points
   * Currently hovered points
   */
  applyInactiveState(points = []) {
    const activeSeries = [];
    points.forEach((item) => {
      const series = item.series;
      activeSeries.push(series);
      if (series.linkedParent) {
        activeSeries.push(series.linkedParent);
      }
      if (series.linkedSeries) {
        activeSeries.push.apply(activeSeries, series.linkedSeries);
      }
      if (series.navigatorSeries) {
        activeSeries.push(series.navigatorSeries);
      }
      if (series.boosted && series.markerGroup) {
        activeSeries.push.apply(activeSeries, this.chart.series.filter((otherSeries) => otherSeries.markerGroup === series.markerGroup));
      }
    });
    this.chart.series.forEach((series) => {
      if (activeSeries.indexOf(series) === -1) {
        series.setState("inactive", true);
      } else if (series.options.inactiveOtherPoints) {
        series.setAllPointsToState("inactive");
      }
    });
  }
  /**
   * Destroys the Pointer object and disconnects DOM events.
   *
   * @function Highcharts.Pointer#destroy
   */
  destroy() {
    const pointer = this;
    this.eventsToUnbind.forEach((unbind) => unbind());
    this.eventsToUnbind = [];
    if (!Highcharts.chartCount) {
      Pointer.unbindDocumentMouseUp.forEach((el) => el.unbind());
      Pointer.unbindDocumentMouseUp.length = 0;
      if (Pointer.unbindDocumentTouchEnd) {
        Pointer.unbindDocumentTouchEnd = Pointer.unbindDocumentTouchEnd();
      }
    }
    clearInterval(pointer.tooltipTimeout);
    objectEach$o(pointer, function(_val, prop) {
      pointer[prop] = void 0;
    });
  }
  /**
   * Calculate attrs for selection marker.
   * @private
   * @function Highcharts.Pointer#getSelectionMarkerAttrs
   * @emits getSelectionMarkerAttrs
   */
  getSelectionMarkerAttrs(chartX, chartY) {
    const e = {
      args: { chartX, chartY },
      attrs: {},
      shapeType: "rect"
    };
    fireEvent$E(this, "getSelectionMarkerAttrs", e, (e2) => {
      const { chart, zoomHor, zoomVert } = this, { mouseDownX = 0, mouseDownY = 0 } = chart, attrs = e2.attrs;
      let size;
      attrs.x = chart.plotLeft;
      attrs.y = chart.plotTop;
      attrs.width = zoomHor ? 1 : chart.plotWidth;
      attrs.height = zoomVert ? 1 : chart.plotHeight;
      if (zoomHor) {
        size = chartX - mouseDownX;
        attrs.width = Math.max(1, Math.abs(size));
        attrs.x = (size > 0 ? 0 : size) + mouseDownX;
      }
      if (zoomVert) {
        size = chartY - mouseDownY;
        attrs.height = Math.max(1, Math.abs(size));
        attrs.y = (size > 0 ? 0 : size) + mouseDownY;
      }
    });
    return e;
  }
  /**
   * Perform a drag operation in response to a mousemove event while the mouse
   * is down.
   * @private
   * @function Highcharts.Pointer#drag
   */
  drag(e) {
    const { chart } = this, { mouseDownX = 0, mouseDownY = 0 } = chart, { panning, panKey, selectionMarkerFill } = chart.options.chart, plotLeft = chart.plotLeft, plotTop = chart.plotTop, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, panningEnabled = isObject$h(panning) ? panning.enabled : panning, panKeyPressed = panKey && e[`${panKey}Key`];
    let chartX = e.chartX, chartY = e.chartY, clickedInside, selectionMarker = this.selectionMarker;
    if (selectionMarker && selectionMarker.touch) {
      return;
    }
    if (chartX < plotLeft) {
      chartX = plotLeft;
    } else if (chartX > plotLeft + plotWidth) {
      chartX = plotLeft + plotWidth;
    }
    if (chartY < plotTop) {
      chartY = plotTop;
    } else if (chartY > plotTop + plotHeight) {
      chartY = plotTop + plotHeight;
    }
    this.hasDragged = Math.sqrt(Math.pow(mouseDownX - chartX, 2) + Math.pow(mouseDownY - chartY, 2));
    if (this.hasDragged > 10) {
      clickedInside = chart.isInsidePlot(mouseDownX - plotLeft, mouseDownY - plotTop, {
        visiblePlotOnly: true
      });
      const { shapeType, attrs } = this.getSelectionMarkerAttrs(chartX, chartY);
      if ((chart.hasCartesianSeries || chart.mapView) && this.hasZoom && clickedInside && !panKeyPressed) {
        if (!selectionMarker) {
          this.selectionMarker = selectionMarker = chart.renderer[shapeType]();
          selectionMarker.attr({
            "class": "highcharts-selection-marker",
            zIndex: 7
          }).add();
          if (!chart.styledMode) {
            selectionMarker.attr({
              fill: selectionMarkerFill || color$b(
                "#334eff"
                /* Palette.highlightColor80 */
              ).setOpacity(0.25).get()
            });
          }
        }
      }
      if (selectionMarker) {
        selectionMarker.attr(attrs);
      }
      if (clickedInside && !selectionMarker && panningEnabled) {
        chart.pan(e, panning);
      }
    }
  }
  /**
   * Start a drag operation.
   * @private
   * @function Highcharts.Pointer#dragStart
   */
  dragStart(e) {
    const chart = this.chart;
    chart.mouseIsDown = e.type;
    chart.cancelClick = false;
    chart.mouseDownX = e.chartX;
    chart.mouseDownY = e.chartY;
  }
  /**
   * Get selection box to calculate extremes
   * @private
   * @function Highcharts.Pointer#getSelectionBox
   * @emits getSelectionBox
   */
  getSelectionBox(marker) {
    const e = {
      args: { marker },
      result: marker.getBBox()
    };
    fireEvent$E(this, "getSelectionBox", e);
    return e.result;
  }
  /**
   * On mouse up or touch end across the entire document, drop the selection.
   * @private
   * @function Highcharts.Pointer#drop
   */
  drop(e) {
    const { chart, selectionMarker } = this;
    let redraw;
    for (const axis of chart.axes) {
      if (axis.isPanning) {
        axis.isPanning = false;
        if (axis.options.startOnTick || axis.options.endOnTick || axis.series.some((s) => s.boosted)) {
          axis.forceRedraw = true;
          axis.setExtremes(axis.userMin, axis.userMax, false);
          redraw = true;
        }
      }
    }
    if (redraw) {
      chart.redraw();
    }
    if (selectionMarker && e) {
      if (this.hasDragged) {
        const from = this.getSelectionBox(selectionMarker);
        chart.transform({
          axes: chart.axes.filter((a) => a.zoomEnabled && (a.coll === "xAxis" && this.zoomX || a.coll === "yAxis" && this.zoomY)),
          selection: {
            originalEvent: e,
            // #4890
            xAxis: [],
            yAxis: [],
            ...from
          },
          from
        });
      }
      if (isNumber$Z(chart.index)) {
        this.selectionMarker = selectionMarker.destroy();
      }
    }
    if (chart && isNumber$Z(chart.index)) {
      css$a(chart.container, { cursor: chart._cursor });
      chart.cancelClick = this.hasDragged > 10;
      chart.mouseIsDown = false;
      this.hasDragged = 0;
      this.pinchDown = [];
    }
  }
  /**
   * Finds the closest point to a set of coordinates, using the k-d-tree
   * algorithm.
   *
   * @function Highcharts.Pointer#findNearestKDPoint
   *
   * @param {Array<Highcharts.Series>} series
   * All the series to search in.
   *
   * @param {boolean|undefined} shared
   * Whether it is a shared tooltip or not.
   *
   * @param {Highcharts.PointerEventObject} e
   * The pointer event object, containing chart coordinates of the pointer.
   *
   * @return {Highcharts.Point|undefined}
   * The point closest to given coordinates.
   */
  findNearestKDPoint(series, shared2, e) {
    let closest;
    function sort(p12, p22) {
      const isCloserX = p12.distX - p22.distX, isCloser = p12.dist - p22.dist, isAbove = p22.series.group?.zIndex - p12.series.group?.zIndex;
      let result;
      if (isCloserX !== 0 && shared2) {
        result = isCloserX;
      } else if (isCloser !== 0) {
        result = isCloser;
      } else if (isAbove !== 0) {
        result = isAbove;
      } else {
        result = p12.series.index > p22.series.index ? -1 : 1;
      }
      return result;
    }
    series.forEach(function(s) {
      const noSharedTooltip = s.noSharedTooltip && shared2, compareX = !noSharedTooltip && s.options.findNearestPointBy.indexOf("y") < 0, point = s.searchPoint(e, compareX);
      if (
        // Check that we actually found a point on the series.
        isObject$h(point, true) && point.series && // Use the new point if it is closer.
        (!isObject$h(closest, true) || sort(closest, point) > 0)
      ) {
        closest = point;
      }
    });
    return closest;
  }
  /**
   * @private
   * @function Highcharts.Pointer#getChartCoordinatesFromPoint
   */
  getChartCoordinatesFromPoint(point, inverted) {
    const { xAxis: xAxis2, yAxis: yAxis2 } = point.series, shapeArgs = point.shapeArgs;
    if (xAxis2 && yAxis2) {
      let x = point.clientX ?? point.plotX ?? 0, y = point.plotY || 0;
      if (point.isNode && shapeArgs && isNumber$Z(shapeArgs.x) && isNumber$Z(shapeArgs.y)) {
        x = shapeArgs.x;
        y = shapeArgs.y;
      }
      return inverted ? {
        chartX: yAxis2.len + yAxis2.pos - y,
        chartY: xAxis2.len + xAxis2.pos - x
      } : {
        chartX: x + xAxis2.pos,
        chartY: y + yAxis2.pos
      };
    }
    if (shapeArgs?.x && shapeArgs.y) {
      return {
        chartX: shapeArgs.x,
        chartY: shapeArgs.y
      };
    }
  }
  /**
   * Return the cached chartPosition if it is available on the Pointer,
   * otherwise find it. Running offset is quite expensive, so it should be
   * avoided when we know the chart hasn't moved.
   *
   * @function Highcharts.Pointer#getChartPosition
   *
   * @return {Highcharts.ChartPositionObject}
   * The offset of the chart container within the page
   */
  getChartPosition() {
    if (this.chartPosition) {
      return this.chartPosition;
    }
    const { container } = this.chart;
    const pos = offset(container);
    this.chartPosition = {
      left: pos.left,
      top: pos.top,
      scaleX: 1,
      scaleY: 1
    };
    const { offsetHeight, offsetWidth } = container;
    if (offsetWidth > 2 && // #13342
    offsetHeight > 2) {
      this.chartPosition.scaleX = pos.width / offsetWidth;
      this.chartPosition.scaleY = pos.height / offsetHeight;
    }
    return this.chartPosition;
  }
  /**
   * Get the click position in terms of axis values.
   *
   * @function Highcharts.Pointer#getCoordinates
   *
   * @param {Highcharts.PointerEventObject} e
   * Pointer event, extended with `chartX` and `chartY` properties.
   *
   * @return {Highcharts.PointerAxisCoordinatesObject}
   * Axis coordinates.
   */
  getCoordinates(e) {
    const coordinates2 = {
      xAxis: [],
      yAxis: []
    };
    for (const axis of this.chart.axes) {
      coordinates2[axis.isXAxis ? "xAxis" : "yAxis"].push({
        axis,
        value: axis.toValue(e[axis.horiz ? "chartX" : "chartY"])
      });
    }
    return coordinates2;
  }
  /**
   * Calculates what is the current hovered point/points and series.
   *
   * @private
   * @function Highcharts.Pointer#getHoverData
   *
   * @param {Highcharts.Point|undefined} existingHoverPoint
   * The point currently being hovered.
   *
   * @param {Highcharts.Series|undefined} existingHoverSeries
   * The series currently being hovered.
   *
   * @param {Array<Highcharts.Series>} series
   * All the series in the chart.
   *
   * @param {boolean} isDirectTouch
   * Is the pointer directly hovering the point.
   *
   * @param {boolean|undefined} shared
   * Whether it is a shared tooltip or not.
   *
   * @param {Highcharts.PointerEventObject} [e]
   * The triggering event, containing chart coordinates of the pointer.
   *
   * @return {Object}
   * Object containing resulting hover data: hoverPoint, hoverSeries, and
   * hoverPoints.
   */
  getHoverData(existingHoverPoint, existingHoverSeries, series, isDirectTouch, shared2, e) {
    const hoverPoints = [], useExisting = !!(isDirectTouch && existingHoverPoint), filter = function(s) {
      return s.visible && !(!shared2 && s.directTouch) && // #3821
      pick$1D(s.options.enableMouseTracking, true);
    };
    let hoverSeries = existingHoverSeries, searchSeries, eventArgs = {
      chartX: e ? e.chartX : void 0,
      chartY: e ? e.chartY : void 0,
      shared: shared2
    };
    fireEvent$E(this, "beforeGetHoverData", eventArgs);
    const notSticky = hoverSeries && !hoverSeries.stickyTracking;
    searchSeries = notSticky ? (
      // Only search on hovered series if it has stickyTracking false
      [hoverSeries]
    ) : (
      // Filter what series to look in.
      series.filter((s) => s.stickyTracking && (eventArgs.filter || filter)(s))
    );
    const hoverPoint = useExisting || !e ? existingHoverPoint : this.findNearestKDPoint(searchSeries, shared2, e);
    hoverSeries = hoverPoint?.series;
    if (hoverPoint) {
      if (shared2 && !hoverSeries.noSharedTooltip) {
        searchSeries = series.filter(function(s) {
          return eventArgs.filter ? eventArgs.filter(s) : filter(s) && !s.noSharedTooltip;
        });
        searchSeries.forEach(function(s) {
          const nullInteraction = s.options?.nullInteraction;
          let point = find$i(s.points, function(p) {
            return p.x === hoverPoint.x && (!p.isNull || !!nullInteraction);
          });
          if (isObject$h(point)) {
            if (s.boosted && s.boost) {
              point = s.boost.getPoint(point);
            }
            hoverPoints.push(point);
          }
        });
      } else {
        hoverPoints.push(hoverPoint);
      }
    }
    eventArgs = { hoverPoint };
    fireEvent$E(this, "afterGetHoverData", eventArgs);
    return {
      hoverPoint: eventArgs.hoverPoint,
      hoverSeries,
      hoverPoints
    };
  }
  /**
   * @private
   * @function Highcharts.Pointer#getPointFromEvent
   */
  getPointFromEvent(e) {
    let target = e.target, point;
    while (target && !point) {
      point = target.point;
      target = target.parentNode;
    }
    return point;
  }
  /**
   * @private
   * @function Highcharts.Pointer#onTrackerMouseOut
   */
  onTrackerMouseOut(e) {
    const chart = this.chart;
    const relatedTarget = e.relatedTarget;
    const series = chart.hoverSeries;
    this.isDirectTouch = false;
    if (series && relatedTarget && !series.stickyTracking && !this.inClass(relatedTarget, "highcharts-tooltip") && (!this.inClass(relatedTarget, "highcharts-series-" + series.index) || // #2499, #4465, #5553
    !this.inClass(relatedTarget, "highcharts-tracker"))) {
      series.onMouseOut();
    }
  }
  /**
   * Utility to detect whether an element has, or has a parent with, a
   * specific class name. Used on detection of tracker objects and on deciding
   * whether hovering the tooltip should cause the active series to mouse out.
   *
   * @function Highcharts.Pointer#inClass
   *
   * @param {Highcharts.SVGDOMElement|Highcharts.HTMLDOMElement} element
   * The element to investigate.
   *
   * @param {string} className
   * The class name to look for.
   *
   * @return {boolean|undefined}
   * True if either the element or one of its parents has the given class
   * name.
   */
  inClass(element, className) {
    let elem = element, elemClassName;
    while (elem) {
      elemClassName = attr$9(elem, "class");
      if (elemClassName) {
        if (elemClassName.indexOf(className) !== -1) {
          return true;
        }
        if (elemClassName.indexOf("highcharts-container") !== -1) {
          return false;
        }
      }
      elem = elem.parentElement;
    }
  }
  /**
   * Initialize the Pointer.
   *
   * @private
   * @function Highcharts.Pointer#init
   *
   * @param {Highcharts.Chart} chart
   * The Chart instance.
   *
   * @param {Highcharts.Options} options
   * The root options object. The pointer uses options from the chart and
   * tooltip structures.
   */
  constructor(chart, options2) {
    this.hasDragged = 0;
    this.pointerCaptureEventsToUnbind = [];
    this.eventsToUnbind = [];
    this.options = options2;
    this.chart = chart;
    this.runChartClick = Boolean(options2.chart.events?.click);
    this.pinchDown = [];
    this.setDOMEvents();
    fireEvent$E(this, "afterInit");
  }
  /**
   * Takes a browser event object and extends it with custom Highcharts
   * properties `chartX` and `chartY` in order to work on the internal
   * coordinate system.
   *
   * On map charts, the properties `lon` and `lat` are added to the event
   * object given that the chart has projection information.
   *
   * @function Highcharts.Pointer#normalize
   *
   * @param {global.MouseEvent|global.PointerEvent|global.TouchEvent} e
   * Event object in standard browsers.
   *
   * @param {Highcharts.OffsetObject} [chartPosition]
   * Additional chart offset.
   *
   * @return {Highcharts.PointerEventObject}
   * A browser event with extended properties `chartX` and `chartY`.
   */
  normalize(e, chartPosition) {
    const touches = e.touches;
    const ePos = touches ? touches.length ? touches.item(0) : pick$1D(
      // #13534
      touches.changedTouches,
      e.changedTouches
    )[0] : e;
    if (!chartPosition) {
      chartPosition = this.getChartPosition();
    }
    let chartX = ePos.pageX - chartPosition.left, chartY = ePos.pageY - chartPosition.top;
    chartX /= chartPosition.scaleX;
    chartY /= chartPosition.scaleY;
    return extend$1g(e, {
      chartX: Math.round(chartX),
      chartY: Math.round(chartY)
    });
  }
  /**
   * @private
   * @function Highcharts.Pointer#onContainerClick
   */
  onContainerClick(e) {
    const chart = this.chart;
    const hoverPoint = chart.hoverPoint;
    const pEvt = this.normalize(e);
    const plotLeft = chart.plotLeft;
    const plotTop = chart.plotTop;
    if (!chart.cancelClick) {
      if (hoverPoint && this.inClass(pEvt.target, "highcharts-tracker")) {
        fireEvent$E(hoverPoint.series, "click", extend$1g(pEvt, {
          point: hoverPoint
        }));
        if (chart.hoverPoint) {
          hoverPoint.firePointEvent("click", pEvt);
        }
      } else {
        extend$1g(pEvt, this.getCoordinates(pEvt));
        if (chart.isInsidePlot(pEvt.chartX - plotLeft, pEvt.chartY - plotTop, {
          visiblePlotOnly: true
        })) {
          fireEvent$E(chart, "click", pEvt);
        }
      }
    }
  }
  /**
   * @private
   * @function Highcharts.Pointer#onContainerMouseDown
   */
  onContainerMouseDown(e) {
    const isPrimaryButton = ((e.buttons || e.button) & 1) === 1;
    e = this.normalize(e);
    if (Highcharts.isFirefox && e.button !== 0) {
      this.onContainerMouseMove(e);
    }
    if (typeof e.button === "undefined" || isPrimaryButton) {
      this.zoomOption(e);
      if (isPrimaryButton) {
        e.preventDefault?.();
      }
      this.dragStart(e);
    }
  }
  /**
   * When mouse leaves the container, hide the tooltip.
   * @private
   * @function Highcharts.Pointer#onContainerMouseLeave
   */
  onContainerMouseLeave(e) {
    const { pointer } = charts$2[pick$1D(Pointer.hoverChartIndex, -1)] || {};
    e = this.normalize(e);
    this.onContainerMouseMove(e);
    if (pointer && !this.inClass(e.relatedTarget, "highcharts-tooltip")) {
      pointer.reset();
      pointer.chartPosition = void 0;
    }
  }
  /**
   * When mouse enters the container, delete pointer's chartPosition.
   * @private
   * @function Highcharts.Pointer#onContainerMouseEnter
   */
  onContainerMouseEnter() {
    delete this.chartPosition;
  }
  /**
   * The mousemove, touchmove and touchstart event handler
   * @private
   * @function Highcharts.Pointer#onContainerMouseMove
   */
  onContainerMouseMove(e) {
    const chart = this.chart, tooltip = chart.tooltip, pEvt = this.normalize(e);
    this.setHoverChartIndex(e);
    if (chart.mouseIsDown === "mousedown" || this.touchSelect(pEvt)) {
      this.drag(pEvt);
    }
    if (!chart.openMenu && (this.inClass(pEvt.target, "highcharts-tracker") || chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop, {
      visiblePlotOnly: true
    })) && // If the tooltip has stickOnContact enabled, do nothing. This
    // applies regardless of any combinations of the `split` and
    // `useHTML` options.
    !tooltip?.shouldStickOnContact(pEvt)) {
      if (this.inClass(pEvt.target, "highcharts-no-tooltip")) {
        this.reset(false, 0);
      } else {
        this.runPointActions(pEvt);
      }
    }
  }
  /**
   * @private
   * @function Highcharts.Pointer#onDocumentTouchEnd
   */
  onDocumentTouchEnd(e) {
    this.onDocumentMouseUp(e);
  }
  /**
   * @private
   * @function Highcharts.Pointer#onContainerTouchMove
   */
  onContainerTouchMove(e) {
    if (this.touchSelect(e)) {
      this.onContainerMouseMove(e);
    } else {
      this.touch(e);
    }
  }
  /**
   * @private
   * @function Highcharts.Pointer#onContainerTouchStart
   */
  onContainerTouchStart(e) {
    if (this.touchSelect(e)) {
      this.onContainerMouseDown(e);
    } else {
      this.zoomOption(e);
      this.touch(e, true);
    }
  }
  /**
   * Special handler for mouse move that will hide the tooltip when the mouse
   * leaves the plotarea. Issue #149 workaround. The mouseleave event does not
   * always fire.
   * @private
   * @function Highcharts.Pointer#onDocumentMouseMove
   */
  onDocumentMouseMove(e) {
    const chart = this.chart;
    const tooltip = chart.tooltip;
    const chartPosition = this.chartPosition;
    const pEvt = this.normalize(e, chartPosition);
    if (chartPosition && !chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop, {
      visiblePlotOnly: true
    }) && !tooltip?.shouldStickOnContact(pEvt) && (pEvt.target === chart.container.ownerDocument || !this.inClass(pEvt.target, "highcharts-tracker"))) {
      this.reset();
    }
  }
  /**
   * @private
   * @function Highcharts.Pointer#onDocumentMouseUp
   */
  onDocumentMouseUp(e) {
    charts$2[pick$1D(Pointer.hoverChartIndex, -1)]?.pointer?.drop(e);
  }
  /**
   * Handle touch events with two touches
   * @private
   * @function Highcharts.Pointer#pinch
   */
  pinch(e) {
    const pointer = this, { chart, hasZoom, lastTouches } = pointer, touches = [].map.call(
      e.touches || [],
      // Normalize each touch
      (touch) => pointer.normalize(touch)
    ), touchesLength = touches.length, fireClickEvent = touchesLength === 1 && (pointer.inClass(e.target, "highcharts-tracker") && chart.runTrackerClick || pointer.runChartClick), tooltip = chart.tooltip, followTouchMove = touchesLength === 1 && pick$1D(tooltip?.options.followTouchMove, true);
    if (touchesLength > 1) {
      pointer.initiated = true;
    } else if (followTouchMove) {
      pointer.initiated = false;
    }
    if (hasZoom && pointer.initiated && !fireClickEvent && e.cancelable !== false) {
      e.preventDefault();
    }
    if (e.type === "touchstart") {
      pointer.pinchDown = touches;
      pointer.res = true;
      chart.mouseDownX = e.chartX;
    } else if (followTouchMove) {
      this.runPointActions(pointer.normalize(e));
    } else if (lastTouches) {
      fireEvent$E(chart, "touchpan", {
        originalEvent: e,
        touches
      }, () => {
        const boxFromTouches = (touches2) => {
          const finger0 = touches2[0], finger1 = touches2[1] || finger0;
          return {
            x: finger0.chartX,
            y: finger0.chartY,
            width: finger1.chartX - finger0.chartX,
            height: finger1.chartY - finger0.chartY
          };
        };
        chart.transform({
          axes: chart.axes.filter((axis) => axis.zoomEnabled && (this.zoomHor && axis.horiz || this.zoomVert && !axis.horiz)),
          to: boxFromTouches(touches),
          from: boxFromTouches(lastTouches),
          trigger: e.type
        });
      });
      if (pointer.res) {
        pointer.res = false;
        this.reset(false, 0);
      }
    }
    pointer.lastTouches = touches;
  }
  /**
   * Run translation operations
   * @private
   * @function Highcharts.Pointer#pinchTranslate
   * /
  public pinchTranslate(
      pinchDown: Array<any>,
      touches: Array<PointerEvent>,
      transform: any,
      selectionMarker: any,
      clip: any,
      lastValidTouch: any
  ): void {
      if (this.zoomHor) {
          this.pinchTranslateDirection(
              true,
              pinchDown,
              touches,
              transform,
              selectionMarker,
              clip,
              lastValidTouch
          );
      }
      if (this.zoomVert) {
          this.pinchTranslateDirection(
              false,
              pinchDown,
              touches,
              transform,
              selectionMarker,
              clip,
              lastValidTouch
          );
      }
  }
  */
  /**
       * Run translation operations for each direction (horizontal and vertical)
       * independently.
       * @private
       * @function Highcharts.Pointer#pinchTranslateDirection
       * /
      public pinchTranslateDirection(
          horiz: boolean,
          pinchDown: Array<any>,
          touches: Array<PointerEvent>,
          transform: any,
          selectionMarker: any,
          clip: any,
          lastValidTouch: any,
          forcedScale?: number
      ): void {
          const chart = this.chart,
              xy: ('x'|'y') = horiz ? 'x' : 'y',
              XY: ('X'|'Y') = horiz ? 'X' : 'Y',
              sChartXY: ('chartX'|'chartY') = ('chart' + XY) as any,
              wh = horiz ? 'width' : 'height',
              plotLeftTop = (chart as any)['plot' + (horiz ? 'Left' : 'Top')],
              inverted = chart.inverted,
              bounds = chart.bounds[horiz ? 'h' : 'v'],
              singleTouch = pinchDown.length === 1,
              touch0Start = pinchDown[0][sChartXY],
              touch1Start = !singleTouch && pinchDown[1][sChartXY],
              setScale = function (): void {
                  // Don't zoom if fingers are too close on this axis
                  if (
                      typeof touch1Now === 'number' &&
                      Math.abs(touch0Start - touch1Start) > 20
                  ) {
                      scale = forcedScale ||
                          Math.abs(touch0Now - touch1Now) /
                          Math.abs(touch0Start - touch1Start);
                  }
  
                  clipXY = ((plotLeftTop - touch0Now) / scale) + touch0Start;
                  selectionWH = (chart as any)[
                      'plot' + (horiz ? 'Width' : 'Height')
                  ] / scale;
              };
  
          let selectionWH: any,
              selectionXY,
              clipXY: any,
              scale = forcedScale || 1,
              touch0Now = touches[0][sChartXY],
              touch1Now = !singleTouch && touches[1][sChartXY],
              outOfBounds;
  
          // Set the scale, first pass
          setScale();
  
          // The clip position (x or y) is altered if out of bounds, the selection
          // position is not
          selectionXY = clipXY;
  
          // Out of bounds
          if (selectionXY < bounds.min) {
              selectionXY = bounds.min;
              outOfBounds = true;
          } else if (selectionXY + selectionWH > bounds.max) {
              selectionXY = bounds.max - selectionWH;
              outOfBounds = true;
          }
  
          // Is the chart dragged off its bounds, determined by dataMin and
          // dataMax?
          if (outOfBounds) {
  
              // Modify the touchNow position in order to create an elastic drag
              // movement. This indicates to the user that the chart is responsive
              // but can't be dragged further.
              touch0Now -= 0.8 * (touch0Now - lastValidTouch[xy][0]);
              if (typeof touch1Now === 'number') {
                  touch1Now -= 0.8 * (touch1Now - lastValidTouch[xy][1]);
              }
  
              // Set the scale, second pass to adapt to the modified touchNow
              // positions
              setScale();
  
          } else {
              lastValidTouch[xy] = [touch0Now, touch1Now];
          }
  
          // Set geometry for clipping, selection and transformation
          if (!inverted) {
              clip[xy] = clipXY - plotLeftTop;
              clip[wh] = selectionWH;
          }
          const scaleKey = inverted ?
              (horiz ? 'scaleY' : 'scaleX') : 'scale' + XY;
          const transformScale = inverted ? 1 / scale : scale;
  
          selectionMarker[wh] = selectionWH;
          selectionMarker[xy] = selectionXY;
          // Invert scale if needed (#19217)
          transform[scaleKey] = scale * (inverted && !horiz ? -1 : 1);
          transform['translate' + XY] = (transformScale * plotLeftTop) +
              (touch0Now - (transformScale * touch0Start));
      }
      */
  /**
   * Reset the tracking by hiding the tooltip, the hover series state and the
   * hover point.
   *
   * @function Highcharts.Pointer#reset
   *
   * @param {boolean} [allowMove]
   * Instead of destroying the tooltip altogether, allow moving it if
   * possible.
   *
   * @param {number} [delay]
   * The tooltip hide delay in ms.
   */
  reset(allowMove, delay) {
    const pointer = this, chart = pointer.chart, hoverSeries = chart.hoverSeries, hoverPoint = chart.hoverPoint, hoverPoints = chart.hoverPoints, tooltip = chart.tooltip, tooltipPoints = tooltip?.shared ? hoverPoints : hoverPoint;
    if (allowMove && tooltipPoints) {
      splat$i(tooltipPoints).forEach(function(point) {
        if (point.series.isCartesian && typeof point.plotX === "undefined") {
          allowMove = false;
        }
      });
    }
    if (allowMove) {
      if (tooltip && tooltipPoints && splat$i(tooltipPoints).length) {
        tooltip.refresh(tooltipPoints);
        if (tooltip.shared && hoverPoints) {
          hoverPoints.forEach(function(point) {
            point.setState(point.state, true);
            if (point.series.isCartesian) {
              if (point.series.xAxis.crosshair) {
                point.series.xAxis.drawCrosshair(null, point);
              }
              if (point.series.yAxis.crosshair) {
                point.series.yAxis.drawCrosshair(null, point);
              }
            }
          });
        } else if (hoverPoint) {
          hoverPoint.setState(hoverPoint.state, true);
          chart.axes.forEach(function(axis) {
            if (axis.crosshair && hoverPoint.series[axis.coll] === axis) {
              axis.drawCrosshair(null, hoverPoint);
            }
          });
        }
      }
    } else {
      if (hoverPoint) {
        hoverPoint.onMouseOut();
      }
      if (hoverPoints) {
        hoverPoints.forEach(function(point) {
          point.setState();
        });
      }
      if (hoverSeries) {
        hoverSeries.onMouseOut();
      }
      if (tooltip) {
        tooltip.hide(delay);
      }
      if (pointer.unDocMouseMove) {
        pointer.unDocMouseMove = pointer.unDocMouseMove();
      }
      chart.axes.forEach(function(axis) {
        axis.hideCrosshair();
      });
      chart.hoverPoints = chart.hoverPoint = void 0;
    }
  }
  /**
   * With line type charts with a single tracker, get the point closest to the
   * mouse. Run Point.onMouseOver and display tooltip for the point or points.
   *
   * @private
   * @function Highcharts.Pointer#runPointActions
   *
   * @emits Highcharts.Point#event:mouseOut
   * @emits Highcharts.Point#event:mouseOver
   */
  runPointActions(e, p, force) {
    const pointer = this, chart = pointer.chart, series = chart.series, tooltip = chart.tooltip?.options.enabled ? chart.tooltip : void 0, shared2 = tooltip ? tooltip.shared : false;
    let hoverPoint = p || chart.hoverPoint, hoverSeries = hoverPoint?.series || chart.hoverSeries;
    const isDirectTouch = (!e || e.type !== "touchmove") && (!!p || hoverSeries?.directTouch && pointer.isDirectTouch), hoverData = this.getHoverData(hoverPoint, hoverSeries, series, isDirectTouch, shared2, e);
    hoverPoint = hoverData.hoverPoint;
    hoverSeries = hoverData.hoverSeries;
    const points = hoverData.hoverPoints, followPointer = hoverSeries?.tooltipOptions.followPointer && !hoverSeries.tooltipOptions.split, useSharedTooltip = shared2 && hoverSeries && !hoverSeries.noSharedTooltip;
    if (hoverPoint && (force || hoverPoint !== chart.hoverPoint || tooltip?.isHidden)) {
      (chart.hoverPoints || []).forEach(function(p5) {
        if (points.indexOf(p5) === -1) {
          p5.setState();
        }
      });
      if (chart.hoverSeries !== hoverSeries) {
        hoverSeries.onMouseOver();
      }
      pointer.applyInactiveState(points);
      (points || []).forEach(function(p5) {
        p5.setState("hover");
      });
      if (chart.hoverPoint) {
        chart.hoverPoint.firePointEvent("mouseOut");
      }
      if (!hoverPoint.series) {
        return;
      }
      chart.hoverPoints = points;
      chart.hoverPoint = hoverPoint;
      hoverPoint.firePointEvent("mouseOver", void 0, () => {
        if (tooltip && hoverPoint) {
          tooltip.refresh(useSharedTooltip ? points : hoverPoint, e);
        }
      });
    } else if (followPointer && tooltip && !tooltip.isHidden) {
      const anchor = tooltip.getAnchor([{}], e);
      if (chart.isInsidePlot(anchor[0], anchor[1], {
        visiblePlotOnly: true
      })) {
        tooltip.updatePosition({ plotX: anchor[0], plotY: anchor[1] });
      }
    }
    if (!pointer.unDocMouseMove) {
      pointer.unDocMouseMove = addEvent$1n(chart.container.ownerDocument, "mousemove", (e2) => charts$2[Pointer.hoverChartIndex ?? -1]?.pointer?.onDocumentMouseMove(e2));
      pointer.eventsToUnbind.push(pointer.unDocMouseMove);
    }
    chart.axes.forEach(function drawAxisCrosshair(axis) {
      const snap2 = axis.crosshair?.snap ?? true;
      let point;
      if (snap2) {
        point = chart.hoverPoint;
        if (!point || point.series[axis.coll] !== axis) {
          point = find$i(points, (p5) => p5.series?.[axis.coll] === axis);
        }
      }
      if (point || !snap2) {
        axis.drawCrosshair(e, point);
      } else {
        axis.hideCrosshair();
      }
    });
  }
  /**
   * Set the JS DOM events on the container and document. This method should
   * contain a one-to-one assignment between methods and their handlers. Any
   * advanced logic should be moved to the handler reflecting the event's
   * name.
   * @private
   * @function Highcharts.Pointer#setDOMEvents
   */
  setDOMEvents() {
    const container = this.chart.container, ownerDoc = container.ownerDocument;
    container.onmousedown = this.onContainerMouseDown.bind(this);
    container.onmousemove = this.onContainerMouseMove.bind(this);
    container.onclick = this.onContainerClick.bind(this);
    this.eventsToUnbind.push(addEvent$1n(container, "mouseenter", this.onContainerMouseEnter.bind(this)), addEvent$1n(container, "mouseleave", this.onContainerMouseLeave.bind(this)));
    if (!Pointer.unbindDocumentMouseUp.some((el) => el.doc === ownerDoc)) {
      Pointer.unbindDocumentMouseUp.push({
        doc: ownerDoc,
        unbind: addEvent$1n(ownerDoc, "mouseup", this.onDocumentMouseUp.bind(this))
      });
    }
    let parent = this.chart.renderTo.parentElement;
    while (parent && parent.tagName !== "BODY") {
      this.eventsToUnbind.push(addEvent$1n(parent, "scroll", () => {
        delete this.chartPosition;
      }));
      parent = parent.parentElement;
    }
    this.eventsToUnbind.push(addEvent$1n(container, "touchstart", this.onContainerTouchStart.bind(this), { passive: false }), addEvent$1n(container, "touchmove", this.onContainerTouchMove.bind(this), { passive: false }));
    if (!Pointer.unbindDocumentTouchEnd) {
      Pointer.unbindDocumentTouchEnd = addEvent$1n(ownerDoc, "touchend", this.onDocumentTouchEnd.bind(this), { passive: false });
    }
    this.setPointerCapture();
    addEvent$1n(this.chart, "redraw", this.setPointerCapture.bind(this));
  }
  /**
   * Sets, or removes on update, pointer events using pointer capture for
   * tooltip.followTouchMove if any series has findNearestPointBy that
   * includes the y dimension.
   * @private
   * @function Highcharts.Pointer#setPointerCapture
  */
  setPointerCapture() {
    if (!isTouchDevice$5) {
      return;
    }
    const pointer = this, events = pointer.pointerCaptureEventsToUnbind, chart = pointer.chart, container = chart.container, followTouchMove = pick$1D(chart.options.tooltip?.followTouchMove, true), shouldHave = followTouchMove && chart.series.some((series) => series.options.findNearestPointBy.indexOf("y") > -1);
    if (!pointer.hasPointerCapture && shouldHave) {
      events.push(addEvent$1n(container, "pointerdown", (e) => {
        if (e.target?.hasPointerCapture(e.pointerId)) {
          e.target?.releasePointerCapture(e.pointerId);
        }
      }), addEvent$1n(container, "pointermove", (e) => {
        chart.pointer?.getPointFromEvent(e)?.onMouseOver(e);
      }));
      if (!chart.styledMode) {
        css$a(container, { "touch-action": "none" });
      }
      container.className += " highcharts-no-touch-action";
      pointer.hasPointerCapture = true;
    } else if (pointer.hasPointerCapture && !shouldHave) {
      events.forEach((e) => e());
      events.length = 0;
      if (!chart.styledMode) {
        css$a(container, {
          "touch-action": pick$1D(chart.options.chart.style?.["touch-action"], "manipulation")
        });
      }
      container.className = container.className.replace(" highcharts-no-touch-action", "");
      pointer.hasPointerCapture = false;
    }
  }
  /**
   * Sets the index of the hovered chart and leaves the previous hovered
   * chart, to reset states like tooltip.
   * @private
   * @function Highcharts.Pointer#setHoverChartIndex
   */
  setHoverChartIndex(e) {
    const chart = this.chart;
    const hoverChart = Highcharts.charts[pick$1D(Pointer.hoverChartIndex, -1)];
    if (hoverChart && hoverChart !== chart) {
      const relatedTargetObj = { relatedTarget: chart.container };
      if (e && !e?.relatedTarget) {
        Object.assign({}, e, relatedTargetObj);
      }
      hoverChart.pointer?.onContainerMouseLeave(e || relatedTargetObj);
    }
    if (!hoverChart?.mouseIsDown) {
      Pointer.hoverChartIndex = chart.index;
    }
  }
  /**
   * General touch handler shared by touchstart and touchmove.
   * @private
   * @function Highcharts.Pointer#touch
   */
  touch(e, start2) {
    const { chart, pinchDown = [] } = this;
    let hasMoved, isInside;
    this.setHoverChartIndex();
    e = this.normalize(e);
    if (e.touches.length === 1) {
      isInside = chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop, {
        visiblePlotOnly: true
      });
      if (isInside && !chart.openMenu) {
        if (start2) {
          this.runPointActions(e);
        }
        if (e.type === "touchmove") {
          hasMoved = pinchDown[0] ? (
            // #5266
            Math.pow(pinchDown[0].chartX - e.chartX, 2) + Math.pow(pinchDown[0].chartY - e.chartY, 2) >= 16
          ) : false;
        }
        if (pick$1D(hasMoved, true)) {
          this.pinch(e);
        }
      } else if (start2) {
        this.reset();
      }
    } else if (e.touches.length === 2) {
      this.pinch(e);
    }
  }
  /**
   * Returns true if the chart is set up for zooming by single touch and the
   * event is capable
   * @private
   * @function Highcharts.Pointer#touchSelect
   */
  touchSelect(e) {
    return Boolean(this.chart.zooming.singleTouch && e.touches && e.touches.length === 1);
  }
  /**
   * Resolve the zoomType option, this is reset on all touch start and mouse
   * down events.
   * @private
   * @function Highcharts.Pointer#zoomOption
   */
  zoomOption(e) {
    const chart = this.chart, inverted = chart.inverted;
    let zoomType = chart.zooming.type || "", zoomX, zoomY;
    if (/touch/.test(e.type)) {
      zoomType = pick$1D(chart.zooming.pinchType, zoomType);
    }
    this.zoomX = zoomX = /x/.test(zoomType);
    this.zoomY = zoomY = /y/.test(zoomType);
    this.zoomHor = zoomX && !inverted || zoomY && inverted;
    this.zoomVert = zoomY && !inverted || zoomX && inverted;
    this.hasZoom = zoomX || zoomY;
  }
}
Pointer.unbindDocumentMouseUp = [];
(function(Pointer2) {
  function compose2(ChartClass) {
    if (pushUnique$w(composed$w, "Core.Pointer")) {
      addEvent$1n(ChartClass, "beforeRender", function() {
        this.pointer = new Pointer2(this, this.options);
      });
    }
  }
  Pointer2.compose = compose2;
})(Pointer || (Pointer = {}));
const Pointer$1 = Pointer;
var ColumnUtils;
(function(ColumnUtils2) {
  function setLength2(column2, length, asSubarray) {
    if (Array.isArray(column2)) {
      column2.length = length;
      return column2;
    }
    return column2[asSubarray ? "subarray" : "slice"](0, length);
  }
  ColumnUtils2.setLength = setLength2;
  function splice2(column2, start2, deleteCount, removedAsSubarray, items = []) {
    if (Array.isArray(column2)) {
      if (!Array.isArray(items)) {
        items = Array.from(items);
      }
      return {
        removed: column2.splice(start2, deleteCount, ...items),
        array: column2
      };
    }
    const Constructor = Object.getPrototypeOf(column2).constructor;
    const removed = column2[removedAsSubarray ? "subarray" : "slice"](start2, start2 + deleteCount);
    const newLength = column2.length - deleteCount + items.length;
    const result = new Constructor(newLength);
    result.set(column2.subarray(0, start2), 0);
    result.set(items, start2);
    result.set(column2.subarray(start2 + deleteCount), start2 + items.length);
    return {
      removed,
      array: result
    };
  }
  ColumnUtils2.splice = splice2;
})(ColumnUtils || (ColumnUtils = {}));
const ColumnUtils$1 = ColumnUtils;
const { setLength, splice } = ColumnUtils$1;
const { fireEvent: fireEvent$D, objectEach: objectEach$n, uniqueKey: uniqueKey$6 } = Utilities;
class DataTableCore {
  /**
       * Constructs an instance of the DataTable class.
       *
       * @example
       * const dataTable = new Highcharts.DataTableCore({
       *   columns: {
       *     year: [2020, 2021, 2022, 2023],
       *     cost: [11, 13, 12, 14],
       *     revenue: [12, 15, 14, 18]
       *   }
       * });
  
       *
       * @param {Highcharts.DataTableOptions} [options]
       * Options to initialize the new DataTable instance.
       */
  constructor(options2 = {}) {
    this.autoId = !options2.id;
    this.columns = {};
    this.id = options2.id || uniqueKey$6();
    this.modified = this;
    this.rowCount = 0;
    this.versionTag = uniqueKey$6();
    let rowCount = 0;
    objectEach$n(options2.columns || {}, (column2, columnName) => {
      this.columns[columnName] = column2.slice();
      rowCount = Math.max(rowCount, column2.length);
    });
    this.applyRowCount(rowCount);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Applies a row count to the table by setting the `rowCount` property and
   * adjusting the length of all columns.
   *
   * @private
   * @param {number} rowCount The new row count.
   */
  applyRowCount(rowCount) {
    this.rowCount = rowCount;
    objectEach$n(this.columns, (column2, columnName) => {
      if (column2.length !== rowCount) {
        this.columns[columnName] = setLength(column2, rowCount);
      }
    });
  }
  /**
   * Delete rows. Simplified version of the full
   * `DataTable.deleteRows` method.
   *
   * @param {number} rowIndex
   * The start row index
   *
   * @param {number} [rowCount=1]
   * The number of rows to delete
   *
   * @return {void}
   *
   * @emits #afterDeleteRows
   */
  deleteRows(rowIndex, rowCount = 1) {
    if (rowCount > 0 && rowIndex < this.rowCount) {
      let length = 0;
      objectEach$n(this.columns, (column2, columnName) => {
        this.columns[columnName] = splice(column2, rowIndex, rowCount).array;
        length = column2.length;
      });
      this.rowCount = length;
    }
    fireEvent$D(this, "afterDeleteRows", { rowIndex, rowCount });
    this.versionTag = uniqueKey$6();
  }
  /**
   * Fetches the given column by the canonical column name. Simplified version
   * of the full `DataTable.getRow` method, always returning by reference.
   *
   * @param {string} columnName
   * Name of the column to get.
   *
   * @return {Highcharts.DataTableColumn|undefined}
   * A copy of the column, or `undefined` if not found.
   */
  getColumn(columnName, asReference) {
    return this.columns[columnName];
  }
  /**
   * Retrieves all or the given columns. Simplified version of the full
   * `DataTable.getColumns` method, always returning by reference.
   *
   * @param {Array<string>} [columnNames]
   * Column names to retrieve.
   *
   * @return {Highcharts.DataTableColumnCollection}
   * Collection of columns. If a requested column was not found, it is
   * `undefined`.
   */
  getColumns(columnNames, asReference) {
    return (columnNames || Object.keys(this.columns)).reduce((columns, columnName) => {
      columns[columnName] = this.columns[columnName];
      return columns;
    }, {});
  }
  /**
   * Retrieves the row at a given index.
   *
   * @param {number} rowIndex
   * Row index to retrieve. First row has index 0.
   *
   * @param {Array<string>} [columnNames]
   * Column names to retrieve.
   *
   * @return {Record<string, number|string|undefined>|undefined}
   * Returns the row values, or `undefined` if not found.
   */
  getRow(rowIndex, columnNames) {
    return (columnNames || Object.keys(this.columns)).map((key2) => this.columns[key2]?.[rowIndex]);
  }
  /**
   * Sets cell values for a column. Will insert a new column, if not found.
   *
   * @param {string} columnName
   * Column name to set.
   *
   * @param {Highcharts.DataTableColumn} [column]
   * Values to set in the column.
   *
   * @param {number} [rowIndex]
   * Index of the first row to change. (Default: 0)
   *
   * @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail]
   * Custom information for pending events.
   *
   * @emits #setColumns
   * @emits #afterSetColumns
   */
  setColumn(columnName, column2 = [], rowIndex = 0, eventDetail) {
    this.setColumns({ [columnName]: column2 }, rowIndex, eventDetail);
  }
  /**
   * Sets cell values for multiple columns. Will insert new columns, if not
   * found. Simplified version of the full `DataTableCore.setColumns`, limited
   * to full replacement of the columns (undefined `rowIndex`).
   *
   * @param {Highcharts.DataTableColumnCollection} columns
   * Columns as a collection, where the keys are the column names.
   *
   * @param {number} [rowIndex]
   * Index of the first row to change. Ignored in the `DataTableCore`, as it
   * always replaces the full column.
   *
   * @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail]
   * Custom information for pending events.
   *
   * @emits #setColumns
   * @emits #afterSetColumns
   */
  setColumns(columns, rowIndex, eventDetail) {
    let rowCount = this.rowCount;
    objectEach$n(columns, (column2, columnName) => {
      this.columns[columnName] = column2.slice();
      rowCount = column2.length;
    });
    this.applyRowCount(rowCount);
    if (!eventDetail?.silent) {
      fireEvent$D(this, "afterSetColumns");
      this.versionTag = uniqueKey$6();
    }
  }
  /**
   * Sets cell values of a row. Will insert a new row if no index was
   * provided, or if the index is higher than the total number of table rows.
   * A simplified version of the full `DateTable.setRow`, limited to objects.
   *
   * @param {Record<string, number|string|undefined>} row
   * Cell values to set.
   *
   * @param {number} [rowIndex]
   * Index of the row to set. Leave `undefined` to add as a new row.
   *
   * @param {boolean} [insert]
   * Whether to insert the row at the given index, or to overwrite the row.
   *
   * @param {Record<string, (boolean|number|string|null|undefined)>} [eventDetail]
   * Custom information for pending events.
   *
   * @emits #afterSetRows
   */
  setRow(row, rowIndex = this.rowCount, insert, eventDetail) {
    const { columns } = this, indexRowCount = insert ? this.rowCount + 1 : rowIndex + 1;
    objectEach$n(row, (cellValue, columnName) => {
      let column2 = columns[columnName] || eventDetail?.addColumns !== false && new Array(indexRowCount);
      if (column2) {
        if (insert) {
          column2 = splice(column2, rowIndex, 0, true, [cellValue]).array;
        } else {
          column2[rowIndex] = cellValue;
        }
        columns[columnName] = column2;
      }
    });
    if (indexRowCount > this.rowCount) {
      this.applyRowCount(indexRowCount);
    }
    if (!eventDetail?.silent) {
      fireEvent$D(this, "afterSetRows");
      this.versionTag = uniqueKey$6();
    }
  }
}
const { extend: extend$1f, merge: merge$1x, pick: pick$1C } = Utilities;
var LegendSymbol;
(function(LegendSymbol2) {
  function areaMarker(legend, item) {
    lineMarker.call(this, legend, item, true);
  }
  LegendSymbol2.areaMarker = areaMarker;
  function lineMarker(legend, item, hasArea2) {
    const legendItem = this.legendItem = this.legendItem || {}, { chart, options: options2 } = this, { baseline = 0, symbolWidth, symbolHeight } = legend, symbol = this.symbol || "circle", generalRadius = symbolHeight / 2, renderer = chart.renderer, legendItemGroup = legendItem.group, verticalCenter = baseline - Math.round((legend.fontMetrics?.b || symbolHeight) * // Render line and marker slightly higher to make room for the
    // area
    (hasArea2 ? 0.4 : 0.3)), attr2 = {};
    let legendSymbol, markerOptions = options2.marker, lineSizer = 0;
    if (!chart.styledMode) {
      attr2["stroke-width"] = Math.min(options2.lineWidth || 0, 24);
      if (options2.dashStyle) {
        attr2.dashstyle = options2.dashStyle;
      } else if (options2.linecap !== "square") {
        attr2["stroke-linecap"] = "round";
      }
    }
    legendItem.line = renderer.path().addClass("highcharts-graph").attr(attr2).add(legendItemGroup);
    if (hasArea2) {
      legendItem.area = renderer.path().addClass("highcharts-area").add(legendItemGroup);
    }
    if (attr2["stroke-linecap"]) {
      lineSizer = Math.min(legendItem.line.strokeWidth(), symbolWidth) / 2;
    }
    if (symbolWidth) {
      const d = [
        ["M", lineSizer, verticalCenter],
        ["L", symbolWidth - lineSizer, verticalCenter]
      ];
      legendItem.line.attr({ d });
      legendItem.area?.attr({
        d: [
          ...d,
          ["L", symbolWidth - lineSizer, baseline],
          ["L", lineSizer, baseline]
        ]
      });
    }
    if (markerOptions && markerOptions.enabled !== false && symbolWidth) {
      let radius = Math.min(pick$1C(markerOptions.radius, generalRadius), generalRadius);
      if (symbol.indexOf("url") === 0) {
        markerOptions = merge$1x(markerOptions, {
          width: symbolHeight,
          height: symbolHeight
        });
        radius = 0;
      }
      legendItem.symbol = legendSymbol = renderer.symbol(symbol, symbolWidth / 2 - radius, verticalCenter - radius, 2 * radius, 2 * radius, extend$1f({ context: "legend" }, markerOptions)).addClass("highcharts-point").add(legendItemGroup);
      legendSymbol.isMarker = true;
    }
  }
  LegendSymbol2.lineMarker = lineMarker;
  function rectangle(legend, item) {
    const legendItem = item.legendItem || {}, options2 = legend.options, symbolHeight = legend.symbolHeight, square = options2.squareSymbol, symbolWidth = square ? symbolHeight : legend.symbolWidth;
    legendItem.symbol = this.chart.renderer.rect(
      square ? (legend.symbolWidth - symbolHeight) / 2 : 0,
      legend.baseline - symbolHeight + 1,
      // #3988
      symbolWidth,
      symbolHeight,
      pick$1C(legend.options.symbolRadius, symbolHeight / 2)
    ).addClass("highcharts-point").attr({
      zIndex: 3
    }).add(legendItem.group);
  }
  LegendSymbol2.rectangle = rectangle;
})(LegendSymbol || (LegendSymbol = {}));
const LegendSymbol$1 = LegendSymbol;
const seriesDefaults = {
  // Base series options
  /**
   * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
   * of a line graph. Round means that lines are rounded in the ends and
   * bends.
   *
   * @type       {Highcharts.SeriesLinecapValue}
   * @default    round
   * @since      3.0.7
   * @apioption  plotOptions.line.linecap
   */
  /**
   * Pixel width of the graph line.
   *
   * @see In styled mode, the line stroke-width can be set with the
   *      `.highcharts-graph` class name.
   *
   * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/
   *         On all series
   * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/
   *         On one single series
   *
   * @product highcharts highstock
   */
  lineWidth: 2,
  /**
   * For some series, there is a limit that shuts down animation
   * by default when the total number of points in the chart is too high.
   * For example, for a column chart and its derivatives, animation does
   * not run if there is more than 250 points totally. To disable this
   * cap, set `animationLimit` to `Infinity`. This option works if animation
   * is fired on individual points, not on a group of points like e.g. during
   * the initial animation.
   *
   * @sample {highcharts} highcharts/plotoptions/series-animationlimit/
   *         Animation limit on updating individual points
   *
   * @type      {number}
   * @apioption plotOptions.series.animationLimit
   */
  /**
   * Allow this series' points to be selected by clicking on the graphic
   * (columns, point markers, pie slices, map areas etc).
   *
   * The selected points can be handled by point select and unselect
   * events, or collectively by the [getSelectedPoints
   * ](/class-reference/Highcharts.Chart#getSelectedPoints) function.
   *
   * And alternative way of selecting points is through dragging.
   *
   * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-line/
   *         Line
   * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-column/
   *         Column
   * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-pie/
   *         Pie
   * @sample {highcharts} highcharts/chart/events-selection-points/
   *         Select a range of points through a drag selection
   * @sample {highmaps} maps/plotoptions/series-allowpointselect/
   *         Map area
   * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
   *         Map bubble
   *
   * @since 1.2.0
   *
   * @private
   */
  allowPointSelect: false,
  /**
   * When true, each point or column edge is rounded to its nearest pixel
   * in order to render sharp on screen. In some cases, when there are a
   * lot of densely packed columns, this leads to visible difference
   * in column widths or distance between columns. In these cases,
   * setting `crisp` to `false` may look better, even though each column
   * is rendered blurry.
   *
   * @sample {highcharts} highcharts/plotoptions/column-crisp-false/
   *         Crisp is false
   *
   * @since   5.0.10
   * @product highcharts highstock gantt
   *
   * @private
   */
  crisp: true,
  /**
   * If true, a checkbox is displayed next to the legend item to allow
   * selecting the series. The state of the checkbox is determined by
   * the `selected` option.
   *
   * @productdesc {highmaps}
   * Note that if a `colorAxis` is defined, the color axis is represented
   * in the legend, not the series.
   *
   * @sample {highcharts} highcharts/plotoptions/series-showcheckbox-true/
   *         Show select box
   *
   * @since 1.2.0
   *
   * @private
   */
  showCheckbox: false,
  /**
   * Enable or disable the initial animation when a series is displayed.
   * The animation can also be set as a configuration object. Please
   * note that this option only applies to the initial animation of the
   * series itself. For other animations, see [chart.animation](
   * #chart.animation) and the animation parameter under the API methods.
   * The following properties are supported:
   *
   * - `defer`: The animation delay time in milliseconds.
   *
   * - `duration`: The duration of the animation in milliseconds. (Defaults to
   *   `1000`)
   *
   * - `easing`: Can be a string reference to an easing function set on
   *   the `Math` object or a function. See the _Custom easing function_
   *   demo below. (Defaults to `easeInOutSine`)
   *
   * Due to poor performance, animation is disabled in old IE browsers
   * for several chart types.
   *
   * @sample {highcharts} highcharts/plotoptions/series-animation-disabled/
   *         Animation disabled
   * @sample {highcharts} highcharts/plotoptions/series-animation-slower/
   *         Slower animation
   * @sample {highcharts} highcharts/plotoptions/series-animation-easing/
   *         Custom easing function
   * @sample {highstock} stock/plotoptions/animation-slower/
   *         Slower animation
   * @sample {highstock} stock/plotoptions/animation-easing/
   *         Custom easing function
   * @sample {highmaps} maps/plotoptions/series-animation-true/
   *         Animation enabled on map series
   * @sample {highmaps} maps/plotoptions/mapbubble-animation-false/
   *         Disabled on mapbubble series
   *
   * @type    {boolean|Highcharts.AnimationOptionsObject}
   * @default {highcharts} true
   * @default {highstock} true
   * @default {highmaps} false
   *
   * @private
   */
  animation: {
    /** @ignore-option */
    duration: 1e3
  },
  /**
   * An additional class name to apply to the series' graphical elements.
   * This option does not replace default class names of the graphical
   * element. Changes to the series' color will also be reflected in a
   * chart's legend and tooltip.
   *
   * @sample {highcharts} highcharts/css/point-series-classname
   *         Series and point class name
   *
   * @type      {string}
   * @since     5.0.0
   * @apioption plotOptions.series.className
   */
  /**
   * Disable this option to allow series rendering in the whole plotting
   * area.
   *
   * **Note:** Clipping should be always enabled when
   * [chart.zoomType](#chart.zoomType) is set
   *
   * @sample {highcharts} highcharts/plotoptions/series-clip/
   *         Disabled clipping
   *
   * @default   true
   * @type      {boolean}
   * @since     3.0.0
   * @apioption plotOptions.series.clip
   */
  /**
   * The main color of the series. In line type series it applies to the
   * line and the point markers unless otherwise specified. In bar type
   * series it applies to the bars unless a color is specified per point.
   * The default value is pulled from the `options.colors` array.
   *
   * In styled mode, the color can be defined by the
   * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
   * color can be set with the `.highcharts-series`,
   * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
   * `.highcharts-series-{n}` class, or individual classes given by the
   * `className` option.
   *
   * @productdesc {highmaps}
   * In maps, the series color is rarely used, as most choropleth maps use
   * the color to denote the value of each point. The series color can
   * however be used in a map with multiple series holding categorized
   * data.
   *
   * @sample {highcharts} highcharts/plotoptions/series-color-general/
   *         General plot option
   * @sample {highcharts} highcharts/plotoptions/series-color-specific/
   *         One specific series
   * @sample {highcharts} highcharts/plotoptions/series-color-area/
   *         Area color
   * @sample {highcharts} highcharts/series/infographic/
   *         Pattern fill
   * @sample {highmaps} maps/demo/category-map/
   *         Category map by multiple series
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @apioption plotOptions.series.color
   */
  /**
   * Styled mode only. A specific color index to use for the series, so its
   * graphic representations are given the class name `highcharts-color-{n}`.
   *
   * Since v11, CSS variables on the form `--highcharts-color-{n}` make
   * changing the color scheme very convenient.
   *
   * @sample    {highcharts} highcharts/css/colorindex/ Series and point color
   *            index
   *
   * @type      {number}
   * @since     5.0.0
   * @apioption plotOptions.series.colorIndex
   */
  /**
   * Whether to connect a graph line across null points, or render a gap
   * between the two points on either side of the null.
   *
   * In stacked area chart, if `connectNulls` is set to true,
   * null points are interpreted as 0.
   *
   * @sample {highcharts} highcharts/plotoptions/series-connectnulls-false/
   *         False by default
   * @sample {highcharts} highcharts/plotoptions/series-connectnulls-true/
   *         True
   *
   * @type      {boolean}
   * @default   false
   * @product   highcharts highstock
   * @apioption plotOptions.series.connectNulls
   */
  /**
   * You can set the cursor to "pointer" if you have click events attached
   * to the series, to signal to the user that the points and lines can
   * be clicked.
   *
   * In styled mode, the series cursor can be set with the same classes
   * as listed under [series.color](#plotOptions.series.color).
   *
   * @sample {highcharts} highcharts/plotoptions/series-cursor-line/
   *         On line graph
   * @sample {highcharts} highcharts/plotoptions/series-cursor-column/
   *         On columns
   * @sample {highcharts} highcharts/plotoptions/series-cursor-scatter/
   *         On scatter markers
   * @sample {highstock} stock/plotoptions/cursor/
   *         Pointer on a line graph
   * @sample {highmaps} maps/plotoptions/series-allowpointselect/
   *         Map area
   * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
   *         Map bubble
   *
   * @type      {string|Highcharts.CursorValue}
   * @apioption plotOptions.series.cursor
   */
  /**
   * A reserved subspace to store options and values for customized
   * functionality. Here you can add additional data for your own event
   * callbacks and formatter callbacks.
   *
   * @sample {highcharts} highcharts/point/custom/
   *         Point and series with custom data
   *
   * @type      {Highcharts.Dictionary<*>}
   * @apioption plotOptions.series.custom
   */
  /**
   * Name of the dash style to use for the graph, or for some series types
   * the outline of each shape.
   *
   * In styled mode, the
   * [stroke dash-array](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series-dashstyle/)
   * can be set with the same classes as listed under
   * [series.color](#plotOptions.series.color).
   *
   * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
   *         Possible values demonstrated
   * @sample {highcharts} highcharts/plotoptions/series-dashstyle/
   *         Chart suitable for printing in black and white
   * @sample {highstock} highcharts/plotoptions/series-dashstyle-all/
   *         Possible values demonstrated
   * @sample {highmaps} highcharts/plotoptions/series-dashstyle-all/
   *         Possible values demonstrated
   * @sample {highmaps} maps/plotoptions/series-dashstyle/
   *         Dotted borders on a map
   *
   * @type      {Highcharts.DashStyleValue}
   * @default   Solid
   * @since     2.1
   * @apioption plotOptions.series.dashStyle
   */
  /**
   * A description of the series to add to the screen reader information
   * about the series.
   *
   * @type      {string}
   * @since     5.0.0
   * @requires  modules/accessibility
   * @apioption plotOptions.series.description
   */
  /**
   * Options for the series data sorting.
   *
   * @type      {Highcharts.DataSortingOptionsObject}
   * @since     8.0.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.dataSorting
   */
  /**
   * Enable or disable data sorting for the series. Use [xAxis.reversed](
   * #xAxis.reversed) to change the sorting order.
   *
   * @sample {highcharts} highcharts/datasorting/animation/
   *         Data sorting in scatter-3d
   * @sample {highcharts} highcharts/datasorting/labels-animation/
   *         Axis labels animation
   * @sample {highcharts} highcharts/datasorting/dependent-sorting/
   *         Dependent series sorting
   * @sample {highcharts} highcharts/datasorting/independent-sorting/
   *         Independent series sorting
   *
   * @type      {boolean}
   * @since     8.0.0
   * @apioption plotOptions.series.dataSorting.enabled
   */
  /**
   * Whether to allow matching points by name in an update. If this option
   * is disabled, points will be matched by order.
   *
   * @sample {highcharts} highcharts/datasorting/match-by-name/
   *         Enabled match by name
   *
   * @type      {boolean}
   * @since     8.0.0
   * @apioption plotOptions.series.dataSorting.matchByName
   */
  /**
   * Determines what data value should be used to sort by.
   *
   * @sample {highcharts} highcharts/datasorting/sort-key/
   *         Sort key as `z` value
   *
   * @type      {string}
   * @since     8.0.0
   * @default   y
   * @apioption plotOptions.series.dataSorting.sortKey
   */
  /**
   * Enable or disable the mouse tracking for a specific series. This
   * includes point tooltips and click events on graphs and points. For
   * large datasets it improves performance.
   *
   * @sample {highcharts} highcharts/plotoptions/series-enablemousetracking-false/
   *         No mouse tracking
   * @sample {highmaps} maps/plotoptions/series-enablemousetracking-false/
   *         No mouse tracking
   *
   * @type      {boolean}
   * @default   true
   * @apioption plotOptions.series.enableMouseTracking
   */
  enableMouseTracking: true,
  /**
   * Whether to use the Y extremes of the total chart width or only the
   * zoomed area when zooming in on parts of the X axis. By default, the
   * Y axis adjusts to the min and max of the visible data. Cartesian
   * series only.
   *
   * @type      {boolean}
   * @default   false
   * @since     4.1.6
   * @product   highcharts highstock gantt
   * @apioption plotOptions.series.getExtremesFromAll
   */
  /**
   * Highlight only the hovered point and fade the remaining points.
   *
   * Scatter-type series require enabling the 'inactive' marker state and
   * adjusting opacity. Note that this approach could affect performance
   * with large datasets.
   *
   * @sample {highcharts} highcharts/plotoptions/series-inactiveotherpoints-enabled/
   *         Chart with inactiveOtherPoints option enabled.
   *
   * @type      {boolean}
   * @default   false
   * @apioption plotOptions.series.inactiveOtherPoints
   */
  /**
   * An array specifying which option maps to which key in the data point
   * array. This makes it convenient to work with unstructured data arrays
   * from different sources.
   *
   * @see [series.data](#series.line.data)
   *
   * @sample {highcharts|highstock} highcharts/series/data-keys/
   *         An extended data array with keys
   * @sample {highcharts|highstock} highcharts/series/data-nested-keys/
   *         Nested keys used to access object properties
   *
   * @type      {Array<string>}
   * @since     4.1.6
   * @apioption plotOptions.series.keys
   */
  /**
   * The line cap used for line ends and line joins on the graph.
   *
   * @sample highcharts/series-line/linecap/
   *         Line cap comparison
   *
   * @type       {Highcharts.SeriesLinecapValue}
   * @default    round
   * @product    highcharts highstock
   * @apioption  plotOptions.series.linecap
   */
  /**
   * The [id](#series.id) of another series to link to. Additionally,
   * the value can be ":previous" to link to the previous series. When
   * two series are linked, only the first one appears in the legend.
   * Toggling the visibility of this also toggles the linked series.
   *
   * If master series uses data sorting and linked series does not have
   * its own sorting definition, the linked series will be sorted in the
   * same order as the master one.
   *
   * @sample {highcharts|highstock} highcharts/demo/arearange-line/
   *         Linked series
   *
   * @type      {string}
   * @since     3.0
   * @product   highcharts highstock gantt
   * @apioption plotOptions.series.linkedTo
   */
  /**
   * Options for the corresponding navigator series if `showInNavigator`
   * is `true` for this series. Available options are the same as any
   * series, documented at [plotOptions](#plotOptions.series) and
   * [series](#series).
   *
   * These options are merged with options in [navigator.series](
   * #navigator.series), and will take precedence if the same option is
   * defined both places.
   *
   * @see [navigator.series](#navigator.series)
   *
   * @type      {Highcharts.PlotSeriesOptions}
   * @since     5.0.0
   * @product   highstock
   * @apioption plotOptions.series.navigatorOptions
   */
  /**
   * The color for the parts of the graph or points that are below the
   * [threshold](#plotOptions.series.threshold). Note that `zones` takes
   * precedence over the negative color. Using `negativeColor` is
   * equivalent to applying a zone with value of 0.
   *
   * @see In styled mode, a negative color is applied by setting this option
   *      to `true` combined with the `.highcharts-negative` class name.
   *
   * @sample {highcharts} highcharts/plotoptions/series-negative-color/
   *         Spline, area and column
   * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/
   *         Arearange
   * @sample {highcharts} highcharts/css/series-negative-color/
   *         Styled mode
   * @sample {highstock} highcharts/plotoptions/series-negative-color/
   *         Spline, area and column
   * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/
   *         Arearange
   * @sample {highmaps} highcharts/plotoptions/series-negative-color/
   *         Spline, area and column
   * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/
   *         Arearange
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     3.0
   * @apioption plotOptions.series.negativeColor
   */
  /**
   * Whether or not data-points with the value of `null` should be interactive.
   * When this is set to `true`, tooltips may highlight these points, and this
   * option also enables keyboard navigation for such points. Format options
   * for such points include [`nullFormat`](#tooltip.nullFormat) and [`nullFormater`](#tooltip.nullFormatter).
   * Works for these series: `line`, `spline`, `area`, `area-spline`,
   * `column`, `bar`, and* `timeline`.
   *
   * @sample {highcharts} highcharts/series/null-interaction/
   *         Chart with interactive `null` points
   *
   * @sample {highcharts} highcharts/series-timeline/null-interaction/
   *         Timeline series with `null` points
   *
   * @type      {boolean|undefined}
   * @product   highcharts highstock
   * @apioption plotOptions.series.nullInteraction
   */
  /**
   * Same as
   * [accessibility.point.descriptionFormat](#accessibility.point.descriptionFormat),
   * but for an individual series. Overrides the chart wide configuration.
   *
   * @type      {Function}
   * @since 11.1.0
   * @apioption plotOptions.series.pointDescriptionFormat
   */
  /**
   * Same as
   * [accessibility.series.descriptionFormatter](#accessibility.series.descriptionFormatter),
   * but for an individual series. Overrides the chart wide configuration.
   *
   * @type      {Function}
   * @since     5.0.12
   * @apioption plotOptions.series.pointDescriptionFormatter
   */
  /**
   * If no x values are given for the points in a series, `pointInterval`
   * defines the interval of the x values. For example, if a series
   * contains one value every decade starting from year 0, set
   * `pointInterval` to `10`. In true `datetime` axes, the `pointInterval`
   * is set in milliseconds.
   *
   * It can be also be combined with `pointIntervalUnit` to draw irregular
   * time intervals.
   *
   * If combined with `relativeXValue`, an x value can be set on each
   * point, and the `pointInterval` is added x times to the `pointStart`
   * setting.
   *
   * Please note that this options applies to the _series data_, not the
   * interval of the axis ticks, which is independent.
   *
   * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
   *         Datetime X axis
   * @sample {highcharts} highcharts/plotoptions/series-relativexvalue/
   *         Relative x value
   * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
   *         Using pointStart and pointInterval
   * @sample {highstock} stock/plotoptions/relativexvalue/
   *         Relative x value
   *
   * @type      {number}
   * @default   1
   * @product   highcharts highstock gantt
   * @apioption plotOptions.series.pointInterval
   */
  /**
   * On datetime series, this allows for setting the
   * [pointInterval](#plotOptions.series.pointInterval) to irregular time
   * units, `day`, `month` and `year`. A day is usually the same as 24
   * hours, but `pointIntervalUnit` also takes the DST crossover into
   * consideration when dealing with local time. Combine this option with
   * `pointInterval` to draw weeks, quarters, 6 months, 10 years etc.
   *
   * Please note that this options applies to the _series data_, not the
   * interval of the axis ticks, which is independent.
   *
   * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/
   *         One point a month
   * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/
   *         One point a month
   *
   * @type       {string}
   * @since      4.1.0
   * @product    highcharts highstock gantt
   * @validvalue ["day", "month", "year"]
   * @apioption  plotOptions.series.pointIntervalUnit
   */
  /**
   * Possible values: `"on"`, `"between"`, `number`.
   *
   * In a column chart, when pointPlacement is `"on"`, the point will not
   * create any padding of the X axis. In a polar column chart this means
   * that the first column points directly north. If the pointPlacement is
   * `"between"`, the columns will be laid out between ticks. This is
   * useful for example for visualising an amount between two points in
   * time or in a certain sector of a polar chart.
   *
   * Since Highcharts 3.0.2, the point placement can also be numeric,
   * where 0 is on the axis value, -0.5 is between this value and the
   * previous, and 0.5 is between this value and the next. Unlike the
   * textual options, numeric point placement options won't affect axis
   * padding.
   *
   * Note that pointPlacement needs a [pointRange](
   * #plotOptions.series.pointRange) to work. For column series this is
   * computed, but for line-type series it needs to be set.
   *
   * For the `xrange` series type and gantt charts, if the Y axis is a
   * category axis, the `pointPlacement` applies to the Y axis rather than
   * the (typically datetime) X axis.
   *
   * Defaults to `undefined` in cartesian charts, `"between"` in polar
   * charts.
   *
   * @see [xAxis.tickmarkPlacement](#xAxis.tickmarkPlacement)
   *
   * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-between/
   *         Between in a column chart
   * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-numeric/
   *         Numeric placement for custom layout
   * @sample {highcharts|highstock} maps/plotoptions/heatmap-pointplacement/
   *         Placement in heatmap
   *
   * @type      {string|number}
   * @since     2.3.0
   * @product   highcharts highstock gantt
   * @apioption plotOptions.series.pointPlacement
   */
  /**
   * If no x values are given for the points in a series, `pointStart`
   * defines on what value to start. For example, if a series contains one
   * yearly value starting from 1945, set `pointStart` to 1945.
   *
   * The `pointStart` setting can be a number, or a datetime string that is
   * parsed according to the `time.timezone` setting.
   *
   * If combined with `relativeXValue`, an x value can be set on each
   * point. The x value from the point options is multiplied by
   * `pointInterval` and added to `pointStart` to produce a modified x
   * value.
   *
   * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/
   *         Linear
   * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
   *         Datetime
   * @sample {highcharts} highcharts/plotoptions/series-relativexvalue/
   *         Relative x value
   * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
   *         Using pointStart and pointInterval
   * @sample {highstock} stock/plotoptions/relativexvalue/
   *         Relative x value
   *
   * @type      {number|string}
   * @default   0
   * @product   highcharts highstock gantt
   * @apioption plotOptions.series.pointStart
   */
  /**
   * When true, X values in the data set are relative to the current
   * `pointStart`, `pointInterval` and `pointIntervalUnit` settings. This
   * allows compression of the data for datasets with irregular X values.
   *
   * The real X values are computed on the formula `f(x) = ax + b`, where
   * `a` is the `pointInterval` (optionally with a time unit given by
   * `pointIntervalUnit`), and `b` is the `pointStart`.
   *
   * @sample {highcharts} highcharts/plotoptions/series-relativexvalue/
   *         Relative X value
   * @sample {highstock} stock/plotoptions/relativexvalue/
   *         Relative X value
   *
   * @type      {boolean}
   * @default   false
   * @product   highcharts highstock
   * @apioption plotOptions.series.relativeXValue
   */
  /**
   * Whether to select the series initially. If `showCheckbox` is true,
   * the checkbox next to the series name in the legend will be checked
   * for a selected series.
   *
   * @sample {highcharts} highcharts/plotoptions/series-selected/
   *         One out of two series selected
   *
   * @type      {boolean}
   * @default   false
   * @since     1.2.0
   * @apioption plotOptions.series.selected
   */
  /**
   * Whether to apply a drop shadow to the graph line. Since 2.3 the
   * shadow can be an object configuration containing `color`, `offsetX`,
   * `offsetY`, `opacity` and `width`.
   *
   * Note that in some cases, like stacked columns or other dense layouts, the
   * series may cast shadows on each other. In that case, the
   * `chart.seriesGroupShadow` allows applying a common drop shadow to the
   * whole series group.
   *
   * @sample {highcharts} highcharts/plotoptions/series-shadow/
   *         Shadow enabled
   *
   * @type      {boolean|Highcharts.ShadowOptionsObject}
   * @default   false
   * @apioption plotOptions.series.shadow
   */
  /**
   * Whether to display this particular series or series type in the
   * legend. Standalone series are shown in legend by default, and linked
   * series are not. Since v7.2.0 it is possible to show series that use
   * colorAxis by setting this option to `true`.
   *
   * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
   *         One series in the legend, one hidden
   *
   * @type      {boolean}
   * @apioption plotOptions.series.showInLegend
   */
  /**
   * Whether or not to show the series in the navigator. Takes precedence
   * over [navigator.baseSeries](#navigator.baseSeries) if defined.
   *
   * @type      {boolean}
   * @since     5.0.0
   * @product   highstock
   * @apioption plotOptions.series.showInNavigator
   */
  /**
   * If set to `true`, the accessibility module will skip past the points
   * in this series for keyboard navigation.
   *
   * @type      {boolean}
   * @since     5.0.12
   * @apioption plotOptions.series.skipKeyboardNavigation
   */
  /**
   * Whether to stack the values of each series on top of each other.
   * Possible values are `undefined` to disable, `"normal"` to stack by
   * value or `"percent"`.
   *
   * When stacking is enabled, data must be sorted
   * in ascending X order.
   *
   * Some stacking options are related to specific series types. In the
   * streamgraph series type, the stacking option is set to `"stream"`.
   * The second one is `"overlap"`, which only applies to waterfall
   * series.
   *
   * @see [yAxis.reversedStacks](#yAxis.reversedStacks)
   *
   * @sample {highcharts} highcharts/plotoptions/series-stacking-line/
   *         Line
   * @sample {highcharts} highcharts/plotoptions/series-stacking-column/
   *         Column
   * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/
   *         Bar
   * @sample {highcharts} highcharts/plotoptions/series-stacking-area/
   *         Area
   * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/
   *         Line
   * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-column/
   *         Column
   * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/
   *         Bar
   * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/
   *         Area
   * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-normal-stacking
   *         Waterfall with normal stacking
   * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-overlap-stacking
   *         Waterfall with overlap stacking
   * @sample {highstock} stock/plotoptions/stacking/
   *         Area
   *
   * @type       {string}
   * @product    highcharts highstock
   * @validvalue ["normal", "overlap", "percent", "stream"]
   * @apioption  plotOptions.series.stacking
   */
  /**
   * Whether to apply steps to the line. Possible values are `left`,
   * `center` and `right`.
   *
   * @sample {highcharts} highcharts/plotoptions/line-step/
   *         Different step line options
   * @sample {highcharts} highcharts/plotoptions/area-step/
   *         Stepped, stacked area
   * @sample {highstock} stock/plotoptions/line-step/
   *         Step line
   *
   * @type       {string}
   * @since      1.2.5
   * @product    highcharts highstock
   * @validvalue ["left", "center", "right"]
   * @apioption  plotOptions.series.step
   */
  /**
   * The threshold, also called zero level or base level. For line type
   * series this is only used in conjunction with
   * [negativeColor](#plotOptions.series.negativeColor).
   *
   * @see [softThreshold](#plotOptions.series.softThreshold).
   *
   * @type      {number|null}
   * @default   0
   * @since     3.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.threshold
   */
  /**
   * Set the initial visibility of the series.
   *
   * @sample {highcharts} highcharts/plotoptions/series-visible/
   *         Two series, one hidden and one visible
   * @sample {highstock} stock/plotoptions/series-visibility/
   *         Hidden series
   *
   * @type      {boolean}
   * @default   true
   * @apioption plotOptions.series.visible
   */
  /**
   * Defines the Axis on which the zones are applied.
   *
   * @see [zones](#plotOptions.series.zones)
   *
   * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/
   *         Zones on the X-Axis
   * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/
   *         Zones on the X-Axis
   *
   * @type      {string}
   * @default   y
   * @since     4.1.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.zoneAxis
   */
  /**
   * General event handlers for the series items. These event hooks can
   * also be attached to the series at run time using the
   * `Highcharts.addEvent` function.
   *
   * @declare Highcharts.SeriesEventsOptionsObject
   *
   * @private
   */
  events: {},
  /**
   * Fires after the series has finished its initial animation, or in case
   * animation is disabled, immediately as the series is displayed.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-afteranimate/
   *         Show label after animate
   * @sample {highstock} highcharts/plotoptions/series-events-afteranimate/
   *         Show label after animate
   *
   * @type      {Highcharts.SeriesAfterAnimateCallbackFunction}
   * @since     4.0
   * @product   highcharts highstock gantt
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.afterAnimate
   */
  /**
   * Fires when the checkbox next to the series' name in the legend is
   * clicked. One parameter, `event`, is passed to the function. The state
   * of the checkbox is found by `event.checked`. The checked item is
   * found by `event.item`. Return `false` to prevent the default action
   * which is to toggle the select state of the series.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
   *         Alert checkbox status
   *
   * @type      {Highcharts.SeriesCheckboxClickCallbackFunction}
   * @since     1.2.0
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.checkboxClick
   */
  /**
   * Fires when the series is clicked. One parameter, `event`, is passed
   * to the function, containing common event information. Additionally,
   * `event.point` holds a pointer to the nearest point on the graph.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-click/
   *         Alert click info
   * @sample {highstock} stock/plotoptions/series-events-click/
   *         Alert click info
   * @sample {highmaps} maps/plotoptions/series-events-click/
   *         Display click info in subtitle
   *
   * @type      {Highcharts.SeriesClickCallbackFunction}
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.click
   */
  /**
   * Fires when the series is hidden after chart generation time, either
   * by clicking the legend item or by calling `.hide()`.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-hide/
   *         Alert when the series is hidden by clicking the legend item
   *
   * @type      {Highcharts.SeriesHideCallbackFunction}
   * @since     1.2.0
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.hide
   */
  /**
   * Fires when the legend item belonging to the series is clicked. One
   * parameter, `event`, is passed to the function. The default action
   * is to toggle the visibility of the series. This can be prevented
   * by returning `false` or calling `event.preventDefault()`.
   *
   * **Note:** This option is deprecated in favor of
   * [legend.events.itemClick](#legend.events.itemClick).
   *
   * @type       {Highcharts.SeriesLegendItemClickCallbackFunction}
   * @deprecated 11.4.4
   * @context    Highcharts.Series
   * @apioption  plotOptions.series.events.legendItemClick
   */
  /**
   * Fires when the mouse leaves the graph. One parameter, `event`, is
   * passed to the function, containing common event information. If the
   * [stickyTracking](#plotOptions.series) option is true, `mouseOut`
   * doesn't happen before the mouse enters another graph or leaves the
   * plot area.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
   *         With sticky tracking by default
   * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
   *         Without sticky tracking
   *
   * @type      {Highcharts.SeriesMouseOutCallbackFunction}
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.mouseOut
   */
  /**
   * Fires when the mouse enters the graph. One parameter, `event`, is
   * passed to the function, containing common event information.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
   *         With sticky tracking by default
   * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
   *         Without sticky tracking
   *
   * @type      {Highcharts.SeriesMouseOverCallbackFunction}
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.mouseOver
   */
  /**
   * Fires when the series is shown after chart generation time, either
   * by clicking the legend item or by calling `.show()`.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-show/
   *         Alert when the series is shown by clicking the legend item.
   *
   * @type      {Highcharts.SeriesShowCallbackFunction}
   * @since     1.2.0
   * @context   Highcharts.Series
   * @apioption plotOptions.series.events.show
   */
  /**
   * Options for the point markers of line and scatter-like series. Properties
   * like `fillColor`, `lineColor` and `lineWidth` define the visual
   * appearance of the markers. The `symbol` option defines the shape. Other
   * series types, like column series, don't have markers, but have visual
   * options on the series level instead.
   *
   * In styled mode, the markers can be styled with the `.highcharts-point`,
   * `.highcharts-point-hover` and `.highcharts-point-select` class names.
   *
   * @declare Highcharts.PointMarkerOptionsObject
   *
   * @sample {highmaps} maps/demo/mappoint-mapmarker
   *         Using the mapmarker symbol for points
   *
   * @private
   */
  marker: {
    /**
     * Enable or disable the point marker. If `undefined`, the markers
     * are hidden when the data is dense, and shown for more widespread
     * data points.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-enabled/
     *         Disabled markers
     * @sample {highcharts} highcharts/plotoptions/series-marker-enabled-false/
     *         Disabled in normal state but enabled on hover
     * @sample {highstock} stock/plotoptions/series-marker/
     *         Enabled markers
     *
     * @type      {boolean}
     * @default   {highcharts} undefined
     * @default   {highstock} false
     * @apioption plotOptions.series.marker.enabled
     */
    /**
     * The threshold for how dense the point markers should be before
     * they are hidden, given that `enabled` is not defined. The number
     * indicates the horizontal distance between the two closest points
     * in the series, as multiples of the `marker.radius`. In other
     * words, the default value of 2 means points are hidden if
     * overlapping horizontally.
     *
     * @sample highcharts/plotoptions/series-marker-enabledthreshold
     *         A higher threshold
     *
     * @since 6.0.5
     */
    enabledThreshold: 2,
    /**
     * The fill color of the point marker. When `undefined`, the series'
     * or point's color is used.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
     *         White fill
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption plotOptions.series.marker.fillColor
     */
    /**
     * Image markers only. Set the image width explicitly. When using
     * this option, a `width` must also be set.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
     *         Fixed width and height
     * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
     *         Fixed width and height
     *
     * @type      {number}
     * @since     4.0.4
     * @apioption plotOptions.series.marker.height
     */
    /**
     * The color of the point marker's outline. When `undefined`, the
     * series' or point's color is used.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
     *         Inherit from series color (undefined)
     *
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    lineColor: "#ffffff",
    /**
     * The width of the point marker's outline.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
     *         2px blue marker
     */
    lineWidth: 0,
    /**
     * The radius of the point marker.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-radius/
     *         Bigger markers
     *
     * @default {highstock} 2
     * @default {highcharts} 4
     *
     */
    radius: 4,
    /**
     * A predefined shape or symbol for the marker. When undefined, the
     * symbol is pulled from options.symbols. Other possible values are
     * `'circle'`, `'square'`,`'diamond'`, `'triangle'` and
     * `'triangle-down'`.
     *
     * Additionally, the URL to a graphic can be given on this form:
     * `'url(graphic.png)'`. Note that for the image to be applied to
     * exported charts, its URL needs to be accessible by the export
     * server.
     *
     * Custom callbacks for symbol path generation can also be added to
     * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
     * used by its method name, as shown in the demo.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
     *         Predefined, graphic and custom markers
     * @sample {highstock} highcharts/plotoptions/series-marker-symbol/
     *         Predefined, graphic and custom markers
     * @sample {highmaps} maps/demo/mappoint-mapmarker
     *         Using the mapmarker symbol for points
     *
     * @type      {string}
     * @apioption plotOptions.series.marker.symbol
     */
    /**
     * Image markers only. Set the image width explicitly. When using
     * this option, a `height` must also be set.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
     *         Fixed width and height
     * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
     *         Fixed width and height
     *
     * @type      {number}
     * @since     4.0.4
     * @apioption plotOptions.series.marker.width
     */
    /**
     * States for a single point marker.
     *
     * @declare Highcharts.PointStatesOptionsObject
     */
    states: {
      /**
       * The normal state of a single point marker. Currently only
       * used for setting animation when returning to normal state
       * from hover.
       *
       * @declare Highcharts.PointStatesNormalOptionsObject
       */
      normal: {
        /**
         * Animation when returning to normal state after hovering.
         *
         * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
         */
        animation: true
      },
      /**
       * The hover state for a single point marker.
       *
       * @declare Highcharts.PointStatesHoverOptionsObject
       */
      hover: {
        /**
         * Animation when hovering over the marker.
         *
         * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
         */
        animation: {
          /** @internal */
          duration: 150
        },
        /**
         * Enable or disable the point marker.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-enabled/
         *         Disabled hover state
         */
        enabled: true,
        /**
         * The fill color of the marker in hover state. When
         * `undefined`, the series' or point's fillColor for normal
         * state is used.
         *
         * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
         * @apioption plotOptions.series.marker.states.hover.fillColor
         */
        /**
         * The color of the point marker's outline. When
         * `undefined`, the series' or point's lineColor for normal
         * state is used.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linecolor/
         *         White fill color, black line color
         *
         * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
         * @apioption plotOptions.series.marker.states.hover.lineColor
         */
        /**
         * The width of the point marker's outline. When
         * `undefined`, the series' or point's lineWidth for normal
         * state is used.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linewidth/
         *         3px line width
         *
         * @type      {number}
         * @apioption plotOptions.series.marker.states.hover.lineWidth
         */
        /**
         * The radius of the point marker. In hover state, it
         * defaults to the normal state's radius + 2 as per the
         * [radiusPlus](#plotOptions.series.marker.states.hover.radiusPlus)
         * option.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-radius/
         *         10px radius
         *
         * @type      {number}
         * @apioption plotOptions.series.marker.states.hover.radius
         */
        /**
         * The number of pixels to increase the radius of the
         * hovered point.
         *
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
         *         5 pixels greater radius on hover
         * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
         *         5 pixels greater radius on hover
         *
         * @since 4.0.3
         */
        radiusPlus: 2,
        /**
         * The additional line width for a hovered point.
         *
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
         *         2 pixels wider on hover
         * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
         *         2 pixels wider on hover
         *
         * @since 4.0.3
         */
        lineWidthPlus: 1
      },
      /**
       * The appearance of the point marker when selected. In order to
       * allow a point to be selected, set the
       * `series.allowPointSelect` option to true.
       *
       * @declare Highcharts.PointStatesSelectOptionsObject
       */
      select: {
        /**
         * Enable or disable visible feedback for selection.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-enabled/
         *         Disabled select state
         *
         * @type      {boolean}
         * @default   true
         * @apioption plotOptions.series.marker.states.select.enabled
         */
        /**
         * The radius of the point marker. In hover state, it
         * defaults to the normal state's radius + 2.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-radius/
         *         10px radius for selected points
         *
         * @type      {number}
         * @apioption plotOptions.series.marker.states.select.radius
         */
        /**
         * The fill color of the point marker.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/
         *         Solid red discs for selected points
         *
         * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
         */
        fillColor: "#cccccc",
        /**
         * The color of the point marker's outline. When
         * `undefined`, the series' or point's color is used.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/
         *         Red line color for selected points
         *
         * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
         */
        lineColor: "#000000",
        /**
         * The width of the point marker's outline.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/
         *         3px line width for selected points
         */
        lineWidth: 2
      }
    }
  },
  /**
   * Properties for each single point.
   *
   * @declare Highcharts.PlotSeriesPointOptions
   *
   * @private
   */
  point: {
    /**
     * Fires when a point is clicked. One parameter, `event`, is passed
     * to the function, containing common event information.
     *
     * If the `series.allowPointSelect` option is true, the default
     * action for the point's click event is to toggle the point's
     * select state. Returning `false` cancels this action.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-click/
     *         Click marker to alert values
     * @sample {highcharts} highcharts/plotoptions/series-point-events-click-column/
     *         Click column
     * @sample {highcharts} highcharts/plotoptions/series-point-events-click-url/
     *         Go to URL
     * @sample {highmaps} maps/plotoptions/series-point-events-click/
     *         Click marker to display values
     * @sample {highmaps} maps/plotoptions/series-point-events-click-url/
     *         Go to URL
     *
     * @type      {Highcharts.PointClickCallbackFunction}
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.click
     */
    /**
     * Fires when the mouse leaves the area close to the point. One
     * parameter, `event`, is passed to the function, containing common
     * event information.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
     *         Show values in the chart's corner on mouse over
     *
     * @type      {Highcharts.PointMouseOutCallbackFunction}
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.mouseOut
     */
    /**
     * Fires when the mouse enters the area close to the point. One
     * parameter, `event`, is passed to the function, containing common
     * event information.
     *
     * Returning `false` cancels the default behavior, which is to show a
     * tooltip for the point.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
     *         Show values in the chart's corner on mouse over
     *
     * @type      {Highcharts.PointMouseOverCallbackFunction}
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.mouseOver
     */
    /**
     * Fires when the point is removed using the `.remove()` method. One
     * parameter, `event`, is passed to the function. Returning `false`
     * cancels the operation.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-remove/
     *         Remove point and confirm
     *
     * @type      {Highcharts.PointRemoveCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.remove
     */
    /**
     * Fires when the point is selected either programmatically or
     * following a click on the point. One parameter, `event`, is passed
     * to the function. Returning `false` cancels the operation.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-select/
     *         Report the last selected point
     * @sample {highmaps} maps/plotoptions/series-allowpointselect/
     *         Report select and unselect
     *
     * @type      {Highcharts.PointSelectCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.select
     */
    /**
     * Fires when the point is unselected either programmatically or
     * following a click on the point. One parameter, `event`, is passed
     * to the function.
     *  Returning `false` cancels the operation.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-unselect/
     *         Report the last unselected point
     * @sample {highmaps} maps/plotoptions/series-allowpointselect/
     *         Report select and unselect
     *
     * @type      {Highcharts.PointUnselectCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.unselect
     */
    /**
     * Fires when the point is updated programmatically through the
     * `.update()` method. One parameter, `event`, is passed to the
     * function. The new point options can be accessed through
     * `event.options`. Returning `false` cancels the operation.
     *
     * @sample {highcharts} highcharts/plotoptions/series-point-events-update/
     *         Confirm point updating
     *
     * @type      {Highcharts.PointUpdateCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Point
     * @apioption plotOptions.series.point.events.update
     */
    /**
     * Events for each single point.
     *
     * @declare Highcharts.PointEventsOptionsObject
     */
    events: {}
  },
  /**
   * Options for the series data labels, appearing next to each data
   * point.
   *
   * Since v6.2.0, multiple data labels can be applied to each single
   * point by defining them as an array of configs.
   *
   * In styled mode, the data labels can be styled with the
   * `.highcharts-data-label-box` and `.highcharts-data-label` class names
   * ([see example](https://www.highcharts.com/samples/highcharts/css/series-datalabels)).
   *
   * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled
   *         Data labels enabled
   * @sample {highcharts} highcharts/plotoptions/series-datalabels-multiple
   *         Multiple data labels on a bar series
   * @sample {highcharts} highcharts/css/series-datalabels
   *         Styled mode example
   * @sample {highmaps} maps/demo/color-axis
   *         Choropleth map with data labels
   * @sample {highmaps} maps/demo/mappoint-datalabels-mapmarker
   *         Using data labels as map markers
   *
   * @type    {*|Array<*>}
   * @product highcharts highstock highmaps gantt
   *
   * @private
   */
  dataLabels: {
    /**
     * Enable or disable the initial animation when a series is displayed
     * for the `dataLabels`. The animation can also be set as a
     * configuration object. Please note that this option only applies to
     * the initial animation.
     *
     * For other animations, see [chart.animation](#chart.animation) and the
     * animation parameter under the API methods. The following properties
     * are supported:
     *
     * - `defer`: The animation delay time in milliseconds.
     *
     * @sample {highcharts} highcharts/plotoptions/animation-defer/
     *          Animation defer settings
     *
     * @type      {boolean|Partial<Highcharts.AnimationOptionsObject>}
     * @since     8.2.0
     * @apioption plotOptions.series.dataLabels.animation
     */
    animation: {},
    /**
     * The animation delay time in milliseconds. Set to `0` to render the
     * data labels immediately. As `undefined` inherits defer time from the
     * [series.animation.defer](#plotOptions.series.animation.defer).
     *
     * @type      {number}
     * @since     8.2.0
     * @apioption plotOptions.series.dataLabels.animation.defer
     */
    /**
     * The alignment of the data label compared to the point. If `right`,
     * the right side of the label should be touching the point. For points
     * with an extent, like columns, the alignments also dictates how to
     * align it inside the box, as given with the
     * [inside](#plotOptions.column.dataLabels.inside) option. Can be one of
     * `left`, `center` or `right`.
     *
     * @sample {highcharts}
     *         highcharts/plotoptions/series-datalabels-align-left/ Left
     *         aligned
     * @sample {highcharts}
     *         highcharts/plotoptions/bar-datalabels-align-inside-bar/ Data
     *         labels inside the bar
     *
     * @type {Highcharts.AlignValue|null}
     */
    align: "center",
    /**
     * Alignment method for data labels. If set to `plotEdges`, the labels
     * are aligned within the plot area in the direction of the y-axis. So
     * in a regular column chart, the labels are aligned vertically
     * according to the `verticalAlign` setting. In a bar chart, which is
     * inverted, the labels are aligned horizontally according to the
     * `align` setting. Applies to cartesian series only.
     *
     * @sample {highcharts} highcharts/series-bar/datalabels-alignto/
     *         Align to plot edges
     *
     * @type      {string}
     * @since 11.4.2
     * @apioption plotOptions.series.dataLabels.alignTo
     */
    /**
     * Whether to allow data labels to overlap. To make the labels less
     * sensitive for overlapping, the
     * [dataLabels.padding](#plotOptions.series.dataLabels.padding)
     * can be set to 0.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-allowoverlap-false/
     *         Don't allow overlap
     *
     * @type      {boolean}
     * @default   false
     * @since     4.1.0
     * @apioption plotOptions.series.dataLabels.allowOverlap
     */
    /**
     * The background color or gradient for the data label. Setting it to
     * `auto` will use the point's color.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
     *         Data labels box options
     * @sample {highmaps} maps/plotoptions/series-datalabels-box/
     *         Data labels box options
     * @sample {highmaps} maps/demo/mappoint-datalabels-mapmarker
     *         Data labels as map markers
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     2.2.1
     * @apioption plotOptions.series.dataLabels.backgroundColor
     */
    /**
     * The border color for the data label. Setting it to `auto` will use
     * the point's color. Defaults to `undefined`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
     *         Data labels box options
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     2.2.1
     * @apioption plotOptions.series.dataLabels.borderColor
     */
    /**
     * The border radius in pixels for the data label.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
     *         Data labels box options
     * @sample {highmaps} maps/plotoptions/series-datalabels-box/
     *         Data labels box options
     *
     * @type      {number}
     * @default   0
     * @since     2.2.1
     * @apioption plotOptions.series.dataLabels.borderRadius
     */
    /**
     * The border width in pixels for the data label.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
     *         Data labels box options
     *
     * @type      {number}
     * @default   0
     * @since     2.2.1
     * @apioption plotOptions.series.dataLabels.borderWidth
     */
    borderWidth: 0,
    /**
     * A class name for the data label. Particularly in styled mode,
     * this can be used to give each series' or point's data label
     * unique styling. In addition to this option, a default color class
     * name is added so that we can give the labels a contrast text
     * shadow.
     *
     * @sample {highcharts} highcharts/css/data-label-contrast/
     *         Contrast text shadow
     * @sample {highcharts} highcharts/css/series-datalabels/
     *         Styling by CSS
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption plotOptions.series.dataLabels.className
     */
    /**
     * This options is deprecated.
     * Use [style.color](#plotOptions.series.dataLabels.style) instead.
     *
     * The text color for the data labels. Defaults to `undefined`. For
     * certain series types, like column or map, the data labels can be
     * drawn inside the points. In this case the data label will be
     * drawn with maximum contrast by default. Additionally, it will be
     * given a `text-outline` style with the opposite color, to further
     * increase the contrast. This can be overridden by setting the
     * `text-outline` style to `none` in the `dataLabels.style` option.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-color/
     *         Red data labels
     * @sample {highmaps} maps/demo/color-axis/
     *         White data labels
     *
     * @see [style.color](#plotOptions.series.dataLabels.style)
     *
     * @type       {Highcharts.ColorType}
     * @deprecated 10.3
     * @apioption  plotOptions.series.dataLabels.color
     */
    /**
     * Whether to hide data labels that are outside the plot area. By
     * default, the data label is moved inside the plot area according
     * to the
     * [overflow](#plotOptions.series.dataLabels.overflow)
     * option.
     *
     * @type      {boolean}
     * @default   true
     * @since     2.3.3
     * @apioption plotOptions.series.dataLabels.crop
     */
    /**
     * Whether to defer displaying the data labels until the initial
     * series animation has finished. Setting to `false` renders the
     * data label immediately. If set to `true` inherits the defer
     * time set in [plotOptions.series.animation](#plotOptions.series.animation).
     *
     * @since     4.0.0
     * @type      {boolean}
     * @product   highcharts highstock gantt
     */
    defer: true,
    /**
     * Enable or disable the data labels.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled/
     *         Data labels enabled
     * @sample {highmaps} maps/demo/color-axis/
     *         Data labels enabled
     *
     * @type      {boolean}
     * @default   false
     * @apioption plotOptions.series.dataLabels.enabled
     */
    /**
     * A declarative filter to control of which data labels to display.
     * The declarative filter is designed for use when callback
     * functions are not available, like when the chart options require
     * a pure JSON structure or for use with graphical editors. For
     * programmatic control, use the `formatter` instead, and return
     * `undefined` to disable a single data label.
     *
     * @example
     * filter: {
     *     property: 'percentage',
     *     operator: '>',
     *     value: 4
     * }
     *
     * @sample {highcharts} highcharts/demo/pie-monochrome
     *         Data labels filtered by percentage
     *
     * @declare   Highcharts.DataLabelsFilterOptionsObject
     * @since     6.0.3
     * @apioption plotOptions.series.dataLabels.filter
     */
    /**
     * The operator to compare by. Can be one of `>`, `<`, `>=`, `<=`,
     * `==`, `===`, `!=` and `!==`.
     *
     * @type       {string}
     * @validvalue [">", "<", ">=", "<=", "==", "===", "!=", "!=="]
     * @apioption  plotOptions.series.dataLabels.filter.operator
     */
    /**
     * The point property to filter by. Point options are passed
     * directly to properties, additionally there are `y` value,
     * `percentage` and others listed under {@link Highcharts.Point}
     * members.
     *
     * @type      {string}
     * @apioption plotOptions.series.dataLabels.filter.property
     */
    /**
     * The value to compare against.
     *
     * @type      {number}
     * @apioption plotOptions.series.dataLabels.filter.value
     */
    /**
     * A
     * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * for the data label. Available variables are the same as for
     * `formatter`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
     *         Add a unit
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-format-subexpression/
     *         Complex logic in the format string
     * @sample {highmaps} maps/plotoptions/series-datalabels-format/
     *         Formatted value in the data label
     *
     * @type      {string}
     * @default   y
     * @default   point.value
     * @since     3.0
     * @apioption plotOptions.series.dataLabels.format
     */
    // eslint-disable-next-line valid-jsdoc
    /**
     * Callback JavaScript function to format the data label. Note that if a
     * `format` is defined, the format takes precedence and the formatter is
     * ignored.
     *
     * @sample {highmaps} maps/plotoptions/series-datalabels-format/
     *         Formatted value
     *
     * @type {Highcharts.DataLabelsFormatterCallbackFunction}
     */
    formatter: function() {
      const { numberFormatter } = this.series.chart;
      return typeof this.y !== "number" ? "" : numberFormatter(this.y, -1);
    },
    /**
     * For points with an extent, like columns or map areas, whether to
     * align the data label inside the box or to the actual value point.
     * Defaults to `false` in most cases, `true` in stacked columns.
     *
     * @type      {boolean}
     * @since     3.0
     * @apioption plotOptions.series.dataLabels.inside
     */
    /**
     * Format for points with the value of null. Works analogously to
     * [format](#plotOptions.series.dataLabels.format). `nullFormat` can
     * be applied only to series which support displaying null points.
     * `heatmap` and `tilemap` supports `nullFormat` by default while the
     * following series requires [#series.nullInteraction] set to `true`:
     * `line`, `spline`, `area`, `area-spline`, `column`, `bar`, and
     * `timeline`. Does not work with series that don't display null
     * points, like `pie`.
     *
     * @sample {highcharts} highcharts/series/null-interaction/
     *         Line chart with null interaction
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-nullformat/
     *         Heatmap with null interaction
     *
     * @type      {boolean|string}
     * @since     7.1.0
     * @apioption plotOptions.series.dataLabels.nullFormat
     */
    /**
             * Callback JavaScript function that defines formatting for points
             * with the value of null. Works analogously to [formatter](#plotOptions.series.dataLabels.formatter).
             * `nullFormatter` can be applied only to series which support
             * displaying null points. `heatmap` and `tilemap` supports
             * `nullFormatter` by default while the following series requires [#series.nullInteraction]
             * set to `true`: `line`, `spline`, `area`, `area-spline`, `column`,
             * `bar`, and `timeline`. Does not work with series that don't display
             * null points, like `pie`.
    
             * @sample {highcharts} highcharts/plotoptions/series-datalabels-nullformat/
             *         Format data label for null points in heat map
             *
             * @type      {Highcharts.DataLabelsFormatterCallbackFunction}
             * @since     7.1.0
             * @apioption plotOptions.series.dataLabels.nullFormatter
             */
    /**
     * How to handle data labels that flow outside the plot area. The
     * default is `"justify"`, which aligns them inside the plot area.
     * For columns and bars, this means it will be moved inside the bar.
     * To display data labels outside the plot area, set `crop` to
     * `false` and `overflow` to `"allow"`.
     *
     * @type       {Highcharts.DataLabelsOverflowValue}
     * @default    justify
     * @since      3.0.6
     * @apioption  plotOptions.series.dataLabels.overflow
     */
    /**
     * When either the `borderWidth` or the `backgroundColor` is set,
     * this is the padding within the box.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
     *         Data labels box options
     * @sample {highmaps} maps/plotoptions/series-datalabels-box/
     *         Data labels box options
     *
     * @since 2.2.1
     */
    padding: 5,
    /**
     * Aligns data labels relative to points. If `center` alignment is
     * not possible, it defaults to `right`.
     *
     * @type      {Highcharts.AlignValue}
     * @default   center
     * @apioption plotOptions.series.dataLabels.position
     */
    /**
     * Text rotation in degrees. Note that due to a more complex
     * structure, backgrounds, borders and padding will be lost on a
     * rotated data label.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
     *         Vertical labels
     *
     * @type      {number}
     * @default   0
     * @apioption plotOptions.series.dataLabels.rotation
     */
    /**
     * The shadow of the box. Works best with `borderWidth` or
     * `backgroundColor`. Since 2.3 the shadow can be an object
     * configuration containing `color`, `offsetX`, `offsetY`, `opacity`
     * and `width`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
     *         Data labels box options
     *
     * @type      {boolean|Highcharts.ShadowOptionsObject}
     * @default   false
     * @since     2.2.1
     * @apioption plotOptions.series.dataLabels.shadow
     */
    /**
     * The name of a symbol to use for the border around the label.
     * Symbols are predefined functions on the Renderer object.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-shape/
     *         A callout for annotations
     *
     * @type      {string}
     * @default   square
     * @since     4.1.2
     * @apioption plotOptions.series.dataLabels.shape
     */
    /**
     * Styles for the label. The default `color` setting is
     * `"contrast"`, which is a pseudo color that Highcharts picks up
     * and applies the maximum contrast to the underlying point item,
     * for example the bar in a bar chart.
     *
     * The `textOutline` is a pseudo property that applies an outline of
     * the given width with the given color, which by default is the
     * maximum contrast to the text. So a bright text color will result
     * in a black text outline for maximum readability on a mixed
     * background. In some cases, especially with grayscale text, the
     * text outline doesn't work well, in which cases it can be disabled
     * by setting it to `"none"`. When `useHTML` is true, the
     * `textOutline` will not be picked up. In this, case, the same
     * effect can be acheived through the `text-shadow` CSS property.
     *
     * For some series types, where each point has an extent, like for
     * example tree maps, the data label may overflow the point. There
     * are two strategies for handling overflow. By default, the text
     * will wrap to multiple lines. The other strategy is to set
     * `style.textOverflow` to `ellipsis`, which will keep the text on
     * one line plus it will break inside long words.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-style/
     *         Bold labels
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow/
     *         Long labels truncated with an ellipsis in a pie
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap/
     *         Long labels are wrapped in a pie
     * @sample {highmaps} maps/demo/color-axis/
     *         Bold labels
     *
     * @type      {Highcharts.CSSObject}
     * @since     4.1.0
     * @apioption plotOptions.series.dataLabels.style
     */
    style: {
      /** @internal */
      fontSize: "0.7em",
      /** @internal */
      fontWeight: "bold",
      /** @internal */
      color: "contrast",
      /** @internal */
      textOutline: "1px contrast"
    },
    /**
     * Options for a label text which should follow marker's shape.
     * Border and background are disabled for a label that follows a
     * path.
     *
     * **Note:** Only SVG-based renderer supports this option. Setting
     * `useHTML` to true will disable this option.
     *
     * @declare   Highcharts.DataLabelsTextPathOptionsObject
     * @since     7.1.0
     * @apioption plotOptions.series.dataLabels.textPath
     */
    /**
     * Presentation attributes for the text path.
     *
     * @type      {Highcharts.SVGAttributes}
     * @since     7.1.0
     * @apioption plotOptions.series.dataLabels.textPath.attributes
     */
    /**
     * Enable or disable `textPath` option for link's or marker's data
     * labels.
     *
     * @type      {boolean}
     * @since     7.1.0
     * @apioption plotOptions.series.dataLabels.textPath.enabled
     */
    /**
     * Whether to
     * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the labels.
     *
     * @type      {boolean}
     * @default   false
     * @apioption plotOptions.series.dataLabels.useHTML
     */
    /**
     * The vertical alignment of a data label. Can be one of `top`,
     * `middle` or `bottom`. The default value depends on the data, for
     * instance in a column chart, the label is above positive values
     * and below negative values.
     *
     * @type  {Highcharts.VerticalAlignValue|null}
     * @since 2.3.3
     */
    verticalAlign: "bottom",
    /**
     * The x position offset of the label relative to the point in
     * pixels.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
     *         Vertical and positioned
     * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
     *         Data labels inside the bar
     */
    x: 0,
    /**
     * The z index of the data labels. Use a `zIndex` of 6 to display it above
     * the series, or use a `zIndex` of 2 to display it behind the series.
     *
     * @type      {number}
     * @default   6
     * @since     2.3.5
     * @apioption plotOptions.series.dataLabels.zIndex
     */
    /**
     * The y position offset of the label relative to the point in
     * pixels.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
     *         Vertical and positioned
     */
    y: 0
  },
  /**
   * When the series contains less points than the crop threshold, all
   * points are drawn, even if the points fall outside the visible plot
   * area at the current zoom. The advantage of drawing all points
   * (including markers and columns), is that animation is performed on
   * updates. On the other hand, when the series contains more points than
   * the crop threshold, the series data is cropped to only contain points
   * that fall within the plot area. The advantage of cropping away
   * invisible points is to increase performance on large series.
   *
   * @since   2.2
   * @product highcharts highstock
   *
   * @private
   */
  cropThreshold: 300,
  /**
   * Opacity of a series parts: line, fill (e.g. area) and dataLabels.
   *
   * @see [states.inactive.opacity](#plotOptions.series.states.inactive.opacity)
   *
   * @since 7.1.0
   *
   * @private
   */
  opacity: 1,
  /**
   * The width of each point on the x axis. For example in a column chart
   * with one value each day, the pointRange would be 1 day (= 24 * 3600
   * * 1000 milliseconds). This is normally computed automatically, but
   * this option can be used to override the automatic value.
   *
   * @product highstock
   *
   * @private
   */
  pointRange: 0,
  /**
   * When this is true, the series will not cause the Y axis to cross
   * the zero plane (or [threshold](#plotOptions.series.threshold) option)
   * unless the data actually crosses the plane.
   *
   * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
   * 3 will make the Y axis show negative values according to the
   * `minPadding` option. If `softThreshold` is `true`, the Y axis starts
   * at 0.
   *
   * @since   4.1.9
   * @product highcharts highstock
   *
   * @private
   */
  softThreshold: true,
  /**
   * @declare Highcharts.SeriesStatesOptionsObject
   *
   * @private
   */
  states: {
    /**
     * The normal state of a series, or for point items in column, pie
     * and similar series. Currently only used for setting animation
     * when returning to normal state from hover.
     *
     * @declare Highcharts.SeriesStatesNormalOptionsObject
     */
    normal: {
      /**
       * Animation when returning to normal state after hovering.
       *
           * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
       */
      animation: true
    },
    /**
     * Options for the hovered series. These settings override the
     * normal state options when a series is moused over or touched.
     *
     * @declare Highcharts.SeriesStatesHoverOptionsObject
     */
    hover: {
      /**
       * Enable separate styles for the hovered series to visualize
       * that the user hovers either the series itself or the legend.
       *
       * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled/
       *         Line
       * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-column/
       *         Column
       * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-pie/
       *         Pie
       *
       * @type      {boolean}
       * @default   true
       * @since     1.2
       * @apioption plotOptions.series.states.hover.enabled
       */
      /**
       * Animation setting for hovering the graph in line-type series.
       *
       * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
       * @since   5.0.8
       * @product highcharts highstock
       */
      animation: {
        /**
         * The duration of the hover animation in milliseconds. By
         * default the hover state animates quickly in, and slowly
         * back to normal.
         *
         * @internal
         */
        duration: 150
      },
      /**
       * Pixel width of the graph line. By default this property is
       * undefined, and the `lineWidthPlus` property dictates how much
       * to increase the linewidth from normal state.
       *
       * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidth/
       *         5px line on hover
       *
       * @type      {number}
       * @product   highcharts highstock
       * @apioption plotOptions.series.states.hover.lineWidth
       */
      /**
       * The additional line width for the graph of a hovered series.
       *
       * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
       *         5 pixels wider
       * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
       *         5 pixels wider
       *
       * @since   4.0.3
       * @product highcharts highstock
       */
      lineWidthPlus: 1,
      /**
       * In Highcharts 1.0, the appearance of all markers belonging
       * to the hovered series. For settings on the hover state of the
       * individual point, see
       * [marker.states.hover](#plotOptions.series.marker.states.hover).
       *
       * @deprecated
       *
       * @extends   plotOptions.series.marker
       * @excluding states, symbol
       * @product   highcharts highstock
       */
      marker: {
        // `lineWidth: base + 1`,
        // `radius: base + 1`
      },
      /**
       * Options for the halo appearing around the hovered point in
       * line-type series as well as outside the hovered slice in pie
       * charts. By default the halo is filled by the current point or
       * series color with an opacity of 0.25\. The halo can be
       * disabled by setting the `halo` option to `null`.
       *
       * In styled mode, the halo is styled with the
       * `.highcharts-halo` class, with colors inherited from
       * `.highcharts-color-{n}`.
       *
       * @sample {highcharts} highcharts/plotoptions/halo/
       *         Halo options
       * @sample {highstock} highcharts/plotoptions/halo/
       *         Halo options
       *
       * @declare Highcharts.SeriesStatesHoverHaloOptionsObject
       * @type    {null|*}
       * @since   4.0
       * @product highcharts highstock
       */
      halo: {
        /**
         * A collection of SVG attributes to override the appearance
         * of the halo, for example `fill`, `stroke` and
         * `stroke-width`.
         *
         * @type      {Highcharts.SVGAttributes}
         * @since     4.0
         * @product   highcharts highstock
         * @apioption plotOptions.series.states.hover.halo.attributes
         */
        /**
         * The pixel size of the halo. For point markers this is the
         * radius of the halo. For pie slices it is the width of the
         * halo outside the slice. For bubbles it defaults to 5 and
         * is the width of the halo outside the bubble.
         *
         * @since   4.0
         * @product highcharts highstock
         */
        size: 10,
        /**
         * Opacity for the halo unless a specific fill is overridden
         * using the `attributes` setting. Note that Highcharts is
         * only able to apply opacity to colors of hex or rgb(a)
         * formats.
         *
         * @since   4.0
         * @product highcharts highstock
         */
        opacity: 0.25
      }
    },
    /**
     * Specific options for point in selected states, after being
     * selected by
     * [allowPointSelect](#plotOptions.series.allowPointSelect)
     * or programmatically.
     *
     * @sample maps/plotoptions/series-allowpointselect/
     *         Allow point select demo
     *
     * @declare   Highcharts.SeriesStatesSelectOptionsObject
     * @extends   plotOptions.series.states.hover
     * @excluding brightness
     */
    select: {
      animation: {
        /** @internal */
        duration: 0
      }
    },
    /**
     * The opposite state of a hover for series.
     *
     * @sample highcharts/plotoptions/series-states-inactive-disabled
     *         Disabled inactive state
     *
     * @declare Highcharts.SeriesStatesInactiveOptionsObject
     */
    inactive: {
      /**
       * Enable or disable the inactive state for a series
       *
       * @sample highcharts/plotoptions/series-states-inactive-disabled
       *         Disabled inactive state
       *
       * @type {boolean}
       * @default true
       * @apioption plotOptions.series.states.inactive.enabled
       */
      /**
       * The animation for entering the inactive state.
       *
       * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
       */
      animation: {
        /** @internal */
        duration: 150
      },
      /**
       * Opacity of series elements (dataLabels, line, area).
       *
       * @type {number}
       */
      opacity: 0.2
    }
  },
  /**
   * Sticky tracking of mouse events. When true, the `mouseOut` event on a
   * series isn't triggered until the mouse moves over another series, or
   * out of the plot area. When false, the `mouseOut` event on a series is
   * triggered when the mouse leaves the area around the series' graph or
   * markers. This also implies the tooltip when not shared. When
   * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
   * will be hidden when moving the mouse between series. Defaults to true
   * for line and area type series, but to false for columns, pies etc.
   *
   * **Note:** The boost module will force this option because of
   * technical limitations.
   *
   * @sample {highcharts} highcharts/plotoptions/series-stickytracking-true/
   *         True by default
   * @sample {highcharts} highcharts/plotoptions/series-stickytracking-false/
   *         False
   *
   * @default {highcharts} true
   * @default {highstock} true
   * @default {highmaps} false
   * @since   2.0
   *
   * @private
   */
  stickyTracking: true,
  /**
   * A configuration object for the tooltip rendering of each single
   * series. Properties are inherited from [tooltip](#tooltip), but only
   * the following properties can be defined on a series level.
   *
   * @declare   Highcharts.SeriesTooltipOptionsObject
   * @since     2.3
   * @extends   tooltip
   * @excluding animation, backgroundColor, borderColor, borderRadius,
   *            borderWidth, className, crosshairs, enabled, fixed, formatter,
   *            headerShape, hideDelay, outside, padding, positioner,
   *            shadow, shape, shared, snap, split, stickOnContact,
   *            style, useHTML
   * @apioption plotOptions.series.tooltip
   */
  /**
   * When a series contains a `data` array that is longer than this, the
   * Series class looks for data configurations of plain numbers or arrays of
   * numbers. The first and last valid points are checked. If found, the rest
   * of the data is assumed to be the same. This saves expensive data checking
   * and indexing in long series, and makes data-heavy charts render faster.
   *
   * Set it to `0` disable.
   *
   * Note:
   * - In boost mode turbo threshold is forced. Only array of numbers or two
   *   dimensional arrays are allowed.
   * - In version 11.4.3 and earlier, if object configurations were passed
   *   beyond the turbo threshold, a warning was logged in the console and the
   *   data series didn't render.
   *
   * @since   2.2
   * @product highcharts highstock gantt
   *
   * @private
   */
  turboThreshold: 1e3,
  /**
   * An array defining zones within a series. Zones can be applied to the
   * X axis, Y axis or Z axis for bubbles, according to the `zoneAxis`
   * option. The zone definitions have to be in ascending order regarding
   * to the value.
   *
   * In styled mode, the color zones are styled with the
   * `.highcharts-zone-{n}` class, or custom classed from the `className`
   * option
   * ([view live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/color-zones/)).
   *
   * @see [zoneAxis](#plotOptions.series.zoneAxis)
   *
   * @sample {highcharts} highcharts/series/color-zones-simple/
   *         Color zones
   * @sample {highstock} highcharts/series/color-zones-simple/
   *         Color zones
   *
   * @declare   Highcharts.SeriesZonesOptionsObject
   * @type      {Array<*>}
   * @since     4.1.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.zones
   */
  /**
   * Styled mode only. A custom class name for the zone.
   *
   * @sample highcharts/css/color-zones/
   *         Zones styled by class name
   *
   * @type      {string}
   * @since     5.0.0
   * @apioption plotOptions.series.zones.className
   */
  /**
   * Defines the color of the series.
   *
   * @see [series color](#plotOptions.series.color)
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     4.1.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.zones.color
   */
  /**
   * A name for the dash style to use for the graph.
   *
   * @see [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
   *
   * @sample {highcharts|highstock} highcharts/series/color-zones-dashstyle-dot/
   *         Dashed line indicates prognosis
   *
   * @type      {Highcharts.DashStyleValue}
   * @since     4.1.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.zones.dashStyle
   */
  /**
   * Defines the fill color for the series (in area type series)
   *
   * @see [fillColor](#plotOptions.area.fillColor)
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     4.1.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.zones.fillColor
   */
  /**
   * The value up to where the zone extends, if undefined the zones
   * stretches to the last value in the series.
   *
   * @type      {number}
   * @since     4.1.0
   * @product   highcharts highstock
   * @apioption plotOptions.series.zones.value
   */
  /**
   * When using dual or multiple color axes, this number defines which
   * colorAxis the particular series is connected to. It refers to
   * either the
   * {@link #colorAxis.id|axis id}
   * or the index of the axis in the colorAxis array, with 0 being the
   * first. Set this option to false to prevent a series from connecting
   * to the default color axis.
   *
   * Since v7.2.0 the option can also be an axis id or an axis index
   * instead of a boolean flag.
   *
   * @sample highcharts/coloraxis/coloraxis-with-pie/
   *         Color axis with pie series
   * @sample highcharts/coloraxis/multiple-coloraxis/
   *         Multiple color axis
   *
   * @type      {number|string|boolean}
   * @default   0
   * @product   highcharts highstock highmaps
   * @apioption plotOptions.series.colorAxis
   */
  /**
   * Determines what data value should be used to calculate point color
   * if `colorAxis` is used. Requires to set `min` and `max` if some
   * custom point property is used or if approximation for data grouping
   * is set to `'sum'`.
   *
   * @sample highcharts/coloraxis/custom-color-key/
   *         Custom color key
   * @sample highcharts/coloraxis/color-key-with-stops/
   *         Custom colorKey with color axis stops
   * @sample highcharts/coloraxis/changed-default-color-key/
   *         Changed default color key
   *
   * @type      {string}
   * @default   y
   * @since     7.2.0
   * @product   highcharts highstock highmaps
   * @apioption plotOptions.series.colorKey
   */
  /**
   * What type of legend symbol to render for this series. Can be one of
   * `areaMarker`, `lineMarker` or `rectangle`.
   *
   * @validvalue ["areaMarker", "lineMarker", "rectangle"]
   *
   * @sample {highcharts} highcharts/series/legend-symbol/
   *         Change the legend symbol
   *
   * @type      {string}
   * @default   rectangle
   * @since     11.0.1
   * @apioption plotOptions.series.legendSymbol
   */
  /**
   * Defines the color of the legend symbol for this series. Defaults to
   * undefined, in which case the series color is used. Does not work with
   * styled mode.
   *
   * @sample {highcharts|highstock} highcharts/series/legend-symbol-color/
   *         Change the legend symbol color
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default   undefined
   * @since 12.0.0
   * @product   highcharts highstock highmaps
   * @apioption plotOptions.series.legendSymbolColor
   */
  /**
   * Determines whether the series should look for the nearest point
   * in both dimensions or just the x-dimension when hovering the series.
   * Defaults to `'xy'` for scatter series and `'x'` for most other
   * series. If the data has duplicate x-values, it is recommended to
   * set this to `'xy'` to allow hovering over all points.
   *
   * Applies only to series types using nearest neighbor search (not
   * direct hover) for tooltip.
   *
   * @sample {highcharts} highcharts/series/findnearestpointby/
   *         Different hover behaviors
   * @sample {highstock} highcharts/series/findnearestpointby/
   *         Different hover behaviors
   * @sample {highmaps} highcharts/series/findnearestpointby/
   *         Different hover behaviors
   *
   * @since      5.0.10
   * @validvalue ["x", "xy"]
   *
   * @private
   */
  findNearestPointBy: "x"
};
const { defaultOptions: defaultOptions$i } = DefaultOptions;
const { extend: extend$1e, extendClass, merge: merge$1w } = Utilities;
var SeriesRegistry;
(function(SeriesRegistry2) {
  SeriesRegistry2.seriesTypes = Highcharts.seriesTypes;
  function registerSeriesType(seriesType2, SeriesClass) {
    const defaultPlotOptions = defaultOptions$i.plotOptions || {}, seriesOptions = SeriesClass.defaultOptions, seriesProto2 = SeriesClass.prototype;
    seriesProto2.type = seriesType2;
    if (!seriesProto2.pointClass) {
      seriesProto2.pointClass = Point$3;
    }
    if (SeriesRegistry2.seriesTypes[seriesType2]) {
      return false;
    }
    if (seriesOptions) {
      defaultPlotOptions[seriesType2] = seriesOptions;
    }
    SeriesRegistry2.seriesTypes[seriesType2] = SeriesClass;
    return true;
  }
  SeriesRegistry2.registerSeriesType = registerSeriesType;
  function seriesType(type, parent, options2, seriesProto2, pointProto2) {
    const defaultPlotOptions = defaultOptions$i.plotOptions || {};
    parent = parent || "";
    defaultPlotOptions[type] = merge$1w(defaultPlotOptions[parent], options2);
    delete SeriesRegistry2.seriesTypes[type];
    registerSeriesType(type, extendClass(SeriesRegistry2.seriesTypes[parent] || function() {
    }, seriesProto2));
    SeriesRegistry2.seriesTypes[type].prototype.type = type;
    if (pointProto2) {
      class PointClass extends Point$3 {
      }
      extend$1e(PointClass.prototype, pointProto2);
      SeriesRegistry2.seriesTypes[type].prototype.pointClass = PointClass;
    }
    return SeriesRegistry2.seriesTypes[type];
  }
  SeriesRegistry2.seriesType = seriesType;
})(SeriesRegistry || (SeriesRegistry = {}));
const SeriesRegistry$1 = SeriesRegistry;
const { animObject: animObject$b, setAnimation: setAnimation$4 } = animationExports;
const { defaultOptions: defaultOptions$h } = DefaultOptions;
const { registerEventOptions: registerEventOptions$2 } = Foundation$1;
const { svg: svg$1, win: win$9 } = Highcharts;
const { seriesTypes: seriesTypes$5 } = SeriesRegistry$1;
const { format: format$e } = Templating;
const { arrayMax: arrayMax$8, arrayMin: arrayMin$6, clamp: clamp$j, correctFloat: correctFloat$d, crisp: crisp$c, defined: defined$14, destroyObjectProperties: destroyObjectProperties$6, diffObjects: diffObjects$4, erase: erase$6, error: error$7, extend: extend$1d, find: find$h, fireEvent: fireEvent$C, getClosestDistance, getNestedProperty: getNestedProperty$1, insertItem, isArray: isArray$k, isNumber: isNumber$Y, isString: isString$b, merge: merge$1v, objectEach: objectEach$m, pick: pick$1B, removeEvent: removeEvent$8, syncTimeout: syncTimeout$7 } = Utilities;
let Series$9 = class Series2 {
  constructor() {
    this.zoneAxis = "y";
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  init(chart, userOptions) {
    fireEvent$C(this, "init", { options: userOptions });
    this.dataTable ?? (this.dataTable = new DataTableCore());
    const series = this, chartSeries = chart.series;
    this.eventsToUnbind = [];
    series.chart = chart;
    series.options = series.setOptions(userOptions);
    const options2 = series.options, visible = options2.visible !== false;
    series.linkedSeries = [];
    series.bindAxes();
    extend$1d(series, {
      /**
       * The series name as given in the options. Defaults to
       * "Series {n}".
       *
       * @name Highcharts.Series#name
       * @type {string}
       */
      name: options2.name,
      state: "",
      /**
       * Read only. The series' visibility state as set by {@link
       * Series#show}, {@link Series#hide}, or in the initial
       * configuration.
       *
       * @name Highcharts.Series#visible
       * @type {boolean}
       */
      visible,
      // True by default
      /**
       * Read only. The series' selected state as set by {@link
       * Highcharts.Series#select}.
       *
       * @name Highcharts.Series#selected
       * @type {boolean}
       */
      selected: options2.selected === true
      // False by default
    });
    registerEventOptions$2(this, options2);
    const events = options2.events;
    if (events?.click || options2.point?.events?.click || options2.allowPointSelect) {
      chart.runTrackerClick = true;
    }
    series.getColor();
    series.getSymbol();
    if (series.isCartesian) {
      chart.hasCartesianSeries = true;
    }
    let lastSeries;
    if (chartSeries.length) {
      lastSeries = chartSeries[chartSeries.length - 1];
    }
    series._i = pick$1B(lastSeries?._i, -1) + 1;
    series.opacity = series.options.opacity;
    chart.orderItems("series", insertItem(this, chartSeries));
    if (options2.dataSorting?.enabled) {
      series.setDataSortingOptions();
    } else if (!series.points && !series.data) {
      series.setData(options2.data, false);
    }
    fireEvent$C(this, "afterInit");
  }
  /**
   * Check whether the series item is itself or inherits from a certain
   * series type.
   *
   * @function Highcharts.Series#is
   * @param {string} type The type of series to check for, can be either
   *        featured or custom series types. For example `column`, `pie`,
   *        `ohlc` etc.
   *
   * @return {boolean}
   *        True if this item is or inherits from the given type.
   */
  is(type) {
    return seriesTypes$5[type] && this instanceof seriesTypes$5[type];
  }
  /**
   * Set the xAxis and yAxis properties of cartesian series, and register
   * the series in the `axis.series` array.
   *
   * @private
   * @function Highcharts.Series#bindAxes
   */
  bindAxes() {
    const series = this, seriesOptions = series.options, chart = series.chart;
    let axisOptions;
    fireEvent$C(this, "bindAxes", null, function() {
      (series.axisTypes || []).forEach(function(coll) {
        (chart[coll] || []).forEach(function(axis) {
          axisOptions = axis.options;
          if (pick$1B(seriesOptions[coll], 0) === axis.index || typeof seriesOptions[coll] !== "undefined" && seriesOptions[coll] === axisOptions.id) {
            insertItem(series, axis.series);
            series[coll] = axis;
            axis.isDirty = true;
          }
        });
        if (!series[coll] && series.optionalAxis !== coll) {
          error$7(18, true, chart);
        }
      });
    });
    fireEvent$C(this, "afterBindAxes");
  }
  /**
   * Define hasData functions for series. These return true if there
   * are data points on this series within the plot area.
   *
   * @private
   * @function Highcharts.Series#hasData
   */
  hasData() {
    return this.visible && typeof this.dataMax !== "undefined" && typeof this.dataMin !== "undefined" || // #3703
    this.visible && this.dataTable.rowCount > 0;
  }
  /**
   * Determine whether the marker in a series has changed.
   *
   * @private
   * @function Highcharts.Series#hasMarkerChanged
   */
  hasMarkerChanged(options2, oldOptions) {
    const marker = options2.marker, oldMarker = oldOptions.marker || {};
    return marker && (oldMarker.enabled && !marker.enabled || oldMarker.symbol !== marker.symbol || // #10870, #15946
    oldMarker.height !== marker.height || // #16274
    oldMarker.width !== marker.width);
  }
  /**
   * Return an auto incremented x value based on the pointStart and
   * pointInterval options. This is only used if an x value is not given
   * for the point that calls autoIncrement.
   *
   * @private
   * @function Highcharts.Series#autoIncrement
   */
  autoIncrement(x) {
    const options2 = this.options, { pointIntervalUnit, relativeXValue } = this.options, time = this.chart.time, xIncrement = this.xIncrement ?? time.parse(options2.pointStart) ?? 0;
    let pointInterval;
    this.pointInterval = pointInterval = pick$1B(this.pointInterval, options2.pointInterval, 1);
    if (relativeXValue && isNumber$Y(x)) {
      pointInterval *= x;
    }
    if (pointIntervalUnit) {
      const d = time.toParts(xIncrement);
      if (pointIntervalUnit === "day") {
        d[2] += pointInterval;
      } else if (pointIntervalUnit === "month") {
        d[1] += pointInterval;
      } else if (pointIntervalUnit === "year") {
        d[0] += pointInterval;
      }
      pointInterval = time.makeTime.apply(time, d) - xIncrement;
    }
    if (relativeXValue && isNumber$Y(x)) {
      return xIncrement + pointInterval;
    }
    this.xIncrement = xIncrement + pointInterval;
    return xIncrement;
  }
  /**
   * Internal function to set properties for series if data sorting is
   * enabled.
   *
   * @private
   * @function Highcharts.Series#setDataSortingOptions
   */
  setDataSortingOptions() {
    const options2 = this.options;
    extend$1d(this, {
      requireSorting: false,
      sorted: false,
      enabledDataSorting: true,
      allowDG: false
    });
    if (!defined$14(options2.pointRange)) {
      options2.pointRange = 1;
    }
  }
  /**
   * Set the series options by merging from the options tree. Called
   * internally on initializing and updating series. This function will
   * not redraw the series. For API usage, use {@link Series#update}.
   * @private
   * @function Highcharts.Series#setOptions
   * @param {Highcharts.SeriesOptionsType} itemOptions
   * The series options.
   * @emits Highcharts.Series#event:afterSetOptions
   */
  setOptions(itemOptions) {
    const chart = this.chart, chartOptions = chart.options, plotOptions = chartOptions.plotOptions, userOptions = chart.userOptions || {}, seriesUserOptions = merge$1v(itemOptions), styledMode = chart.styledMode, e = {
      plotOptions,
      userOptions: seriesUserOptions
    };
    let zone;
    fireEvent$C(this, "setOptions", e);
    const typeOptions = e.plotOptions[this.type], userPlotOptions = userOptions.plotOptions || {}, userPlotOptionsSeries = userPlotOptions.series || {}, defaultPlotOptionsType = defaultOptions$h.plotOptions[this.type] || {}, userPlotOptionsType = userPlotOptions[this.type] || {};
    typeOptions.dataLabels = this.mergeArrays(defaultPlotOptionsType.dataLabels, typeOptions.dataLabels);
    this.userOptions = e.userOptions;
    const options2 = merge$1v(
      typeOptions,
      plotOptions.series,
      // #3881, chart instance plotOptions[type] should trump
      // plotOptions.series
      userPlotOptionsType,
      seriesUserOptions
    );
    this.tooltipOptions = merge$1v(
      defaultOptions$h.tooltip,
      // 1
      defaultOptions$h.plotOptions.series?.tooltip,
      // 2
      defaultPlotOptionsType?.tooltip,
      // 3
      chart.userOptions.tooltip,
      // 4
      userPlotOptions.series?.tooltip,
      // 5
      userPlotOptionsType.tooltip,
      // 6
      seriesUserOptions.tooltip
      // 7
    );
    this.stickyTracking = pick$1B(seriesUserOptions.stickyTracking, userPlotOptionsType.stickyTracking, userPlotOptionsSeries.stickyTracking, this.tooltipOptions.shared && !this.noSharedTooltip ? true : options2.stickyTracking);
    if (typeOptions.marker === null) {
      delete options2.marker;
    }
    this.zoneAxis = options2.zoneAxis || "y";
    const zones = this.zones = // #20440, create deep copy of zones options
    (options2.zones || []).map((z) => ({ ...z }));
    if ((options2.negativeColor || options2.negativeFillColor) && !options2.zones) {
      zone = {
        value: options2[this.zoneAxis + "Threshold"] || options2.threshold || 0,
        className: "highcharts-negative"
      };
      if (!styledMode) {
        zone.color = options2.negativeColor;
        zone.fillColor = options2.negativeFillColor;
      }
      zones.push(zone);
    }
    if (zones.length && defined$14(zones[zones.length - 1].value)) {
      zones.push(styledMode ? {} : {
        color: this.color,
        fillColor: this.fillColor
      });
    }
    fireEvent$C(this, "afterSetOptions", { options: options2 });
    return options2;
  }
  /**
   * Return series name in "Series {Number}" format or the one defined by
   * a user. This method can be simply overridden as series name format
   * can vary (e.g. technical indicators).
   *
   * @function Highcharts.Series#getName
   *
   * @return {string}
   * The series name.
   */
  getName() {
    return this.options.name ?? format$e(this.chart.options.lang.seriesName, this, this.chart);
  }
  /**
   * @private
   * @function Highcharts.Series#getCyclic
   */
  getCyclic(prop, value, defaults2) {
    const chart = this.chart, indexName = `${prop}Index`, counterName = `${prop}Counter`, len = (
      // Symbol count
      defaults2?.length || // Color count
      chart.options.chart.colorCount
    );
    let i, setting;
    if (!value) {
      setting = pick$1B(prop === "color" ? this.options.colorIndex : void 0, this[indexName]);
      if (defined$14(setting)) {
        i = setting;
      } else {
        if (!chart.series.length) {
          chart[counterName] = 0;
        }
        i = chart[counterName] % len;
        chart[counterName] += 1;
      }
      if (defaults2) {
        value = defaults2[i];
      }
    }
    if (typeof i !== "undefined") {
      this[indexName] = i;
    }
    this[prop] = value;
  }
  /**
   * Get the series' color based on either the options or pulled from
   * global options.
   *
   * @private
   * @function Highcharts.Series#getColor
   */
  getColor() {
    if (this.chart.styledMode) {
      this.getCyclic("color");
    } else if (this.options.colorByPoint) {
      this.color = "#cccccc";
    } else {
      this.getCyclic("color", this.options.color || defaultOptions$h.plotOptions[this.type].color, this.chart.options.colors);
    }
  }
  /**
   * Get all points' instances created for this series.
   *
   * @private
   * @function Highcharts.Series#getPointsCollection
   */
  getPointsCollection() {
    return (this.hasGroupedData ? this.points : this.data) || [];
  }
  /**
   * Get the series' symbol based on either the options or pulled from
   * global options.
   *
   * @private
   * @function Highcharts.Series#getSymbol
   */
  getSymbol() {
    const seriesMarkerOption = this.options.marker;
    this.getCyclic("symbol", seriesMarkerOption.symbol, this.chart.options.symbols);
  }
  /**
   * Shorthand to get one of the series' data columns from `Series.dataTable`.
   *
   * @private
   * @function Highcharts.Series#getColumn
   */
  getColumn(columnName, modified) {
    return (modified ? this.dataTable.modified : this.dataTable).getColumn(columnName, true) || [];
  }
  /**
   * Finds the index of an existing point that matches the given point
   * options.
   *
   * @private
   * @function Highcharts.Series#findPointIndex
   * @param {Highcharts.PointOptionsObject} optionsObject
   * The options of the point.
   * @param {number} fromIndex
   * The index to start searching from, used for optimizing series with
   * required sorting.
   * @return {number|undefined}
   * Returns the index of a matching point, or undefined if no match is found.
   */
  findPointIndex(optionsObject, fromIndex) {
    const { id, x } = optionsObject, oldData = this.points, dataSorting = this.options.dataSorting, cropStart = this.cropStart || 0;
    let matchingPoint, matchedById, pointIndex;
    if (id) {
      const item = this.chart.get(id);
      if (item instanceof Point$3) {
        matchingPoint = item;
      }
    } else if (this.linkedParent || this.enabledDataSorting || this.options.relativeXValue) {
      let matcher = (oldPoint) => !oldPoint.touched && oldPoint.index === optionsObject.index;
      if (dataSorting?.matchByName) {
        matcher = (oldPoint) => !oldPoint.touched && oldPoint.name === optionsObject.name;
      } else if (this.options.relativeXValue) {
        matcher = (oldPoint) => !oldPoint.touched && oldPoint.options.x === optionsObject.x;
      }
      matchingPoint = find$h(oldData, matcher);
      if (!matchingPoint) {
        return void 0;
      }
    }
    if (matchingPoint) {
      pointIndex = matchingPoint?.index;
      if (typeof pointIndex !== "undefined") {
        matchedById = true;
      }
    }
    if (typeof pointIndex === "undefined" && isNumber$Y(x)) {
      pointIndex = this.getColumn("x").indexOf(x, fromIndex);
    }
    if (pointIndex !== -1 && typeof pointIndex !== "undefined" && this.cropped) {
      pointIndex = pointIndex >= cropStart ? pointIndex - cropStart : pointIndex;
    }
    if (!matchedById && isNumber$Y(pointIndex) && oldData[pointIndex]?.touched) {
      pointIndex = void 0;
    }
    return pointIndex;
  }
  /**
   * Internal function called from setData. If the point count is the same
   * as it was, or if there are overlapping X values, just run
   * Point.update which is cheaper, allows animation, and keeps references
   * to points. This also allows adding or removing points if the X-es
   * don't match.
   *
   * @private
   * @function Highcharts.Series#updateData
   */
  updateData(data, animation) {
    const { options: options2, requireSorting } = this, dataSorting = options2.dataSorting, oldData = this.points, pointsToAdd = [], equalLength = data.length === oldData.length;
    let hasUpdatedByKey, i, point, lastIndex, succeeded = true;
    this.xIncrement = null;
    data.forEach((pointOptions, i2) => {
      const optionsObject = defined$14(pointOptions) && this.pointClass.prototype.optionsToObject.call({ series: this }, pointOptions) || {}, { id, x } = optionsObject;
      let pointIndex;
      if (id || isNumber$Y(x)) {
        pointIndex = this.findPointIndex(optionsObject, lastIndex);
        if (pointIndex === -1 || typeof pointIndex === "undefined") {
          pointsToAdd.push(pointOptions);
        } else if (oldData[pointIndex] && pointOptions !== options2.data?.[pointIndex]) {
          oldData[pointIndex].update(pointOptions, false, void 0, false);
          oldData[pointIndex].touched = true;
          if (requireSorting) {
            lastIndex = pointIndex + 1;
          }
        } else if (oldData[pointIndex]) {
          oldData[pointIndex].touched = true;
        }
        if (!equalLength || i2 !== pointIndex || dataSorting?.enabled || this.hasDerivedData) {
          hasUpdatedByKey = true;
        }
      } else {
        pointsToAdd.push(pointOptions);
      }
    }, this);
    if (hasUpdatedByKey) {
      i = oldData.length;
      while (i--) {
        point = oldData[i];
        if (point && !point.touched) {
          point.remove?.(false, animation);
        }
      }
    } else if (equalLength && !dataSorting?.enabled) {
      data.forEach((point2, i2) => {
        if (point2 !== oldData[i2].y && !oldData[i2].destroyed) {
          oldData[i2].update(point2, false, void 0, false);
        }
      });
      pointsToAdd.length = 0;
    } else {
      succeeded = false;
    }
    oldData.forEach((point2) => {
      if (point2) {
        point2.touched = false;
      }
    });
    if (!succeeded) {
      return false;
    }
    pointsToAdd.forEach((point2) => {
      this.addPoint(point2, false, void 0, void 0, false);
    }, this);
    const xData = this.getColumn("x");
    if (this.xIncrement === null && xData.length) {
      this.xIncrement = arrayMax$8(xData);
      this.autoIncrement();
    }
    return true;
  }
  dataColumnKeys() {
    return ["x", ...this.pointArrayMap || ["y"]];
  }
  /**
   * Apply a new set of data to the series and optionally redraw it. The
   * new data array is passed by reference (except in case of
   * `updatePoints`), and may later be mutated when updating the chart
   * data.
   *
   * Note the difference in behaviour when setting the same amount of
   * points, or a different amount of points, as handled by the
   * `updatePoints` parameter.
   *
   * @sample highcharts/members/series-setdata/
   *         Set new data from a button
   * @sample highcharts/members/series-setdata-pie/
   *         Set data in a pie
   * @sample stock/members/series-setdata/
   *         Set new data in Highcharts Stock
   * @sample maps/members/series-setdata/
   *         Set new data in Highmaps
   *
   * @function Highcharts.Series#setData
   *
   * @param {Array<Highcharts.PointOptionsType>} data
   *        Takes an array of data in the same format as described under
   *        `series.{type}.data` for the given series type, for example a
   *        line series would take data in the form described under
   *        [series.line.data](https://api.highcharts.com/highcharts/series.line.data).
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after the series is altered. If
   *        doing more operations on the chart, it is a good idea to set
   *        redraw to false and call {@link Chart#redraw} after.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        When the updated data is the same length as the existing data,
   *        points will be updated by default, and animation visualizes
   *        how the points are changed. Set false to disable animation, or
   *        a configuration object to set duration or easing.
   *
   * @param {boolean} [updatePoints=true]
   *        When this is true, points will be updated instead of replaced
   *        whenever possible. This occurs a) when the updated data is the
   *        same length as the existing data, b) when points are matched
   *        by their id's, or c) when points can be matched by X values.
   *        This allows updating with animation and performs better. In
   *        this case, the original array is not passed by reference. Set
   *        `false` to prevent.
   */
  setData(data, redraw = true, animation, updatePoints2) {
    const series = this, oldData = series.points, oldDataLength = oldData?.length || 0, options2 = series.options, chart = series.chart, dataSorting = options2.dataSorting, xAxis2 = series.xAxis, turboThreshold = options2.turboThreshold, table = this.dataTable, dataColumnKeys = this.dataColumnKeys(), pointValKey = series.pointValKey || "y", pointArrayMap = series.pointArrayMap || [], valueCount = pointArrayMap.length, keys = options2.keys;
    let i, updatedData, indexOfX = 0, indexOfY = 1, copiedData;
    if (!chart.options.chart.allowMutatingData) {
      if (options2.data) {
        delete series.options.data;
      }
      if (series.userOptions.data) {
        delete series.userOptions.data;
      }
      copiedData = merge$1v(true, data);
    }
    data = copiedData || data || [];
    const dataLength = data.length;
    if (dataSorting?.enabled) {
      data = this.sortData(data);
    }
    if (chart.options.chart.allowMutatingData && updatePoints2 !== false && dataLength && oldDataLength && !series.cropped && !series.hasGroupedData && series.visible && // Soft updating has no benefit in boost, and causes JS error
    // (#8355)
    !series.boosted) {
      updatedData = this.updateData(data, animation);
    }
    if (!updatedData) {
      series.xIncrement = null;
      series.colorCounter = 0;
      let runTurbo = turboThreshold && dataLength > turboThreshold;
      if (runTurbo) {
        const firstPoint = series.getFirstValidPoint(data), lastPoint = series.getFirstValidPoint(data, dataLength - 1, -1), isShortArray = (a) => Boolean(isArray$k(a) && (keys || isNumber$Y(a[0])));
        if (isNumber$Y(firstPoint) && isNumber$Y(lastPoint)) {
          const x = [], valueData = [];
          for (const value of data) {
            x.push(this.autoIncrement());
            valueData.push(value);
          }
          table.setColumns({
            x,
            [pointValKey]: valueData
          });
        } else if (isShortArray(firstPoint) && isShortArray(lastPoint)) {
          if (valueCount) {
            const autoX = firstPoint.length === valueCount ? 1 : 0, colArray = new Array(dataColumnKeys.length).fill(0).map(() => []);
            for (const pt of data) {
              if (autoX) {
                colArray[0].push(this.autoIncrement());
              }
              for (let j = autoX; j <= valueCount; j++) {
                colArray[j]?.push(pt[j - autoX]);
              }
            }
            table.setColumns(dataColumnKeys.reduce((columns, columnName, i2) => {
              columns[columnName] = colArray[i2];
              return columns;
            }, {}));
          } else {
            if (keys) {
              indexOfX = keys.indexOf("x");
              indexOfY = keys.indexOf("y");
              indexOfX = indexOfX >= 0 ? indexOfX : 0;
              indexOfY = indexOfY >= 0 ? indexOfY : 1;
            }
            if (firstPoint.length === 1) {
              indexOfY = 0;
            }
            const xData = [], valueData = [];
            if (indexOfX === indexOfY) {
              for (const pt of data) {
                xData.push(this.autoIncrement());
                valueData.push(pt[indexOfY]);
              }
            } else {
              for (const pt of data) {
                xData.push(pt[indexOfX]);
                valueData.push(pt[indexOfY]);
              }
            }
            table.setColumns({
              x: xData,
              [pointValKey]: valueData
            });
          }
        } else {
          runTurbo = false;
        }
      }
      if (!runTurbo) {
        const columns = dataColumnKeys.reduce((columns2, columnName) => {
          columns2[columnName] = [];
          return columns2;
        }, {});
        for (i = 0; i < dataLength; i++) {
          const pt = series.pointClass.prototype.applyOptions.apply({ series }, [data[i]]);
          for (const key2 of dataColumnKeys) {
            columns[key2][i] = pt[key2];
          }
        }
        table.setColumns(columns);
      }
      if (isString$b(this.getColumn("y")[0])) {
        error$7(14, true, chart);
      }
      series.data = [];
      series.options.data = series.userOptions.data = data;
      i = oldDataLength;
      while (i--) {
        oldData[i]?.destroy();
      }
      if (xAxis2) {
        xAxis2.minRange = xAxis2.userMinRange;
      }
      series.isDirty = chart.isDirtyBox = true;
      series.isDirtyData = !!oldData;
      animation = false;
    }
    if (options2.legendType === "point") {
      this.processData();
      this.generatePoints();
    }
    if (redraw) {
      chart.redraw(animation);
    }
  }
  /**
   * Internal function to sort series data
   *
   * @private
   * @function Highcharts.Series#sortData
   * @param {Array<Highcharts.PointOptionsType>} data
   * Force data grouping.
   */
  sortData(data) {
    const series = this, options2 = series.options, dataSorting = options2.dataSorting, sortKey = dataSorting.sortKey || "y", getPointOptionsObject = function(series2, pointOptions) {
      return defined$14(pointOptions) && series2.pointClass.prototype.optionsToObject.call({
        series: series2
      }, pointOptions) || {};
    };
    data.forEach(function(pointOptions, i) {
      data[i] = getPointOptionsObject(series, pointOptions);
      data[i].index = i;
    }, this);
    const sortedData = data.concat().sort((a, b) => {
      const aValue = getNestedProperty$1(sortKey, a);
      const bValue = getNestedProperty$1(sortKey, b);
      return bValue < aValue ? -1 : bValue > aValue ? 1 : 0;
    });
    sortedData.forEach(function(point, i) {
      point.x = i;
    }, this);
    if (series.linkedSeries) {
      series.linkedSeries.forEach(function(linkedSeries) {
        const options3 = linkedSeries.options, seriesData = options3.data;
        if (!options3.dataSorting?.enabled && seriesData) {
          seriesData.forEach(function(pointOptions, i) {
            seriesData[i] = getPointOptionsObject(linkedSeries, pointOptions);
            if (data[i]) {
              seriesData[i].x = data[i].x;
              seriesData[i].index = i;
            }
          });
          linkedSeries.setData(seriesData, false);
        }
      });
    }
    return data;
  }
  /**
   * Internal function to process the data by cropping away unused data
   * points if the series is longer than the crop threshold. This saves
   * computing time for large series.
   *
   * @private
   * @function Highcharts.Series#getProcessedData
   * @param {boolean} [forceExtremesFromAll]
   * Force getting extremes of a total series data range.
   */
  getProcessedData(forceExtremesFromAll) {
    const series = this, { dataTable: table, isCartesian, options: options2, xAxis: xAxis2 } = series, cropThreshold = options2.cropThreshold, getExtremesFromAll = forceExtremesFromAll || // X-range series etc, #21003
    series.getExtremesFromAll, logarithmic = xAxis2?.logarithmic, dataLength = table.rowCount;
    let croppedData, cropped, cropStart = 0, xExtremes, min2, max2, xData = series.getColumn("x"), modified = table, updatingNames = false;
    if (xAxis2) {
      xExtremes = xAxis2.getExtremes();
      min2 = xExtremes.min;
      max2 = xExtremes.max;
      updatingNames = !!(xAxis2.categories && !xAxis2.names.length);
      if (isCartesian && series.sorted && !getExtremesFromAll && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
        if (xData[dataLength - 1] < min2 || xData[0] > max2) {
          modified = new DataTableCore();
        } else if (
          // Don't understand why this condition is needed
          series.getColumn(series.pointValKey || "y").length && (xData[0] < min2 || xData[dataLength - 1] > max2)
        ) {
          croppedData = this.cropData(table, min2, max2);
          modified = croppedData.modified;
          cropStart = croppedData.start;
          cropped = true;
        }
      }
    }
    xData = modified.getColumn("x") || [];
    const closestPointRange = getClosestDistance(
      [
        logarithmic ? xData.map(logarithmic.log2lin) : xData
      ],
      // Unsorted data is not supported by the line tooltip, as well as
      // data grouping and navigation in Stock charts (#725) and width
      // calculation of columns (#1900). Avoid warning during the
      // premature processing pass in updateNames (#16104).
      () => series.requireSorting && !updatingNames && error$7(15, false, series.chart)
    );
    return {
      modified,
      cropped,
      cropStart,
      closestPointRange
    };
  }
  /**
   * Internal function to apply processed data.
   * In Highcharts Stock, this function is extended to provide data grouping.
   *
   * @private
   * @function Highcharts.Series#processData
   * @param {boolean} [force]
   * Force data grouping.
   */
  processData(force) {
    const series = this, xAxis2 = series.xAxis, table = series.dataTable;
    if (series.isCartesian && !series.isDirty && !xAxis2.isDirty && !series.yAxis.isDirty && !force) {
      return false;
    }
    const processedData = series.getProcessedData();
    table.modified = processedData.modified;
    series.cropped = processedData.cropped;
    series.cropStart = processedData.cropStart;
    series.closestPointRange = series.basePointRange = processedData.closestPointRange;
    fireEvent$C(series, "afterProcessData");
  }
  /**
   * Iterate over xData and crop values between min and max. Returns
   * object containing crop start/end cropped xData with corresponding
   * part of yData, dataMin and dataMax within the cropped range.
   *
   * @private
   * @function Highcharts.Series#cropData
   */
  cropData(table, min2, max2) {
    const xData = table.getColumn("x", true) || [], dataLength = xData.length, columns = {};
    let i, j, start2 = 0, end = dataLength;
    for (i = 0; i < dataLength; i++) {
      if (xData[i] >= min2) {
        start2 = Math.max(0, i - 1);
        break;
      }
    }
    for (j = i; j < dataLength; j++) {
      if (xData[j] > max2) {
        end = j + 1;
        break;
      }
    }
    for (const key2 of this.dataColumnKeys()) {
      const column2 = table.getColumn(key2, true);
      if (column2) {
        columns[key2] = column2.slice(start2, end);
      }
    }
    return {
      modified: new DataTableCore({ columns }),
      start: start2,
      end
    };
  }
  /**
   * Generate the data point after the data has been processed by cropping
   * away unused points and optionally grouped in Highcharts Stock.
   *
   * @private
   * @function Highcharts.Series#generatePoints
   */
  generatePoints() {
    const series = this, options2 = series.options, dataOptions = series.processedData || options2.data, table = series.dataTable.modified, xData = series.getColumn("x", true), PointClass = series.pointClass, processedDataLength = table.rowCount, cropStart = series.cropStart || 0, hasGroupedData = series.hasGroupedData, keys = options2.keys, points = [], groupCropStartIndex = options2.dataGrouping?.groupAll ? cropStart : 0, categories = series.xAxis?.categories, pointArrayMap = series.pointArrayMap || ["y"], dataColumnKeys = this.dataColumnKeys();
    let dataLength, cursor, point, i, data = series.data, pOptions;
    if (!data && !hasGroupedData) {
      const arr = [];
      arr.length = dataOptions?.length || 0;
      data = series.data = arr;
    }
    if (keys && hasGroupedData) {
      series.options.keys = false;
    }
    for (i = 0; i < processedDataLength; i++) {
      cursor = cropStart + i;
      if (!hasGroupedData) {
        point = data[cursor];
        pOptions = dataOptions ? dataOptions[cursor] : table.getRow(i, pointArrayMap);
        if (!point && pOptions !== void 0) {
          data[cursor] = point = new PointClass(series, pOptions, xData[i]);
        }
      } else {
        point = new PointClass(series, table.getRow(i, dataColumnKeys) || []);
        point.dataGroup = series.groupMap[groupCropStartIndex + i];
        if (point.dataGroup?.options) {
          point.options = point.dataGroup.options;
          extend$1d(point, point.dataGroup.options);
          delete point.dataLabels;
        }
      }
      if (point) {
        point.index = hasGroupedData ? groupCropStartIndex + i : cursor;
        points[i] = point;
        point.category = categories?.[point.x] ?? point.x;
        point.key = point.name ?? point.category;
      }
    }
    series.options.keys = keys;
    if (data && (processedDataLength !== (dataLength = data.length) || hasGroupedData)) {
      for (i = 0; i < dataLength; i++) {
        if (i === cropStart && !hasGroupedData) {
          i += processedDataLength;
        }
        if (data[i]) {
          data[i].destroyElements();
          data[i].plotX = void 0;
        }
      }
    }
    series.data = data;
    series.points = points;
    fireEvent$C(this, "afterGeneratePoints");
  }
  /**
   * Get current X extremes for the visible data.
   *
   * @private
   * @function Highcharts.Series#getXExtremes
   * @param {Array<number>} xData
   * The data to inspect. Defaults to the current data within the visible
   * range.
   */
  getXExtremes(xData) {
    return {
      min: arrayMin$6(xData),
      max: arrayMax$8(xData)
    };
  }
  /**
   * Calculate Y extremes for the visible data. The result is returned
   * as an object with `dataMin` and `dataMax` properties.
   *
   * @private
   * @function Highcharts.Series#getExtremes
   * @param {Array<number>} [yData]
   * The data to inspect. Defaults to the current data within the visible
   * range.
   * @param {boolean} [forceExtremesFromAll]
   * Force getting extremes of a total series data range.
   */
  getExtremes(yData, forceExtremesFromAll) {
    const { xAxis: xAxis2, yAxis: yAxis2 } = this, getExtremesFromAll = forceExtremesFromAll || this.getExtremesFromAll || this.options.getExtremesFromAll, table = getExtremesFromAll && this.cropped ? this.dataTable : this.dataTable.modified, rowCount = table.rowCount, customData = yData || this.stackedYData, yAxisData = customData ? [customData] : (this.keysAffectYAxis || this.pointArrayMap || ["y"])?.map((key2) => table.getColumn(key2, true) || []) || [], xData = this.getColumn("x", true), activeYData = [], shoulder = this.requireSorting && !this.is("column") ? 1 : 0, positiveValuesOnly = yAxis2 ? yAxis2.positiveValuesOnly : false, doAll = getExtremesFromAll || this.cropped || !xAxis2;
    let xExtremes, x, i, xMin = 0, xMax = 0;
    if (xAxis2) {
      xExtremes = xAxis2.getExtremes();
      xMin = xExtremes.min;
      xMax = xExtremes.max;
    }
    for (i = 0; i < rowCount; i++) {
      x = xData[i];
      if (doAll || (xData[i + shoulder] || x) >= xMin && (xData[i - shoulder] || x) <= xMax) {
        for (const values of yAxisData) {
          const val = values[i];
          if (isNumber$Y(val) && (val > 0 || !positiveValuesOnly)) {
            activeYData.push(val);
          }
        }
      }
    }
    const dataExtremes = {
      activeYData,
      // Needed for Stock Cumulative Sum
      dataMin: arrayMin$6(activeYData),
      dataMax: arrayMax$8(activeYData)
    };
    fireEvent$C(this, "afterGetExtremes", { dataExtremes });
    return dataExtremes;
  }
  /**
   * Set the current data extremes as `dataMin` and `dataMax` on the
   * Series item. Use this only when the series properties should be
   * updated.
   *
   * @private
   * @function Highcharts.Series#applyExtremes
   */
  applyExtremes() {
    const dataExtremes = this.getExtremes();
    this.dataMin = dataExtremes.dataMin;
    this.dataMax = dataExtremes.dataMax;
    return dataExtremes;
  }
  /**
   * Find and return the first non nullish point in the data
   *
   * @private
   * @function Highcharts.Series.getFirstValidPoint
   * @param {Array<Highcharts.PointOptionsType>} data
   *        Array of options for points
   * @param {number} [start=0]
   *        Index to start searching from
   * @param {number} [increment=1]
   *        Index increment, set -1 to search backwards
   */
  getFirstValidPoint(data, start2 = 0, increment = 1) {
    const dataLength = data.length;
    let i = start2;
    while (i >= 0 && i < dataLength) {
      if (defined$14(data[i])) {
        return data[i];
      }
      i += increment;
    }
  }
  /**
   * Translate data points from raw data values to chart specific
   * positioning data needed later in the `drawPoints` and `drawGraph`
   * functions. This function can be overridden in plugins and custom
   * series type implementations.
   *
   * @function Highcharts.Series#translate
   *
   * @emits Highcharts.Series#events:translate
   */
  translate() {
    this.generatePoints();
    const series = this, options2 = series.options, stacking = options2.stacking, xAxis2 = series.xAxis, enabledDataSorting = series.enabledDataSorting, yAxis2 = series.yAxis, points = series.points, dataLength = points.length, pointPlacement = series.pointPlacementToXValue(), dynamicallyPlaced = Boolean(pointPlacement), threshold = options2.threshold, stackThreshold = options2.startFromThreshold ? threshold : 0, nullYSubstitute = options2?.nullInteraction && yAxis2.len;
    let i, plotX, lastPlotX, stackIndicator, closestPointRangePx = Number.MAX_VALUE;
    function limitedRange(val) {
      return clamp$j(val, -1e9, 1e9);
    }
    for (i = 0; i < dataLength; i++) {
      const point = points[i], xValue = point.x;
      let stackItem, stackValues, yValue = point.y, lowValue = point.low;
      const stacks = stacking && yAxis2.stacking?.stacks[(series.negStacks && yValue < (stackThreshold ? 0 : threshold) ? "-" : "") + series.stackKey];
      plotX = xAxis2.translate(
        // #3923
        xValue,
        false,
        false,
        false,
        true,
        pointPlacement
      );
      point.plotX = isNumber$Y(plotX) ? correctFloat$d(
        // #5236
        limitedRange(plotX)
        // #3923
      ) : void 0;
      if (stacking && series.visible && stacks && stacks[xValue]) {
        stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
        if (!point.isNull && stackIndicator.key) {
          stackItem = stacks[xValue];
          stackValues = stackItem.points[stackIndicator.key];
        }
        if (stackItem && isArray$k(stackValues)) {
          lowValue = stackValues[0];
          yValue = stackValues[1];
          if (lowValue === stackThreshold && stackIndicator.key === stacks[xValue].base) {
            lowValue = pick$1B(isNumber$Y(threshold) ? threshold : yAxis2.min);
          }
          if (yAxis2.positiveValuesOnly && defined$14(lowValue) && lowValue <= 0) {
            lowValue = void 0;
          }
          point.total = point.stackTotal = pick$1B(stackItem.total);
          point.percentage = defined$14(point.y) && stackItem.total ? point.y / stackItem.total * 100 : void 0;
          point.stackY = yValue;
          if (!series.irregularWidths) {
            stackItem.setOffset(series.pointXOffset || 0, series.barW || 0, void 0, void 0, void 0, series.xAxis);
          }
        }
      }
      point.yBottom = defined$14(lowValue) ? limitedRange(yAxis2.translate(lowValue, false, true, false, true)) : void 0;
      if (series.dataModify) {
        yValue = series.dataModify.modifyValue(yValue, i);
      }
      let plotY;
      if (isNumber$Y(yValue) && point.plotX !== void 0) {
        plotY = yAxis2.translate(yValue, false, true, false, true);
        plotY = isNumber$Y(plotY) ? limitedRange(plotY) : void 0;
      } else if (!isNumber$Y(yValue) && nullYSubstitute) {
        plotY = nullYSubstitute;
      }
      point.plotY = plotY;
      point.isInside = this.isPointInside(point);
      point.clientX = dynamicallyPlaced ? correctFloat$d(xAxis2.translate(xValue, false, false, false, true, pointPlacement)) : plotX;
      point.negative = (point.y || 0) < (threshold || 0);
      if (!point.isNull && point.visible !== false) {
        if (typeof lastPlotX !== "undefined") {
          closestPointRangePx = Math.min(closestPointRangePx, Math.abs(plotX - lastPlotX));
        }
        lastPlotX = plotX;
      }
      point.zone = this.zones.length ? point.getZone() : void 0;
      if (!point.graphic && series.group && enabledDataSorting) {
        point.isNew = true;
      }
    }
    series.closestPointRangePx = closestPointRangePx;
    fireEvent$C(this, "afterTranslate");
  }
  /**
   * Return the series points with null points filtered out.
   *
   * @function Highcharts.Series#getValidPoints
   *
   * @param {Array<Highcharts.Point>} [points]
   * The points to inspect, defaults to {@link Series.points}.
   *
   * @param {boolean} [insideOnly=false]
   * Whether to inspect only the points that are inside the visible view.
   *
   * @param {boolean} [allowNull=false]
   * Whether to allow null points to pass as valid points.
   *
   * @return {Array<Highcharts.Point>}
   * The valid points.
   */
  getValidPoints(points, insideOnly, allowNull) {
    const chart = this.chart;
    return (points || this.points || []).filter(function(point) {
      const { plotX, plotY } = point, asNull = !allowNull && (point.isNull || !isNumber$Y(plotY));
      if (asNull || insideOnly && !chart.isInsidePlot(plotX, plotY, { inverted: chart.inverted })) {
        return false;
      }
      return point.visible !== false;
    });
  }
  /**
   * Get the shared clip key, creating it if it doesn't exist.
   *
   * @private
   * @function Highcharts.Series#getSharedClipKey
   */
  getSharedClipKey() {
    this.sharedClipKey = (this.options.xAxis || 0) + "," + (this.options.yAxis || 0);
    return this.sharedClipKey;
  }
  /**
   * Set the clipping for the series. For animated series the clip is later
   * modified.
   *
   * @private
   * @function Highcharts.Series#setClip
   */
  setClip() {
    const { chart, group: group2, markerGroup } = this, sharedClips = chart.sharedClips, renderer = chart.renderer, clipBox = chart.getClipBox(this), sharedClipKey = this.getSharedClipKey();
    let clipRect = sharedClips[sharedClipKey];
    if (!clipRect) {
      sharedClips[sharedClipKey] = clipRect = renderer.clipRect(clipBox);
    } else {
      clipRect.animate(clipBox);
    }
    if (group2) {
      group2.clip(this.options.clip === false ? void 0 : clipRect);
    }
    if (markerGroup) {
      markerGroup.clip();
    }
  }
  /**
   * Animate in the series. Called internally twice. First with the `init`
   * parameter set to true, which sets up the initial state of the
   * animation. Then when ready, it is called with the `init` parameter
   * undefined, in order to perform the actual animation.
   *
   * @function Highcharts.Series#animate
   *
   * @param {boolean} [init]
   * Initialize the animation.
   */
  animate(init2) {
    const { chart, group: group2, markerGroup } = this, inverted = chart.inverted, animation = animObject$b(this.options.animation), animationClipKey = [
      this.getSharedClipKey(),
      animation.duration,
      animation.easing,
      animation.defer
    ].join(",");
    let animationClipRect = chart.sharedClips[animationClipKey], markerAnimationClipRect = chart.sharedClips[animationClipKey + "m"];
    if (init2 && group2) {
      const clipBox = chart.getClipBox(this);
      if (!animationClipRect) {
        clipBox.width = 0;
        if (inverted) {
          clipBox.x = chart.plotHeight;
        }
        animationClipRect = chart.renderer.clipRect(clipBox);
        chart.sharedClips[animationClipKey] = animationClipRect;
        const markerClipBox = {
          x: inverted ? -99 : -99,
          y: inverted ? -99 : -99,
          width: inverted ? chart.plotWidth + 199 : 99,
          height: inverted ? 99 : chart.plotHeight + 199
        };
        markerAnimationClipRect = chart.renderer.clipRect(markerClipBox);
        chart.sharedClips[animationClipKey + "m"] = markerAnimationClipRect;
      } else {
        animationClipRect.attr("height", clipBox.height);
      }
      group2.clip(animationClipRect);
      markerGroup?.clip(markerAnimationClipRect);
    } else if (animationClipRect && // Only first series in this pane
    !animationClipRect.hasClass("highcharts-animating")) {
      const finalBox = chart.getClipBox(this), step = animation.step;
      if (markerGroup?.element.childNodes.length || chart.series.length > 1) {
        animation.step = function(val, fx) {
          if (step) {
            step.apply(fx, arguments);
          }
          if (fx.prop === "width" && markerAnimationClipRect?.element) {
            markerAnimationClipRect.attr(inverted ? "height" : "width", val + 99);
          }
        };
      }
      animationClipRect.addClass("highcharts-animating").animate(finalBox, animation);
    }
  }
  /**
   * This runs after animation to land on the final plot clipping.
   *
   * @private
   * @function Highcharts.Series#afterAnimate
   *
   * @emits Highcharts.Series#event:afterAnimate
   */
  afterAnimate() {
    this.setClip();
    objectEach$m(this.chart.sharedClips, (clip, key2, sharedClips) => {
      if (clip && !this.chart.container.querySelector(`[clip-path="url(#${clip.id})"]`)) {
        clip.destroy();
        delete sharedClips[key2];
      }
    });
    this.finishedAnimating = true;
    fireEvent$C(this, "afterAnimate");
  }
  /**
   * Draw the markers for line-like series types, and columns or other
   * graphical representation for {@link Point} objects for other series
   * types. The resulting element is typically stored as
   * {@link Point.graphic}, and is created on the first call and updated
   * and moved on subsequent calls.
   *
   * @function Highcharts.Series#drawPoints
   */
  drawPoints(points = this.points) {
    const series = this, chart = series.chart, styledMode = chart.styledMode, { colorAxis, options: options2 } = series, seriesMarkerOptions = options2.marker, nullInteraction = options2.nullInteraction, markerGroup = series[series.specialGroup || "markerGroup"], xAxis2 = series.xAxis, globallyEnabled = pick$1B(
      seriesMarkerOptions.enabled,
      !xAxis2 || xAxis2.isRadial ? true : null,
      // Use larger or equal as radius is null in bubbles (#6321)
      series.closestPointRangePx >= seriesMarkerOptions.enabledThreshold * seriesMarkerOptions.radius
    );
    let i, point, graphic, verb, pointMarkerOptions, hasPointMarker, markerAttribs;
    if (seriesMarkerOptions.enabled !== false || series._hasPointMarkers) {
      for (i = 0; i < points.length; i++) {
        point = points[i];
        graphic = point.graphic;
        verb = graphic ? "animate" : "attr";
        pointMarkerOptions = point.marker || {};
        hasPointMarker = !!point.marker;
        const isNull = point.isNull, shouldDrawMarker = (globallyEnabled && !defined$14(pointMarkerOptions.enabled) || pointMarkerOptions.enabled) && (!isNull || nullInteraction) && point.visible !== false;
        if (shouldDrawMarker) {
          const symbol = pick$1B(pointMarkerOptions.symbol, series.symbol, "rect");
          markerAttribs = series.markerAttribs(point, point.selected && "select");
          if (series.enabledDataSorting) {
            point.startXPos = xAxis2.reversed ? -(markerAttribs.width || 0) : xAxis2.width;
          }
          const isInside = point.isInside !== false;
          if (!graphic && isInside && ((markerAttribs.width || 0) > 0 || point.hasImage)) {
            point.graphic = graphic = chart.renderer.symbol(symbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height, hasPointMarker ? pointMarkerOptions : seriesMarkerOptions).add(markerGroup);
            if (series.enabledDataSorting && chart.hasRendered) {
              graphic.attr({
                x: point.startXPos
              });
              verb = "animate";
            }
          }
          if (graphic && verb === "animate") {
            graphic[isInside ? "show" : "hide"](isInside).animate(markerAttribs);
          }
          if (graphic) {
            const pointAttr = series.pointAttribs(point, styledMode || !point.selected ? void 0 : "select");
            if (!styledMode) {
              graphic[verb](pointAttr);
            } else if (colorAxis) {
              graphic["css"]({
                fill: pointAttr.fill
              });
            }
          }
          if (graphic) {
            graphic.addClass(point.getClassName(), true);
          }
        } else if (graphic) {
          point.graphic = graphic.destroy();
        }
      }
    }
  }
  /**
   * Get non-presentational attributes for a point. Used internally for
   * both styled mode and classic. Can be overridden for different series
   * types.
   *
   * @see Series#pointAttribs
   *
   * @function Highcharts.Series#markerAttribs
   *
   * @param {Highcharts.Point} point
   * The Point to inspect.
   *
   * @param {string} [state]
   * The state, can be either `hover`, `select` or undefined.
   *
   * @return {Highcharts.SVGAttributes}
   * A hash containing those attributes that are not settable from CSS.
   */
  markerAttribs(point, state) {
    const seriesOptions = this.options, seriesMarkerOptions = seriesOptions.marker, pointMarkerOptions = point.marker || {}, symbol = pointMarkerOptions.symbol || seriesMarkerOptions.symbol, attribs = {};
    let seriesStateOptions, pointStateOptions, radius = pick$1B(pointMarkerOptions.radius, seriesMarkerOptions?.radius);
    if (state) {
      seriesStateOptions = seriesMarkerOptions.states[state];
      pointStateOptions = pointMarkerOptions.states && pointMarkerOptions.states[state];
      radius = pick$1B(pointStateOptions?.radius, seriesStateOptions?.radius, radius && radius + (seriesStateOptions?.radiusPlus || 0));
    }
    point.hasImage = symbol && symbol.indexOf("url") === 0;
    if (point.hasImage) {
      radius = 0;
    }
    const pos = point.pos();
    if (isNumber$Y(radius) && pos) {
      if (seriesOptions.crisp) {
        pos[0] = crisp$c(pos[0], point.hasImage ? 0 : symbol === "rect" ? (
          // Rectangle symbols need crisp edges, others don't
          seriesMarkerOptions?.lineWidth || 0
        ) : 1);
      }
      attribs.x = pos[0] - radius;
      attribs.y = pos[1] - radius;
    }
    if (radius) {
      attribs.width = attribs.height = 2 * radius;
    }
    return attribs;
  }
  /**
   * Internal function to get presentational attributes for each point.
   * Unlike {@link Series#markerAttribs}, this function should return
   * those attributes that can also be set in CSS. In styled mode,
   * `pointAttribs` won't be called.
   *
   * @private
   * @function Highcharts.Series#pointAttribs
   *
   * @param {Highcharts.Point} [point]
   * The point instance to inspect.
   *
   * @param {string} [state]
   * The point state, can be either `hover`, `select` or 'normal'. If
   * undefined, normal state is assumed.
   *
   * @return {Highcharts.SVGAttributes}
   * The presentational attributes to be set on the point.
   */
  pointAttribs(point, state) {
    const options2 = this.options, seriesMarkerOptions = options2.marker, pointOptions = point?.options, pointMarkerOptions = pointOptions?.marker || {}, pointColorOption = pointOptions?.color, pointColor = point?.color, zoneColor = point?.zone?.color;
    let seriesStateOptions, pointStateOptions, color2 = this.color, fill, stroke, strokeWidth = pick$1B(pointMarkerOptions.lineWidth, seriesMarkerOptions.lineWidth), opacity = point?.isNull && options2.nullInteraction ? 0 : 1;
    color2 = pointColorOption || zoneColor || pointColor || color2;
    fill = pointMarkerOptions.fillColor || seriesMarkerOptions.fillColor || color2;
    stroke = pointMarkerOptions.lineColor || seriesMarkerOptions.lineColor || color2;
    state = state || "normal";
    if (state) {
      seriesStateOptions = seriesMarkerOptions.states[state] || {};
      pointStateOptions = pointMarkerOptions.states && pointMarkerOptions.states[state] || {};
      strokeWidth = pick$1B(pointStateOptions.lineWidth, seriesStateOptions.lineWidth, strokeWidth + pick$1B(pointStateOptions.lineWidthPlus, seriesStateOptions.lineWidthPlus, 0));
      fill = pointStateOptions.fillColor || seriesStateOptions.fillColor || fill;
      stroke = pointStateOptions.lineColor || seriesStateOptions.lineColor || stroke;
      opacity = pick$1B(pointStateOptions.opacity, seriesStateOptions.opacity, opacity);
    }
    return {
      "stroke": stroke,
      "stroke-width": strokeWidth,
      "fill": fill,
      "opacity": opacity
    };
  }
  /**
   * Clear DOM objects and free up memory.
   *
   * @private
   * @function Highcharts.Series#destroy
   *
   * @emits Highcharts.Series#event:destroy
   */
  destroy(keepEventsForUpdate) {
    const series = this, chart = series.chart, issue134 = /AppleWebKit\/533/.test(win$9.navigator.userAgent), data = series.data || [];
    let destroy, i, axis;
    fireEvent$C(series, "destroy", { keepEventsForUpdate });
    this.removeEvents(keepEventsForUpdate);
    (series.axisTypes || []).forEach(function(AXIS) {
      axis = series[AXIS];
      if (axis?.series) {
        erase$6(axis.series, series);
        axis.isDirty = axis.forceRedraw = true;
      }
    });
    if (series.legendItem) {
      series.chart.legend.destroyItem(series);
    }
    i = data.length;
    while (i--) {
      data[i]?.destroy?.();
    }
    for (const zone of series.zones) {
      destroyObjectProperties$6(zone, void 0, true);
    }
    Utilities.clearTimeout(series.animationTimeout);
    objectEach$m(series, function(val, prop) {
      if (val instanceof SVGElement$1 && !val.survive) {
        destroy = issue134 && prop === "group" ? "hide" : "destroy";
        val[destroy]();
      }
    });
    if (chart.hoverSeries === series) {
      chart.hoverSeries = void 0;
    }
    erase$6(chart.series, series);
    chart.orderItems("series");
    objectEach$m(series, function(val, prop) {
      if (!keepEventsForUpdate || prop !== "hcEvents") {
        delete series[prop];
      }
    });
  }
  /**
   * Clip the graphs into zones for colors and styling.
   *
   * @private
   * @function Highcharts.Series#applyZones
   */
  applyZones() {
    const series = this, { area, chart, graph, zones, points, xAxis: xAxis2, yAxis: yAxis2, zoneAxis } = series, { inverted, renderer } = chart, axis = this[`${zoneAxis}Axis`], { isXAxis, len = 0, minPointOffset = 0 } = axis || {}, halfWidth = (graph?.strokeWidth() || 0) / 2 + 1, avoidClose = (zone, plotX = 0, plotY = 0) => {
      if (inverted) {
        plotY = len - plotY;
      }
      const { translated = 0, lineClip } = zone, distance = plotY - translated;
      lineClip?.push([
        "L",
        plotX,
        Math.abs(distance) < halfWidth ? plotY - halfWidth * (distance <= 0 ? -1 : 1) : translated
      ]);
    };
    if (zones.length && (graph || area) && axis && isNumber$Y(axis.min)) {
      const axisMax2 = axis.getExtremes().max + minPointOffset, invertPath = (path) => {
        path.forEach((segment, i) => {
          if (segment[0] === "M" || segment[0] === "L") {
            path[i] = [
              segment[0],
              isXAxis ? len - segment[1] : segment[1],
              isXAxis ? segment[2] : len - segment[2]
            ];
          }
        });
      };
      zones.forEach((zone) => {
        zone.lineClip = [];
        zone.translated = clamp$j(axis.toPixels(pick$1B(zone.value, axisMax2), true) || 0, 0, len);
      });
      if (graph && !this.showLine) {
        graph.hide();
      }
      if (area) {
        area.hide();
      }
      if (zoneAxis === "y" && // Overheat protection
      points.length < xAxis2.len) {
        for (const point of points) {
          const { plotX, plotY, zone } = point, zoneBelow = zone && zones[zones.indexOf(zone) - 1];
          if (zone) {
            avoidClose(zone, plotX, plotY);
          }
          if (zoneBelow) {
            avoidClose(zoneBelow, plotX, plotY);
          }
        }
      }
      let lastLineClip = [], lastTranslated = axis.toPixels(axis.getExtremes().min - minPointOffset, true);
      zones.forEach((zone) => {
        const lineClip = zone.lineClip || [], translated = Math.round(zone.translated || 0);
        if (xAxis2.reversed) {
          lineClip.reverse();
        }
        let { clip, simpleClip } = zone, x1 = 0, y1 = 0, x2 = xAxis2.len, y2 = yAxis2.len;
        if (isXAxis) {
          x1 = translated;
          x2 = lastTranslated;
        } else {
          y1 = translated;
          y2 = lastTranslated;
        }
        const simplePath = [
          ["M", x1, y1],
          ["L", x2, y1],
          ["L", x2, y2],
          ["L", x1, y2],
          ["Z"]
        ], adaptivePath = [
          simplePath[0],
          ...lineClip,
          simplePath[1],
          simplePath[2],
          ...lastLineClip,
          simplePath[3],
          simplePath[4]
        ];
        lastLineClip = lineClip.reverse();
        lastTranslated = translated;
        if (inverted) {
          invertPath(adaptivePath);
          if (area) {
            invertPath(simplePath);
          }
        }
        if (clip) {
          clip.animate({ d: adaptivePath });
          simpleClip?.animate({ d: simplePath });
        } else {
          clip = zone.clip = renderer.path(adaptivePath);
          if (area) {
            simpleClip = zone.simpleClip = renderer.path(simplePath);
          }
        }
        if (graph) {
          zone.graph?.clip(clip);
        }
        if (area) {
          zone.area?.clip(simpleClip);
        }
      });
    } else if (series.visible) {
      if (graph) {
        graph.show();
      }
      if (area) {
        area.show();
      }
    }
  }
  /**
   * General abstraction for creating plot groups like series.group,
   * series.dataLabelsGroup and series.markerGroup. On subsequent calls,
   * the group will only be adjusted to the updated plot size.
   *
   * @private
   * @function Highcharts.Series#plotGroup
   */
  plotGroup(prop, name, visibility, zIndex, parent) {
    let group2 = this[prop];
    const isNew = !group2, attrs = {
      visibility,
      zIndex: zIndex || 0.1
      // Pointer logic uses this
    };
    if (defined$14(this.opacity) && !this.chart.styledMode && this.state !== "inactive") {
      attrs.opacity = this.opacity;
    }
    if (!group2) {
      this[prop] = group2 = this.chart.renderer.g().add(parent);
    }
    group2.addClass("highcharts-" + name + " highcharts-series-" + this.index + " highcharts-" + this.type + "-series " + (defined$14(this.colorIndex) ? "highcharts-color-" + this.colorIndex + " " : "") + (this.options.className || "") + (group2.hasClass("highcharts-tracker") ? " highcharts-tracker" : ""), true);
    group2.attr(attrs)[isNew ? "attr" : "animate"](this.getPlotBox(name));
    return group2;
  }
  /**
   * Get the translation and scale for the plot area of this series.
   *
   * @function Highcharts.Series#getPlotBox
   */
  getPlotBox(name) {
    let horAxis = this.xAxis, vertAxis = this.yAxis;
    const chart = this.chart, inverted = chart.inverted && !chart.polar && horAxis && this.invertible && name === "series";
    if (chart.inverted) {
      horAxis = vertAxis;
      vertAxis = this.xAxis;
    }
    return {
      translateX: horAxis ? horAxis.left : chart.plotLeft,
      translateY: vertAxis ? vertAxis.top : chart.plotTop,
      rotation: inverted ? 90 : 0,
      rotationOriginX: inverted ? (horAxis.len - vertAxis.len) / 2 : 0,
      rotationOriginY: inverted ? (horAxis.len + vertAxis.len) / 2 : 0,
      scaleX: inverted ? -1 : 1,
      // #1623
      scaleY: 1
    };
  }
  /**
   * Removes the event handlers attached previously with addEvents.
   * @private
   * @function Highcharts.Series#removeEvents
   */
  removeEvents(keepEventsForUpdate) {
    const { eventsToUnbind } = this;
    if (!keepEventsForUpdate) {
      removeEvent$8(this);
    }
    if (eventsToUnbind.length) {
      eventsToUnbind.forEach((unbind) => {
        unbind();
      });
      eventsToUnbind.length = 0;
    }
  }
  /**
   * Render the graph and markers. Called internally when first rendering
   * and later when redrawing the chart. This function can be extended in
   * plugins, but normally shouldn't be called directly.
   *
   * @function Highcharts.Series#render
   *
   * @emits Highcharts.Series#event:afterRender
   */
  render() {
    const series = this, { chart, options: options2, hasRendered } = series, animOptions = animObject$b(options2.animation), visibility = series.visible ? "inherit" : "hidden", zIndex = options2.zIndex, chartSeriesGroup = chart.seriesGroup;
    let animDuration = series.finishedAnimating ? 0 : animOptions.duration;
    fireEvent$C(this, "render");
    series.plotGroup("group", "series", visibility, zIndex, chartSeriesGroup);
    series.markerGroup = series.plotGroup("markerGroup", "markers", visibility, zIndex, chartSeriesGroup);
    if (options2.clip !== false) {
      series.setClip();
    }
    if (animDuration) {
      series.animate?.(true);
    }
    if (series.drawGraph) {
      series.drawGraph();
      series.applyZones();
    }
    if (series.visible) {
      series.drawPoints();
    }
    series.drawDataLabels?.();
    series.redrawPoints?.();
    if (options2.enableMouseTracking) {
      series.drawTracker?.();
    }
    if (animDuration) {
      series.animate?.();
    }
    if (!hasRendered) {
      if (animDuration && animOptions.defer) {
        animDuration += animOptions.defer;
      }
      series.animationTimeout = syncTimeout$7(() => {
        series.afterAnimate();
      }, animDuration || 0);
    }
    series.isDirty = false;
    series.hasRendered = true;
    fireEvent$C(series, "afterRender");
  }
  /**
   * Redraw the series. This function is called internally from
   * `chart.redraw` and normally shouldn't be called directly.
   * @private
   * @function Highcharts.Series#redraw
   */
  redraw() {
    const wasDirty = this.isDirty || this.isDirtyData;
    this.translate();
    this.render();
    if (wasDirty) {
      delete this.kdTree;
    }
  }
  /**
   * Whether to reserve space for the series, either because it is visible or
   * because the `chart.ignoreHiddenSeries` option is false.
   *
   * @private
   */
  reserveSpace() {
    return this.visible || !this.chart.options.chart.ignoreHiddenSeries;
  }
  /**
   * Find the nearest point from a pointer event. This applies to series that
   * use k-d-trees to get the nearest point. Native pointer events must be
   * normalized using `Pointer.normalize`, that adds `chartX` and `chartY`
   * properties.
   *
   * @sample highcharts/demo/synchronized-charts
   *         Synchronized charts with tooltips
   *
   * @function Highcharts.Series#searchPoint
   *
   * @param {Highcharts.PointerEvent} e
   *        The normalized pointer event
   * @param {boolean} [compareX=false]
   *        Search only by the X value, not Y
   *
   * @return {Point|undefined}
   *        The closest point to the pointer event
   */
  searchPoint(e, compareX) {
    const { xAxis: xAxis2, yAxis: yAxis2 } = this, inverted = this.chart.inverted;
    return this.searchKDTree({
      clientX: inverted ? xAxis2.len - e.chartY + xAxis2.pos : e.chartX - xAxis2.pos,
      plotY: inverted ? yAxis2.len - e.chartX + yAxis2.pos : e.chartY - yAxis2.pos
    }, compareX, e);
  }
  /**
   * Build the k-d-tree that is used by mouse and touch interaction to get
   * the closest point. Line-like series typically have a one-dimensional
   * tree where points are searched along the X axis, while scatter-like
   * series typically search in two dimensions, X and Y.
   *
   * @private
   * @function Highcharts.Series#buildKDTree
   */
  buildKDTree(e) {
    this.buildingKdTree = true;
    const series = this, seriesOptions = series.options, dimensions = seriesOptions.findNearestPointBy.indexOf("y") > -1 ? 2 : 1;
    function kdtree(points, depth, dimensions2) {
      const length = points?.length;
      let axis, median;
      if (length) {
        axis = series.kdAxisArray[depth % dimensions2];
        points.sort((a, b) => (a[axis] || 0) - (b[axis] || 0));
        median = Math.floor(length / 2);
        return {
          point: points[median],
          left: kdtree(points.slice(0, median), depth + 1, dimensions2),
          right: kdtree(points.slice(median + 1), depth + 1, dimensions2)
        };
      }
    }
    function startRecursive() {
      series.kdTree = kdtree(series.getValidPoints(
        void 0,
        // For line-type series restrict to plot area, but
        // column-type series not (#3916, #4511)
        !series.directTouch,
        seriesOptions?.nullInteraction
      ), dimensions, dimensions);
      series.buildingKdTree = false;
    }
    delete series.kdTree;
    syncTimeout$7(startRecursive, seriesOptions.kdNow || e?.type === "touchstart" ? 0 : 1);
  }
  /**
   * @private
   * @function Highcharts.Series#searchKDTree
   */
  searchKDTree(point, compareX, e, suppliedPointEvaluator, suppliedBSideCheckEvaluator) {
    const series = this, [kdX, kdY] = this.kdAxisArray, kdComparer = compareX ? "distX" : "dist", kdDimensions = (series.options.findNearestPointBy || "").indexOf("y") > -1 ? 2 : 1, useRadius = !!series.isBubble, pointEvaluator = suppliedPointEvaluator || ((p12, p22, comparisonProp) => {
      const p1Val = p12[comparisonProp] || 0, p2Val = p22[comparisonProp] || 0;
      return [
        p1Val === p2Val && p12.index > p22.index || p1Val < p2Val ? p12 : p22,
        false
      ];
    }), bSideCheckEvaluator = suppliedBSideCheckEvaluator || ((a, b) => a < b);
    function setDistance(p12, p22) {
      const p1kdX = p12[kdX], p2kdX = p22[kdX], x = defined$14(p1kdX) && defined$14(p2kdX) ? p1kdX - p2kdX : null, p1kdY = p12[kdY], p2kdY = p22[kdY], y = defined$14(p1kdY) && defined$14(p2kdY) ? p1kdY - p2kdY : 0, radius = useRadius ? p22.marker?.radius || 0 : 0;
      p22.dist = Math.sqrt((x && x * x || 0) + y * y) - radius;
      p22.distX = defined$14(x) ? Math.abs(x) - radius : Number.MAX_VALUE;
    }
    function doSearch(search, tree, depth, dimensions) {
      const point2 = tree.point, axis = series.kdAxisArray[depth % dimensions];
      let ret = point2, flip = false;
      setDistance(search, point2);
      const tdist = (search[axis] || 0) - (point2[axis] || 0) + (useRadius ? point2.marker?.radius || 0 : 0), sideA = tdist < 0 ? "left" : "right", sideB = tdist < 0 ? "right" : "left";
      if (tree[sideA]) {
        [ret, flip] = pointEvaluator(point2, doSearch(search, tree[sideA], depth + 1, dimensions), kdComparer);
      }
      if (tree[sideB]) {
        const sqrtTDist = Math.sqrt(tdist * tdist), retDist = ret[kdComparer];
        if (bSideCheckEvaluator(sqrtTDist, retDist, flip)) {
          ret = pointEvaluator(ret, doSearch(search, tree[sideB], depth + 1, dimensions), kdComparer)[0];
        }
      }
      return ret;
    }
    if (!this.kdTree && !this.buildingKdTree) {
      this.buildKDTree(e);
    }
    if (this.kdTree) {
      return doSearch(point, this.kdTree, kdDimensions, kdDimensions);
    }
  }
  /**
   * @private
   * @function Highcharts.Series#pointPlacementToXValue
   */
  pointPlacementToXValue() {
    const { options: options2, xAxis: xAxis2 } = this;
    let factor = options2.pointPlacement;
    if (factor === "between") {
      factor = xAxis2.reversed ? -0.5 : 0.5;
    }
    return isNumber$Y(factor) ? factor * (options2.pointRange || xAxis2.pointRange) : 0;
  }
  /**
   * @private
   * @function Highcharts.Series#isPointInside
   */
  isPointInside(point) {
    const { chart, xAxis: xAxis2, yAxis: yAxis2 } = this, { plotX = -1, plotY = -1 } = point, isInside = plotY >= 0 && plotY <= (yAxis2 ? yAxis2.len : chart.plotHeight) && plotX >= 0 && plotX <= (xAxis2 ? xAxis2.len : chart.plotWidth);
    return isInside;
  }
  /**
   * Draw the tracker object that sits above all data labels and markers to
   * track mouse events on the graph or points. For the line type charts
   * the tracker uses the same graphPath, but with a greater stroke width
   * for better control.
   * @private
   */
  drawTracker() {
    const series = this, options2 = series.options, trackByArea = options2.trackByArea, trackerPath = [].concat((trackByArea ? series.areaPath : series.graphPath) || []), chart = series.chart, pointer = chart.pointer, renderer = chart.renderer, snap2 = chart.options.tooltip?.snap || 0, onMouseOver = () => {
      if (options2.enableMouseTracking && chart.hoverSeries !== series) {
        series.onMouseOver();
      }
    }, TRACKER_FILL2 = "rgba(192,192,192," + (svg$1 ? 1e-4 : 2e-3) + ")";
    let tracker = series.tracker;
    if (tracker) {
      tracker.attr({ d: trackerPath });
    } else if (series.graph) {
      series.tracker = tracker = renderer.path(trackerPath).attr({
        visibility: series.visible ? "inherit" : "hidden",
        zIndex: 2
      }).addClass(trackByArea ? "highcharts-tracker-area" : "highcharts-tracker-line").add(series.group);
      if (!chart.styledMode) {
        tracker.attr({
          "stroke-linecap": "round",
          "stroke-linejoin": "round",
          // #1225
          stroke: TRACKER_FILL2,
          fill: trackByArea ? TRACKER_FILL2 : "none",
          "stroke-width": series.graph.strokeWidth() + (trackByArea ? 0 : 2 * snap2)
        });
      }
      [
        series.tracker,
        series.markerGroup,
        series.dataLabelsGroup
      ].forEach((tracker2) => {
        if (tracker2) {
          tracker2.addClass("highcharts-tracker").on("mouseover", onMouseOver).on("mouseout", (e) => {
            pointer?.onTrackerMouseOut(e);
          });
          if (options2.cursor && !chart.styledMode) {
            tracker2.css({ cursor: options2.cursor });
          }
          tracker2.on("touchstart", onMouseOver);
        }
      });
    }
    fireEvent$C(this, "afterDrawTracker");
  }
  /**
   * Add a point to the series after render time. The point can be added at
   * the end, or by giving it an X value, to the start or in the middle of the
   * series.
   *
   * @sample highcharts/members/series-addpoint-append/
   *         Append point
   * @sample highcharts/members/series-addpoint-append-and-shift/
   *         Append and shift
   * @sample highcharts/members/series-addpoint-x-and-y/
   *         Both X and Y values given
   * @sample highcharts/members/series-addpoint-pie/
   *         Append pie slice
   * @sample stock/members/series-addpoint/
   *         Append 100 points in Highcharts Stock
   * @sample stock/members/series-addpoint-shift/
   *         Append and shift in Highcharts Stock
   * @sample maps/members/series-addpoint/
   *         Add a point in Highmaps
   *
   * @function Highcharts.Series#addPoint
   *
   * @param {Highcharts.PointOptionsType} options
   *        The point options. If options is a single number, a point with
   *        that y value is appended to the series. If it is an array, it will
   *        be interpreted as x and y values respectively. If it is an
   *        object, advanced options as outlined under `series.data` are
   *        applied.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after the point is added. When adding
   *        more than one point, it is highly recommended that the redraw
   *        option be set to false, and instead {@link Chart#redraw} is
   *        explicitly called after the adding of points is finished.
   *        Otherwise, the chart will redraw after adding each point.
   *
   * @param {boolean} [shift=false]
   *        If true, a point is shifted off the start of the series as one is
   *        appended to the end.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether to apply animation, and optionally animation
   *        configuration.
   *
   * @param {boolean} [withEvent=true]
   *        Used internally, whether to fire the series `addPoint` event.
   *
   * @emits Highcharts.Series#event:addPoint
   */
  addPoint(options2, redraw, shift, animation, withEvent) {
    const series = this, seriesOptions = series.options, { chart, data, dataTable: table, xAxis: xAxis2 } = series, names2 = xAxis2?.hasNames && xAxis2.names, dataOptions = seriesOptions.data, xData = series.getColumn("x");
    let isInTheMiddle, i;
    redraw = pick$1B(redraw, true);
    const point = { series };
    series.pointClass.prototype.applyOptions.apply(point, [options2]);
    const x = point.x;
    i = xData.length;
    if (series.requireSorting && x < xData[i - 1]) {
      isInTheMiddle = true;
      while (i && xData[i - 1] > x) {
        i--;
      }
    }
    table.setRow(point, i, true, { addColumns: false });
    if (names2 && point.name) {
      names2[x] = point.name;
    }
    dataOptions?.splice(i, 0, options2);
    if (isInTheMiddle || // When processedData is present we need to splice an empty slot
    // into series.data, otherwise generatePoints won't pick it up.
    series.processedData) {
      series.data.splice(i, 0, null);
      series.processData();
    }
    if (seriesOptions.legendType === "point") {
      series.generatePoints();
    }
    if (shift) {
      if (data[0] && !!data[0].remove) {
        data[0].remove(false);
      } else {
        [
          data,
          dataOptions
        ].filter(defined$14).forEach((coll) => {
          coll.shift();
        });
        table.deleteRows(0);
      }
    }
    if (withEvent !== false) {
      fireEvent$C(series, "addPoint", { point });
    }
    series.isDirty = true;
    series.isDirtyData = true;
    if (redraw) {
      chart.redraw(animation);
    }
  }
  /**
   * Remove a point from the series. Unlike the
   * {@link Highcharts.Point#remove} method, this can also be done on a point
   * that is not instantiated because it is outside the view or subject to
   * Highcharts Stock data grouping.
   *
   * @sample highcharts/members/series-removepoint/
   *         Remove cropped point
   *
   * @function Highcharts.Series#removePoint
   *
   * @param {number} i
   *        The index of the point in the {@link Highcharts.Series.data|data}
   *        array.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after the point is added. When
   *        removing more than one point, it is highly recommended that the
   *        `redraw` option be set to `false`, and instead {@link
   *        Highcharts.Chart#redraw} is explicitly called after the adding of
   *        points is finished.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether and optionally how the series should be animated.
   *
   * @emits Highcharts.Point#event:remove
   */
  removePoint(i, redraw, animation) {
    const series = this, { chart, data, points, dataTable: table } = series, point = data[i], remove = function() {
      [
        // #4935
        points?.length === data.length ? points : void 0,
        data,
        series.options.data
      ].filter(defined$14).forEach((coll) => {
        coll.splice(i, 1);
      });
      table.deleteRows(i);
      point?.destroy();
      series.isDirty = true;
      series.isDirtyData = true;
      if (redraw) {
        chart.redraw();
      }
    };
    setAnimation$4(animation, chart);
    redraw = pick$1B(redraw, true);
    if (point) {
      point.firePointEvent("remove", null, remove);
    } else {
      remove();
    }
  }
  /**
   * Remove a series and optionally redraw the chart.
   *
   * @sample highcharts/members/series-remove/
   *         Remove first series from a button
   *
   * @function Highcharts.Series#remove
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart or wait for an explicit call to
   *        {@link Highcharts.Chart#redraw}.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether to apply animation, and optionally animation
   *        configuration.
   *
   * @param {boolean} [withEvent=true]
   *        Used internally, whether to fire the series `remove` event.
   *
   * @emits Highcharts.Series#event:remove
   */
  remove(redraw, animation, withEvent, keepEvents) {
    const series = this, chart = series.chart;
    function remove() {
      series.destroy(keepEvents);
      chart.isDirtyLegend = chart.isDirtyBox = true;
      chart.linkSeries(keepEvents);
      if (pick$1B(redraw, true)) {
        chart.redraw(animation);
      }
    }
    if (withEvent !== false) {
      fireEvent$C(series, "remove", null, remove);
    } else {
      remove();
    }
  }
  /**
   * Update the series with a new set of options. For a clean and precise
   * handling of new options, all methods and elements from the series are
   * removed, and it is initialized from scratch. Therefore, this method is
   * more performance expensive than some other utility methods like {@link
   * Series#setData} or {@link Series#setVisible}.
   *
   * Note that `Series.update` may mutate the passed `data` options.
   *
   * @sample highcharts/members/series-update/
   *         Updating series options
   * @sample maps/members/series-update/
   *         Update series options in Highmaps
   *
   * @function Highcharts.Series#update
   *
   * @param {Highcharts.SeriesOptionsType} options
   *        New options that will be merged with the series' existing options.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after the series is altered. If doing
   *        more operations on the chart, it is a good idea to set redraw to
   *        false and call {@link Chart#redraw} after.
   *
   * @emits Highcharts.Series#event:update
   * @emits Highcharts.Series#event:afterUpdate
   */
  update(options2, redraw) {
    options2 = diffObjects$4(options2, this.userOptions);
    fireEvent$C(this, "update", { options: options2 });
    const series = this, chart = series.chart, oldOptions = series.userOptions, initialType = series.initialType || series.type, plotOptions = chart.options.plotOptions, initialSeriesProto = seriesTypes$5[initialType].prototype, groups = [
      "group",
      "markerGroup",
      "dataLabelsGroup",
      "transformGroup"
    ], optionsToCheck = [
      "dataGrouping",
      "pointStart",
      "pointInterval",
      "pointIntervalUnit",
      "keys"
    ], animation = series.finishedAnimating && { animation: false }, kinds = {};
    let seriesOptions, n, keepProps = Series2.keepProps.slice(), newType = options2.type || oldOptions.type || chart.options.chart.type;
    const keepPoints = !// Indicators, histograms etc recalculate the data. It should be
    // possible to omit this.
    (this.hasDerivedData || // New type requires new point classes
    newType && newType !== this.type || // New options affecting how the data points are built
    typeof options2.keys !== "undefined" || typeof options2.pointStart !== "undefined" || typeof options2.pointInterval !== "undefined" || typeof options2.relativeXValue !== "undefined" || options2.joinBy || options2.mapData || // #11636
    // Changes to data grouping requires new points in new group
    optionsToCheck.some((option) => series.hasOptionChanged(option)));
    newType = newType || initialType;
    if (keepPoints) {
      keepProps.push.apply(keepProps, Series2.keepPropsForPoints);
      if (options2.visible !== false) {
        keepProps.push("area", "graph");
      }
      series.parallelArrays.forEach(function(key2) {
        keepProps.push(key2 + "Data");
      });
      if (options2.data) {
        if (options2.dataSorting) {
          extend$1d(series.options.dataSorting, options2.dataSorting);
        }
        this.setData(options2.data, false);
      }
    } else {
      this.dataTable.modified = this.dataTable;
    }
    options2 = merge$1v(oldOptions, {
      // When oldOptions.index is null it should't be cleared.
      // Otherwise navigator series will have wrong indexes (#10193).
      index: oldOptions.index === void 0 ? series.index : oldOptions.index,
      pointStart: (
        // When updating from blank (#7933)
        plotOptions?.series?.pointStart ?? oldOptions.pointStart ?? // When updating after addPoint
        series.getColumn("x")[0]
      )
    }, !keepPoints && { data: series.options.data }, options2, animation);
    if (keepPoints && options2.data) {
      options2.data = series.options.data;
    }
    keepProps = groups.concat(keepProps);
    keepProps.forEach(function(prop) {
      keepProps[prop] = series[prop];
      delete series[prop];
    });
    let casting = false;
    if (seriesTypes$5[newType]) {
      casting = newType !== series.type;
      series.remove(false, false, false, true);
      if (casting) {
        chart.propFromSeries();
        if (Object.setPrototypeOf) {
          Object.setPrototypeOf(series, seriesTypes$5[newType].prototype);
        } else {
          const ownEvents = Object.hasOwnProperty.call(series, "hcEvents") && series.hcEvents;
          for (n in initialSeriesProto) {
            series[n] = void 0;
          }
          extend$1d(series, seriesTypes$5[newType].prototype);
          if (ownEvents) {
            series.hcEvents = ownEvents;
          } else {
            delete series.hcEvents;
          }
        }
      }
    } else {
      error$7(17, true, chart, { missingModuleFor: newType });
    }
    keepProps.forEach(function(prop) {
      series[prop] = keepProps[prop];
    });
    series.init(chart, options2);
    if (keepPoints && this.points) {
      seriesOptions = series.options;
      if (seriesOptions.visible === false) {
        kinds.graphic = 1;
        kinds.dataLabel = 1;
      } else {
        if (this.hasMarkerChanged(seriesOptions, oldOptions)) {
          kinds.graphic = 1;
        }
        if (!series.hasDataLabels?.()) {
          kinds.dataLabel = 1;
        }
      }
      for (const point of this.points) {
        if (point?.series) {
          point.resolveColor();
          if (Object.keys(kinds).length) {
            point.destroyElements(kinds);
          }
          if (seriesOptions.showInLegend === false && point.legendItem) {
            chart.legend.destroyItem(point);
          }
        }
      }
    }
    series.initialType = initialType;
    chart.linkSeries();
    chart.setSortedData();
    if (casting && series.linkedSeries.length) {
      series.isDirtyData = true;
    }
    fireEvent$C(this, "afterUpdate");
    if (pick$1B(redraw, true)) {
      chart.redraw(keepPoints ? void 0 : false);
    }
  }
  /**
   * Used from within series.update
   * @private
   */
  setName(name) {
    this.name = this.options.name = this.userOptions.name = name;
    this.chart.isDirtyLegend = true;
  }
  /**
   * Check if the option has changed.
   * @private
   */
  hasOptionChanged(optionName) {
    const chart = this.chart, option = this.options[optionName], plotOptions = chart.options.plotOptions, oldOption = this.userOptions[optionName], plotOptionsOption = pick$1B(plotOptions?.[this.type]?.[optionName], plotOptions?.series?.[optionName]);
    if (oldOption && !defined$14(plotOptionsOption)) {
      return option !== oldOption;
    }
    return option !== pick$1B(plotOptionsOption, option);
  }
  /**
   * Runs on mouse over the series graphical items.
   *
   * @function Highcharts.Series#onMouseOver
   * @emits Highcharts.Series#event:mouseOver
   */
  onMouseOver() {
    const series = this, chart = series.chart, hoverSeries = chart.hoverSeries, pointer = chart.pointer;
    pointer?.setHoverChartIndex();
    if (hoverSeries && hoverSeries !== series) {
      hoverSeries.onMouseOut();
    }
    if (series.options.events.mouseOver) {
      fireEvent$C(series, "mouseOver");
    }
    series.setState("hover");
    chart.hoverSeries = series;
  }
  /**
   * Runs on mouse out of the series graphical items.
   *
   * @function Highcharts.Series#onMouseOut
   *
   * @emits Highcharts.Series#event:mouseOut
   */
  onMouseOut() {
    const series = this, options2 = series.options, chart = series.chart, tooltip = chart.tooltip, hoverPoint = chart.hoverPoint;
    chart.hoverSeries = null;
    if (hoverPoint) {
      hoverPoint.onMouseOut();
    }
    if (series && options2.events.mouseOut) {
      fireEvent$C(series, "mouseOut");
    }
    if (tooltip && !series.stickyTracking && (!tooltip.shared || series.noSharedTooltip)) {
      tooltip.hide();
    }
    chart.series.forEach(function(s) {
      s.setState("", true);
    });
  }
  /**
   * Set the state of the series. Called internally on mouse interaction
   * operations, but it can also be called directly to visually
   * highlight a series.
   *
   * @function Highcharts.Series#setState
   *
   * @param {Highcharts.SeriesStateValue|""} [state]
   *        The new state, can be either `'hover'`, `'inactive'`, `'select'`,
   *        or `''` (an empty string), `'normal'` or `undefined` to set to
   *        normal state.
   * @param {boolean} [inherit]
   *        Determines if state should be inherited by points too.
   */
  setState(state, inherit) {
    const series = this, options2 = series.options, graph = series.graph, inactiveOtherPoints = options2.inactiveOtherPoints, stateOptions = options2.states, stateAnimation = pick$1B(stateOptions[state || "normal"] && stateOptions[state || "normal"].animation, series.chart.options.chart.animation);
    let lineWidth = options2.lineWidth, opacity = options2.opacity;
    state = state || "";
    if (series.state !== state) {
      [
        series.group,
        series.markerGroup,
        series.dataLabelsGroup
      ].forEach(function(group2) {
        if (group2) {
          if (series.state) {
            group2.removeClass("highcharts-series-" + series.state);
          }
          if (state) {
            group2.addClass("highcharts-series-" + state);
          }
        }
      });
      series.state = state;
      if (!series.chart.styledMode) {
        if (stateOptions[state] && stateOptions[state].enabled === false) {
          return;
        }
        if (state) {
          lineWidth = stateOptions[state].lineWidth || lineWidth + (stateOptions[state].lineWidthPlus || 0);
          opacity = pick$1B(stateOptions[state].opacity, opacity);
        }
        if (graph && !graph.dashstyle && isNumber$Y(lineWidth)) {
          for (const graphElement of [
            graph,
            ...this.zones.map((zone) => zone.graph)
          ]) {
            graphElement?.animate({
              "stroke-width": lineWidth
            }, stateAnimation);
          }
        }
        if (!inactiveOtherPoints) {
          [
            series.group,
            series.markerGroup,
            series.dataLabelsGroup,
            series.labelBySeries
          ].forEach(function(group2) {
            if (group2) {
              group2.animate({
                opacity
              }, stateAnimation);
            }
          });
        }
      }
    }
    if (inherit && inactiveOtherPoints && series.points) {
      series.setAllPointsToState(state || void 0);
    }
  }
  /**
   * Set the state for all points in the series.
   *
   * @function Highcharts.Series#setAllPointsToState
   *
   * @private
   *
   * @param {string} [state]
   *        Can be either `hover` or undefined to set to normal state.
   */
  setAllPointsToState(state) {
    this.points.forEach(function(point) {
      if (point.setState) {
        point.setState(state);
      }
    });
  }
  /**
   * Show or hide the series.
   *
   * @function Highcharts.Series#setVisible
   *
   * @param {boolean} [visible]
   * True to show the series, false to hide. If undefined, the visibility is
   * toggled.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart after the series is altered. If doing more
   * operations on the chart, it is a good idea to set redraw to false and
   * call {@link Chart#redraw|chart.redraw()} after.
   *
   * @emits Highcharts.Series#event:hide
   * @emits Highcharts.Series#event:show
   */
  setVisible(vis, redraw) {
    const series = this, chart = series.chart, ignoreHiddenSeries = chart.options.chart.ignoreHiddenSeries, oldVisibility = series.visible;
    series.visible = vis = series.options.visible = series.userOptions.visible = typeof vis === "undefined" ? !oldVisibility : vis;
    const showOrHide = vis ? "show" : "hide";
    [
      "group",
      "dataLabelsGroup",
      "markerGroup",
      "tracker",
      "tt"
    ].forEach((key2) => {
      series[key2]?.[showOrHide]();
    });
    if (chart.hoverSeries === series || chart.hoverPoint?.series === series) {
      series.onMouseOut();
    }
    if (series.legendItem) {
      chart.legend.colorizeItem(series, vis);
    }
    series.isDirty = true;
    if (series.options.stacking) {
      chart.series.forEach((otherSeries) => {
        if (otherSeries.options.stacking && otherSeries.visible) {
          otherSeries.isDirty = true;
        }
      });
    }
    series.linkedSeries.forEach((otherSeries) => {
      otherSeries.setVisible(vis, false);
    });
    if (ignoreHiddenSeries) {
      chart.isDirtyBox = true;
    }
    fireEvent$C(series, showOrHide);
    if (redraw !== false) {
      chart.redraw();
    }
  }
  /**
   * Show the series if hidden.
   *
   * @sample highcharts/members/series-hide/
   *         Toggle visibility from a button
   *
   * @function Highcharts.Series#show
   * @emits Highcharts.Series#event:show
   */
  show() {
    this.setVisible(true);
  }
  /**
   * Hide the series if visible. If the
   * [chart.ignoreHiddenSeries](https://api.highcharts.com/highcharts/chart.ignoreHiddenSeries)
   * option is true, the chart is redrawn without this series.
   *
   * @sample highcharts/members/series-hide/
   *         Toggle visibility from a button
   *
   * @function Highcharts.Series#hide
   * @emits Highcharts.Series#event:hide
   */
  hide() {
    this.setVisible(false);
  }
  /**
   * Select or unselect the series. This means its
   * {@link Highcharts.Series.selected|selected}
   * property is set, the checkbox in the legend is toggled and when selected,
   * the series is returned by the {@link Highcharts.Chart#getSelectedSeries}
   * function.
   *
   * @sample highcharts/members/series-select/
   *         Select a series from a button
   *
   * @function Highcharts.Series#select
   *
   * @param {boolean} [selected]
   * True to select the series, false to unselect. If undefined, the selection
   * state is toggled.
   *
   * @emits Highcharts.Series#event:select
   * @emits Highcharts.Series#event:unselect
   */
  select(selected) {
    const series = this;
    series.selected = selected = this.options.selected = typeof selected === "undefined" ? !series.selected : selected;
    if (series.checkbox) {
      series.checkbox.checked = selected;
    }
    fireEvent$C(series, selected ? "select" : "unselect");
  }
  /**
   * Checks if a tooltip should be shown for a given point.
   *
   * @private
   */
  shouldShowTooltip(plotX, plotY, options2 = {}) {
    options2.series = this;
    options2.visiblePlotOnly = true;
    return this.chart.isInsidePlot(plotX, plotY, options2);
  }
  /**
   * Draws the legend symbol based on the legendSymbol user option.
   *
   * @private
   */
  drawLegendSymbol(legend, item) {
    LegendSymbol$1[this.options.legendSymbol || "rectangle"]?.call(this, legend, item);
  }
};
Series$9.defaultOptions = seriesDefaults;
Series$9.types = SeriesRegistry$1.seriesTypes;
Series$9.registerType = SeriesRegistry$1.registerSeriesType;
Series$9.keepProps = [
  "colorIndex",
  "eventOptions",
  "navigatorSeries",
  "symbolIndex",
  "baseSeries"
];
Series$9.keepPropsForPoints = [
  "data",
  "isDirtyData",
  // GeoHeatMap interpolation
  "isDirtyCanvas",
  "points",
  "dataTable",
  "processedData",
  // #17057
  "xIncrement",
  "cropped",
  "_hasPointMarkers",
  "hasDataLabels",
  // Networkgraph (#14397)
  "nodes",
  "layout",
  // Treemap
  "level",
  // Map specific, consider moving it to series-specific preserve-
  // properties (#10617)
  "mapMap",
  "mapData",
  "minY",
  "maxY",
  "minX",
  "maxX",
  "transformGroups"
  // #18857
];
extend$1d(Series$9.prototype, {
  axisTypes: ["xAxis", "yAxis"],
  coll: "series",
  colorCounter: 0,
  directTouch: false,
  invertible: true,
  isCartesian: true,
  kdAxisArray: ["clientX", "plotY"],
  // Each point's x and y values are stored in this.xData and this.yData:
  parallelArrays: ["x", "y"],
  pointClass: Point$3,
  requireSorting: true,
  // Requires the data to be sorted:
  sorted: true
});
SeriesRegistry$1.series = Series$9;
const { animObject: animObject$a, setAnimation: setAnimation$3 } = animationExports;
const { registerEventOptions: registerEventOptions$1 } = Foundation$1;
const { composed: composed$v, marginNames: marginNames$1 } = Highcharts;
const { distribute: distribute$2 } = R$1;
const { format: format$d } = Templating;
const { addEvent: addEvent$1m, createElement: createElement$9, css: css$9, defined: defined$13, discardElement: discardElement$4, find: find$g, fireEvent: fireEvent$B, isNumber: isNumber$X, merge: merge$1u, pick: pick$1A, pushUnique: pushUnique$v, relativeLength: relativeLength$g, stableSort: stableSort$6, syncTimeout: syncTimeout$6 } = Utilities;
class Legend {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the legend.
   *
   * @private
   * @function Highcharts.Legend#init
   *
   * @param {Highcharts.Chart} chart
   * The chart instance.
   *
   * @param {Highcharts.LegendOptions} options
   * Legend options.
   */
  constructor(chart, options2) {
    this.allItems = [];
    this.initialItemY = 0;
    this.itemHeight = 0;
    this.itemMarginBottom = 0;
    this.itemMarginTop = 0;
    this.itemX = 0;
    this.itemY = 0;
    this.lastItemY = 0;
    this.lastLineHeight = 0;
    this.legendHeight = 0;
    this.legendWidth = 0;
    this.maxItemWidth = 0;
    this.maxLegendWidth = 0;
    this.offsetWidth = 0;
    this.padding = 0;
    this.pages = [];
    this.symbolHeight = 0;
    this.symbolWidth = 0;
    this.titleHeight = 0;
    this.totalItemWidth = 0;
    this.widthOption = 0;
    this.chart = chart;
    this.setOptions(options2);
    if (options2.enabled) {
      this.render();
      registerEventOptions$1(this, options2);
      addEvent$1m(this.chart, "endResize", function() {
        this.legend.positionCheckboxes();
      });
    }
    addEvent$1m(this.chart, "render", () => {
      if (this.options.enabled && this.proximate) {
        this.proximatePositions();
        this.positionItems();
      }
    });
  }
  /**
   * @private
   * @function Highcharts.Legend#setOptions
   * @param {Highcharts.LegendOptions} options
   */
  setOptions(options2) {
    const padding = pick$1A(options2.padding, 8);
    this.options = options2;
    if (!this.chart.styledMode) {
      this.itemStyle = options2.itemStyle;
      this.itemHiddenStyle = merge$1u(this.itemStyle, options2.itemHiddenStyle);
    }
    this.itemMarginTop = options2.itemMarginTop;
    this.itemMarginBottom = options2.itemMarginBottom;
    this.padding = padding;
    this.initialItemY = padding - 5;
    this.symbolWidth = pick$1A(options2.symbolWidth, 16);
    this.pages = [];
    this.proximate = options2.layout === "proximate" && !this.chart.inverted;
    this.baseline = void 0;
  }
  /**
   * Update the legend with new options. Equivalent to running `chart.update`
   * with a legend configuration option.
   *
   * @sample highcharts/legend/legend-update/
   *         Legend update
   *
   * @function Highcharts.Legend#update
   *
   * @param {Highcharts.LegendOptions} options
   * Legend options.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart after the axis is altered. If doing more
   * operations on the chart, it is a good idea to set redraw to false and
   * call {@link Chart#redraw} after. Whether to redraw the chart.
   *
   * @emits Highcharts.Legends#event:afterUpdate
   */
  update(options2, redraw) {
    const chart = this.chart;
    this.setOptions(merge$1u(true, this.options, options2));
    if ("events" in this.options) {
      registerEventOptions$1(this, this.options);
    }
    this.destroy();
    chart.isDirtyLegend = chart.isDirtyBox = true;
    if (pick$1A(redraw, true)) {
      chart.redraw();
    }
    fireEvent$B(this, "afterUpdate", { redraw });
  }
  /**
   * Set the colors for the legend item.
   *
   * @private
   * @function Highcharts.Legend#colorizeItem
   * @param {Highcharts.BubbleLegendItem|Highcharts.Point|Highcharts.Series} item
   *        A Series or Point instance
   * @param {boolean} [visible=false]
   *        Dimmed or colored
   *
   * @todo
   * Make events official: Fires the event `afterColorizeItem`.
   */
  colorizeItem(item, visible) {
    const originalColor = item.color, { area, group: group2, label, line: line2, symbol } = item.legendItem || {};
    if (item instanceof Series$9 || item instanceof Point$3) {
      item.color = item.options?.legendSymbolColor || originalColor;
    }
    group2?.[visible ? "removeClass" : "addClass"]("highcharts-legend-item-hidden");
    if (!this.chart.styledMode) {
      const { itemHiddenStyle = {} } = this, hiddenColor = itemHiddenStyle.color, { fillColor, fillOpacity, lineColor, marker } = item.options, colorizeHidden = (attr2) => {
        if (!visible) {
          if (attr2.fill) {
            attr2.fill = hiddenColor;
          }
          if (attr2.stroke) {
            attr2.stroke = hiddenColor;
          }
        }
        return attr2;
      };
      label?.css(merge$1u(visible ? this.itemStyle : itemHiddenStyle));
      line2?.attr(colorizeHidden({ stroke: lineColor || item.color }));
      if (symbol) {
        symbol.attr(colorizeHidden(marker && symbol.isMarker ? (
          // #585
          item.pointAttribs()
        ) : { fill: item.color }));
      }
      area?.attr(colorizeHidden({
        fill: fillColor || item.color,
        "fill-opacity": fillColor ? 1 : fillOpacity ?? 0.75
      }));
    }
    item.color = originalColor;
    fireEvent$B(this, "afterColorizeItem", { item, visible });
  }
  /**
   * @private
   * @function Highcharts.Legend#positionItems
   */
  positionItems() {
    this.allItems.forEach(this.positionItem, this);
    if (!this.chart.isResizing) {
      this.positionCheckboxes();
    }
  }
  /**
   * Position the legend item.
   *
   * @private
   * @function Highcharts.Legend#positionItem
   * @param {Highcharts.BubbleLegendItem|Highcharts.Point|Highcharts.Series} item
   * The item to position
   */
  positionItem(item) {
    const legend = this, { group: group2, x = 0, y = 0 } = item.legendItem || {}, options2 = legend.options, symbolPadding = options2.symbolPadding, ltr = !options2.rtl, checkbox = item.checkbox;
    if (group2?.element) {
      const attribs = {
        translateX: ltr ? x : legend.legendWidth - x - 2 * symbolPadding - 4,
        translateY: y
      };
      const complete = () => {
        fireEvent$B(this, "afterPositionItem", { item });
      };
      group2[defined$13(group2.translateY) ? "animate" : "attr"](attribs, void 0, complete);
    }
    if (checkbox) {
      checkbox.x = x;
      checkbox.y = y;
    }
  }
  /**
   * Destroy a single legend item, used internally on removing series items.
   *
   * @private
   * @function Highcharts.Legend#destroyItem
   * @param {Highcharts.BubbleLegendItem|Highcharts.Point|Highcharts.Series} item
   * The item to remove
   */
  destroyItem(item) {
    const checkbox = item.checkbox, legendItem = item.legendItem || {};
    for (const key2 of ["group", "label", "line", "symbol"]) {
      if (legendItem[key2]) {
        legendItem[key2] = legendItem[key2].destroy();
      }
    }
    if (checkbox) {
      discardElement$4(checkbox);
    }
    item.legendItem = void 0;
  }
  /**
   * Destroy the legend. Used internally. To reflow objects, `chart.redraw`
   * must be called after destruction.
   *
   * @private
   * @function Highcharts.Legend#destroy
   */
  destroy() {
    const legend = this;
    for (const item of this.getAllItems()) {
      this.destroyItem(item);
    }
    for (const key2 of [
      "clipRect",
      "up",
      "down",
      "pager",
      "nav",
      "box",
      "title",
      "group"
    ]) {
      if (legend[key2]) {
        legend[key2] = legend[key2].destroy();
      }
    }
    this.display = null;
  }
  /**
   * Position the checkboxes after the width is determined.
   *
   * @private
   * @function Highcharts.Legend#positionCheckboxes
   */
  positionCheckboxes() {
    const alignAttr = this.group?.alignAttr, clipHeight = this.clipHeight || this.legendHeight, titleHeight = this.titleHeight;
    let translateY;
    if (alignAttr) {
      translateY = alignAttr.translateY;
      this.allItems.forEach(function(item) {
        const checkbox = item.checkbox;
        let top;
        if (checkbox) {
          top = translateY + titleHeight + checkbox.y + (this.scrollOffset || 0) + 3;
          css$9(checkbox, {
            left: alignAttr.translateX + item.checkboxOffset + checkbox.x - 20 + "px",
            top: top + "px",
            display: this.proximate || top > translateY - 6 && top < translateY + clipHeight - 6 ? "" : "none"
          });
        }
      }, this);
    }
  }
  /**
   * Render the legend title on top of the legend.
   *
   * @private
   * @function Highcharts.Legend#renderTitle
   */
  renderTitle() {
    const options2 = this.options, padding = this.padding, titleOptions = options2.title;
    let bBox, titleHeight = 0;
    if (titleOptions.text) {
      if (!this.title) {
        this.title = this.chart.renderer.label(titleOptions.text, padding - 3, padding - 4, void 0, void 0, void 0, options2.useHTML, void 0, "legend-title").attr({ zIndex: 1 });
        if (!this.chart.styledMode) {
          this.title.css(titleOptions.style);
        }
        this.title.add(this.group);
      }
      if (!titleOptions.width) {
        this.title.css({
          width: this.maxLegendWidth + "px"
        });
      }
      bBox = this.title.getBBox();
      titleHeight = bBox.height;
      this.offsetWidth = bBox.width;
      this.contentGroup.attr({ translateY: titleHeight });
    }
    this.titleHeight = titleHeight;
  }
  /**
   * Set the legend item text.
   *
   * @function Highcharts.Legend#setText
   * @param {Highcharts.Point|Highcharts.Series} item
   *        The item for which to update the text in the legend.
   */
  setText(item) {
    const options2 = this.options;
    item.legendItem.label.attr({
      text: options2.labelFormat ? format$d(options2.labelFormat, item, this.chart) : options2.labelFormatter.call(item)
    });
  }
  /**
   * Render a single specific legend item. Called internally from the `render`
   * function.
   *
   * @private
   * @function Highcharts.Legend#renderItem
   * @param {Highcharts.BubbleLegendItem|Highcharts.Point|Highcharts.Series} item
   * The item to render.
   */
  renderItem(item) {
    const legend = this, legendItem = item.legendItem = item.legendItem || {}, chart = legend.chart, renderer = chart.renderer, options2 = legend.options, horizontal = options2.layout === "horizontal", symbolWidth = legend.symbolWidth, symbolPadding = options2.symbolPadding || 0, itemStyle = legend.itemStyle, itemHiddenStyle = legend.itemHiddenStyle, itemDistance = horizontal ? pick$1A(options2.itemDistance, 20) : 0, ltr = !options2.rtl, isSeries = !item.series, series = !isSeries && item.series.drawLegendSymbol ? item.series : item, seriesOptions = series.options, showCheckbox = !!legend.createCheckboxForItem && seriesOptions && seriesOptions.showCheckbox, useHTML = options2.useHTML, itemClassName = item.options.className;
    let label = legendItem.label, itemExtraWidth = symbolWidth + symbolPadding + itemDistance + (showCheckbox ? 20 : 0);
    if (!label) {
      legendItem.group = renderer.g("legend-item").addClass("highcharts-" + series.type + "-series highcharts-color-" + item.colorIndex + (itemClassName ? " " + itemClassName : "") + (isSeries ? " highcharts-series-" + item.index : "")).attr({ zIndex: 1 }).add(legend.scrollGroup);
      legendItem.label = label = renderer.text("", ltr ? symbolWidth + symbolPadding : -symbolPadding, legend.baseline || 0, useHTML);
      if (!chart.styledMode) {
        label.css(merge$1u(item.visible ? itemStyle : itemHiddenStyle));
      }
      label.attr({
        align: ltr ? "left" : "right",
        zIndex: 2
      }).add(legendItem.group);
      if (!legend.baseline) {
        legend.fontMetrics = renderer.fontMetrics(label);
        legend.baseline = legend.fontMetrics.f + 3 + legend.itemMarginTop;
        label.attr("y", legend.baseline);
        legend.symbolHeight = pick$1A(options2.symbolHeight, legend.fontMetrics.f);
        if (options2.squareSymbol) {
          legend.symbolWidth = pick$1A(options2.symbolWidth, Math.max(legend.symbolHeight, 16));
          itemExtraWidth = legend.symbolWidth + symbolPadding + itemDistance + (showCheckbox ? 20 : 0);
          if (ltr) {
            label.attr("x", legend.symbolWidth + symbolPadding);
          }
        }
      }
      series.drawLegendSymbol(legend, item);
      if (legend.setItemEvents) {
        legend.setItemEvents(item, label, useHTML);
      }
    }
    if (showCheckbox && !item.checkbox && legend.createCheckboxForItem) {
      legend.createCheckboxForItem(item);
    }
    legend.colorizeItem(item, item.visible);
    if (chart.styledMode || !itemStyle.width) {
      label.css({
        width: (options2.itemWidth || legend.widthOption || chart.spacingBox.width) - itemExtraWidth + "px"
      });
    }
    legend.setText(item);
    const bBox = label.getBBox();
    const fontMetricsH = legend.fontMetrics?.h || 0;
    item.itemWidth = item.checkboxOffset = options2.itemWidth || legendItem.labelWidth || bBox.width + itemExtraWidth;
    legend.maxItemWidth = Math.max(legend.maxItemWidth, item.itemWidth);
    legend.totalItemWidth += item.itemWidth;
    legend.itemHeight = item.itemHeight = Math.round(legendItem.labelHeight || // Use bBox for multiline (#16398)
    (bBox.height > fontMetricsH * 1.5 ? bBox.height : fontMetricsH));
  }
  /**
   * Get the position of the item in the layout. We now know the
   * maxItemWidth from the previous loop.
   *
   * @private
   * @function Highcharts.Legend#layoutItem
   * @param {Highcharts.BubbleLegendItem|Highcharts.Point|Highcharts.Series} item
   */
  layoutItem(item) {
    const options2 = this.options, padding = this.padding, horizontal = options2.layout === "horizontal", itemHeight = item.itemHeight, itemMarginBottom = this.itemMarginBottom, itemMarginTop = this.itemMarginTop, itemDistance = horizontal ? pick$1A(options2.itemDistance, 20) : 0, maxLegendWidth = this.maxLegendWidth, itemWidth = options2.alignColumns && this.totalItemWidth > maxLegendWidth ? this.maxItemWidth : item.itemWidth, legendItem = item.legendItem || {};
    if (horizontal && this.itemX - padding + itemWidth > maxLegendWidth) {
      this.itemX = padding;
      if (this.lastLineHeight) {
        this.itemY += itemMarginTop + this.lastLineHeight + itemMarginBottom;
      }
      this.lastLineHeight = 0;
    }
    this.lastItemY = itemMarginTop + this.itemY + itemMarginBottom;
    this.lastLineHeight = Math.max(
      // #915
      itemHeight,
      this.lastLineHeight
    );
    legendItem.x = this.itemX;
    legendItem.y = this.itemY;
    if (horizontal) {
      this.itemX += itemWidth;
    } else {
      this.itemY += itemMarginTop + itemHeight + itemMarginBottom;
      this.lastLineHeight = itemHeight;
    }
    this.offsetWidth = this.widthOption || Math.max((horizontal ? this.itemX - padding - (item.checkbox ? (
      // Decrease by itemDistance only when no checkbox #4853
      0
    ) : itemDistance) : itemWidth) + padding, this.offsetWidth);
  }
  /**
   * Get all items, which is one item per series for most series and one
   * item per point for pie series and its derivatives. Fires the event
   * `afterGetAllItems`.
   *
   * @private
   * @function Highcharts.Legend#getAllItems
   * @return {Array<(Highcharts.BubbleLegendItem|Highcharts.Point|Highcharts.Series)>}
   * The current items in the legend.
   * @emits Highcharts.Legend#event:afterGetAllItems
   */
  getAllItems() {
    let allItems = [];
    this.chart.series.forEach(function(series) {
      const seriesOptions = series?.options;
      if (series && pick$1A(seriesOptions.showInLegend, !defined$13(seriesOptions.linkedTo) ? void 0 : false, true)) {
        allItems = allItems.concat(series.legendItem?.labels || (seriesOptions.legendType === "point" ? series.data : series));
      }
    });
    fireEvent$B(this, "afterGetAllItems", { allItems });
    return allItems;
  }
  /**
   * Get a short, three letter string reflecting the alignment and layout.
   *
   * @private
   * @function Highcharts.Legend#getAlignment
   * @return {string}
   * The alignment, empty string if floating
   */
  getAlignment() {
    const options2 = this.options;
    if (this.proximate) {
      return options2.align.charAt(0) + "tv";
    }
    return options2.floating ? "" : options2.align.charAt(0) + options2.verticalAlign.charAt(0) + options2.layout.charAt(0);
  }
  /**
   * Adjust the chart margins by reserving space for the legend on only one
   * side of the chart. If the position is set to a corner, top or bottom is
   * reserved for horizontal legends and left or right for vertical ones.
   *
   * @private
   * @function Highcharts.Legend#adjustMargins
   * @param {Array<number>} margin
   * @param {Array<number>} spacing
   */
  adjustMargins(margin, spacing) {
    const chart = this.chart, options2 = this.options, alignment = this.getAlignment();
    if (alignment) {
      [
        /(lth|ct|rth)/,
        /(rtv|rm|rbv)/,
        /(rbh|cb|lbh)/,
        /(lbv|lm|ltv)/
      ].forEach(function(alignments, side) {
        if (alignments.test(alignment) && !defined$13(margin[side])) {
          chart[marginNames$1[side]] = Math.max(chart[marginNames$1[side]], chart.legend[(side + 1) % 2 ? "legendHeight" : "legendWidth"] + [1, -1, -1, 1][side] * options2[side % 2 ? "x" : "y"] + pick$1A(options2.margin, 12) + spacing[side] + (chart.titleOffset[side] || 0));
        }
      });
    }
  }
  /**
   * @private
   * @function Highcharts.Legend#proximatePositions
   */
  proximatePositions() {
    const chart = this.chart, boxes = [], alignLeft = this.options.align === "left";
    this.allItems.forEach(function(item) {
      let lastPoint, height, useFirstPoint = alignLeft, target, top;
      if (item.yAxis) {
        if (item.xAxis.options.reversed) {
          useFirstPoint = !useFirstPoint;
        }
        if (item.points) {
          lastPoint = find$g(useFirstPoint ? item.points : item.points.slice(0).reverse(), function(item2) {
            return isNumber$X(item2.plotY);
          });
        }
        height = this.itemMarginTop + item.legendItem.label.getBBox().height + this.itemMarginBottom;
        top = item.yAxis.top - chart.plotTop;
        if (item.visible) {
          target = lastPoint ? lastPoint.plotY : item.yAxis.height;
          target += top - 0.3 * height;
        } else {
          target = top + item.yAxis.height;
        }
        boxes.push({
          target,
          size: height,
          item
        });
      }
    }, this);
    let legendItem;
    for (const box of distribute$2(boxes, chart.plotHeight)) {
      legendItem = box.item.legendItem || {};
      if (isNumber$X(box.pos)) {
        legendItem.y = chart.plotTop - chart.spacing[0] + box.pos;
      }
    }
  }
  /**
   * Render the legend. This method can be called both before and after
   * `chart.render`. If called after, it will only rearrange items instead
   * of creating new ones. Called internally on initial render and after
   * redraws.
   *
   * @private
   * @function Highcharts.Legend#render
   */
  render() {
    const legend = this, chart = legend.chart, renderer = chart.renderer, options2 = legend.options, padding = legend.padding, allItems = legend.getAllItems();
    let display, legendWidth, legendHeight, legendGroup = legend.group, allowedWidth, box = legend.box;
    legend.itemX = padding;
    legend.itemY = legend.initialItemY;
    legend.offsetWidth = 0;
    legend.lastItemY = 0;
    legend.widthOption = relativeLength$g(options2.width, chart.spacingBox.width - padding);
    allowedWidth = chart.spacingBox.width - 2 * padding - options2.x;
    if (["rm", "lm"].indexOf(legend.getAlignment().substring(0, 2)) > -1) {
      allowedWidth /= 2;
    }
    legend.maxLegendWidth = legend.widthOption || allowedWidth;
    if (!legendGroup) {
      legend.group = legendGroup = renderer.g("legend").addClass(options2.className || "").attr({ zIndex: 7 }).add();
      legend.contentGroup = renderer.g().attr({ zIndex: 1 }).add(legendGroup);
      legend.scrollGroup = renderer.g().add(legend.contentGroup);
    }
    legend.renderTitle();
    stableSort$6(allItems, (a, b) => (a.options?.legendIndex || 0) - (b.options?.legendIndex || 0));
    if (options2.reversed) {
      allItems.reverse();
    }
    legend.allItems = allItems;
    legend.display = display = !!allItems.length;
    legend.lastLineHeight = 0;
    legend.maxItemWidth = 0;
    legend.totalItemWidth = 0;
    legend.itemHeight = 0;
    allItems.forEach(legend.renderItem, legend);
    allItems.forEach(legend.layoutItem, legend);
    legendWidth = (legend.widthOption || legend.offsetWidth) + padding;
    legendHeight = legend.lastItemY + legend.lastLineHeight + legend.titleHeight;
    legendHeight = legend.handleOverflow(legendHeight);
    legendHeight += padding;
    if (!box) {
      legend.box = box = renderer.rect().addClass("highcharts-legend-box").attr({
        r: options2.borderRadius
      }).add(legendGroup);
    }
    if (!chart.styledMode) {
      box.attr({
        stroke: options2.borderColor,
        "stroke-width": options2.borderWidth || 0,
        fill: options2.backgroundColor || "none"
      }).shadow(options2.shadow);
    }
    if (legendWidth > 0 && legendHeight > 0) {
      box[box.placed ? "animate" : "attr"](box.crisp.call({}, {
        x: 0,
        y: 0,
        width: legendWidth,
        height: legendHeight
      }, box.strokeWidth()));
    }
    legendGroup[display ? "show" : "hide"]();
    if (chart.styledMode && legendGroup.getStyle("display") === "none") {
      legendWidth = legendHeight = 0;
    }
    legend.legendWidth = legendWidth;
    legend.legendHeight = legendHeight;
    if (display) {
      legend.align();
    }
    if (!this.proximate) {
      this.positionItems();
    }
    fireEvent$B(this, "afterRender");
  }
  /**
   * Align the legend to chart's box.
   *
   * @private
   * @function Highcharts.align
   * @param {Highcharts.BBoxObject} alignTo
   */
  align(alignTo = this.chart.spacingBox) {
    const chart = this.chart, options2 = this.options;
    let y = alignTo.y;
    if (/(lth|ct|rth)/.test(this.getAlignment()) && chart.titleOffset[0] > 0) {
      y += chart.titleOffset[0];
    } else if (/(lbh|cb|rbh)/.test(this.getAlignment()) && chart.titleOffset[2] > 0) {
      y -= chart.titleOffset[2];
    }
    if (y !== alignTo.y) {
      alignTo = merge$1u(alignTo, { y });
    }
    if (!chart.hasRendered) {
      this.group.placed = false;
    }
    this.group.align(merge$1u(options2, {
      width: this.legendWidth,
      height: this.legendHeight,
      verticalAlign: this.proximate ? "top" : options2.verticalAlign
    }), true, alignTo);
  }
  /**
   * Set up the overflow handling by adding navigation with up and down arrows
   * below the legend.
   *
   * @private
   * @function Highcharts.Legend#handleOverflow
   */
  handleOverflow(legendHeight) {
    const legend = this, chart = this.chart, renderer = chart.renderer, options2 = this.options, optionsY = options2.y, alignTop = options2.verticalAlign === "top", padding = this.padding, maxHeight = options2.maxHeight, navOptions = options2.navigation, animation = pick$1A(navOptions.animation, true), arrowSize = navOptions.arrowSize || 12, pages = this.pages, allItems = this.allItems, clipToHeight = function(height) {
      if (typeof height === "number") {
        clipRect.attr({
          height
        });
      } else if (clipRect) {
        legend.clipRect = clipRect.destroy();
        legend.contentGroup.clip();
      }
      if (legend.contentGroup.div) {
        legend.contentGroup.div.style.clip = height ? "rect(" + padding + "px,9999px," + (padding + height) + "px,0)" : "auto";
      }
    }, addTracker = function(key2) {
      legend[key2] = renderer.circle(0, 0, arrowSize * 1.3).translate(arrowSize / 2, arrowSize / 2).add(nav);
      if (!chart.styledMode) {
        legend[key2].attr("fill", "rgba(0,0,0,0.0001)");
      }
      return legend[key2];
    };
    let clipHeight, lastY, legendItem, lastLegendItem, spaceHeight = chart.spacingBox.height + (alignTop ? -optionsY : optionsY) - padding, nav = this.nav, clipRect = this.clipRect;
    if (options2.layout === "horizontal" && options2.verticalAlign !== "middle" && !options2.floating) {
      spaceHeight /= 2;
    }
    if (maxHeight) {
      spaceHeight = Math.min(spaceHeight, maxHeight);
    }
    pages.length = 0;
    if (legendHeight && spaceHeight > 0 && legendHeight > spaceHeight && navOptions.enabled !== false) {
      this.clipHeight = clipHeight = Math.max(spaceHeight - 20 - this.titleHeight - padding, 0);
      this.currentPage = pick$1A(this.currentPage, 1);
      this.fullHeight = legendHeight;
      allItems.forEach((item, i) => {
        legendItem = item.legendItem || {};
        const y = legendItem.y || 0, h = Math.round(legendItem.label.getBBox().height);
        let len = pages.length;
        if (!len || y - pages[len - 1] > clipHeight && (lastY || y) !== pages[len - 1]) {
          pages.push(lastY || y);
          len++;
        }
        legendItem.pageIx = len - 1;
        if (lastY && lastLegendItem) {
          lastLegendItem.pageIx = len - 1;
        }
        if (
          // Check the last item
          i === allItems.length - 1 && // If adding next page is needed (#18768)
          y + h - pages[len - 1] > clipHeight && y > pages[len - 1]
        ) {
          pages.push(y);
          legendItem.pageIx = len;
        }
        if (y !== lastY) {
          lastY = y;
        }
        lastLegendItem = legendItem;
      });
      if (!clipRect) {
        clipRect = legend.clipRect = renderer.clipRect(0, padding - 2, 9999, 0);
        legend.contentGroup.clip(clipRect);
      }
      clipToHeight(clipHeight);
      if (!nav) {
        this.nav = nav = renderer.g().attr({ zIndex: 1 }).add(this.group);
        this.up = renderer.symbol("triangle", 0, 0, arrowSize, arrowSize).add(nav);
        addTracker("upTracker").on("click", function() {
          legend.scroll(-1, animation);
        });
        this.pager = renderer.text("", 15, 10).addClass("highcharts-legend-navigation");
        if (!chart.styledMode && navOptions.style) {
          this.pager.css(navOptions.style);
        }
        this.pager.add(nav);
        this.down = renderer.symbol("triangle-down", 0, 0, arrowSize, arrowSize).add(nav);
        addTracker("downTracker").on("click", function() {
          legend.scroll(1, animation);
        });
      }
      legend.scroll(0);
      legendHeight = spaceHeight;
    } else if (nav) {
      clipToHeight();
      this.nav = nav.destroy();
      this.scrollGroup.attr({
        translateY: 1
      });
      this.clipHeight = 0;
    }
    return legendHeight;
  }
  /**
   * Scroll the legend by a number of pages.
   *
   * @private
   * @function Highcharts.Legend#scroll
   *
   * @param {number} scrollBy
   *        The number of pages to scroll.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether and how to apply animation.
   *
   */
  scroll(scrollBy, animation) {
    const chart = this.chart, pages = this.pages, pageCount = pages.length, clipHeight = this.clipHeight, navOptions = this.options.navigation, pager = this.pager, padding = this.padding;
    let currentPage = this.currentPage + scrollBy;
    if (currentPage > pageCount) {
      currentPage = pageCount;
    }
    if (currentPage > 0) {
      if (typeof animation !== "undefined") {
        setAnimation$3(animation, chart);
      }
      this.nav.attr({
        translateX: padding,
        translateY: clipHeight + this.padding + 7 + this.titleHeight,
        visibility: "inherit"
      });
      [this.up, this.upTracker].forEach(function(elem) {
        elem.attr({
          "class": currentPage === 1 ? "highcharts-legend-nav-inactive" : "highcharts-legend-nav-active"
        });
      });
      pager.attr({
        text: currentPage + "/" + pageCount
      });
      [this.down, this.downTracker].forEach(function(elem) {
        elem.attr({
          // Adjust to text width
          x: 18 + this.pager.getBBox().width,
          "class": currentPage === pageCount ? "highcharts-legend-nav-inactive" : "highcharts-legend-nav-active"
        });
      }, this);
      if (!chart.styledMode) {
        this.up.attr({
          fill: currentPage === 1 ? navOptions.inactiveColor : navOptions.activeColor
        });
        this.upTracker.css({
          cursor: currentPage === 1 ? "default" : "pointer"
        });
        this.down.attr({
          fill: currentPage === pageCount ? navOptions.inactiveColor : navOptions.activeColor
        });
        this.downTracker.css({
          cursor: currentPage === pageCount ? "default" : "pointer"
        });
      }
      this.scrollOffset = -pages[currentPage - 1] + this.initialItemY;
      this.scrollGroup.animate({
        translateY: this.scrollOffset
      });
      this.currentPage = currentPage;
      this.positionCheckboxes();
      const animOptions = animObject$a(pick$1A(animation, chart.renderer.globalAnimation, true));
      syncTimeout$6(() => {
        fireEvent$B(this, "afterScroll", { currentPage });
      }, animOptions.duration);
    }
  }
  /**
   * @private
   * @function Highcharts.Legend#setItemEvents
   * @param {Highcharts.BubbleLegendItem|Point|Highcharts.Series} item
   * @param {Highcharts.SVGElement} legendLabel
   * @param {boolean} [useHTML=false]
   * @emits Highcharts.Legend#event:itemClick
   */
  setItemEvents(item, legendLabel, useHTML) {
    const legend = this, legendItem = item.legendItem || {}, boxWrapper = legend.chart.renderer.boxWrapper, isPoint = item instanceof Point$3, isSeries = item instanceof Series$9, activeClass = "highcharts-legend-" + (isPoint ? "point" : "series") + "-active", styledMode = legend.chart.styledMode, legendElements = useHTML ? [legendLabel, legendItem.symbol] : [legendItem.group];
    const setOtherItemsState = (state) => {
      legend.allItems.forEach((otherItem) => {
        if (item !== otherItem) {
          [otherItem].concat(otherItem.linkedSeries || []).forEach((otherItem2) => {
            otherItem2.setState(state, !isPoint);
          });
        }
      });
    };
    for (const element of legendElements) {
      if (element) {
        element.on("mouseover", function() {
          if (item.visible) {
            setOtherItemsState("inactive");
          }
          item.setState("hover");
          if (item.visible) {
            boxWrapper.addClass(activeClass);
          }
          if (!styledMode) {
            legendLabel.css(legend.options.itemHoverStyle);
          }
        }).on("mouseout", function() {
          if (!legend.chart.styledMode) {
            legendLabel.css(merge$1u(item.visible ? legend.itemStyle : legend.itemHiddenStyle));
          }
          setOtherItemsState("");
          boxWrapper.removeClass(activeClass);
          item.setState();
        }).on("click", function(event) {
          const defaultItemClick = function() {
            if (item.setVisible) {
              item.setVisible();
            }
            setOtherItemsState(item.visible ? "inactive" : "");
          };
          boxWrapper.removeClass(activeClass);
          fireEvent$B(legend, "itemClick", {
            // Pass over the click/touch event. #4.
            browserEvent: event,
            legendItem: item
          }, defaultItemClick);
          if (isPoint) {
            item.firePointEvent("legendItemClick", {
              browserEvent: event
            });
          } else if (isSeries) {
            fireEvent$B(item, "legendItemClick", {
              browserEvent: event
            });
          }
        });
      }
    }
  }
  /**
   * @private
   * @function Highcharts.Legend#createCheckboxForItem
   * @param {Highcharts.BubbleLegendItem|Point|Highcharts.Series} item
   * @emits Highcharts.Series#event:checkboxClick
   */
  createCheckboxForItem(item) {
    const legend = this;
    item.checkbox = createElement$9("input", {
      type: "checkbox",
      className: "highcharts-legend-checkbox",
      checked: item.selected,
      defaultChecked: item.selected
      // Required by IE7
    }, legend.options.itemCheckboxStyle, legend.chart.container);
    addEvent$1m(item.checkbox, "click", function(event) {
      const target = event.target;
      fireEvent$B(item.series || item, "checkboxClick", {
        checked: target.checked,
        item
      }, function() {
        item.select();
      });
    });
  }
}
(function(Legend2) {
  function compose2(ChartClass) {
    if (pushUnique$v(composed$v, "Core.Legend")) {
      addEvent$1m(ChartClass, "beforeMargins", function() {
        this.legend = new Legend2(this, this.options.legend);
      });
    }
  }
  Legend2.compose = compose2;
})(Legend || (Legend = {}));
const Legend$1 = Legend;
const { animate, animObject: animObject$9, setAnimation: setAnimation$2 } = animationExports;
const { defaultOptions: defaultOptions$g } = DefaultOptions;
const { numberFormat: numberFormat$1 } = Templating;
const { registerEventOptions } = Foundation$1;
const { charts: charts$1, doc: doc$n, marginNames, svg, win: win$8 } = Highcharts;
const { seriesTypes: seriesTypes$4 } = SeriesRegistry$1;
const { addEvent: addEvent$1l, attr: attr$8, createElement: createElement$8, css: css$8, defined: defined$12, diffObjects: diffObjects$3, discardElement: discardElement$3, erase: erase$5, error: error$6, extend: extend$1c, find: find$f, fireEvent: fireEvent$A, getAlignFactor: getAlignFactor$5, getStyle, isArray: isArray$j, isNumber: isNumber$W, isObject: isObject$g, isString: isString$a, merge: merge$1t, objectEach: objectEach$l, pick: pick$1z, pInt: pInt$3, relativeLength: relativeLength$f, removeEvent: removeEvent$7, splat: splat$h, syncTimeout: syncTimeout$5, uniqueKey: uniqueKey$5 } = Utilities;
let Chart$1 = class Chart2 {
  /**
   * Factory function for basic charts.
   *
   * @example
   * // Render a chart in to div#container
   * let chart = Highcharts.chart('container', {
   *     title: {
   *         text: 'My chart'
   *     },
   *     series: [{
   *         data: [1, 3, 2, 4]
   *     }]
   * });
   *
   * @function Highcharts.chart
   *
   * @param {string|Highcharts.HTMLDOMElement} [renderTo]
   * The DOM element to render to, or its id.
   *
   * @param {Highcharts.Options} options
   * The chart options structure.
   *
   * @param {Highcharts.ChartCallbackFunction} [callback]
   * Function to run when the chart has loaded and all external images are
   * loaded. Defining a
   * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
   * handler is equivalent.
   *
   * @return {Highcharts.Chart}
   * Returns the Chart object.
   */
  static chart(a, b, c) {
    return new Chart2(a, b, c);
  }
  // Implementation
  constructor(a, b, c) {
    this.sharedClips = {};
    const args = [
      // ES5 builds fail unless we cast it to an Array
      ...arguments
    ];
    if (isString$a(a) || a.nodeName) {
      this.renderTo = args.shift();
    }
    this.init(args[0], args[1]);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Function setting zoom options after chart init and after chart update.
   * Offers support for deprecated options.
   *
   * @private
   * @function Highcharts.Chart#setZoomOptions
   */
  setZoomOptions() {
    const chart = this, options2 = chart.options.chart, zooming = options2.zooming;
    chart.zooming = {
      ...zooming,
      type: pick$1z(options2.zoomType, zooming.type),
      key: pick$1z(options2.zoomKey, zooming.key),
      pinchType: pick$1z(options2.pinchType, zooming.pinchType),
      singleTouch: pick$1z(options2.zoomBySingleTouch, zooming.singleTouch, false),
      resetButton: merge$1t(zooming.resetButton, options2.resetZoomButton)
    };
  }
  /**
   * Overridable function that initializes the chart. The constructor's
   * arguments are passed on directly.
   *
   * @function Highcharts.Chart#init
   *
   * @param {Highcharts.Options} userOptions
   *        Custom options.
   *
   * @param {Function} [callback]
   *        Function to run when the chart has loaded and all external
   *        images are loaded.
   *
   *
   * @emits Highcharts.Chart#event:init
   * @emits Highcharts.Chart#event:afterInit
   */
  init(userOptions, callback) {
    fireEvent$A(this, "init", { args: arguments }, function() {
      const options2 = merge$1t(defaultOptions$g, userOptions), optionsChart = options2.chart, renderTo = this.renderTo || optionsChart.renderTo;
      this.userOptions = extend$1c({}, userOptions);
      if (!(this.renderTo = isString$a(renderTo) ? doc$n.getElementById(renderTo) : renderTo)) {
        error$6(13, true, this);
      }
      this.margin = [];
      this.spacing = [];
      this.labelCollectors = [];
      this.callback = callback;
      this.isResizing = 0;
      this.options = options2;
      this.axes = [];
      this.series = [];
      this.locale = options2.lang.locale ?? this.renderTo.closest("[lang]")?.lang;
      this.time = new Time(extend$1c(options2.time || {}, {
        locale: this.locale
      }), options2.lang);
      options2.time = this.time.options;
      this.numberFormatter = (optionsChart.numberFormatter || numberFormat$1).bind(this);
      this.styledMode = optionsChart.styledMode;
      this.hasCartesianSeries = optionsChart.showAxes;
      const chart = this;
      chart.index = charts$1.length;
      charts$1.push(chart);
      Highcharts.chartCount++;
      registerEventOptions(this, optionsChart);
      chart.xAxis = [];
      chart.yAxis = [];
      chart.pointCount = chart.colorCounter = chart.symbolCounter = 0;
      this.setZoomOptions();
      fireEvent$A(chart, "afterInit");
      chart.firstRender();
    });
  }
  /**
   * Internal function to unitialize an individual series.
   *
   * @private
   * @function Highcharts.Chart#initSeries
   */
  initSeries(options2) {
    const chart = this, optionsChart = chart.options.chart, type = options2.type || optionsChart.type, SeriesClass = seriesTypes$4[type];
    if (!SeriesClass) {
      error$6(17, true, chart, { missingModuleFor: type });
    }
    const series = new SeriesClass();
    if (typeof series.init === "function") {
      series.init(chart, options2);
    }
    return series;
  }
  /**
   * Internal function to set data for all series with enabled sorting.
   *
   * @private
   * @function Highcharts.Chart#setSortedData
   */
  setSortedData() {
    this.getSeriesOrderByLinks().forEach(function(series) {
      if (!series.points && !series.data && series.enabledDataSorting) {
        series.setData(series.options.data, false);
      }
    });
  }
  /**
   * Sort and return chart series in order depending on the number of linked
   * series.
   *
   * @private
   * @function Highcharts.Series#getSeriesOrderByLinks
   */
  getSeriesOrderByLinks() {
    return this.series.concat().sort(function(a, b) {
      if (a.linkedSeries.length || b.linkedSeries.length) {
        return b.linkedSeries.length - a.linkedSeries.length;
      }
      return 0;
    });
  }
  /**
   * Order all series or axes above a given index. When series or axes are
   * added and ordered by configuration, only the last series is handled
   * (#248, #1123, #2456, #6112). This function is called on series and axis
   * initialization and destroy.
   *
   * @private
   * @function Highcharts.Chart#orderItems
   * @param {string} coll The collection name
   * @param {number} [fromIndex=0]
   * If this is given, only the series above this index are handled.
   */
  orderItems(coll, fromIndex = 0) {
    const collection = this[coll], optionsArray = this.options[coll] = splat$h(this.options[coll]).slice(), userOptionsArray = this.userOptions[coll] = this.userOptions[coll] ? splat$h(this.userOptions[coll]).slice() : [];
    if (this.hasRendered) {
      optionsArray.splice(fromIndex);
      userOptionsArray.splice(fromIndex);
    }
    if (collection) {
      for (let i = fromIndex, iEnd = collection.length; i < iEnd; ++i) {
        const item = collection[i];
        if (item) {
          item.index = i;
          if (item instanceof Series$9) {
            item.name = item.getName();
          }
          if (!item.options.isInternal) {
            optionsArray[i] = item.options;
            userOptionsArray[i] = item.userOptions;
          }
        }
      }
    }
  }
  /**
   * Get the clipping for a series. Could be called for a series to initialate
   * animating the clip or to set the final clip (only width and x).
   *
   * @private
   * @function Highcharts.Chart#getClipBox
   */
  getClipBox(series, chartCoords) {
    const inverted = this.inverted, { xAxis: xAxis2, yAxis: yAxis2 } = series || {};
    let { x, y, width, height } = merge$1t(this.clipBox);
    if (series) {
      if (xAxis2 && xAxis2.len !== this.plotSizeX) {
        width = xAxis2.len;
      }
      if (yAxis2 && yAxis2.len !== this.plotSizeY) {
        height = yAxis2.len;
      }
      if (inverted && !series.invertible) {
        [width, height] = [height, width];
      }
    }
    if (chartCoords) {
      x += (inverted ? yAxis2 : xAxis2)?.pos ?? this.plotLeft;
      y += (inverted ? xAxis2 : yAxis2)?.pos ?? this.plotTop;
    }
    return { x, y, width, height };
  }
  /**
   * Check whether a given point is within the plot area.
   *
   * @function Highcharts.Chart#isInsidePlot
   *
   * @param {number} plotX
   * Pixel x relative to the plot area.
   *
   * @param {number} plotY
   * Pixel y relative to the plot area.
   *
   * @param {Highcharts.ChartIsInsideOptionsObject} [options]
   * Options object.
   *
   * @return {boolean}
   * Returns true if the given point is inside the plot area.
   */
  isInsidePlot(plotX, plotY, options2 = {}) {
    const { inverted, plotBox, plotLeft, plotTop, scrollablePlotBox } = this, { scrollLeft = 0, scrollTop = 0 } = options2.visiblePlotOnly && this.scrollablePlotArea?.scrollingContainer || {}, series = options2.series, box = options2.visiblePlotOnly && scrollablePlotBox || plotBox, x = options2.inverted ? plotY : plotX, y = options2.inverted ? plotX : plotY, e = {
      x,
      y,
      isInsidePlot: true,
      options: options2
    };
    if (!options2.ignoreX) {
      const xAxis2 = series && (inverted && !this.polar ? series.yAxis : series.xAxis) || {
        pos: plotLeft,
        len: Infinity
      };
      const chartX = options2.paneCoordinates ? xAxis2.pos + x : plotLeft + x;
      if (!(chartX >= Math.max(scrollLeft + plotLeft, xAxis2.pos) && chartX <= Math.min(scrollLeft + plotLeft + box.width, xAxis2.pos + xAxis2.len))) {
        e.isInsidePlot = false;
      }
    }
    if (!options2.ignoreY && e.isInsidePlot) {
      const yAxis2 = !inverted && options2.axis && !options2.axis.isXAxis && options2.axis || series && (inverted ? series.xAxis : series.yAxis) || {
        pos: plotTop,
        len: Infinity
      };
      const chartY = options2.paneCoordinates ? yAxis2.pos + y : plotTop + y;
      if (!(chartY >= Math.max(scrollTop + plotTop, yAxis2.pos) && chartY <= Math.min(scrollTop + plotTop + box.height, yAxis2.pos + yAxis2.len))) {
        e.isInsidePlot = false;
      }
    }
    fireEvent$A(this, "afterIsInsidePlot", e);
    return e.isInsidePlot;
  }
  /**
   * Redraw the chart after changes have been done to the data, axis extremes
   * chart size or chart elements. All methods for updating axes, series or
   * points have a parameter for redrawing the chart. This is `true` by
   * default. But in many cases you want to do more than one operation on the
   * chart before redrawing, for example add a number of points. In those
   * cases it is a waste of resources to redraw the chart for each new point
   * added. So you add the points and call `chart.redraw()` after.
   *
   * @function Highcharts.Chart#redraw
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   * If or how to apply animation to the redraw. When `undefined`, it applies
   * the animation that is set in the `chart.animation` option.
   *
   * @emits Highcharts.Chart#event:afterSetExtremes
   * @emits Highcharts.Chart#event:beforeRedraw
   * @emits Highcharts.Chart#event:predraw
   * @emits Highcharts.Chart#event:redraw
   * @emits Highcharts.Chart#event:render
   * @emits Highcharts.Chart#event:updatedData
   */
  redraw(animation) {
    fireEvent$A(this, "beforeRedraw");
    const chart = this, axes = chart.hasCartesianSeries ? chart.axes : chart.colorAxis || [], series = chart.series, pointer = chart.pointer, legend = chart.legend, legendUserOptions = chart.userOptions.legend, renderer = chart.renderer, isHiddenChart = renderer.isHidden(), afterRedraw = [];
    let hasDirtyStacks, hasStackedSeries, i, isDirtyBox = chart.isDirtyBox, redrawLegend = chart.isDirtyLegend, serie;
    renderer.rootFontSize = renderer.boxWrapper.getStyle("font-size");
    if (chart.setResponsive) {
      chart.setResponsive(false);
    }
    setAnimation$2(chart.hasRendered ? animation : false, chart);
    if (isHiddenChart) {
      chart.temporaryDisplay();
    }
    chart.layOutTitles(false);
    i = series.length;
    while (i--) {
      serie = series[i];
      if (serie.options.stacking || serie.options.centerInCategory) {
        hasStackedSeries = true;
        if (serie.isDirty) {
          hasDirtyStacks = true;
          break;
        }
      }
    }
    if (hasDirtyStacks) {
      i = series.length;
      while (i--) {
        serie = series[i];
        if (serie.options.stacking) {
          serie.isDirty = true;
        }
      }
    }
    series.forEach(function(serie2) {
      if (serie2.isDirty) {
        if (serie2.options.legendType === "point") {
          if (typeof serie2.updateTotals === "function") {
            serie2.updateTotals();
          }
          redrawLegend = true;
        } else if (legendUserOptions && (!!legendUserOptions.labelFormatter || legendUserOptions.labelFormat)) {
          redrawLegend = true;
        }
      }
      if (serie2.isDirtyData) {
        fireEvent$A(serie2, "updatedData");
      }
    });
    if (redrawLegend && legend && legend.options.enabled) {
      legend.render();
      chart.isDirtyLegend = false;
    }
    if (hasStackedSeries) {
      chart.getStacks();
    }
    axes.forEach(function(axis) {
      axis.updateNames();
      axis.setScale();
    });
    chart.getMargins();
    axes.forEach(function(axis) {
      if (axis.isDirty) {
        isDirtyBox = true;
      }
    });
    axes.forEach(function(axis) {
      const key2 = axis.min + "," + axis.max;
      if (axis.extKey !== key2) {
        axis.extKey = key2;
        afterRedraw.push(function() {
          fireEvent$A(axis, "afterSetExtremes", extend$1c(axis.eventArgs, axis.getExtremes()));
          delete axis.eventArgs;
        });
      }
      if (isDirtyBox || hasStackedSeries) {
        axis.redraw();
      }
    });
    if (isDirtyBox) {
      chart.drawChartBox();
    }
    fireEvent$A(chart, "predraw");
    series.forEach(function(serie2) {
      if ((isDirtyBox || serie2.isDirty) && serie2.visible) {
        serie2.redraw();
      }
      serie2.isDirtyData = false;
    });
    if (pointer) {
      pointer.reset(true);
    }
    renderer.draw();
    fireEvent$A(chart, "redraw");
    fireEvent$A(chart, "render");
    if (isHiddenChart) {
      chart.temporaryDisplay(true);
    }
    afterRedraw.forEach(function(callback) {
      callback.call();
    });
  }
  /**
   * Get an axis, series or point object by `id` as given in the configuration
   * options. Returns `undefined` if no item is found.
   *
   * @sample highcharts/plotoptions/series-id/
   *         Get series by id
   *
   * @function Highcharts.Chart#get
   *
   * @param {string} id
   * The id as given in the configuration options.
   *
   * @return {Highcharts.Axis|Highcharts.Series|Highcharts.Point|undefined}
   * The retrieved item.
   */
  get(id) {
    const series = this.series;
    function itemById(item) {
      return item.id === id || item.options && item.options.id === id;
    }
    let ret = (
      // Search axes
      find$f(this.axes, itemById) || // Search series
      find$f(this.series, itemById)
    );
    for (let i = 0; !ret && i < series.length; i++) {
      ret = find$f(series[i].points || [], itemById);
    }
    return ret;
  }
  /**
   * Create the Axis instances based on the config options.
   *
   * @private
   * @function Highcharts.Chart#createAxes
   * @emits Highcharts.Chart#event:afterCreateAxes
   * @emits Highcharts.Chart#event:createAxes
   */
  createAxes() {
    const options2 = this.userOptions;
    fireEvent$A(this, "createAxes");
    for (const coll of ["xAxis", "yAxis"]) {
      const arr = options2[coll] = splat$h(options2[coll] || {});
      for (const axisOptions of arr) {
        new Axis(this, axisOptions, coll);
      }
    }
    fireEvent$A(this, "afterCreateAxes");
  }
  /**
   * Returns an array of all currently selected points in the chart. Points
   * can be selected by clicking or programmatically by the
   * {@link Highcharts.Point#select}
   * function.
   *
   * @sample highcharts/plotoptions/series-allowpointselect-line/
   *         Get selected points
   * @sample highcharts/members/point-select-lasso/
   *         Lasso selection
   * @sample highcharts/chart/events-selection-points/
   *         Rectangle selection
   *
   * @function Highcharts.Chart#getSelectedPoints
   *
   * @return {Array<Highcharts.Point>}
   *         The currently selected points.
   */
  getSelectedPoints() {
    return this.series.reduce((acc, series) => {
      series.getPointsCollection().forEach((point) => {
        if (pick$1z(point.selectedStaging, point.selected)) {
          acc.push(point);
        }
      });
      return acc;
    }, []);
  }
  /**
   * Returns an array of all currently selected series in the chart. Series
   * can be selected either programmatically by the
   * {@link Highcharts.Series#select}
   * function or by checking the checkbox next to the legend item if
   * [series.showCheckBox](https://api.highcharts.com/highcharts/plotOptions.series.showCheckbox)
   * is true.
   *
   * @sample highcharts/members/chart-getselectedseries/
   *         Get selected series
   *
   * @function Highcharts.Chart#getSelectedSeries
   *
   * @return {Array<Highcharts.Series>}
   *         The currently selected series.
   */
  getSelectedSeries() {
    return this.series.filter((s) => s.selected);
  }
  /**
   * Set a new title or subtitle for the chart.
   *
   * @sample highcharts/members/chart-settitle/
   *         Set title text and styles
   *
   * @function Highcharts.Chart#setTitle
   *
   * @param {Highcharts.TitleOptions} [titleOptions]
   *        New title options. The title text itself is set by the
   *        `titleOptions.text` property.
   *
   * @param {Highcharts.SubtitleOptions} [subtitleOptions]
   *        New subtitle options. The subtitle text itself is set by the
   *        `subtitleOptions.text` property.
   *
   * @param {boolean} [redraw]
   *        Whether to redraw the chart or wait for a later call to
   *        `chart.redraw()`.
   */
  setTitle(titleOptions, subtitleOptions, redraw) {
    this.applyDescription("title", titleOptions);
    this.applyDescription("subtitle", subtitleOptions);
    this.applyDescription("caption", void 0);
    this.layOutTitles(redraw);
  }
  /**
   * Apply a title, subtitle or caption for the chart
   *
   * @private
   * @function Highcharts.Chart#applyDescription
   * @param key {string}
   * Either title, subtitle or caption
   * @param {Highcharts.TitleOptions|Highcharts.SubtitleOptions|Highcharts.CaptionOptions|undefined} explicitOptions
   * The options to set, will be merged with default options.
   */
  applyDescription(key2, explicitOptions) {
    const chart = this;
    const options2 = this.options[key2] = merge$1t(this.options[key2], explicitOptions);
    let elem = this[key2];
    if (elem && explicitOptions) {
      this[key2] = elem = elem.destroy();
    }
    if (options2 && !elem) {
      elem = this.renderer.text(options2.text, 0, 0, options2.useHTML).attr({
        align: options2.align,
        "class": "highcharts-" + key2,
        zIndex: options2.zIndex || 4
      }).css({
        textOverflow: "ellipsis",
        whiteSpace: "nowrap"
      }).add();
      elem.update = function(updateOptions, redraw) {
        chart.applyDescription(key2, updateOptions);
        chart.layOutTitles(redraw);
      };
      if (!this.styledMode) {
        elem.css(extend$1c(key2 === "title" ? {
          // #2944
          fontSize: this.options.isStock ? "1em" : "1.2em"
        } : {}, options2.style));
      }
      elem.textPxLength = elem.getBBox().width;
      elem.css({ whiteSpace: options2.style?.whiteSpace });
      this[key2] = elem;
    }
  }
  /**
   * Internal function to lay out the chart title, subtitle and caption, and
   * cache the full offset height for use in `getMargins`. The result is
   * stored in `this.titleOffset`.
   *
   * @private
   * @function Highcharts.Chart#layOutTitles
   *
   * @param {boolean} [redraw=true]
   * @emits Highcharts.Chart#event:afterLayOutTitles
   */
  layOutTitles(redraw = true) {
    const titleOffset = [0, 0, 0], { options: options2, renderer, spacingBox } = this;
    ["title", "subtitle", "caption"].forEach((key2) => {
      const desc = this[key2], descOptions = this.options[key2], alignTo = merge$1t(spacingBox), textPxLength = desc?.textPxLength || 0;
      if (desc && descOptions) {
        fireEvent$A(this, "layOutTitle", { alignTo, key: key2, textPxLength });
        const fontMetrics = renderer.fontMetrics(desc), baseline = fontMetrics.b, lineHeight = fontMetrics.h, verticalAlign = descOptions.verticalAlign || "top", topAligned = verticalAlign === "top", minScale = topAligned && descOptions.minScale || 1, offset2 = key2 === "title" ? topAligned ? -3 : 0 : (
          // Floating subtitle (#6574)
          topAligned ? titleOffset[0] + 2 : 0
        ), uncappedScale = Math.min(alignTo.width / textPxLength, 1), scale2 = Math.max(minScale, uncappedScale), alignAttr = merge$1t({
          y: verticalAlign === "bottom" ? baseline : offset2 + baseline
        }, {
          align: key2 === "title" ? (
            // Title defaults to center for short titles,
            // left for word-wrapped titles
            uncappedScale < minScale ? "left" : "center"
          ) : (
            // Subtitle defaults to the title.align
            this.title?.alignValue
          )
        }, descOptions), width = (descOptions.width || (uncappedScale > minScale ? (
          // One line
          this.chartWidth
        ) : (
          // Allow word wrap
          alignTo.width
        )) / scale2) + "px";
        if (desc.alignValue !== alignAttr.align) {
          desc.placed = false;
        }
        const height = Math.round(desc.css({ width }).getBBox(descOptions.useHTML).height);
        alignAttr.height = height;
        desc.align(alignAttr, false, alignTo).attr({
          align: alignAttr.align,
          scaleX: scale2,
          scaleY: scale2,
          "transform-origin": `${alignTo.x + textPxLength * scale2 * getAlignFactor$5(alignAttr.align)} ${lineHeight}`
        });
        if (!descOptions.floating) {
          const offset3 = height * // When scaling down the title, preserve the offset as
          // long as it's only one line, but scale down the offset
          // if the title wraps to multiple lines.
          (height < lineHeight * 1.2 ? 1 : scale2);
          if (verticalAlign === "top") {
            titleOffset[0] = Math.ceil(titleOffset[0] + offset3);
          } else if (verticalAlign === "bottom") {
            titleOffset[2] = Math.ceil(titleOffset[2] + offset3);
          }
        }
      }
    }, this);
    if (titleOffset[0] && (options2.title?.verticalAlign || "top") === "top") {
      titleOffset[0] += options2.title?.margin || 0;
    }
    if (titleOffset[2] && options2.caption?.verticalAlign === "bottom") {
      titleOffset[2] += options2.caption?.margin || 0;
    }
    const requiresDirtyBox = !this.titleOffset || this.titleOffset.join(",") !== titleOffset.join(",");
    this.titleOffset = titleOffset;
    fireEvent$A(this, "afterLayOutTitles");
    if (!this.isDirtyBox && requiresDirtyBox) {
      this.isDirtyBox = this.isDirtyLegend = requiresDirtyBox;
      if (this.hasRendered && redraw && this.isDirtyBox) {
        this.redraw();
      }
    }
  }
  /**
   * Internal function to get the available size of the container element
   *
   * @private
   * @function Highcharts.Chart#getContainerBox
   */
  getContainerBox() {
    const nonContainers = [].map.call(this.renderTo.children, (child) => {
      if (child !== this.container) {
        const display = child.style.display;
        child.style.display = "none";
        return [child, display];
      }
    }), box = {
      width: getStyle(this.renderTo, "width", true) || 0,
      height: getStyle(this.renderTo, "height", true) || 0
    };
    nonContainers.filter(Boolean).forEach(([div, display]) => {
      div.style.display = display;
    });
    return box;
  }
  /**
   * Internal function to get the chart width and height according to options
   * and container size. Sets {@link Chart.chartWidth} and
   * {@link Chart.chartHeight}.
   *
   * @private
   * @function Highcharts.Chart#getChartSize
   */
  getChartSize() {
    const chart = this, optionsChart = chart.options.chart, widthOption = optionsChart.width, heightOption = optionsChart.height, containerBox = chart.getContainerBox(), enableDefaultHeight = containerBox.height <= 1 || // #21510, prevent infinite reflow
    !chart.renderTo.parentElement?.style.height && chart.renderTo.style.height === "100%";
    chart.chartWidth = Math.max(
      // #1393
      0,
      widthOption || containerBox.width || 600
      // #1460
    );
    chart.chartHeight = Math.max(0, relativeLength$f(heightOption, chart.chartWidth) || (enableDefaultHeight ? 400 : containerBox.height));
    chart.containerBox = containerBox;
  }
  /**
   * If the renderTo element has no offsetWidth, most likely one or more of
   * its parents are hidden. Loop up the DOM tree to temporarily display the
   * parents, then save the original display properties, and when the true
   * size is retrieved, reset them. Used on first render and on redraws.
   *
   * @private
   * @function Highcharts.Chart#temporaryDisplay
   *
   * @param {boolean} [revert]
   * Revert to the saved original styles.
   */
  temporaryDisplay(revert) {
    let node = this.renderTo, tempStyle;
    if (!revert) {
      while (node?.style) {
        if (!doc$n.body.contains(node) && !node.parentNode) {
          node.hcOrigDetached = true;
          doc$n.body.appendChild(node);
        }
        if (getStyle(node, "display", false) === "none" || node.hcOricDetached) {
          node.hcOrigStyle = {
            display: node.style.display,
            height: node.style.height,
            overflow: node.style.overflow
          };
          tempStyle = {
            display: "block",
            overflow: "hidden"
          };
          if (node !== this.renderTo) {
            tempStyle.height = 0;
          }
          css$8(node, tempStyle);
          if (!node.offsetWidth) {
            node.style.setProperty("display", "block", "important");
          }
        }
        node = node.parentNode;
        if (node === doc$n.body) {
          break;
        }
      }
    } else {
      while (node?.style) {
        if (node.hcOrigStyle) {
          css$8(node, node.hcOrigStyle);
          delete node.hcOrigStyle;
        }
        if (node.hcOrigDetached) {
          doc$n.body.removeChild(node);
          node.hcOrigDetached = false;
        }
        node = node.parentNode;
      }
    }
  }
  /**
   * Set the {@link Chart.container|chart container's} class name, in
   * addition to `highcharts-container`.
   *
   * @function Highcharts.Chart#setClassName
   *
   * @param {string} [className]
   * The additional class name.
   */
  setClassName(className) {
    this.container.className = "highcharts-container " + (className || "");
  }
  /**
   * Get the containing element, determine the size and create the inner
   * container div to hold the chart.
   *
   * @private
   * @function Highcharts.Chart#afterGetContainer
   * @emits Highcharts.Chart#event:afterGetContainer
   */
  getContainer() {
    const chart = this, options2 = chart.options, optionsChart = options2.chart, indexAttrName = "data-highcharts-chart", containerId = uniqueKey$5(), renderTo = chart.renderTo;
    let containerStyle;
    const oldChartIndex = pInt$3(attr$8(renderTo, indexAttrName));
    if (isNumber$W(oldChartIndex) && charts$1[oldChartIndex] && charts$1[oldChartIndex].hasRendered) {
      charts$1[oldChartIndex].destroy();
    }
    attr$8(renderTo, indexAttrName, chart.index);
    renderTo.innerHTML = AST.emptyHTML;
    if (!optionsChart.skipClone && !renderTo.offsetWidth) {
      chart.temporaryDisplay();
    }
    chart.getChartSize();
    const chartHeight = chart.chartHeight;
    let chartWidth = chart.chartWidth;
    css$8(renderTo, { overflow: "hidden" });
    if (!chart.styledMode) {
      containerStyle = extend$1c({
        position: "relative",
        // Needed for context menu (avoidscrollbars) and content
        // overflow in IE
        overflow: "hidden",
        width: chartWidth + "px",
        height: chartHeight + "px",
        textAlign: "left",
        lineHeight: "normal",
        // #427
        zIndex: 0,
        // #1072
        "-webkit-tap-highlight-color": "rgba(0,0,0,0)",
        userSelect: "none",
        // #13503
        "touch-action": "manipulation",
        outline: "none",
        padding: "0px"
      }, optionsChart.style || {});
    }
    const container = createElement$8("div", {
      id: containerId
    }, containerStyle, renderTo);
    chart.container = container;
    chart.getChartSize();
    if (chartWidth !== chart.chartWidth) {
      chartWidth = chart.chartWidth;
      if (!chart.styledMode) {
        css$8(container, {
          width: pick$1z(optionsChart.style?.width, chartWidth + "px")
        });
      }
    }
    chart.containerBox = chart.getContainerBox();
    chart._cursor = container.style.cursor;
    const Renderer = optionsChart.renderer || !svg ? RendererRegistry$1.getRendererType(optionsChart.renderer) : SVGRenderer;
    chart.renderer = new Renderer(container, chartWidth, chartHeight, void 0, optionsChart.forExport, options2.exporting?.allowHTML, chart.styledMode);
    setAnimation$2(void 0, chart);
    chart.setClassName(optionsChart.className);
    if (!chart.styledMode) {
      chart.renderer.setStyle(optionsChart.style);
    } else {
      for (const key2 in options2.defs) {
        this.renderer.definition(options2.defs[key2]);
      }
    }
    chart.renderer.chartIndex = chart.index;
    fireEvent$A(this, "afterGetContainer");
  }
  /**
   * Calculate margins by rendering axis labels in a preliminary position.
   * Title, subtitle and legend have already been rendered at this stage, but
   * will be moved into their final positions.
   *
   * @private
   * @function Highcharts.Chart#getMargins
   * @emits Highcharts.Chart#event:getMargins
   */
  getMargins(skipAxes) {
    const { spacing, margin, titleOffset } = this;
    this.resetMargins();
    if (titleOffset[0] && !defined$12(margin[0])) {
      this.plotTop = Math.max(this.plotTop, titleOffset[0] + spacing[0]);
    }
    if (titleOffset[2] && !defined$12(margin[2])) {
      this.marginBottom = Math.max(this.marginBottom, titleOffset[2] + spacing[2]);
    }
    if (this.legend?.display) {
      this.legend.adjustMargins(margin, spacing);
    }
    fireEvent$A(this, "getMargins");
    if (!skipAxes) {
      this.getAxisMargins();
    }
  }
  /**
   * @private
   * @function Highcharts.Chart#getAxisMargins
   */
  getAxisMargins() {
    const chart = this, axisOffset = chart.axisOffset = [0, 0, 0, 0], colorAxis = chart.colorAxis, margin = chart.margin, getOffset2 = function(axes) {
      axes.forEach(function(axis) {
        if (axis.visible) {
          axis.getOffset();
        }
      });
    };
    if (chart.hasCartesianSeries) {
      getOffset2(chart.axes);
    } else if (colorAxis?.length) {
      getOffset2(colorAxis);
    }
    marginNames.forEach(function(m, side) {
      if (!defined$12(margin[side])) {
        chart[m] += axisOffset[side];
      }
    });
    chart.setChartSize();
  }
  /**
   * Return the current options of the chart, but only those that differ from
   * default options. Items that can be either an object or an array of
   * objects, like `series`, `xAxis` and `yAxis`, are always returned as
   * array.
   *
   * @sample highcharts/members/chart-getoptions
   *
   * @function Highcharts.Chart#getOptions
   *
   * @since 11.1.0
   */
  getOptions() {
    return diffObjects$3(this.userOptions, defaultOptions$g);
  }
  /**
   * Reflows the chart to its container. By default, the Resize Observer is
   * attached to the chart's div which allows to reflows the chart
   * automatically to its container, as per the
   * [chart.reflow](https://api.highcharts.com/highcharts/chart.reflow)
   * option.
   *
   * @sample highcharts/chart/events-container/
   *         Pop up and reflow
   *
   * @function Highcharts.Chart#reflow
   *
   * @param {global.Event} [e]
   *        Event arguments. Used primarily when the function is called
   *        internally as a response to window resize.
   */
  reflow(e) {
    const chart = this, oldBox = chart.containerBox, containerBox = chart.getContainerBox();
    delete chart.pointer?.chartPosition;
    if (!chart.isPrinting && !chart.isResizing && oldBox && // When fired by resize observer inside hidden container
    containerBox.width) {
      if (containerBox.width !== oldBox.width || containerBox.height !== oldBox.height) {
        Utilities.clearTimeout(chart.reflowTimeout);
        chart.reflowTimeout = syncTimeout$5(function() {
          if (chart.container) {
            chart.setSize(void 0, void 0, false);
          }
        }, e ? 100 : 0);
      }
      chart.containerBox = containerBox;
    }
  }
  /**
   * Toggle the event handlers necessary for auto resizing, depending on the
   * `chart.reflow` option.
   *
   * @private
   * @function Highcharts.Chart#setReflow
   */
  setReflow() {
    const chart = this;
    const runReflow = (e) => {
      if (chart.options?.chart.reflow && chart.hasLoaded) {
        chart.reflow(e);
      }
    };
    if (typeof ResizeObserver === "function") {
      new ResizeObserver(runReflow).observe(chart.renderTo);
    } else {
      const unbind = addEvent$1l(win$8, "resize", runReflow);
      addEvent$1l(this, "destroy", unbind);
    }
  }
  /**
   * Resize the chart to a given width and height. In order to set the width
   * only, the height argument may be skipped. To set the height only, pass
   * `undefined` for the width.
   *
   * @sample highcharts/members/chart-setsize-button/
   *         Test resizing from buttons
   * @sample highcharts/members/chart-setsize-jquery-resizable/
   *         Add a jQuery UI resizable
   * @sample stock/members/chart-setsize/
   *         Highcharts Stock with UI resizable
   *
   * @function Highcharts.Chart#setSize
   *
   * @param {number|null} [width]
   *        The new pixel width of the chart. Since v4.2.6, the argument can
   *        be `undefined` in order to preserve the current value (when
   *        setting height only), or `null` to adapt to the width of the
   *        containing element.
   *
   * @param {number|null} [height]
   *        The new pixel height of the chart. Since v4.2.6, the argument can
   *        be `undefined` in order to preserve the current value, or `null`
   *        in order to adapt to the height of the containing element.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether and how to apply animation. When `undefined`, it applies
   *        the animation that is set in the `chart.animation` option.
   *
   *
   * @emits Highcharts.Chart#event:endResize
   * @emits Highcharts.Chart#event:resize
   */
  setSize(width, height, animation) {
    const chart = this, renderer = chart.renderer;
    chart.isResizing += 1;
    setAnimation$2(animation, chart);
    const globalAnimation = renderer.globalAnimation;
    chart.oldChartHeight = chart.chartHeight;
    chart.oldChartWidth = chart.chartWidth;
    if (typeof width !== "undefined") {
      chart.options.chart.width = width;
    }
    if (typeof height !== "undefined") {
      chart.options.chart.height = height;
    }
    chart.getChartSize();
    const { chartWidth, chartHeight, scrollablePixelsX = 0, scrollablePixelsY = 0 } = chart;
    if (chart.isDirtyBox || chartWidth !== chart.oldChartWidth || chartHeight !== chart.oldChartHeight) {
      if (!chart.styledMode) {
        (globalAnimation ? animate : css$8)(chart.container, {
          width: `${chartWidth + scrollablePixelsX}px`,
          height: `${chartHeight + scrollablePixelsY}px`
        }, globalAnimation);
      }
      chart.setChartSize(true);
      renderer.setSize(chartWidth, chartHeight, globalAnimation);
      chart.axes.forEach(function(axis) {
        axis.isDirty = true;
        axis.setScale();
      });
      chart.isDirtyLegend = true;
      chart.isDirtyBox = true;
      chart.layOutTitles();
      chart.getMargins();
      chart.redraw(globalAnimation);
      chart.oldChartHeight = void 0;
      fireEvent$A(chart, "resize");
      setTimeout(() => {
        if (chart) {
          fireEvent$A(chart, "endResize");
        }
      }, animObject$9(globalAnimation).duration);
    }
    chart.isResizing -= 1;
  }
  /**
   * Set the public chart properties. This is done before and after the
   * pre-render to determine margin sizes.
   *
   * @private
   * @function Highcharts.Chart#setChartSize
   * @emits Highcharts.Chart#event:afterSetChartSize
   */
  setChartSize(skipAxes) {
    const chart = this, { chartHeight, chartWidth, inverted, spacing, renderer } = chart, clipOffset = chart.clipOffset, clipRoundFunc = Math[inverted ? "floor" : "round"];
    let plotLeft, plotTop, plotWidth, plotHeight;
    chart.plotLeft = plotLeft = Math.round(chart.plotLeft);
    chart.plotTop = plotTop = Math.round(chart.plotTop);
    chart.plotWidth = plotWidth = Math.max(0, Math.round(chartWidth - plotLeft - (chart.marginRight ?? 0)));
    chart.plotHeight = plotHeight = Math.max(0, Math.round(chartHeight - plotTop - (chart.marginBottom ?? 0)));
    chart.plotSizeX = inverted ? plotHeight : plotWidth;
    chart.plotSizeY = inverted ? plotWidth : plotHeight;
    chart.spacingBox = renderer.spacingBox = {
      x: spacing[3],
      y: spacing[0],
      width: chartWidth - spacing[3] - spacing[1],
      height: chartHeight - spacing[0] - spacing[2]
    };
    chart.plotBox = renderer.plotBox = {
      x: plotLeft,
      y: plotTop,
      width: plotWidth,
      height: plotHeight
    };
    if (clipOffset) {
      chart.clipBox = {
        x: clipRoundFunc(clipOffset[3]),
        y: clipRoundFunc(clipOffset[0]),
        width: clipRoundFunc(chart.plotSizeX - clipOffset[1] - clipOffset[3]),
        height: clipRoundFunc(chart.plotSizeY - clipOffset[0] - clipOffset[2])
      };
    }
    if (!skipAxes) {
      chart.axes.forEach(function(axis) {
        axis.setAxisSize();
        axis.setAxisTranslation();
      });
      renderer.alignElements();
    }
    fireEvent$A(chart, "afterSetChartSize", { skipAxes });
  }
  /**
   * Initial margins before auto size margins are applied.
   *
   * @private
   * @function Highcharts.Chart#resetMargins
   */
  resetMargins() {
    fireEvent$A(this, "resetMargins");
    const chart = this, chartOptions = chart.options.chart, plotBorderWidth = chartOptions.plotBorderWidth || 0, halfWidth = Math.round(plotBorderWidth) / 2;
    ["margin", "spacing"].forEach(function splashArrays(target) {
      const value = chartOptions[target], values = isObject$g(value) ? value : [value, value, value, value];
      [
        "Top",
        "Right",
        "Bottom",
        "Left"
      ].forEach(function(sideName, side) {
        chart[target][side] = pick$1z(chartOptions[target + sideName], values[side]);
      });
    });
    marginNames.forEach(function(m, side) {
      chart[m] = pick$1z(chart.margin[side], chart.spacing[side]);
    });
    chart.axisOffset = [0, 0, 0, 0];
    chart.clipOffset = [
      halfWidth,
      halfWidth,
      halfWidth,
      halfWidth
    ];
    chart.plotBorderWidth = plotBorderWidth;
  }
  /**
   * Internal function to draw or redraw the borders and backgrounds for chart
   * and plot area.
   *
   * @private
   * @function Highcharts.Chart#drawChartBox
   * @emits Highcharts.Chart#event:afterDrawChartBox
   */
  drawChartBox() {
    const chart = this, optionsChart = chart.options.chart, renderer = chart.renderer, chartWidth = chart.chartWidth, chartHeight = chart.chartHeight, styledMode = chart.styledMode, plotBGImage = chart.plotBGImage, chartBackgroundColor = optionsChart.backgroundColor, plotBackgroundColor = optionsChart.plotBackgroundColor, plotBackgroundImage = optionsChart.plotBackgroundImage, plotLeft = chart.plotLeft, plotTop = chart.plotTop, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, plotBox = chart.plotBox, clipRect = chart.clipRect, clipBox = chart.clipBox;
    let chartBackground = chart.chartBackground, plotBackground = chart.plotBackground, plotBorder = chart.plotBorder, chartBorderWidth, mgn, bgAttr, verb = "animate";
    if (!chartBackground) {
      chart.chartBackground = chartBackground = renderer.rect().addClass("highcharts-background").add();
      verb = "attr";
    }
    if (!styledMode) {
      chartBorderWidth = optionsChart.borderWidth || 0;
      mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
      bgAttr = {
        fill: chartBackgroundColor || "none"
      };
      if (chartBorderWidth || chartBackground["stroke-width"]) {
        bgAttr.stroke = optionsChart.borderColor;
        bgAttr["stroke-width"] = chartBorderWidth;
      }
      chartBackground.attr(bgAttr).shadow(optionsChart.shadow);
    } else {
      chartBorderWidth = mgn = chartBackground.strokeWidth();
    }
    chartBackground[verb]({
      x: mgn / 2,
      y: mgn / 2,
      width: chartWidth - mgn - chartBorderWidth % 2,
      height: chartHeight - mgn - chartBorderWidth % 2,
      r: optionsChart.borderRadius
    });
    verb = "animate";
    if (!plotBackground) {
      verb = "attr";
      chart.plotBackground = plotBackground = renderer.rect().addClass("highcharts-plot-background").add();
    }
    plotBackground[verb](plotBox);
    if (!styledMode) {
      plotBackground.attr({
        fill: plotBackgroundColor || "none"
      }).shadow(optionsChart.plotShadow);
      if (plotBackgroundImage) {
        if (!plotBGImage) {
          chart.plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight).add();
        } else {
          if (plotBackgroundImage !== plotBGImage.attr("href")) {
            plotBGImage.attr("href", plotBackgroundImage);
          }
          plotBGImage.animate(plotBox);
        }
      }
    }
    if (!clipRect) {
      chart.clipRect = renderer.clipRect(clipBox);
    } else {
      clipRect.animate({
        width: clipBox.width,
        height: clipBox.height
      });
    }
    verb = "animate";
    if (!plotBorder) {
      verb = "attr";
      chart.plotBorder = plotBorder = renderer.rect().addClass("highcharts-plot-border").attr({
        zIndex: 1
        // Above the grid
      }).add();
    }
    if (!styledMode) {
      plotBorder.attr({
        stroke: optionsChart.plotBorderColor,
        "stroke-width": optionsChart.plotBorderWidth || 0,
        fill: "none"
      });
    }
    plotBorder[verb](plotBorder.crisp(
      plotBox,
      // #3282 plotBorder should be negative
      -plotBorder.strokeWidth()
    ));
    chart.isDirtyBox = false;
    fireEvent$A(this, "afterDrawChartBox");
  }
  /**
   * Detect whether a certain chart property is needed based on inspecting its
   * options and series. This mainly applies to the chart.inverted property,
   * and in extensions to the chart.angular and chart.polar properties.
   *
   * @private
   * @function Highcharts.Chart#propFromSeries
   */
  propFromSeries() {
    const chart = this, optionsChart = chart.options.chart, seriesOptions = chart.options.series;
    let i, klass, value;
    ["inverted", "angular", "polar"].forEach(function(key2) {
      klass = seriesTypes$4[optionsChart.type];
      value = // It is set in the options:
      optionsChart[key2] || // The default series class:
      klass && klass.prototype[key2];
      i = seriesOptions?.length;
      while (!value && i--) {
        klass = seriesTypes$4[seriesOptions[i].type];
        if (klass && klass.prototype[key2]) {
          value = true;
        }
      }
      chart[key2] = value;
    });
  }
  /**
   * Internal function to link two or more series together, based on the
   * `linkedTo` option. This is done from `Chart.render`, and after
   * `Chart.addSeries` and `Series.remove`.
   *
   * @private
   * @function Highcharts.Chart#linkSeries
   * @emits Highcharts.Chart#event:afterLinkSeries
   */
  linkSeries(isUpdating) {
    const chart = this, chartSeries = chart.series;
    chartSeries.forEach(function(series) {
      series.linkedSeries.length = 0;
    });
    chartSeries.forEach(function(series) {
      const { linkedTo } = series.options;
      if (isString$a(linkedTo)) {
        let linkedParent;
        if (linkedTo === ":previous") {
          linkedParent = chart.series[series.index - 1];
        } else {
          linkedParent = chart.get(linkedTo);
        }
        if (linkedParent && linkedParent.linkedParent !== series) {
          linkedParent.linkedSeries.push(series);
          series.linkedParent = linkedParent;
          if (linkedParent.enabledDataSorting) {
            series.setDataSortingOptions();
          }
          series.visible = pick$1z(series.options.visible, linkedParent.options.visible, series.visible);
        }
      }
    });
    fireEvent$A(this, "afterLinkSeries", { isUpdating });
  }
  /**
   * Render series for the chart.
   *
   * @private
   * @function Highcharts.Chart#renderSeries
   */
  renderSeries() {
    this.series.forEach(function(serie) {
      serie.translate();
      serie.render();
    });
  }
  /**
   * Render all graphics for the chart. Runs internally on initialization.
   *
   * @private
   * @function Highcharts.Chart#render
   */
  render() {
    const chart = this, axes = chart.axes, colorAxis = chart.colorAxis, renderer = chart.renderer, axisLayoutRuns = chart.options.chart.axisLayoutRuns || 2, renderAxes = (axes2) => {
      axes2.forEach((axis) => {
        if (axis.visible) {
          axis.render();
        }
      });
    };
    let expectedSpace = 0, redoHorizontal = true, redoVertical, run = 0;
    chart.setTitle();
    fireEvent$A(chart, "beforeMargins");
    chart.getStacks?.();
    chart.getMargins(true);
    chart.setChartSize();
    for (const axis of axes) {
      const { options: options2 } = axis, { labels } = options2;
      if (chart.hasCartesianSeries && // #20948
      axis.horiz && axis.visible && labels.enabled && axis.series.length && axis.coll !== "colorAxis" && !chart.polar) {
        expectedSpace = options2.tickLength;
        axis.createGroups();
        const mockTick = new Tick(axis, 0, "", true), label = mockTick.createLabel("x", labels);
        mockTick.destroy();
        if (label && pick$1z(labels.reserveSpace, !isNumber$W(options2.crossing))) {
          expectedSpace = label.getBBox().height + labels.distance + Math.max(options2.offset || 0, 0);
        }
        if (expectedSpace) {
          label?.destroy();
          break;
        }
      }
    }
    chart.plotHeight = Math.max(chart.plotHeight - expectedSpace, 0);
    while ((redoHorizontal || redoVertical || axisLayoutRuns > 1) && run < axisLayoutRuns) {
      const tempWidth = chart.plotWidth, tempHeight = chart.plotHeight;
      for (const axis of axes) {
        if (run === 0) {
          axis.setScale();
        } else if (axis.horiz && redoHorizontal || !axis.horiz && redoVertical) {
          axis.setTickInterval(true);
        }
      }
      if (run === 0) {
        chart.getAxisMargins();
      } else {
        chart.getMargins();
      }
      redoHorizontal = tempWidth / chart.plotWidth > (run ? 1 : 1.1);
      redoVertical = tempHeight / chart.plotHeight > (run ? 1 : 1.05);
      run++;
    }
    chart.drawChartBox();
    if (chart.hasCartesianSeries) {
      renderAxes(axes);
    } else if (colorAxis?.length) {
      renderAxes(colorAxis);
    }
    if (!chart.seriesGroup) {
      chart.seriesGroup = renderer.g("series-group").attr({ zIndex: 3 }).shadow(chart.options.chart.seriesGroupShadow).add();
    }
    chart.renderSeries();
    chart.addCredits();
    if (chart.setResponsive) {
      chart.setResponsive();
    }
    chart.hasRendered = true;
  }
  /**
   * Set a new credits label for the chart.
   *
   * @sample highcharts/credits/credits-update/
   *         Add and update credits
   *
   * @function Highcharts.Chart#addCredits
   *
   * @param {Highcharts.CreditsOptions} [credits]
   * A configuration object for the new credits.
   */
  addCredits(credits) {
    const chart = this, creds = merge$1t(true, this.options.credits, credits);
    if (creds.enabled && !this.credits) {
      this.credits = this.renderer.text(creds.text + (this.mapCredits || ""), 0, 0).addClass("highcharts-credits").on("click", function() {
        if (creds.href) {
          win$8.location.href = creds.href;
        }
      }).attr({
        align: creds.position.align,
        zIndex: 8
      });
      if (!chart.styledMode) {
        this.credits.css(creds.style);
      }
      this.credits.add().align(creds.position);
      this.credits.update = function(options2) {
        chart.credits = chart.credits.destroy();
        chart.addCredits(options2);
      };
    }
  }
  /**
   * Remove the chart and purge memory. This method is called internally
   * before adding a second chart into the same container, as well as on
   * window unload to prevent leaks.
   *
   * @sample highcharts/members/chart-destroy/
   *         Destroy the chart from a button
   * @sample stock/members/chart-destroy/
   *         Destroy with Highcharts Stock
   *
   * @function Highcharts.Chart#destroy
   *
   * @emits Highcharts.Chart#event:destroy
   */
  destroy() {
    const chart = this, axes = chart.axes, series = chart.series, container = chart.container, parentNode = container?.parentNode;
    let i;
    fireEvent$A(chart, "destroy");
    if (chart.renderer.forExport) {
      erase$5(charts$1, chart);
    } else {
      charts$1[chart.index] = void 0;
    }
    Highcharts.chartCount--;
    chart.renderTo.removeAttribute("data-highcharts-chart");
    removeEvent$7(chart);
    i = axes.length;
    while (i--) {
      axes[i] = axes[i].destroy();
    }
    this.scroller?.destroy?.();
    i = series.length;
    while (i--) {
      series[i] = series[i].destroy();
    }
    [
      "title",
      "subtitle",
      "chartBackground",
      "plotBackground",
      "plotBGImage",
      "plotBorder",
      "seriesGroup",
      "clipRect",
      "credits",
      "pointer",
      "rangeSelector",
      "legend",
      "resetZoomButton",
      "tooltip",
      "renderer"
    ].forEach((name) => {
      chart[name] = chart[name]?.destroy?.();
    });
    if (container) {
      container.innerHTML = AST.emptyHTML;
      removeEvent$7(container);
      if (parentNode) {
        discardElement$3(container);
      }
    }
    objectEach$l(chart, function(val, key2) {
      delete chart[key2];
    });
  }
  /**
   * Prepare for first rendering after all data are loaded.
   *
   * @private
   * @function Highcharts.Chart#firstRender
   * @emits Highcharts.Chart#event:beforeRender
   */
  firstRender() {
    const chart = this, options2 = chart.options;
    chart.getContainer();
    chart.resetMargins();
    chart.setChartSize();
    chart.propFromSeries();
    chart.createAxes();
    const series = isArray$j(options2.series) ? options2.series : [];
    options2.series = [];
    series.forEach(
      // #9680
      function(serieOptions) {
        chart.initSeries(serieOptions);
      }
    );
    chart.linkSeries();
    chart.setSortedData();
    fireEvent$A(chart, "beforeRender");
    chart.render();
    chart.pointer?.getChartPosition();
    if (!chart.renderer.imgCount && !chart.hasLoaded) {
      chart.onload();
    }
    chart.temporaryDisplay(true);
  }
  /**
   * Internal function that runs on chart load, async if any images are loaded
   * in the chart. Runs the callbacks and triggers the `load` and `render`
   * events.
   *
   * @private
   * @function Highcharts.Chart#onload
   * @emits Highcharts.Chart#event:load
   * @emits Highcharts.Chart#event:render
   */
  onload() {
    this.callbacks.concat([this.callback]).forEach(function(fn) {
      if (fn && typeof this.index !== "undefined") {
        fn.apply(this, [this]);
      }
    }, this);
    fireEvent$A(this, "load");
    fireEvent$A(this, "render");
    if (defined$12(this.index)) {
      this.setReflow();
    }
    this.warnIfA11yModuleNotLoaded();
    this.hasLoaded = true;
  }
  /**
   * Emit console warning if the a11y module is not loaded.
   * @private
   */
  warnIfA11yModuleNotLoaded() {
    const { options: options2, title } = this;
    if (options2 && !this.accessibility) {
      this.renderer.boxWrapper.attr({
        role: "img",
        "aria-label": (title?.element.textContent || "").replace(/</g, "&lt;")
      });
      if (!(options2.accessibility && options2.accessibility.enabled === false)) {
        error$6('Highcharts warning: Consider including the "accessibility.js" module to make your chart more usable for people with disabilities. Set the "accessibility.enabled" option to false to remove this warning. See https://www.highcharts.com/docs/accessibility/accessibility-module.', false, this);
      }
    }
  }
  /**
   * Add a series to the chart after render time. Note that this method should
   * never be used when adding data synchronously at chart render time, as it
   * adds expense to the calculations and rendering. When adding data at the
   * same time as the chart is initialized, add the series as a configuration
   * option instead. With multiple axes, the `offset` is dynamically adjusted.
   *
   * @sample highcharts/members/chart-addseries/
   *         Add a series from a button
   * @sample stock/members/chart-addseries/
   *         Add a series in Highcharts Stock
   *
   * @function Highcharts.Chart#addSeries
   *
   * @param {Highcharts.SeriesOptionsType} options
   *        The config options for the series.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after adding.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether to apply animation, and optionally animation
   *        configuration. When `undefined`, it applies the animation that is
   *        set in the `chart.animation` option.
   *
   * @return {Highcharts.Series}
   *         The newly created series object.
   *
   * @emits Highcharts.Chart#event:addSeries
   * @emits Highcharts.Chart#event:afterAddSeries
   */
  addSeries(options2, redraw, animation) {
    const chart = this;
    let series;
    if (options2) {
      redraw = pick$1z(redraw, true);
      fireEvent$A(chart, "addSeries", { options: options2 }, function() {
        series = chart.initSeries(options2);
        chart.isDirtyLegend = true;
        chart.linkSeries();
        if (series.enabledDataSorting) {
          series.setData(options2.data, false);
        }
        fireEvent$A(chart, "afterAddSeries", { series });
        if (redraw) {
          chart.redraw(animation);
        }
      });
    }
    return series;
  }
  /**
   * Add an axis to the chart after render time. Note that this method should
   * never be used when adding data synchronously at chart render time, as it
   * adds expense to the calculations and rendering. When adding data at the
   * same time as the chart is initialized, add the axis as a configuration
   * option instead.
   *
   * @sample highcharts/members/chart-addaxis/
   *         Add and remove axes
   *
   * @function Highcharts.Chart#addAxis
   *
   * @param {Highcharts.AxisOptions} options
   *        The axis options.
   *
   * @param {boolean} [isX=false]
   *        Whether it is an X axis or a value axis.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after adding.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether and how to apply animation in the redraw. When
   *        `undefined`, it applies the animation that is set in the
   *        `chart.animation` option.
   *
   * @return {Highcharts.Axis}
   *         The newly generated Axis object.
   */
  addAxis(options2, isX, redraw, animation) {
    return this.createAxis(isX ? "xAxis" : "yAxis", { axis: options2, redraw, animation });
  }
  /**
   * Add a color axis to the chart after render time. Note that this method
   * should never be used when adding data synchronously at chart render time,
   * as it adds expense to the calculations and rendering. When adding data at
   * the same time as the chart is initialized, add the axis as a
   * configuration option instead.
   *
   * @sample highcharts/members/chart-addaxis/
   *         Add and remove axes
   *
   * @function Highcharts.Chart#addColorAxis
   *
   * @param {Highcharts.ColorAxisOptions} options
   *        The axis options.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after adding.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether and how to apply animation in the redraw. When
   *        `undefined`, it applies the animation that is set in the
   *        `chart.animation` option.
   *
   * @return {Highcharts.Axis}
   *         The newly generated Axis object.
   */
  addColorAxis(options2, redraw, animation) {
    return this.createAxis("colorAxis", { axis: options2, redraw, animation });
  }
  /**
   * Factory for creating different axis types.
   *
   * @private
   * @function Highcharts.Chart#createAxis
   *
   * @param {string} coll
   *        An axis type.
   *
   * @param {...Array<*>} arguments
   *        All arguments for the constructor.
   *
   * @return {Highcharts.Axis}
   *         The newly generated Axis object.
   */
  createAxis(coll, options2) {
    const axis = new Axis(this, options2.axis, coll);
    if (pick$1z(options2.redraw, true)) {
      this.redraw(options2.animation);
    }
    return axis;
  }
  /**
   * Dim the chart and show a loading text or symbol. Options for the loading
   * screen are defined in {@link
   * https://api.highcharts.com/highcharts/loading|the loading options}.
   *
   * @sample highcharts/members/chart-hideloading/
   *         Show and hide loading from a button
   * @sample highcharts/members/chart-showloading/
   *         Apply different text labels
   * @sample stock/members/chart-show-hide-loading/
   *         Toggle loading in Highcharts Stock
   *
   * @function Highcharts.Chart#showLoading
   *
   * @param {string} [str]
   *        An optional text to show in the loading label instead of the
   *        default one. The default text is set in
   *        [lang.loading](https://api.highcharts.com/highcharts/lang.loading).
   */
  showLoading(str) {
    const chart = this, options2 = chart.options, loadingOptions = options2.loading, setLoadingSize = function() {
      if (loadingDiv) {
        css$8(loadingDiv, {
          left: chart.plotLeft + "px",
          top: chart.plotTop + "px",
          width: chart.plotWidth + "px",
          height: chart.plotHeight + "px"
        });
      }
    };
    let loadingDiv = chart.loadingDiv, loadingSpan = chart.loadingSpan;
    if (!loadingDiv) {
      chart.loadingDiv = loadingDiv = createElement$8("div", {
        className: "highcharts-loading highcharts-loading-hidden"
      }, null, chart.container);
    }
    if (!loadingSpan) {
      chart.loadingSpan = loadingSpan = createElement$8("span", { className: "highcharts-loading-inner" }, null, loadingDiv);
      addEvent$1l(chart, "redraw", setLoadingSize);
    }
    loadingDiv.className = "highcharts-loading";
    AST.setElementHTML(loadingSpan, pick$1z(str, options2.lang.loading, ""));
    if (!chart.styledMode) {
      css$8(loadingDiv, extend$1c(loadingOptions.style, {
        zIndex: 10
      }));
      css$8(loadingSpan, loadingOptions.labelStyle);
      if (!chart.loadingShown) {
        css$8(loadingDiv, {
          opacity: 0,
          display: ""
        });
        animate(loadingDiv, {
          opacity: loadingOptions.style.opacity || 0.5
        }, {
          duration: loadingOptions.showDuration || 0
        });
      }
    }
    chart.loadingShown = true;
    setLoadingSize();
  }
  /**
   * Hide the loading layer.
   *
   * @see Highcharts.Chart#showLoading
   *
   * @sample highcharts/members/chart-hideloading/
   *         Show and hide loading from a button
   * @sample stock/members/chart-show-hide-loading/
   *         Toggle loading in Highcharts Stock
   *
   * @function Highcharts.Chart#hideLoading
   */
  hideLoading() {
    const options2 = this.options, loadingDiv = this.loadingDiv;
    if (loadingDiv) {
      loadingDiv.className = "highcharts-loading highcharts-loading-hidden";
      if (!this.styledMode) {
        animate(loadingDiv, {
          opacity: 0
        }, {
          duration: options2.loading.hideDuration || 100,
          complete: function() {
            css$8(loadingDiv, { display: "none" });
          }
        });
      }
    }
    this.loadingShown = false;
  }
  /**
   * A generic function to update any element of the chart. Elements can be
   * enabled and disabled, moved, re-styled, re-formatted etc.
   *
   * A special case is configuration objects that take arrays, for example
   * [xAxis](https://api.highcharts.com/highcharts/xAxis),
   * [yAxis](https://api.highcharts.com/highcharts/yAxis) or
   * [series](https://api.highcharts.com/highcharts/series). For these
   * collections, an `id` option is used to map the new option set to an
   * existing object. If an existing object of the same id is not found, the
   * corresponding item is updated. So for example, running `chart.update`
   * with a series item without an id, will cause the existing chart's series
   * with the same index in the series array to be updated. When the
   * `oneToOne` parameter is true, `chart.update` will also take care of
   * adding and removing items from the collection. Read more under the
   * parameter description below.
   *
   * Note that when changing series data, `chart.update` may mutate the passed
   * data options.
   *
   * See also the
   * [responsive option set](https://api.highcharts.com/highcharts/responsive).
   * Switching between `responsive.rules` basically runs `chart.update` under
   * the hood.
   *
   * @sample highcharts/members/chart-update/
   *         Update chart geometry
   *
   * @function Highcharts.Chart#update
   *
   * @param {Highcharts.Options} options
   *        A configuration object for the new chart options.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart.
   *
   * @param {boolean} [oneToOne=false]
   *        When `true`, the `series`, `xAxis`, `yAxis` and `annotations`
   *        collections will be updated one to one, and items will be either
   *        added or removed to match the new updated options. For example,
   *        if the chart has two series and we call `chart.update` with a
   *        configuration containing three series, one will be added. If we
   *        call `chart.update` with one series, one will be removed. Setting
   *        an empty `series` array will remove all series, but leaving out
   *        the`series` property will leave all series untouched. If the
   *        series have id's, the new series options will be matched by id,
   *        and the remaining ones removed.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Whether to apply animation, and optionally animation
   *        configuration. When `undefined`, it applies the animation that is
   *        set in the `chart.animation` option.
   *
   * @emits Highcharts.Chart#event:update
   * @emits Highcharts.Chart#event:afterUpdate
   */
  update(options2, redraw, oneToOne, animation) {
    const chart = this, adders = {
      credits: "addCredits",
      title: "setTitle",
      subtitle: "setSubtitle",
      caption: "setCaption"
    }, isResponsiveOptions = options2.isResponsiveOptions, itemsForRemoval = [];
    let updateAllAxes, updateAllSeries, runSetSize;
    fireEvent$A(chart, "update", { options: options2 });
    if (!isResponsiveOptions) {
      chart.setResponsive(false, true);
    }
    options2 = diffObjects$3(options2, chart.options);
    chart.userOptions = merge$1t(chart.userOptions, options2);
    const optionsChart = options2.chart;
    if (optionsChart) {
      merge$1t(true, chart.options.chart, optionsChart);
      this.setZoomOptions();
      if ("className" in optionsChart) {
        chart.setClassName(optionsChart.className);
      }
      if ("inverted" in optionsChart || "polar" in optionsChart || "type" in optionsChart) {
        chart.propFromSeries();
        updateAllAxes = true;
      }
      if ("alignTicks" in optionsChart) {
        updateAllAxes = true;
      }
      if ("events" in optionsChart) {
        registerEventOptions(this, optionsChart);
      }
      objectEach$l(optionsChart, function(val, key2) {
        if (chart.propsRequireUpdateSeries.indexOf("chart." + key2) !== -1) {
          updateAllSeries = true;
        }
        if (chart.propsRequireDirtyBox.indexOf(key2) !== -1) {
          chart.isDirtyBox = true;
        }
        if (chart.propsRequireReflow.indexOf(key2) !== -1) {
          chart.isDirtyBox = true;
          if (!isResponsiveOptions) {
            runSetSize = true;
          }
        }
      });
      if (!chart.styledMode && optionsChart.style) {
        chart.renderer.setStyle(chart.options.chart.style || {});
      }
    }
    if (!chart.styledMode && options2.colors) {
      this.options.colors = options2.colors;
    }
    objectEach$l(options2, function(val, key2) {
      if (chart[key2] && typeof chart[key2].update === "function") {
        chart[key2].update(val, false);
      } else if (typeof chart[adders[key2]] === "function") {
        chart[adders[key2]](val);
      } else if (key2 !== "colors" && chart.collectionsWithUpdate.indexOf(key2) === -1) {
        merge$1t(true, chart.options[key2], options2[key2]);
      }
      if (key2 !== "chart" && chart.propsRequireUpdateSeries.indexOf(key2) !== -1) {
        updateAllSeries = true;
      }
    });
    this.collectionsWithUpdate.forEach(function(coll) {
      if (options2[coll]) {
        splat$h(options2[coll]).forEach(function(newOptions, i) {
          const hasId = defined$12(newOptions.id);
          let item;
          if (hasId) {
            item = chart.get(newOptions.id);
          }
          if (!item && chart[coll]) {
            item = chart[coll][pick$1z(newOptions.index, i)];
            if (item && (hasId && defined$12(item.options.id) || item.options.isInternal)) {
              item = void 0;
            }
          }
          if (item && item.coll === coll) {
            item.update(newOptions, false);
            if (oneToOne) {
              item.touched = true;
            }
          }
          if (!item && oneToOne && chart.collectionsWithInit[coll]) {
            chart.collectionsWithInit[coll][0].apply(
              chart,
              // [newOptions, ...extraArguments, redraw=false]
              [
                newOptions
              ].concat(
                // Not all initializers require extra args
                chart.collectionsWithInit[coll][1] || []
              ).concat([
                false
              ])
            ).touched = true;
          }
        });
        if (oneToOne) {
          chart[coll].forEach(function(item) {
            if (!item.touched && !item.options.isInternal) {
              itemsForRemoval.push(item);
            } else {
              delete item.touched;
            }
          });
        }
      }
    });
    itemsForRemoval.forEach(function(item) {
      if (item.chart && item.remove) {
        item.remove(false);
      }
    });
    if (updateAllAxes) {
      chart.axes.forEach(function(axis) {
        axis.update({}, false);
      });
    }
    if (updateAllSeries) {
      chart.getSeriesOrderByLinks().forEach(function(series) {
        if (series.chart) {
          series.update({}, false);
        }
      }, this);
    }
    const newWidth = optionsChart?.width;
    const newHeight = optionsChart && (isString$a(optionsChart.height) ? relativeLength$f(optionsChart.height, newWidth || chart.chartWidth) : optionsChart.height);
    if (
      // In this case, run chart.setSize with newWidth and newHeight which
      // are undefined, only for reflowing chart elements because margin
      // or spacing has been set (#8190)
      runSetSize || // In this case, the size is actually set
      isNumber$W(newWidth) && newWidth !== chart.chartWidth || isNumber$W(newHeight) && newHeight !== chart.chartHeight
    ) {
      chart.setSize(newWidth, newHeight, animation);
    } else if (pick$1z(redraw, true)) {
      chart.redraw(animation);
    }
    fireEvent$A(chart, "afterUpdate", {
      options: options2,
      redraw,
      animation
    });
  }
  /**
   * Shortcut to set the subtitle options. This can also be done from {@link
   * Chart#update} or {@link Chart#setTitle}.
   *
   * @function Highcharts.Chart#setSubtitle
   *
   * @param {Highcharts.SubtitleOptions} options
   *        New subtitle options. The subtitle text itself is set by the
   *        `options.text` property.
   */
  setSubtitle(options2, redraw) {
    this.applyDescription("subtitle", options2);
    this.layOutTitles(redraw);
  }
  /**
   * Set the caption options. This can also be done from {@link
   * Chart#update}.
   *
   * @function Highcharts.Chart#setCaption
   *
   * @param {Highcharts.CaptionOptions} options
   *        New caption options. The caption text itself is set by the
   *        `options.text` property.
   */
  setCaption(options2, redraw) {
    this.applyDescription("caption", options2);
    this.layOutTitles(redraw);
  }
  /**
   * Display the zoom button, so users can reset zoom to the default view
   * settings.
   *
   * @function Highcharts.Chart#showResetZoom
   *
   * @emits Highcharts.Chart#event:afterShowResetZoom
   * @emits Highcharts.Chart#event:beforeShowResetZoom
   */
  showResetZoom() {
    const chart = this, lang2 = defaultOptions$g.lang, btnOptions = chart.zooming.resetButton, theme2 = btnOptions.theme, alignTo = btnOptions.relativeTo === "chart" || btnOptions.relativeTo === "spacingBox" ? null : "plotBox";
    function zoomOut() {
      chart.zoomOut();
    }
    fireEvent$A(this, "beforeShowResetZoom", null, function() {
      chart.resetZoomButton = chart.renderer.button(lang2.resetZoom, null, null, zoomOut, theme2).attr({
        align: btnOptions.position.align,
        title: lang2.resetZoomTitle
      }).addClass("highcharts-reset-zoom").add().align(btnOptions.position, false, alignTo);
    });
    fireEvent$A(this, "afterShowResetZoom");
  }
  /**
   * Zoom the chart out after a user has zoomed in. See also
   * [Axis.setExtremes](/class-reference/Highcharts.Axis#setExtremes).
   *
   * @function Highcharts.Chart#zoomOut
   *
   * @emits Highcharts.Chart#event:selection
   */
  zoomOut() {
    fireEvent$A(this, "selection", { resetSelection: true }, () => this.transform({ reset: true, trigger: "zoom" }));
  }
  /**
   * Pan the chart by dragging the mouse across the pane. This function is
   * called on mouse move, and the distance to pan is computed from chartX
   * compared to the first chartX position in the dragging operation.
   *
   * @private
   * @function Highcharts.Chart#pan
   * @param {Highcharts.PointerEventObject} event
   * @param {string} panning
   */
  pan(event, panning) {
    const chart = this, panningOptions = typeof panning === "object" ? panning : {
      enabled: panning,
      type: "x"
    }, type = panningOptions.type, axes = type && chart[{
      x: "xAxis",
      xy: "axes",
      y: "yAxis"
    }[type]].filter((axis) => axis.options.panningEnabled && !axis.options.isInternal), chartOptions = chart.options.chart;
    if (chartOptions?.panning) {
      chartOptions.panning = panningOptions;
    }
    fireEvent$A(this, "pan", { originalEvent: event }, () => {
      chart.transform({
        axes,
        event,
        to: {
          x: event.chartX - (chart.mouseDownX || 0),
          y: event.chartY - (chart.mouseDownY || 0)
        },
        trigger: "pan"
      });
      css$8(chart.container, { cursor: "move" });
    });
  }
  /**
   * Pan and scale the chart. Used internally by mouse-pan, touch-pan,
   * touch-zoom, and mousewheel zoom.
   *
   * The main positioning logic is created around two imaginary boxes. What is
   * currently within the `from` rectangle, should be transformed to fill up
   * the `to` rectangle.
   * - In a mouse zoom, the `from` rectangle is the selection, while the `to`
   *   rectangle is the full plot area.
   * - In a touch zoom, the `from` rectangle is made up of the last two-finger
   *   touch, while the `to`` rectangle is the current touch.
   * - In a mousewheel zoom, the `to` rectangle is a 10x10 px square,
   *   while the `to` rectangle reflects the scale around that.
   *
   * @private
   * @function Highcharts.Chart#transform
   */
  transform(params2) {
    const { axes = this.axes, event, from = {}, reset, selection, to = {}, trigger } = params2, { inverted, time } = this;
    let hasZoomed = false, displayButton, isAnyAxisPanning;
    this.hoverPoints?.forEach((point) => point.setState());
    for (const axis of axes) {
      const { horiz, len, minPointOffset = 0, options: options2, reversed } = axis, wh = horiz ? "width" : "height", xy = horiz ? "x" : "y", toLength = pick$1z(to[wh], axis.len), fromLength = pick$1z(from[wh], axis.len), scale2 = Math.abs(toLength) < 10 ? 1 : toLength / fromLength, fromCenter = (from[xy] || 0) + fromLength / 2 - axis.pos, toCenter = (to[xy] ?? axis.pos) + toLength / 2 - axis.pos, move = fromCenter - toCenter / scale2, pointRangeDirection = reversed && !inverted || !reversed && inverted ? -1 : 1, minPx = move;
      if (!reset && (fromCenter < 0 || fromCenter > axis.len)) {
        continue;
      }
      let newMin = axis.toValue(minPx, true) + // Don't apply offset for selection (#20784)
      (selection || axis.isOrdinal ? 0 : minPointOffset * pointRangeDirection), newMax = axis.toValue(minPx + len / scale2, true) - // Don't apply offset for selection (#20784)
      (selection || axis.isOrdinal ? 0 : minPointOffset * pointRangeDirection || // Polar zoom tests failed when this was not
      // commented:
      // (axis.isXAxis && axis.pointRangePadding) ||
      0), allExtremes = axis.allExtremes;
      if (newMin > newMax) {
        [newMin, newMax] = [newMax, newMin];
      }
      if (scale2 === 1 && !reset && axis.coll === "yAxis" && !allExtremes) {
        for (const series of axis.series) {
          const seriesExtremes = series.getExtremes(series.getProcessedData(true).modified.getColumn("y") || [], true);
          allExtremes ?? (allExtremes = {
            dataMin: Number.MAX_VALUE,
            dataMax: -Number.MAX_VALUE
          });
          if (isNumber$W(seriesExtremes.dataMin) && isNumber$W(seriesExtremes.dataMax)) {
            allExtremes.dataMin = Math.min(seriesExtremes.dataMin, allExtremes.dataMin);
            allExtremes.dataMax = Math.max(seriesExtremes.dataMax, allExtremes.dataMax);
          }
        }
        axis.allExtremes = allExtremes;
      }
      const { dataMin, dataMax, min: min2, max: max2 } = extend$1c(axis.getExtremes(), allExtremes || {}), optionsMin = time.parse(options2.min), optionsMax = time.parse(options2.max), safeDataMin = dataMin ?? optionsMin, safeDataMax = dataMax ?? optionsMax, range2 = newMax - newMin, padRange = axis.categories ? 0 : Math.min(range2, safeDataMax - safeDataMin), paddedMin = safeDataMin - padRange * (defined$12(optionsMin) ? 0 : options2.minPadding), paddedMax = safeDataMax + padRange * (defined$12(optionsMax) ? 0 : options2.maxPadding), allowZoomOutside = axis.allowZoomOutside || scale2 === 1 || trigger !== "zoom" && scale2 > 1, floor2 = Math.min(optionsMin ?? paddedMin, paddedMin, allowZoomOutside ? min2 : paddedMin), ceiling = Math.max(optionsMax ?? paddedMax, paddedMax, allowZoomOutside ? max2 : paddedMax);
      if (!axis.isOrdinal || axis.options.overscroll || // #21316
      scale2 !== 1 || reset) {
        if (newMin < floor2) {
          newMin = floor2;
          if (scale2 >= 1) {
            newMax = newMin + range2;
          }
        }
        if (newMax > ceiling) {
          newMax = ceiling;
          if (scale2 >= 1) {
            newMin = newMax - range2;
          }
        }
        if (reset || axis.series.length && (newMin !== min2 || newMax !== max2) && newMin >= floor2 && newMax <= ceiling) {
          if (selection) {
            selection[axis.coll].push({
              axis,
              min: newMin,
              max: newMax
            });
          } else {
            axis.isPanning = trigger !== "zoom";
            if (axis.isPanning) {
              isAnyAxisPanning = true;
            }
            axis.setExtremes(reset ? void 0 : newMin, reset ? void 0 : newMax, false, false, { move, trigger, scale: scale2 });
            if (!reset && (newMin > floor2 || newMax < ceiling) && trigger !== "mousewheel") {
              displayButton = true;
            }
          }
          hasZoomed = true;
        }
        if (event) {
          this[horiz ? "mouseDownX" : "mouseDownY"] = event[horiz ? "chartX" : "chartY"];
        }
      }
    }
    if (hasZoomed) {
      if (selection) {
        fireEvent$A(
          this,
          "selection",
          selection,
          // Run transform again, this time without the selection data
          // so that the transform is applied.
          () => {
            delete params2.selection;
            params2.trigger = "zoom";
            this.transform(params2);
          }
        );
      } else {
        if (displayButton && !isAnyAxisPanning && !this.resetZoomButton) {
          this.showResetZoom();
        } else if (!displayButton && this.resetZoomButton) {
          this.resetZoomButton = this.resetZoomButton.destroy();
        }
        this.redraw(trigger === "zoom" && (this.options.chart.animation ?? this.pointCount < 100));
      }
    }
    return hasZoomed;
  }
};
extend$1c(Chart$1.prototype, {
  // Hook for adding callbacks in modules
  callbacks: [],
  /**
   * These collections (arrays) implement `Chart.addSomething` method used in
   * chart.update() to create new object in the collection. Equivalent for
   * deleting is resolved by simple `Something.remove()`.
   *
   * Note: We need to define these references after initializers are bound to
   * chart's prototype.
   *
   * @private
   */
  collectionsWithInit: {
    // CollectionName: [ initializingMethod, [extraArguments] ]
    xAxis: [Chart$1.prototype.addAxis, [true]],
    yAxis: [Chart$1.prototype.addAxis, [false]],
    series: [Chart$1.prototype.addSeries]
  },
  /**
   * These collections (arrays) implement update() methods with support for
   * one-to-one option.
   * @private
   */
  collectionsWithUpdate: [
    "xAxis",
    "yAxis",
    "series"
  ],
  /**
   * These properties cause isDirtyBox to be set to true when updating. Can be
   * extended from plugins.
   * @private
   */
  propsRequireDirtyBox: [
    "backgroundColor",
    "borderColor",
    "borderWidth",
    "borderRadius",
    "plotBackgroundColor",
    "plotBackgroundImage",
    "plotBorderColor",
    "plotBorderWidth",
    "plotShadow",
    "shadow"
  ],
  /**
   * These properties require a full reflow of chart elements, best
   * implemented through running `Chart.setSize` internally (#8190).
   * @private
   */
  propsRequireReflow: [
    "margin",
    "marginTop",
    "marginRight",
    "marginBottom",
    "marginLeft",
    "spacing",
    "spacingTop",
    "spacingRight",
    "spacingBottom",
    "spacingLeft"
  ],
  /**
   * These properties cause all series to be updated when updating. Can be
   * extended from plugins.
   * @private
   */
  propsRequireUpdateSeries: [
    "chart.inverted",
    "chart.polar",
    "chart.ignoreHiddenSeries",
    "chart.type",
    "colors",
    "plotOptions",
    "time",
    "tooltip"
  ]
});
const { stop } = animationExports;
const { composed: composed$u } = Highcharts;
const { addEvent: addEvent$1k, createElement: createElement$7, css: css$7, defined: defined$11, erase: erase$4, merge: merge$1s, pushUnique: pushUnique$u } = Utilities;
function onChartRender$5() {
  let scrollablePlotArea = this.scrollablePlotArea;
  if ((this.scrollablePixelsX || this.scrollablePixelsY) && !scrollablePlotArea) {
    this.scrollablePlotArea = scrollablePlotArea = new ScrollablePlotArea(this);
  }
  scrollablePlotArea?.applyFixed();
}
function markDirty() {
  if (this.chart.scrollablePlotArea) {
    this.chart.scrollablePlotArea.isDirty = true;
  }
}
class ScrollablePlotArea {
  static compose(AxisClass, ChartClass, SeriesClass) {
    if (pushUnique$u(composed$u, this.compose)) {
      addEvent$1k(AxisClass, "afterInit", markDirty);
      addEvent$1k(ChartClass, "afterSetChartSize", (e) => this.afterSetSize(e.target, e));
      addEvent$1k(ChartClass, "render", onChartRender$5);
      addEvent$1k(SeriesClass, "show", markDirty);
    }
  }
  static afterSetSize(chart, e) {
    const { minWidth, minHeight } = chart.options.chart.scrollablePlotArea || {}, { clipBox, plotBox, inverted, renderer } = chart;
    let scrollablePixelsX, scrollablePixelsY, recalculateHoriz;
    if (!renderer.forExport) {
      if (minWidth) {
        chart.scrollablePixelsX = scrollablePixelsX = Math.max(0, minWidth - chart.chartWidth);
        if (scrollablePixelsX) {
          chart.scrollablePlotBox = merge$1s(chart.plotBox);
          plotBox.width = chart.plotWidth += scrollablePixelsX;
          clipBox[inverted ? "height" : "width"] += scrollablePixelsX;
          recalculateHoriz = true;
        }
      } else if (minHeight) {
        chart.scrollablePixelsY = scrollablePixelsY = Math.max(0, minHeight - chart.chartHeight);
        if (defined$11(scrollablePixelsY)) {
          chart.scrollablePlotBox = merge$1s(chart.plotBox);
          plotBox.height = chart.plotHeight += scrollablePixelsY;
          clipBox[inverted ? "width" : "height"] += scrollablePixelsY;
          recalculateHoriz = false;
        }
      }
      if (defined$11(recalculateHoriz) && !e.skipAxes) {
        for (const axis of chart.axes) {
          if (axis.horiz === recalculateHoriz || // Or parallel axes
          chart.hasParallelCoordinates && axis.coll === "yAxis") {
            axis.setAxisSize();
            axis.setAxisTranslation();
          }
        }
      }
    }
  }
  constructor(chart) {
    const chartOptions = chart.options.chart, Renderer = RendererRegistry$1.getRendererType(), scrollableOptions = chartOptions.scrollablePlotArea || {}, moveFixedElements = this.moveFixedElements.bind(this), styles = {
      WebkitOverflowScrolling: "touch",
      overflowX: "hidden",
      overflowY: "hidden"
    };
    if (chart.scrollablePixelsX) {
      styles.overflowX = "auto";
    }
    if (chart.scrollablePixelsY) {
      styles.overflowY = "auto";
    }
    this.chart = chart;
    const parentDiv = this.parentDiv = createElement$7("div", {
      className: "highcharts-scrolling-parent"
    }, {
      position: "relative"
    }, chart.renderTo), scrollingContainer = this.scrollingContainer = createElement$7("div", {
      "className": "highcharts-scrolling"
    }, styles, parentDiv), innerContainer = this.innerContainer = createElement$7("div", {
      "className": "highcharts-inner-container"
    }, void 0, scrollingContainer), fixedDiv = this.fixedDiv = createElement$7("div", {
      className: "highcharts-fixed"
    }, {
      position: "absolute",
      overflow: "hidden",
      pointerEvents: "none",
      zIndex: (chartOptions.style?.zIndex || 0) + 2,
      top: 0
    }, void 0, true), fixedRenderer = this.fixedRenderer = new Renderer(fixedDiv, chart.chartWidth, chart.chartHeight, chartOptions.style);
    this.mask = fixedRenderer.path().attr({
      fill: chartOptions.backgroundColor || "#fff",
      "fill-opacity": scrollableOptions.opacity ?? 0.85,
      zIndex: -1
    }).addClass("highcharts-scrollable-mask").add();
    scrollingContainer.parentNode.insertBefore(fixedDiv, scrollingContainer);
    css$7(chart.renderTo, { overflow: "visible" });
    addEvent$1k(chart, "afterShowResetZoom", moveFixedElements);
    addEvent$1k(chart, "afterApplyDrilldown", moveFixedElements);
    addEvent$1k(chart, "afterLayOutTitles", moveFixedElements);
    let lastHoverPoint;
    addEvent$1k(scrollingContainer, "scroll", () => {
      const { pointer, hoverPoint } = chart;
      if (pointer) {
        delete pointer.chartPosition;
        if (hoverPoint) {
          lastHoverPoint = hoverPoint;
        }
        pointer.runPointActions(void 0, lastHoverPoint, true);
      }
    });
    innerContainer.appendChild(chart.container);
  }
  applyFixed() {
    const { chart, fixedRenderer, isDirty, scrollingContainer } = this, { axisOffset, chartWidth, chartHeight, container, plotHeight, plotLeft, plotTop, plotWidth, scrollablePixelsX = 0, scrollablePixelsY = 0 } = chart, chartOptions = chart.options.chart, scrollableOptions = chartOptions.scrollablePlotArea || {}, { scrollPositionX = 0, scrollPositionY = 0 } = scrollableOptions, scrollableWidth = chartWidth + scrollablePixelsX, scrollableHeight = chartHeight + scrollablePixelsY;
    fixedRenderer.setSize(chartWidth, chartHeight);
    if (isDirty ?? true) {
      this.isDirty = false;
      this.moveFixedElements();
    }
    stop(chart.container);
    css$7(container, {
      width: `${scrollableWidth}px`,
      height: `${scrollableHeight}px`
    });
    chart.renderer.boxWrapper.attr({
      width: scrollableWidth,
      height: scrollableHeight,
      viewBox: [0, 0, scrollableWidth, scrollableHeight].join(" ")
    });
    chart.chartBackground?.attr({
      width: scrollableWidth,
      height: scrollableHeight
    });
    css$7(scrollingContainer, {
      width: `${chartWidth}px`,
      height: `${chartHeight}px`
    });
    if (!defined$11(isDirty)) {
      scrollingContainer.scrollLeft = scrollablePixelsX * scrollPositionX;
      scrollingContainer.scrollTop = scrollablePixelsY * scrollPositionY;
    }
    const maskTop = plotTop - axisOffset[0] - 1, maskLeft = plotLeft - axisOffset[3] - 1, maskBottom = plotTop + plotHeight + axisOffset[2] + 1, maskRight = plotLeft + plotWidth + axisOffset[1] + 1, maskPlotRight = plotLeft + plotWidth - scrollablePixelsX, maskPlotBottom = plotTop + plotHeight - scrollablePixelsY;
    let d = [["M", 0, 0]];
    if (scrollablePixelsX) {
      d = [
        // Left side
        ["M", 0, maskTop],
        ["L", plotLeft - 1, maskTop],
        ["L", plotLeft - 1, maskBottom],
        ["L", 0, maskBottom],
        ["Z"],
        // Right side
        ["M", maskPlotRight, maskTop],
        ["L", chartWidth, maskTop],
        ["L", chartWidth, maskBottom],
        ["L", maskPlotRight, maskBottom],
        ["Z"]
      ];
    } else if (scrollablePixelsY) {
      d = [
        // Top side
        ["M", maskLeft, 0],
        ["L", maskLeft, plotTop - 1],
        ["L", maskRight, plotTop - 1],
        ["L", maskRight, 0],
        ["Z"],
        // Bottom side
        ["M", maskLeft, maskPlotBottom],
        ["L", maskLeft, chartHeight],
        ["L", maskRight, chartHeight],
        ["L", maskRight, maskPlotBottom],
        ["Z"]
      ];
    }
    if (chart.redrawTrigger !== "adjustHeight") {
      this.mask.attr({ d });
    }
  }
  /**
   * These elements are moved over to the fixed renderer and stay fixed when
   * the user scrolls the chart
   * @private
   */
  moveFixedElements() {
    const { container, inverted, scrollablePixelsX, scrollablePixelsY } = this.chart, fixedRenderer = this.fixedRenderer, fixedSelectors = ScrollablePlotArea.fixedSelectors;
    let axisClass;
    if (scrollablePixelsX && !inverted) {
      axisClass = ".highcharts-yaxis";
    } else if (scrollablePixelsX && inverted) {
      axisClass = ".highcharts-xaxis";
    } else if (scrollablePixelsY && !inverted) {
      axisClass = ".highcharts-xaxis";
    } else if (scrollablePixelsY && inverted) {
      axisClass = ".highcharts-yaxis";
    }
    if (axisClass && !(this.chart.hasParallelCoordinates && axisClass === ".highcharts-yaxis")) {
      for (const className of [
        `${axisClass}:not(.highcharts-radial-axis)`,
        `${axisClass}-labels:not(.highcharts-radial-axis-labels)`
      ]) {
        pushUnique$u(fixedSelectors, className);
      }
    } else {
      for (const classBase of [
        ".highcharts-xaxis",
        ".highcharts-yaxis"
      ]) {
        for (const className of [
          `${classBase}:not(.highcharts-radial-axis)`,
          `${classBase}-labels:not(.highcharts-radial-axis-labels)`
        ]) {
          erase$4(fixedSelectors, className);
        }
      }
    }
    for (const className of fixedSelectors) {
      [].forEach.call(container.querySelectorAll(className), (elem) => {
        (elem.namespaceURI === fixedRenderer.SVG_NS ? fixedRenderer.box : fixedRenderer.box.parentNode).appendChild(elem);
        elem.style.pointerEvents = "auto";
      });
    }
  }
}
ScrollablePlotArea.fixedSelectors = [
  ".highcharts-breadcrumbs-group",
  ".highcharts-contextbutton",
  ".highcharts-caption",
  ".highcharts-credits",
  ".highcharts-drillup-button",
  ".highcharts-legend",
  ".highcharts-legend-checkbox",
  ".highcharts-navigator-series",
  ".highcharts-navigator-xaxis",
  ".highcharts-navigator-yaxis",
  ".highcharts-navigator",
  ".highcharts-range-selector-group",
  ".highcharts-reset-zoom",
  ".highcharts-scrollbar",
  ".highcharts-subtitle",
  ".highcharts-title"
];
const { format: format$c } = Templating;
const { series: Series$8 } = SeriesRegistry$1;
const { destroyObjectProperties: destroyObjectProperties$5, fireEvent: fireEvent$z, getAlignFactor: getAlignFactor$4, isNumber: isNumber$V, pick: pick$1y } = Utilities;
class StackItem {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(axis, options2, negativeValue, x, stackOption) {
    const inverted = axis.chart.inverted, reversed = axis.reversed;
    this.axis = axis;
    const isNegative = this.isNegative = !!negativeValue !== !!reversed;
    this.options = options2 = options2 || {};
    this.x = x;
    this.total = null;
    this.cumulative = null;
    this.points = {};
    this.hasValidPoints = false;
    this.stack = stackOption;
    this.leftCliff = 0;
    this.rightCliff = 0;
    this.alignOptions = {
      align: options2.align || (inverted ? isNegative ? "left" : "right" : "center"),
      verticalAlign: options2.verticalAlign || (inverted ? "middle" : isNegative ? "bottom" : "top"),
      y: options2.y,
      x: options2.x
    };
    this.textAlign = options2.textAlign || (inverted ? !isNegative ? "left" : "right" : "center");
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  destroy() {
    destroyObjectProperties$5(this, this.axis);
  }
  /**
   * Renders the stack total label and adds it to the stack label group.
   * @private
   */
  render(group2) {
    const chart = this.axis.chart, options2 = this.options, formatOption = options2.format, str = formatOption ? format$c(formatOption, this, chart) : options2.formatter.call(this);
    if (this.label) {
      this.label.attr({ text: str, visibility: "hidden" });
    } else {
      this.label = chart.renderer.label(str, null, void 0, options2.shape, void 0, void 0, options2.useHTML, false, "stack-labels");
      const attr2 = {
        r: options2.borderRadius || 0,
        text: str,
        // Set default padding to 5 as it is in datalabels #12308
        padding: pick$1y(options2.padding, 5),
        visibility: "hidden"
        // Hidden until setOffset is called
      };
      if (!chart.styledMode) {
        attr2.fill = options2.backgroundColor;
        attr2.stroke = options2.borderColor;
        attr2["stroke-width"] = options2.borderWidth;
        this.label.css(options2.style || {});
      }
      this.label.attr(attr2);
      if (!this.label.added) {
        this.label.add(group2);
      }
    }
    this.label.labelrank = chart.plotSizeY;
    fireEvent$z(this, "afterRender");
  }
  /**
   * Sets the offset that the stack has from the x value and repositions the
   * label.
   * @private
   */
  setOffset(xOffset, width, boxBottom, boxTop, defaultX, xAxis2) {
    const { alignOptions, axis, label, options: options2, textAlign } = this, chart = axis.chart, stackBox = this.getStackBox({
      xOffset,
      width,
      boxBottom,
      boxTop,
      defaultX,
      xAxis: xAxis2
    }), { verticalAlign } = alignOptions;
    if (label && stackBox) {
      const labelBox = label.getBBox(void 0, 0), padding = label.padding;
      let isJustify = pick$1y(options2.overflow, "justify") === "justify", visible;
      alignOptions.x = options2.x || 0;
      alignOptions.y = options2.y || 0;
      const { x, y } = this.adjustStackPosition({
        labelBox,
        verticalAlign,
        textAlign
      });
      stackBox.x -= x;
      stackBox.y -= y;
      label.align(alignOptions, false, stackBox);
      visible = chart.isInsidePlot(label.alignAttr.x + alignOptions.x + x, label.alignAttr.y + alignOptions.y + y);
      if (!visible) {
        isJustify = false;
      }
      if (isJustify) {
        Series$8.prototype.justifyDataLabel.call(axis, label, alignOptions, label.alignAttr, labelBox, stackBox);
      }
      label.attr({
        x: label.alignAttr.x,
        y: label.alignAttr.y,
        rotation: options2.rotation,
        rotationOriginX: labelBox.width * getAlignFactor$4(options2.textAlign || "center"),
        rotationOriginY: labelBox.height / 2
      });
      if (pick$1y(!isJustify && options2.crop, true)) {
        visible = isNumber$V(label.x) && isNumber$V(label.y) && chart.isInsidePlot(label.x - padding + (label.width || 0), label.y) && chart.isInsidePlot(label.x + padding, label.y);
      }
      label[visible ? "show" : "hide"]();
    }
    fireEvent$z(this, "afterSetOffset", { xOffset, width });
  }
  /**
   * Adjust the stack BBox position, to take into consideration the alignment
   * of the dataLabel. This is necessary to make the stackDataLabel work with
   * core methods like `SVGLabel.adjust` and `Series.justifyDataLabel`.
   * @param AdjustStackPositionProps
   * @return {{x: number, y: number}} Adjusted BBox position of the stack.
   */
  adjustStackPosition({ labelBox, verticalAlign, textAlign }) {
    return {
      x: labelBox.width / 2 + labelBox.width / 2 * (2 * getAlignFactor$4(textAlign) - 1),
      y: labelBox.height / 2 * 2 * (1 - getAlignFactor$4(verticalAlign))
    };
  }
  /**
   * Get the bbox of the stack.
   * @private
   * @function Highcharts.StackItem#getStackBox
   * @return {BBoxObject} The x, y, height, width of the stack.
   */
  getStackBox(stackBoxProps) {
    const stackItem = this, axis = this.axis, chart = axis.chart, { boxTop, defaultX, xOffset, width, boxBottom } = stackBoxProps, totalStackValue = axis.stacking.usePercentage ? 100 : pick$1y(boxTop, this.total, 0), y = axis.toPixels(totalStackValue), xAxis2 = stackBoxProps.xAxis || chart.xAxis[0], x = pick$1y(defaultX, xAxis2.translate(this.x)) + xOffset, yZero = axis.toPixels(boxBottom || isNumber$V(axis.min) && axis.logarithmic && axis.logarithmic.lin2log(axis.min) || 0), height = Math.abs(y - yZero), inverted = chart.inverted, neg = stackItem.isNegative;
    return inverted ? {
      x: (neg ? y : y - height) - chart.plotLeft,
      y: xAxis2.height - x - width + xAxis2.top - chart.plotTop,
      width: height,
      height: width
    } : {
      x: x + xAxis2.transB - chart.plotLeft,
      y: (neg ? y - height : y) - chart.plotTop,
      width,
      height
    };
  }
}
const { getDeferredAnimation: getDeferredAnimation$2 } = animationExports;
const { series: { prototype: seriesProto$5 } } = SeriesRegistry$1;
const { addEvent: addEvent$1j, correctFloat: correctFloat$c, defined: defined$10, destroyObjectProperties: destroyObjectProperties$4, fireEvent: fireEvent$y, isNumber: isNumber$U, objectEach: objectEach$k, pick: pick$1x } = Utilities;
function chartGetStacks() {
  const chart = this, inverted = chart.inverted;
  chart.axes.forEach((axis) => {
    if (axis.stacking?.stacks && axis.hasVisibleSeries) {
      axis.stacking.oldStacks = axis.stacking.stacks;
    }
  });
  chart.series.forEach((series) => {
    const xAxisOptions = series.xAxis?.options || {};
    if (series.options.stacking && series.reserveSpace()) {
      series.stackKey = [
        series.type,
        pick$1x(series.options.stack, ""),
        inverted ? xAxisOptions.top : xAxisOptions.left,
        inverted ? xAxisOptions.height : xAxisOptions.width
      ].join(",");
    }
  });
}
function onAxisDestroy() {
  const stacking = this.stacking;
  if (stacking) {
    const stacks = stacking.stacks;
    objectEach$k(stacks, (stack, stackKey) => {
      destroyObjectProperties$4(stack);
      delete stacks[stackKey];
    });
    stacking.stackTotalGroup?.destroy();
  }
}
function onAxisInit$2() {
  if (!this.stacking) {
    this.stacking = new AxisAdditions(this);
  }
}
function seriesGetStackIndicator(stackIndicator, x, index, key2) {
  if (!defined$10(stackIndicator) || stackIndicator.x !== x || key2 && stackIndicator.stackKey !== key2) {
    stackIndicator = {
      x,
      index: 0,
      key: key2,
      stackKey: key2
    };
  } else {
    stackIndicator.index++;
  }
  stackIndicator.key = [index, x, stackIndicator.index].join(",");
  return stackIndicator;
}
function seriesModifyStacks() {
  const series = this, yAxis2 = series.yAxis, stackKey = series.stackKey || "", stacks = yAxis2.stacking.stacks, processedXData = series.getColumn("x", true), stacking = series.options.stacking, stacker = series[stacking + "Stacker"];
  let stackIndicator;
  if (stacker) {
    [stackKey, "-" + stackKey].forEach((key2) => {
      let i = processedXData.length, x, stackItem, pointExtremes;
      while (i--) {
        x = processedXData[i];
        stackIndicator = series.getStackIndicator(stackIndicator, x, series.index, key2);
        stackItem = stacks[key2]?.[x];
        pointExtremes = stackItem?.points[stackIndicator.key || ""];
        if (pointExtremes) {
          stacker.call(series, pointExtremes, stackItem, i);
        }
      }
    });
  }
}
function seriesPercentStacker(pointExtremes, stack, i) {
  const totalFactor = stack.total ? 100 / stack.total : 0;
  pointExtremes[0] = correctFloat$c(pointExtremes[0] * totalFactor);
  pointExtremes[1] = correctFloat$c(pointExtremes[1] * totalFactor);
  this.stackedYData[i] = pointExtremes[1];
}
function seriesSetGroupedPoints(axis) {
  if (this.is("column") || this.is("columnrange")) {
    if (this.options.centerInCategory && // With only one series, we don't need to consider centerInCategory
    this.chart.series.length > 1) {
      seriesProto$5.setStackedPoints.call(this, axis, "group");
    } else {
      axis.stacking.resetStacks();
    }
  }
}
function seriesSetStackedPoints(axis, stackingParam) {
  const type = stackingParam || this.options.stacking;
  if (!type || !this.reserveSpace() || // Group stacks (centerInCategory) belong on the x-axis, other stacks on
  // the y-axis.
  ({ group: "xAxis" }[type] || "yAxis") !== axis.coll) {
    return;
  }
  const series = this, xData = series.getColumn("x", true), yData = series.getColumn(series.pointValKey || "y", true), stackedYData = [], yDataLength = yData.length, seriesOptions = series.options, threshold = seriesOptions.threshold || 0, stackThreshold = seriesOptions.startFromThreshold ? threshold : 0, stackOption = seriesOptions.stack, stackKey = stackingParam ? `${series.type},${type}` : series.stackKey || "", negKey = "-" + stackKey, negStacks = series.negStacks, stacking = axis.stacking, stacks = stacking.stacks, oldStacks = stacking.oldStacks;
  let stackIndicator, isNegative, stack, other, key2, pointKey, i;
  stacking.stacksTouched += 1;
  for (i = 0; i < yDataLength; i++) {
    const x = xData[i] || 0, y = yData[i], yNumber = isNumber$U(y) && y || 0;
    stackIndicator = series.getStackIndicator(stackIndicator, x, series.index);
    pointKey = stackIndicator.key || "";
    isNegative = negStacks && yNumber < (stackThreshold ? 0 : threshold);
    key2 = isNegative ? negKey : stackKey;
    if (!stacks[key2]) {
      stacks[key2] = {};
    }
    if (!stacks[key2][x]) {
      if (oldStacks[key2]?.[x]) {
        stacks[key2][x] = oldStacks[key2][x];
        stacks[key2][x].total = null;
      } else {
        stacks[key2][x] = new StackItem(axis, axis.options.stackLabels, !!isNegative, x, stackOption);
      }
    }
    stack = stacks[key2][x];
    if (y !== null) {
      stack.points[pointKey] = stack.points[series.index] = [
        pick$1x(stack.cumulative, stackThreshold)
      ];
      if (!defined$10(stack.cumulative)) {
        stack.base = pointKey;
      }
      stack.touched = stacking.stacksTouched;
      if (stackIndicator.index > 0 && series.singleStacks === false) {
        stack.points[pointKey][0] = stack.points[series.index + "," + x + ",0"][0];
      }
    } else {
      delete stack.points[pointKey];
      delete stack.points[series.index];
    }
    let total = stack.total || 0;
    if (type === "percent") {
      other = isNegative ? stackKey : negKey;
      if (negStacks && stacks[other]?.[x]) {
        other = stacks[other][x];
        total = other.total = Math.max(other.total || 0, total) + Math.abs(yNumber);
      } else {
        total = correctFloat$c(total + Math.abs(yNumber));
      }
    } else if (type === "group") {
      if (isNumber$U(y)) {
        total++;
      }
    } else {
      total = correctFloat$c(total + yNumber);
    }
    if (type === "group") {
      stack.cumulative = (total || 1) - 1;
    } else {
      stack.cumulative = correctFloat$c(pick$1x(stack.cumulative, stackThreshold) + yNumber);
    }
    stack.total = total;
    if (y !== null) {
      stack.points[pointKey].push(stack.cumulative);
      stackedYData[i] = stack.cumulative;
      stack.hasValidPoints = true;
    }
  }
  if (type === "percent") {
    stacking.usePercentage = true;
  }
  if (type !== "group") {
    this.stackedYData = stackedYData;
  }
  stacking.oldStacks = {};
}
class AxisAdditions {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(axis) {
    this.oldStacks = {};
    this.stacks = {};
    this.stacksTouched = 0;
    this.axis = axis;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Build the stacks from top down
   * @private
   */
  buildStacks() {
    const stacking = this, axis = stacking.axis, axisSeries = axis.series, isXAxis = axis.coll === "xAxis", reversedStacks = axis.options.reversedStacks, len = axisSeries.length;
    let actualSeries, i;
    this.resetStacks();
    stacking.usePercentage = false;
    i = len;
    while (i--) {
      actualSeries = axisSeries[reversedStacks ? i : len - i - 1];
      if (isXAxis) {
        actualSeries.setGroupedPoints(axis);
      }
      actualSeries.setStackedPoints(axis);
    }
    if (!isXAxis) {
      for (i = 0; i < len; i++) {
        axisSeries[i].modifyStacks();
      }
    }
    fireEvent$y(axis, "afterBuildStacks");
  }
  /**
   * @private
   */
  cleanStacks() {
    if (this.oldStacks) {
      this.stacks = this.oldStacks;
      objectEach$k(this.stacks, (type) => {
        objectEach$k(type, (stack) => {
          stack.cumulative = stack.total;
        });
      });
    }
  }
  /**
   * Set all the stacks to initial states and destroy unused ones.
   * @private
   */
  resetStacks() {
    objectEach$k(this.stacks, (type) => {
      objectEach$k(type, (stack, x) => {
        if (isNumber$U(stack.touched) && stack.touched < this.stacksTouched) {
          stack.destroy();
          delete type[x];
        } else {
          stack.total = null;
          stack.cumulative = null;
        }
      });
    });
  }
  /**
   * @private
   */
  renderStackTotals() {
    const stacking = this, axis = stacking.axis, chart = axis.chart, renderer = chart.renderer, stacks = stacking.stacks, stackLabelsAnim = axis.options.stackLabels?.animation, animationConfig = getDeferredAnimation$2(chart, stackLabelsAnim || false), stackTotalGroup = stacking.stackTotalGroup = stacking.stackTotalGroup || renderer.g("stack-labels").attr({
      zIndex: 6,
      opacity: 0
    }).add();
    stackTotalGroup.translate(chart.plotLeft, chart.plotTop);
    objectEach$k(stacks, (type) => {
      objectEach$k(type, (stack) => {
        stack.render(stackTotalGroup);
      });
    });
    stackTotalGroup.animate({
      opacity: 1
    }, animationConfig);
  }
}
var StackingAxis;
(function(StackingAxis2) {
  function compose2(AxisClass, ChartClass, SeriesClass) {
    const chartProto = ChartClass.prototype, seriesProto2 = SeriesClass.prototype;
    if (!chartProto.getStacks) {
      addEvent$1j(AxisClass, "init", onAxisInit$2);
      addEvent$1j(AxisClass, "destroy", onAxisDestroy);
      chartProto.getStacks = chartGetStacks;
      seriesProto2.getStackIndicator = seriesGetStackIndicator;
      seriesProto2.modifyStacks = seriesModifyStacks;
      seriesProto2.percentStacker = seriesPercentStacker;
      seriesProto2.setGroupedPoints = seriesSetGroupedPoints;
      seriesProto2.setStackedPoints = seriesSetStackedPoints;
    }
  }
  StackingAxis2.compose = compose2;
})(StackingAxis || (StackingAxis = {}));
const StackingAxis$1 = StackingAxis;
const { defined: defined$$, merge: merge$1r, isObject: isObject$f } = Utilities;
let LineSeries$7 = class LineSeries2 extends Series$9 {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Draw the graph. Called internally when rendering line-like series
   * types. The first time it generates the `series.graph` item and
   * optionally other series-wide items like `series.area` for area
   * charts. On subsequent calls these items are updated with new
   * positions and attributes.
   *
   * @function Highcharts.Series#drawGraph
   */
  drawGraph() {
    const options2 = this.options, graphPath = (this.gappedPath || this.getGraphPath).call(this), styledMode = this.chart.styledMode;
    [this, ...this.zones].forEach((owner, i) => {
      let attribs, graph = owner.graph;
      const verb = graph ? "animate" : "attr", dashStyle = owner.dashStyle || options2.dashStyle;
      if (graph) {
        graph.endX = this.preventGraphAnimation ? null : graphPath.xMap;
        graph.animate({ d: graphPath });
      } else if (graphPath.length) {
        owner.graph = graph = this.chart.renderer.path(graphPath).addClass("highcharts-graph" + (i ? ` highcharts-zone-graph-${i - 1} ` : " ") + (i && owner.className || "")).attr({ zIndex: 1 }).add(this.group);
      }
      if (graph && !styledMode) {
        attribs = {
          "stroke": !i && options2.lineColor || // Series only
          owner.color || this.color || "#cccccc",
          "stroke-width": options2.lineWidth || 0,
          // Polygon series use filled graph
          "fill": this.fillGraph && this.color || "none"
        };
        if (dashStyle) {
          attribs.dashstyle = dashStyle;
        } else if (options2.linecap !== "square") {
          attribs["stroke-linecap"] = attribs["stroke-linejoin"] = "round";
        }
        graph[verb](attribs).shadow(options2.shadow && // If shadow is defined, call function with
        // `filterUnits: 'userSpaceOnUse'` to avoid known
        // SVG filter bug (#19093)
        merge$1r({ filterUnits: "userSpaceOnUse" }, isObject$f(options2.shadow) ? options2.shadow : {}));
      }
      if (graph) {
        graph.startX = graphPath.xMap;
        graph.isArea = graphPath.isArea;
      }
    });
  }
  // eslint-disable-next-line valid-jsdoc
  /**
   * Get the graph path.
   *
   * @private
   */
  getGraphPath(points, nullsAsZeroes, connectCliffs) {
    const series = this, options2 = series.options, graphPath = [], xMap = [];
    let gap, step = options2.step;
    points = points || series.points;
    const reversed = points.reversed;
    if (reversed) {
      points.reverse();
    }
    step = {
      right: 1,
      center: 2
    }[step] || step && 3;
    if (step && reversed) {
      step = 4 - step;
    }
    points = this.getValidPoints(points, false, options2.nullInteraction || !(options2.connectNulls && !nullsAsZeroes && !connectCliffs));
    points.forEach(function(point, i) {
      const plotX = point.plotX, plotY = point.plotY, lastPoint = points[i - 1], isNull = point.isNull || typeof plotY !== "number";
      let pathToPoint;
      if ((point.leftCliff || lastPoint?.rightCliff) && !connectCliffs) {
        gap = true;
      }
      if (isNull && !defined$$(nullsAsZeroes) && i > 0) {
        gap = !options2.connectNulls;
      } else if (isNull && !nullsAsZeroes) {
        gap = true;
      } else {
        if (i === 0 || gap) {
          pathToPoint = [[
            "M",
            point.plotX,
            point.plotY
          ]];
        } else if (series.getPointSpline) {
          pathToPoint = [series.getPointSpline(points, point, i)];
        } else if (step) {
          if (step === 1) {
            pathToPoint = [[
              "L",
              lastPoint.plotX,
              plotY
            ]];
          } else if (step === 2) {
            pathToPoint = [[
              "L",
              (lastPoint.plotX + plotX) / 2,
              lastPoint.plotY
            ], [
              "L",
              (lastPoint.plotX + plotX) / 2,
              plotY
            ]];
          } else {
            pathToPoint = [[
              "L",
              plotX,
              lastPoint.plotY
            ]];
          }
          pathToPoint.push([
            "L",
            plotX,
            plotY
          ]);
        } else {
          pathToPoint = [[
            "L",
            plotX,
            plotY
          ]];
        }
        xMap.push(point.x);
        if (step) {
          xMap.push(point.x);
          if (step === 2) {
            xMap.push(point.x);
          }
        }
        graphPath.push.apply(graphPath, pathToPoint);
        gap = false;
      }
    });
    graphPath.xMap = xMap;
    series.graphPath = graphPath;
    return graphPath;
  }
};
LineSeries$7.defaultOptions = merge$1r(
  Series$9.defaultOptions,
  /**
   * General options for all series types.
   *
   * @optionparent plotOptions.series
   */
  {
    legendSymbol: "lineMarker"
  }
);
SeriesRegistry$1.registerSeriesType("line", LineSeries$7);
const AreaSeriesDefaults = {
  /**
   * @see [fillColor](#plotOptions.area.fillColor)
   * @see [fillOpacity](#plotOptions.area.fillOpacity)
   *
   * @apioption plotOptions.area.color
   */
  /**
   * Fill color or gradient for the area. When `undefined`, the series'
   * `color` is used with the series' `fillOpacity`.
   *
   * In styled mode, the fill color can be set with the `.highcharts-area`
   * class name.
   *
   * @see [color](#plotOptions.area.color)
   * @see [fillOpacity](#plotOptions.area.fillOpacity)
   *
   * @sample {highcharts} highcharts/plotoptions/area-fillcolor-default/
   *         Undefined by default
   * @sample {highcharts} highcharts/plotoptions/area-fillcolor-gradient/
   *         Gradient
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highcharts highstock
   * @apioption plotOptions.area.fillColor
   */
  /**
   * Fill opacity for the area. When you set an explicit `fillColor`,
   * the `fillOpacity` is not applied. Instead, you should define the
   * opacity in the `fillColor` with an rgba color definition. The
   * `fillOpacity` setting, also the default setting, overrides the alpha
   * component of the `color` setting.
   *
   * In styled mode, the fill opacity can be set with the
   * `.highcharts-area` class name.
   *
   * @see [color](#plotOptions.area.color)
   * @see [fillColor](#plotOptions.area.fillColor)
   *
   * @sample {highcharts} highcharts/plotoptions/area-fillopacity/
   *         Automatic fill color and fill opacity of 0.1
   *
   * @type      {number}
   * @default   {highcharts} 0.75
   * @default   {highstock} 0.75
   * @product   highcharts highstock
   * @apioption plotOptions.area.fillOpacity
   */
  /**
   * A separate color for the graph line. By default the line takes the
   * `color` of the series, but the lineColor setting allows setting a
   * separate color for the line without altering the `fillColor`.
   *
   * In styled mode, the line stroke can be set with the
   * `.highcharts-graph` class name.
   *
   * @sample {highcharts} highcharts/plotoptions/area-linecolor/
   *         Dark gray line
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highcharts highstock
   * @apioption plotOptions.area.lineColor
   */
  /**
   * A separate color for the negative part of the area. Note that `zones`
   * takes precedence over the negative fill color.
   *
   * In styled mode, a negative color is set with the
   * `.highcharts-negative` class name.
   *
   * @see [negativeColor](#plotOptions.area.negativeColor)
   *
   * @sample {highcharts} highcharts/css/series-negative-color/
   *         Negative color in styled mode
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.area.negativeFillColor
   */
  /**
   * Whether the whole area or just the line should respond to mouseover
   * tooltips and other mouse or touch events.
   *
   * @sample {highcharts|highstock} highcharts/plotoptions/area-trackbyarea/
   *         Display the tooltip when the area is hovered
   *
   * @type      {boolean}
   * @default   false
   * @since     1.1.6
   * @product   highcharts highstock
   * @apioption plotOptions.area.trackByArea
   */
  /**
   * The Y axis value to serve as the base for the area, for
   * distinguishing between values above and below a threshold. The area
   * between the graph and the threshold is filled.
   *
   * * If a number is given, the Y axis will scale to the threshold.
   * * If `null`, the scaling behaves like a line series with fill between
   *   the graph and the Y axis minimum.
   * * If `Infinity` or `-Infinity`, the area between the graph and the
   *   corresponding Y axis extreme is filled (since v6.1.0).
   *
   * @sample {highcharts} highcharts/plotoptions/area-threshold/
   *         A threshold of 100
   * @sample {highcharts} highcharts/plotoptions/area-threshold-infinity/
   *         A threshold of Infinity
   *
   * @type    {number|null}
   * @since   2.0
   * @product highcharts highstock
   */
  threshold: 0,
  legendSymbol: "areaMarker"
};
const { seriesTypes: { line: LineSeries$6 } } = SeriesRegistry$1;
const { extend: extend$1b, merge: merge$1q, objectEach: objectEach$j, pick: pick$1w } = Utilities;
let AreaSeries$3 = class AreaSeries2 extends LineSeries$6 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Draw the graph and the underlying area. This method calls the Series
   * base function and adds the area. The areaPath is calculated in the
   * getSegmentPath method called from Series.prototype.drawGraph.
   * @private
   */
  drawGraph() {
    this.areaPath = [];
    super.drawGraph.apply(this);
    const { areaPath, options: options2 } = this;
    [this, ...this.zones].forEach((owner, i) => {
      const attribs = {}, fillColor = owner.fillColor || options2.fillColor;
      let area = owner.area;
      const verb = area ? "animate" : "attr";
      if (area) {
        area.endX = this.preventGraphAnimation ? null : areaPath.xMap;
        area.animate({ d: areaPath });
      } else {
        attribs.zIndex = 0;
        area = owner.area = this.chart.renderer.path(areaPath).addClass("highcharts-area" + (i ? ` highcharts-zone-area-${i - 1} ` : " ") + (i && owner.className || "")).add(this.group);
        area.isArea = true;
      }
      if (!this.chart.styledMode) {
        attribs.fill = fillColor || owner.color || this.color;
        attribs["fill-opacity"] = fillColor ? 1 : options2.fillOpacity ?? 0.75;
        area.css({
          pointerEvents: this.stickyTracking ? "none" : "auto"
        });
      }
      area[verb](attribs);
      area.startX = areaPath.xMap;
      area.shiftUnit = options2.step ? 2 : 1;
    });
  }
  /**
   * @private
   */
  getGraphPath(points) {
    const getGraphPath = LineSeries$6.prototype.getGraphPath, options2 = this.options, stacking = options2.stacking, yAxis2 = this.yAxis, bottomPoints = [], graphPoints = [], seriesIndex = this.index, stacks = yAxis2.stacking.stacks[this.stackKey], threshold = options2.threshold, translatedThreshold = Math.round(
      // #10909
      yAxis2.getThreshold(options2.threshold)
    ), connectNulls = pick$1w(
      // #10574
      options2.connectNulls,
      stacking === "percent"
    ), addDummyPoints = function(i, otherI, side) {
      const point = points[i], stackedValues = stacking && stacks[point.x].points[seriesIndex], nullVal = point[side + "Null"] || 0, cliffVal = point[side + "Cliff"] || 0;
      let top, bottom, isNull2 = true;
      if (cliffVal || nullVal) {
        top = (nullVal ? stackedValues[0] : stackedValues[1]) + cliffVal;
        bottom = stackedValues[0] + cliffVal;
        isNull2 = !!nullVal;
      } else if (!stacking && points[otherI] && points[otherI].isNull) {
        top = bottom = threshold;
      }
      if (typeof top !== "undefined") {
        graphPoints.push({
          plotX,
          plotY: top === null ? translatedThreshold : yAxis2.getThreshold(top),
          isNull: isNull2,
          isCliff: true
        });
        bottomPoints.push({
          plotX,
          plotY: bottom === null ? translatedThreshold : yAxis2.getThreshold(bottom),
          doCurve: false
          // #1041, gaps in areaspline areas
        });
      }
    };
    let plotX, isNull, yBottom;
    points = points || this.points;
    if (stacking) {
      points = this.getStackPoints(points);
    }
    for (let i = 0, iEnd = points.length; i < iEnd; ++i) {
      if (!stacking) {
        points[i].leftCliff = points[i].rightCliff = points[i].leftNull = points[i].rightNull = void 0;
      }
      isNull = points[i].isNull;
      plotX = pick$1w(points[i].rectPlotX, points[i].plotX);
      yBottom = stacking ? pick$1w(points[i].yBottom, translatedThreshold) : translatedThreshold;
      if (!isNull || connectNulls) {
        if (!connectNulls) {
          addDummyPoints(i, i - 1, "left");
        }
        if (!(isNull && !stacking && connectNulls)) {
          graphPoints.push(points[i]);
          bottomPoints.push({
            x: i,
            plotX,
            plotY: yBottom
          });
        }
        if (!connectNulls) {
          addDummyPoints(i, i + 1, "right");
        }
      }
    }
    const topPath = getGraphPath.call(this, graphPoints, true, true);
    bottomPoints.reversed = true;
    const bottomPath = getGraphPath.call(this, bottomPoints, true, true);
    const firstBottomPoint = bottomPath[0];
    if (firstBottomPoint && firstBottomPoint[0] === "M") {
      bottomPath[0] = ["L", firstBottomPoint[1], firstBottomPoint[2]];
    }
    const areaPath = topPath.concat(bottomPath);
    if (areaPath.length) {
      areaPath.push(["Z"]);
    }
    const graphPath = getGraphPath.call(this, graphPoints, false, connectNulls);
    if (this.chart.series.length > 1 && stacking && graphPoints.some((point) => point.isCliff)) {
      areaPath.hasStackedCliffs = graphPath.hasStackedCliffs = true;
    }
    areaPath.xMap = topPath.xMap;
    this.areaPath = areaPath;
    return graphPath;
  }
  /**
   * Return an array of stacked points, where null and missing points are
   * replaced by dummy points in order for gaps to be drawn correctly in
   * stacks.
   * @private
   */
  getStackPoints(points) {
    const series = this, segment = [], keys = [], xAxis2 = this.xAxis, yAxis2 = this.yAxis, stack = yAxis2.stacking.stacks[this.stackKey], pointMap = {}, yAxisSeries = yAxis2.series, seriesLength = yAxisSeries.length, upOrDown = yAxis2.options.reversedStacks ? 1 : -1, seriesIndex = yAxisSeries.indexOf(series);
    points = points || this.points;
    if (this.options.stacking) {
      for (let i = 0; i < points.length; i++) {
        points[i].leftNull = points[i].rightNull = void 0;
        pointMap[points[i].x] = points[i];
      }
      objectEach$j(stack, function(stackX, x) {
        if (stackX.total !== null) {
          keys.push(x);
        }
      });
      keys.sort(function(a, b) {
        return a - b;
      });
      const visibleSeries = yAxisSeries.map((s) => s.visible);
      keys.forEach(function(x, idx) {
        let y = 0, stackPoint, stackedValues;
        if (pointMap[x] && !pointMap[x].isNull) {
          segment.push(pointMap[x]);
          [-1, 1].forEach(function(direction) {
            const nullName = direction === 1 ? "rightNull" : "leftNull", cliffName = direction === 1 ? "rightCliff" : "leftCliff", otherStack = stack[keys[idx + direction]];
            let cliff = 0;
            if (otherStack) {
              let i = seriesIndex;
              while (i >= 0 && i < seriesLength) {
                const si = yAxisSeries[i].index;
                stackPoint = otherStack.points[si];
                if (!stackPoint) {
                  if (si === series.index) {
                    pointMap[x][nullName] = true;
                  } else if (visibleSeries[i]) {
                    stackedValues = stack[x].points[si];
                    if (stackedValues) {
                      cliff -= stackedValues[1] - stackedValues[0];
                    }
                  }
                }
                i += upOrDown;
              }
            }
            pointMap[x][cliffName] = cliff;
          });
        } else {
          let i = seriesIndex;
          while (i >= 0 && i < seriesLength) {
            const si = yAxisSeries[i].index;
            stackPoint = stack[x].points[si];
            if (stackPoint) {
              y = stackPoint[1];
              break;
            }
            i += upOrDown;
          }
          y = pick$1w(y, 0);
          y = yAxis2.translate(
            // #6272
            y,
            0,
            1,
            0,
            1
          );
          segment.push({
            isNull: true,
            plotX: xAxis2.translate(
              // #6272
              x,
              0,
              0,
              0,
              1
            ),
            x,
            plotY: y,
            yBottom: y
          });
        }
      });
    }
    return segment;
  }
};
AreaSeries$3.defaultOptions = merge$1q(LineSeries$6.defaultOptions, AreaSeriesDefaults);
extend$1b(AreaSeries$3.prototype, {
  singleStacks: false
});
SeriesRegistry$1.registerSeriesType("area", AreaSeries$3);
const { line: LineSeries$5 } = SeriesRegistry$1.seriesTypes;
const { merge: merge$1p, pick: pick$1v } = Utilities;
class SplineSeries extends LineSeries$5 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Get the spline segment from a given point's previous neighbour to the
   * given point.
   *
   * @private
   * @function Highcharts.seriesTypes.spline#getPointSpline
   */
  getPointSpline(points, point, i) {
    const smoothing = 1.5, denom = smoothing + 1, plotX = point.plotX || 0, plotY = point.plotY || 0, lastPoint = points[i - 1], nextPoint = points[i + 1];
    let leftContX, leftContY, rightContX, rightContY;
    function doCurve(otherPoint) {
      return otherPoint && !otherPoint.isNull && otherPoint.doCurve !== false && // #6387, area splines next to null:
      !point.isCliff;
    }
    if (doCurve(lastPoint) && doCurve(nextPoint)) {
      const lastX = lastPoint.plotX || 0, lastY = lastPoint.plotY || 0, nextX = nextPoint.plotX || 0, nextY = nextPoint.plotY || 0;
      let correction = 0;
      leftContX = (smoothing * plotX + lastX) / denom;
      leftContY = (smoothing * plotY + lastY) / denom;
      rightContX = (smoothing * plotX + nextX) / denom;
      rightContY = (smoothing * plotY + nextY) / denom;
      if (rightContX !== leftContX) {
        correction = (rightContY - leftContY) * (rightContX - plotX) / (rightContX - leftContX) + plotY - rightContY;
      }
      leftContY += correction;
      rightContY += correction;
      if (leftContY > lastY && leftContY > plotY) {
        leftContY = Math.max(lastY, plotY);
        rightContY = 2 * plotY - leftContY;
      } else if (leftContY < lastY && leftContY < plotY) {
        leftContY = Math.min(lastY, plotY);
        rightContY = 2 * plotY - leftContY;
      }
      if (rightContY > nextY && rightContY > plotY) {
        rightContY = Math.max(nextY, plotY);
        leftContY = 2 * plotY - rightContY;
      } else if (rightContY < nextY && rightContY < plotY) {
        rightContY = Math.min(nextY, plotY);
        leftContY = 2 * plotY - rightContY;
      }
      point.rightContX = rightContX;
      point.rightContY = rightContY;
      point.controlPoints = {
        low: [leftContX, leftContY],
        high: [rightContX, rightContY]
      };
    }
    const ret = [
      "C",
      pick$1v(lastPoint.rightContX, lastPoint.plotX, 0),
      pick$1v(lastPoint.rightContY, lastPoint.plotY, 0),
      pick$1v(leftContX, plotX, 0),
      pick$1v(leftContY, plotY, 0),
      plotX,
      plotY
    ];
    lastPoint.rightContX = lastPoint.rightContY = void 0;
    return ret;
  }
}
SplineSeries.defaultOptions = merge$1p(LineSeries$5.defaultOptions);
SeriesRegistry$1.registerSeriesType("spline", SplineSeries);
const { area: AreaSeries$2, area: { prototype: areaProto$2 } } = SeriesRegistry$1.seriesTypes;
const { extend: extend$1a, merge: merge$1o } = Utilities;
class AreaSplineSeries extends SplineSeries {
}
AreaSplineSeries.defaultOptions = merge$1o(SplineSeries.defaultOptions, AreaSeries$2.defaultOptions);
extend$1a(AreaSplineSeries.prototype, {
  getGraphPath: areaProto$2.getGraphPath,
  getStackPoints: areaProto$2.getStackPoints,
  drawGraph: areaProto$2.drawGraph
});
SeriesRegistry$1.registerSeriesType("areaspline", AreaSplineSeries);
const ColumnSeriesDefaults = {
  /**
   * The corner radius of the border surrounding each column or bar. A number
   * signifies pixels. A percentage string, like for example `50%`, signifies
   * a relative size. For columns this is relative to the column width, for
   * pies it is relative to the radius and the inner radius.
   *
   * @sample  {highcharts} highcharts/plotoptions/column-borderradius/
   *          Rounded columns
   * @sample  highcharts/plotoptions/series-border-radius
   *          Column and pie with rounded border
   *
   * @type    {number|string|Highcharts.BorderRadiusOptionsObject}
   * @product highcharts highstock gantt
   */
  borderRadius: 3,
  /**
   * When using automatic point colors pulled from the global
   * [colors](colors) or series-specific
   * [plotOptions.column.colors](series.colors) collections, this option
   * determines whether the chart should receive one color per series or
   * one color per point.
   *
   * In styled mode, the `colors` or `series.colors` arrays are not
   * supported, and instead this option gives the points individual color
   * class names on the form `highcharts-color-{n}`.
   *
   * @see [series colors](#plotOptions.column.colors)
   *
   * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-false/
   *         False by default
   * @sample {highcharts} highcharts/plotoptions/column-colorbypoint-true/
   *         True
   *
   * @type      {boolean}
   * @default   false
   * @since     2.0
   * @product   highcharts highstock gantt
   * @apioption plotOptions.column.colorByPoint
   */
  /**
   * A series specific or series type specific color set to apply instead
   * of the global [colors](#colors) when [colorByPoint](
   * #plotOptions.column.colorByPoint) is true.
   *
   * @type      {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
   * @since     3.0
   * @product   highcharts highstock gantt
   * @apioption plotOptions.column.colors
   */
  /**
   * When `true`, the columns will center in the category, ignoring null
   * or missing points. When `false`, space will be reserved for null or
   * missing points.
   *
   * @sample {highcharts} highcharts/series-column/centerincategory/
   *         Center in category
   * @sample {highcharts} highcharts/series/stack-centerincategory/
   *         Center in category, stacked and grouped
   *
   * @since   8.0.1
   * @product highcharts highstock gantt
   */
  centerInCategory: false,
  /**
   * Padding between each value groups, in x axis units.
   *
   * @sample {highcharts} highcharts/plotoptions/column-grouppadding-default/
   *         0.2 by default
   * @sample {highcharts} highcharts/plotoptions/column-grouppadding-none/
   *         No group padding - all columns are evenly spaced
   *
   * @product highcharts highstock gantt
   */
  groupPadding: 0.2,
  /**
   * Whether to group non-stacked columns or to let them render
   * independent of each other. Non-grouped columns will be laid out
   * individually and overlap each other.
   *
   * @sample {highcharts} highcharts/plotoptions/column-grouping-false/
   *         Grouping disabled
   * @sample {highstock} highcharts/plotoptions/column-grouping-false/
   *         Grouping disabled
   *
   * @type      {boolean}
   * @default   true
   * @since     2.3.0
   * @product   highcharts highstock gantt
   * @apioption plotOptions.column.grouping
   */
  /** @ignore-option */
  marker: null,
  // Point options are specified in the base options
  /**
   * The maximum allowed pixel width for a column, translated to the
   * height of a bar in a bar chart. This prevents the columns from
   * becoming too wide when there is a small number of points in the
   * chart.
   *
   * @see [pointWidth](#plotOptions.column.pointWidth)
   *
   * @sample {highcharts} highcharts/plotoptions/column-maxpointwidth-20/
   *         Limited to 50
   * @sample {highstock} highcharts/plotoptions/column-maxpointwidth-20/
   *         Limited to 50
   *
   * @type      {number}
   * @since     4.1.8
   * @product   highcharts highstock gantt
   * @apioption plotOptions.column.maxPointWidth
   */
  /**
   * Padding between each column or bar, in x axis units.
   *
   * @sample {highcharts} highcharts/plotoptions/column-pointpadding-default/
   *         0.1 by default
   * @sample {highcharts} highcharts/plotoptions/column-pointpadding-025/
   *          0.25
   * @sample {highcharts} highcharts/plotoptions/column-pointpadding-none/
   *         0 for tightly packed columns
   *
   * @product highcharts highstock gantt
   */
  pointPadding: 0.1,
  /**
   * A pixel value specifying a fixed width for each column or bar point.
   * When set to `undefined`, the width is calculated from the
   * `pointPadding` and `groupPadding`. The width effects the dimension
   * that is not based on the point value. For column series it is the
   * horizontal length and for bar series it is the vertical length.
   *
   * @see [maxPointWidth](#plotOptions.column.maxPointWidth)
   *
   * @sample {highcharts} highcharts/plotoptions/column-pointwidth-20/
   *         20px wide columns regardless of chart width or the amount of
   *         data points
   *
   * @type      {number}
   * @since     1.2.5
   * @product   highcharts highstock gantt
   * @apioption plotOptions.column.pointWidth
   */
  /**
   * A pixel value specifying a fixed width for the column or bar.
   * Overrides pointWidth on the series.
   *
   * @see [series.pointWidth](#plotOptions.column.pointWidth)
   *
   * @type      {number}
   * @default   undefined
   * @since     7.0.0
   * @product   highcharts highstock gantt
   * @apioption series.column.data.pointWidth
   */
  /**
   * The minimal height for a column or width for a bar. By default,
   * 0 values are not shown. To visualize a 0 (or close to zero) point,
   * set the minimal point length to a pixel value like 3\. In stacked
   * column charts, minPointLength might not be respected for tightly
   * packed values.
   *
   * @sample {highcharts} highcharts/plotoptions/column-minpointlength/
   *         Zero base value
   * @sample {highcharts} highcharts/plotoptions/column-minpointlength-pos-and-neg/
   *         Positive and negative close to zero values
   *
   * @product highcharts highstock gantt
   */
  minPointLength: 0,
  /**
   * When the series contains less points than the crop threshold, all
   * points are drawn, event if the points fall outside the visible plot
   * area at the current zoom. The advantage of drawing all points
   * (including markers and columns), is that animation is performed on
   * updates. On the other hand, when the series contains more points than
   * the crop threshold, the series data is cropped to only contain points
   * that fall within the plot area. The advantage of cropping away
   * invisible points is to increase performance on large series.
   *
   * @product highcharts highstock gantt
   */
  cropThreshold: 50,
  /**
   * The X axis range that each point is valid for. This determines the
   * width of the column. On a categorized axis, the range will be 1
   * by default (one category unit). On linear and datetime axes, the
   * range will be computed as the distance between the two closest data
   * points.
   *
   * The default `null` means it is computed automatically, but this
   * option can be used to override the automatic value.
   *
   * This option is set by default to 1 if data sorting is enabled.
   *
   * @sample {highcharts} highcharts/plotoptions/column-pointrange/
   *         Set the point range to one day on a data set with one week
   *         between the points
   *
   * @type    {number|null}
   * @since   2.3
   * @product highcharts highstock gantt
   */
  pointRange: null,
  states: {
    /**
     * Options for the hovered point. These settings override the normal
     * state options when a point is moused over or touched.
     *
     * @extends   plotOptions.series.states.hover
     * @excluding halo, lineWidth, lineWidthPlus, marker
     * @product   highcharts highstock gantt
     */
    hover: {
      /** @ignore-option */
      halo: false,
      /**
       * A specific border color for the hovered point. Defaults to
       * inherit the normal state border color.
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @product   highcharts gantt
       * @apioption plotOptions.column.states.hover.borderColor
       */
      /**
       * A specific color for the hovered point.
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @product   highcharts gantt
       * @apioption plotOptions.column.states.hover.color
       */
      /**
       * How much to brighten the point on interaction. Requires the
       * main color to be defined in hex or rgb(a) format.
       *
       * In styled mode, the hover brightening is by default replaced
       * with a fill-opacity set in the `.highcharts-point:hover`
       * rule.
       *
       * @sample {highcharts} highcharts/plotoptions/column-states-hover-brightness/
       *         Brighten by 0.5
       *
       * @product highcharts highstock gantt
       */
      brightness: 0.1
    },
    /**
     * Options for the selected point. These settings override the
     * normal state options when a point is selected.
     *
     * @extends   plotOptions.series.states.select
     * @excluding halo, lineWidth, lineWidthPlus, marker
     * @product   highcharts highstock gantt
     */
    select: {
      /**
       * A specific color for the selected point.
       *
       * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @default #cccccc
       * @product highcharts highstock gantt
       */
      color: "#cccccc",
      /**
       * A specific border color for the selected point.
       *
       * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @default #000000
       * @product highcharts highstock gantt
       */
      borderColor: "#000000"
      /* Palette.neutralColor100 */
    }
  },
  dataLabels: {
    align: void 0,
    verticalAlign: void 0,
    /**
     * The y position offset of the label relative to the point in
     * pixels.
     *
     * @type {number}
     */
    y: void 0
  },
  // False doesn't work well: https://jsfiddle.net/highcharts/hz8fopan/14/
  /** @ignore-option */
  startFromThreshold: true,
  stickyTracking: false,
  tooltip: {
    distance: 6
  },
  /**
   * The Y axis value to serve as the base for the columns, for
   * distinguishing between values above and below a threshold. If `null`,
   * the columns extend from the padding Y axis minimum.
   *
   * @type    {number|null}
   * @since   2.0
   * @product highcharts
   */
  threshold: 0,
  /**
   * The width of the border surrounding each column or bar. Defaults to
   * `1` when there is room for a border, but to `0` when the columns are
   * so dense that a border would cover the next column.
   *
   * In styled mode, the stroke width can be set with the
   * `.highcharts-point` rule.
   *
   * @sample {highcharts} highcharts/plotoptions/column-borderwidth/
   *         2px black border
   *
   * @type      {number}
   * @default   undefined
   * @product   highcharts highstock gantt
   * @apioption plotOptions.column.borderWidth
   */
  /**
   * The color of the border surrounding each column or bar.
   *
   * In styled mode, the border stroke can be set with the
   * `.highcharts-point` rule.
   *
   * @sample {highcharts} highcharts/plotoptions/column-bordercolor/
   *         Dark gray border
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default   #ffffff
   * @product   highcharts highstock gantt
   */
  borderColor: "#ffffff"
  /* Palette.backgroundColor */
};
const { animObject: animObject$8 } = animationExports;
const { parse: color$a } = Color;
const { noop: noop$i } = Highcharts;
const { clamp: clamp$i, crisp: crisp$b, defined: defined$_, extend: extend$19, fireEvent: fireEvent$x, isArray: isArray$i, isNumber: isNumber$T, merge: merge$1n, pick: pick$1u, objectEach: objectEach$i } = Utilities;
let ColumnSeries$f = class ColumnSeries2 extends Series$9 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Animate the column heights one by one from zero.
   *
   * @private
   * @function Highcharts.seriesTypes.column#animate
   *
   * @param {boolean} init
   *        Whether to initialize the animation or run it
   */
  animate(init2) {
    const series = this, yAxis2 = this.yAxis, yAxisPos = yAxis2.pos, reversed = yAxis2.reversed, options2 = series.options, { clipOffset, inverted } = this.chart, attr2 = {}, translateProp = inverted ? "translateX" : "translateY";
    let translateStart, translatedThreshold;
    if (init2 && clipOffset) {
      attr2.scaleY = 1e-3;
      translatedThreshold = clamp$i(yAxis2.toPixels(options2.threshold || 0), yAxisPos, yAxisPos + yAxis2.len);
      if (inverted) {
        translatedThreshold += reversed ? -Math.floor(clipOffset[0]) : Math.ceil(clipOffset[2]);
        attr2.translateX = translatedThreshold - yAxis2.len;
      } else {
        translatedThreshold += reversed ? Math.ceil(clipOffset[0]) : -Math.floor(clipOffset[2]);
        attr2.translateY = translatedThreshold;
      }
      if (series.clipBox) {
        series.setClip();
      }
      series.group.attr(attr2);
    } else {
      translateStart = Number(series.group.attr(translateProp));
      series.group.animate({ scaleY: 1 }, extend$19(animObject$8(series.options.animation), {
        // Do the scale synchronously to ensure smooth
        // updating (#5030, #7228)
        step: function(val, fx) {
          if (series.group) {
            attr2[translateProp] = translateStart + fx.pos * (yAxisPos - translateStart);
            series.group.attr(attr2);
          }
        }
      }));
    }
  }
  /**
   * Initialize the series. Extends the basic Series.init method by
   * marking other series of the same type as dirty.
   *
   * @private
   * @function Highcharts.seriesTypes.column#init
   */
  init(chart, options2) {
    super.init.apply(this, arguments);
    const series = this;
    chart = series.chart;
    if (chart.hasRendered) {
      chart.series.forEach(function(otherSeries) {
        if (otherSeries.type === series.type) {
          otherSeries.isDirty = true;
        }
      });
    }
  }
  /**
   * Return the width and x offset of the columns adjusted for grouping,
   * groupPadding, pointPadding, pointWidth etc.
   *
   * @private
   * @function Highcharts.seriesTypes.column#getColumnMetrics
   */
  getColumnMetrics() {
    const series = this, options2 = series.options, xAxis2 = series.xAxis, yAxis2 = series.yAxis, reversedStacks = xAxis2.options.reversedStacks, reverseStacks = xAxis2.reversed && !reversedStacks || !xAxis2.reversed && reversedStacks, stackGroups = {};
    let stackKey, columnCount = 0;
    if (options2.grouping === false) {
      columnCount = 1;
    } else {
      series.chart.series.forEach(function(otherSeries) {
        const otherYAxis = otherSeries.yAxis, otherOptions = otherSeries.options;
        let columnIndex;
        if (otherSeries.type === series.type && otherSeries.reserveSpace() && yAxis2.len === otherYAxis.len && yAxis2.pos === otherYAxis.pos) {
          if (otherOptions.stacking && otherOptions.stacking !== "group") {
            stackKey = otherSeries.stackKey;
            if (typeof stackGroups[stackKey] === "undefined") {
              stackGroups[stackKey] = columnCount++;
            }
            columnIndex = stackGroups[stackKey];
          } else if (otherOptions.grouping !== false) {
            columnIndex = columnCount++;
          }
          otherSeries.columnIndex = columnIndex;
        }
      });
    }
    const categoryWidth = Math.min(
      Math.abs(xAxis2.transA) * (!xAxis2.brokenAxis?.hasBreaks && xAxis2.ordinal?.slope || options2.pointRange || xAxis2.closestPointRange || xAxis2.tickInterval || 1),
      // #2610
      xAxis2.len
      // #1535
    ), groupPadding = categoryWidth * options2.groupPadding, groupWidth = categoryWidth - 2 * groupPadding, pointOffsetWidth = groupWidth / (columnCount || 1), pointWidth = Math.min(options2.maxPointWidth || xAxis2.len, pick$1u(options2.pointWidth, pointOffsetWidth * (1 - 2 * options2.pointPadding))), pointPadding = (pointOffsetWidth - pointWidth) / 2, colIndex = (series.columnIndex || 0) + (reverseStacks ? 1 : 0), pointXOffset = pointPadding + (groupPadding + colIndex * pointOffsetWidth - categoryWidth / 2) * (reverseStacks ? -1 : 1);
    series.columnMetrics = {
      width: pointWidth,
      offset: pointXOffset,
      paddedWidth: pointOffsetWidth,
      columnCount
    };
    return series.columnMetrics;
  }
  /**
   * Make the columns crisp. The edges are rounded to the nearest full
   * pixel.
   *
   * @private
   * @function Highcharts.seriesTypes.column#crispCol
   */
  crispCol(x, y, width, height) {
    const borderWidth = this.borderWidth, inverted = this.chart.inverted, bottom = crisp$b(y + height, borderWidth, inverted);
    y = crisp$b(y, borderWidth, inverted);
    height = bottom - y;
    if (this.options.crisp) {
      const right = crisp$b(x + width, borderWidth);
      x = crisp$b(x, borderWidth);
      width = right - x;
    }
    return { x, y, width, height };
  }
  /**
   * Adjust for missing columns, according to the `centerInCategory`
   * option. Missing columns are either single points or stacks where the
   * point or points are either missing or null.
   *
   * @private
   * @function Highcharts.seriesTypes.column#adjustForMissingColumns
   * @param {number} x
   * The x coordinate of the column, left side
   *
   * @param {number} pointWidth
   * The pointWidth, already computed upstream
   *
   * @param {Highcharts.ColumnPoint} point
   * The point instance
   *
   * @param {Highcharts.ColumnMetricsObject} metrics
   * The series-wide column metrics
   *
   * @return {number}
   * The adjusted x position, or the original if not adjusted
   */
  adjustForMissingColumns(x, pointWidth, point, metrics) {
    if (!point.isNull && metrics.columnCount > 1) {
      const visibleSeries = this.xAxis.series.filter((s) => s.visible).map((s) => s.index);
      let indexInCategory = 0, totalInCategory = 0;
      objectEach$i(this.xAxis.stacking?.stacks, (stack) => {
        const points = typeof point.x === "number" ? stack[point.x.toString()]?.points : void 0, pointValues = points?.[this.index], yStackMap = {};
        if (points && isArray$i(pointValues)) {
          let baseIndex = this.index;
          const seriesIndexes = Object.keys(points).filter((pointKey) => (
            // Filter out duplicate X's
            !pointKey.match(",") && // Filter out null points
            points[pointKey] && points[pointKey].length > 1
          )).map(parseFloat).filter((index) => visibleSeries.indexOf(index) !== -1).filter((index) => {
            const otherOptions = this.chart.series[index].options, yStack = otherOptions.stacking && otherOptions.stack;
            if (defined$_(yStack)) {
              if (isNumber$T(yStackMap[yStack])) {
                if (baseIndex === index) {
                  baseIndex = yStackMap[yStack];
                }
                return false;
              }
              yStackMap[yStack] = index;
            }
            return true;
          }).sort((a, b) => b - a);
          indexInCategory = seriesIndexes.indexOf(baseIndex);
          totalInCategory = seriesIndexes.length;
        }
      });
      indexInCategory = this.xAxis.reversed ? totalInCategory - 1 - indexInCategory : indexInCategory;
      const boxWidth = (totalInCategory - 1) * metrics.paddedWidth + pointWidth;
      x = (point.plotX || 0) + boxWidth / 2 - pointWidth - indexInCategory * metrics.paddedWidth;
    }
    return x;
  }
  /**
   * Translate each point to the plot area coordinate system and find
   * shape positions
   *
   * @private
   * @function Highcharts.seriesTypes.column#translate
   */
  translate() {
    const series = this, chart = series.chart, options2 = series.options, dense = series.dense = series.closestPointRange * series.xAxis.transA < 2, borderWidth = series.borderWidth = pick$1u(
      options2.borderWidth,
      dense ? 0 : 1
      // #3635
    ), xAxis2 = series.xAxis, yAxis2 = series.yAxis, threshold = options2.threshold, minPointLength = pick$1u(options2.minPointLength, 5), metrics = series.getColumnMetrics(), seriesPointWidth = metrics.width, seriesXOffset = series.pointXOffset = metrics.offset, dataMin = series.dataMin, dataMax = series.dataMax, translatedThreshold = series.translatedThreshold = yAxis2.getThreshold(threshold);
    let seriesBarW = series.barW = Math.max(seriesPointWidth, 1 + 2 * borderWidth);
    if (options2.pointPadding && options2.crisp) {
      seriesBarW = Math.ceil(seriesBarW);
    }
    Series$9.prototype.translate.apply(series);
    series.points.forEach(function(point) {
      const yBottom = pick$1u(point.yBottom, translatedThreshold), safeDistance = 999 + Math.abs(yBottom), plotX = point.plotX || 0, plotY = clamp$i(point.plotY, -safeDistance, yAxis2.len + safeDistance);
      let up, barY = Math.min(plotY, yBottom), barH = Math.max(plotY, yBottom) - barY, pointWidth = seriesPointWidth, barX = plotX + seriesXOffset, barW = seriesBarW;
      if (minPointLength && Math.abs(barH) < minPointLength) {
        barH = minPointLength;
        up = !yAxis2.reversed && !point.negative || yAxis2.reversed && point.negative;
        if (isNumber$T(threshold) && isNumber$T(dataMax) && point.y === threshold && dataMax <= threshold && // And if there's room for it (#7311)
        (yAxis2.min || 0) < threshold && // If all points are the same value (i.e zero) not draw
        // as negative points (#10646), but only if there's room
        // for it (#14876)
        (dataMin !== dataMax || (yAxis2.max || 0) <= threshold)) {
          up = !up;
          point.negative = !point.negative;
        }
        barY = Math.abs(barY - translatedThreshold) > minPointLength ? (
          // ...keep position
          yBottom - minPointLength
        ) : (
          // #1485, #4051
          translatedThreshold - (up ? minPointLength : 0)
        );
      }
      if (defined$_(point.options.pointWidth)) {
        pointWidth = barW = Math.ceil(point.options.pointWidth);
        barX -= Math.round((pointWidth - seriesPointWidth) / 2);
      }
      if (options2.centerInCategory) {
        barX = series.adjustForMissingColumns(barX, pointWidth, point, metrics);
      }
      point.barX = barX;
      point.pointWidth = pointWidth;
      point.tooltipPos = chart.inverted ? [
        clamp$i(yAxis2.len + yAxis2.pos - chart.plotLeft - plotY, yAxis2.pos - chart.plotLeft, yAxis2.len + yAxis2.pos - chart.plotLeft),
        xAxis2.len + xAxis2.pos - chart.plotTop - barX - barW / 2,
        barH
      ] : [
        xAxis2.left - chart.plotLeft + barX + barW / 2,
        clamp$i(plotY + yAxis2.pos - chart.plotTop, yAxis2.pos - chart.plotTop, yAxis2.len + yAxis2.pos - chart.plotTop),
        barH
      ];
      point.shapeType = series.pointClass.prototype.shapeType || "roundedRect";
      point.shapeArgs = series.crispCol(
        barX,
        // #3169, drilldown from null must have a position to work from.
        // #6585, dataLabel should be placed on xAxis, not floating in
        // the middle of the chart.
        barY,
        barW,
        point.isNull ? 0 : barH
      );
    });
    fireEvent$x(this, "afterColumnTranslate");
  }
  /**
   * Columns have no graph
   *
   * @private
   * @function Highcharts.seriesTypes.column#drawGraph
   */
  drawGraph() {
    this.group[this.dense ? "addClass" : "removeClass"]("highcharts-dense-data");
  }
  /**
   * Get presentational attributes
   *
   * @private
   * @function Highcharts.seriesTypes.column#pointAttribs
   */
  pointAttribs(point, state) {
    const options2 = this.options, p2o = this.pointAttrToOptions || {}, strokeOption = p2o.stroke || "borderColor", strokeWidthOption = p2o["stroke-width"] || "borderWidth";
    let stateOptions, zone, brightness, fill = point && point.color || this.color, stroke = point && point[strokeOption] || options2[strokeOption] || fill, dashstyle = point && point.options.dashStyle || options2.dashStyle, strokeWidth = point && point[strokeWidthOption] || options2[strokeWidthOption] || this[strokeWidthOption] || 0, opacity = point?.isNull && options2.nullInteraction ? 0 : point?.opacity ?? options2.opacity ?? 1;
    if (point && this.zones.length) {
      zone = point.getZone();
      fill = point.options.color || zone && (zone.color || point.nonZonedColor) || this.color;
      if (zone) {
        stroke = zone.borderColor || stroke;
        dashstyle = zone.dashStyle || dashstyle;
        strokeWidth = zone.borderWidth || strokeWidth;
      }
    }
    if (state && point) {
      stateOptions = merge$1n(
        options2.states[state],
        // #6401
        point.options.states && point.options.states[state] || {}
      );
      brightness = stateOptions.brightness;
      fill = stateOptions.color || typeof brightness !== "undefined" && color$a(fill).brighten(stateOptions.brightness).get() || fill;
      stroke = stateOptions[strokeOption] || stroke;
      strokeWidth = stateOptions[strokeWidthOption] || strokeWidth;
      dashstyle = stateOptions.dashStyle || dashstyle;
      opacity = pick$1u(stateOptions.opacity, opacity);
    }
    const ret = {
      fill,
      stroke,
      "stroke-width": strokeWidth,
      opacity
    };
    if (dashstyle) {
      ret.dashstyle = dashstyle;
    }
    return ret;
  }
  /**
   * Draw the columns. For bars, the series.group is rotated, so the same
   * coordinates apply for columns and bars. This method is inherited by
   * scatter series.
   *
   * @private
   * @function Highcharts.seriesTypes.column#drawPoints
   */
  drawPoints(points = this.points) {
    const series = this, chart = this.chart, options2 = series.options, nullInteraction = options2.nullInteraction, renderer = chart.renderer, animationLimit = options2.animationLimit || 250;
    let shapeArgs;
    points.forEach(function(point) {
      const plotY = point.plotY;
      let graphic = point.graphic, hasGraphic = !!graphic, verb = graphic && chart.pointCount < animationLimit ? "animate" : "attr";
      if (isNumber$T(plotY) && (point.y !== null || nullInteraction)) {
        shapeArgs = point.shapeArgs;
        if (graphic && point.hasNewShapeType()) {
          graphic = graphic.destroy();
        }
        if (series.enabledDataSorting) {
          point.startXPos = series.xAxis.reversed ? -(shapeArgs ? shapeArgs.width || 0 : 0) : series.xAxis.width;
        }
        if (!graphic) {
          point.graphic = graphic = renderer[point.shapeType](shapeArgs).add(point.group || series.group);
          if (graphic && series.enabledDataSorting && chart.hasRendered && chart.pointCount < animationLimit) {
            graphic.attr({
              x: point.startXPos
            });
            hasGraphic = true;
            verb = "animate";
          }
        }
        if (graphic && hasGraphic) {
          graphic[verb](merge$1n(shapeArgs));
        }
        if (!chart.styledMode) {
          graphic[verb](series.pointAttribs(point, point.selected && "select")).shadow(point.allowShadow !== false && options2.shadow);
        }
        if (graphic) {
          graphic.addClass(point.getClassName(), true);
          graphic.attr({
            visibility: point.visible ? "inherit" : "hidden"
          });
        }
      } else if (graphic) {
        point.graphic = graphic.destroy();
      }
    });
  }
  /**
   * Draw the tracker for a point.
   * @private
   */
  drawTracker(points = this.points) {
    const series = this, chart = series.chart, pointer = chart.pointer, onMouseOver = function(e) {
      pointer?.normalize(e);
      const point = pointer?.getPointFromEvent(e);
      if (pointer && point && series.options.enableMouseTracking && // Run point events only for points inside plot area, #21136
      (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop, {
        visiblePlotOnly: true
      }) || pointer?.inClass(e.target, "highcharts-data-label"))) {
        pointer.isDirectTouch = true;
        point.onMouseOver(e);
      }
    };
    let dataLabels;
    points.forEach(function(point) {
      dataLabels = isArray$i(point.dataLabels) ? point.dataLabels : point.dataLabel ? [point.dataLabel] : [];
      if (point.graphic) {
        point.graphic.element.point = point;
      }
      dataLabels.forEach(function(dataLabel) {
        (dataLabel.div || dataLabel.element).point = point;
      });
    });
    if (!series._hasTracking) {
      series.trackerGroups.forEach(function(key2) {
        if (series[key2]) {
          series[key2].addClass("highcharts-tracker").on("mouseover", onMouseOver).on("mouseout", function(e) {
            pointer?.onTrackerMouseOut(e);
          }).on("touchstart", onMouseOver);
          if (!chart.styledMode && series.options.cursor) {
            series[key2].css({ cursor: series.options.cursor });
          }
        }
      });
      series._hasTracking = true;
    }
    fireEvent$x(this, "afterDrawTracker");
  }
  /**
   * Remove this series from the chart
   *
   * @private
   * @function Highcharts.seriesTypes.column#remove
   */
  remove() {
    const series = this, chart = series.chart;
    if (chart.hasRendered) {
      chart.series.forEach(function(otherSeries) {
        if (otherSeries.type === series.type) {
          otherSeries.isDirty = true;
        }
      });
    }
    Series$9.prototype.remove.apply(series, arguments);
  }
};
ColumnSeries$f.defaultOptions = merge$1n(Series$9.defaultOptions, ColumnSeriesDefaults);
extend$19(ColumnSeries$f.prototype, {
  // When tooltip is not shared, this series (and derivatives) requires
  // direct touch/hover. KD-tree does not apply.
  directTouch: true,
  getSymbol: noop$i,
  // Use separate negative stacks, unlike area stacks where a negative
  // point is subtracted from previous (#1910)
  negStacks: true,
  trackerGroups: ["group", "dataLabelsGroup"]
});
SeriesRegistry$1.registerSeriesType("column", ColumnSeries$f);
const { getDeferredAnimation: getDeferredAnimation$1 } = animationExports;
const { format: format$b } = Templating;
const { defined: defined$Z, extend: extend$18, fireEvent: fireEvent$w, getAlignFactor: getAlignFactor$3, isArray: isArray$h, isString: isString$9, merge: merge$1m, objectEach: objectEach$h, pick: pick$1t, pInt: pInt$2, splat: splat$g } = Utilities;
var DataLabel;
(function(DataLabel2) {
  function hasDataLabels() {
    return mergedDataLabelOptions(this).some((o) => o?.enabled);
  }
  function alignDataLabel(point, dataLabel, options2, alignTo, isNew) {
    const series = this, { chart, enabledDataSorting } = this, inverted = this.isCartesian && chart.inverted, plotX = point.plotX, plotY = point.plotY, rotation = options2.rotation || 0, isInsidePlot = defined$Z(plotX) && defined$Z(plotY) && chart.isInsidePlot(plotX, Math.round(plotY), {
      inverted,
      paneCoordinates: true,
      series
    }), setStartPos = (alignOptions) => {
      if (enabledDataSorting && series.xAxis && !justify) {
        series.setDataLabelStartPos(point, dataLabel, isNew, isInsidePlot, alignOptions);
      }
    }, justify = rotation === 0 ? pick$1t(options2.overflow, enabledDataSorting ? "none" : "justify") === "justify" : false;
    let visible = this.visible && point.visible !== false && defined$Z(plotX) && (point.series.forceDL || enabledDataSorting && !justify || isInsidePlot || // If the data label is inside the align box, it is enough
    // that parts of the align box is inside the plot area
    // (#12370). When stacking, it is always inside regardless
    // of the option (#15148).
    pick$1t(options2.inside, !!this.options.stacking) && alignTo && chart.isInsidePlot(plotX, inverted ? alignTo.x + 1 : alignTo.y + alignTo.height - 1, {
      inverted,
      paneCoordinates: true,
      series
    }));
    const pos = point.pos();
    if (visible && pos) {
      const bBox = dataLabel.getBBox(), unrotatedbBox = dataLabel.getBBox(void 0, 0);
      alignTo = extend$18({
        x: pos[0],
        y: Math.round(pos[1]),
        width: 0,
        height: 0
      }, alignTo || {});
      if (options2.alignTo === "plotEdges" && series.isCartesian) {
        alignTo[inverted ? "x" : "y"] = 0;
        alignTo[inverted ? "width" : "height"] = this.yAxis?.len || 0;
      }
      extend$18(options2, {
        width: bBox.width,
        height: bBox.height
      });
      setStartPos(alignTo);
      dataLabel.align(merge$1m(options2, {
        width: unrotatedbBox.width,
        height: unrotatedbBox.height
      }), false, alignTo, false);
      dataLabel.alignAttr.x += getAlignFactor$3(options2.align) * (unrotatedbBox.width - bBox.width);
      dataLabel.alignAttr.y += getAlignFactor$3(options2.verticalAlign) * (unrotatedbBox.height - bBox.height);
      dataLabel[dataLabel.placed ? "animate" : "attr"]({
        "text-align": dataLabel.alignAttr["text-align"] || "center",
        x: dataLabel.alignAttr.x + (bBox.width - unrotatedbBox.width) / 2,
        y: dataLabel.alignAttr.y + (bBox.height - unrotatedbBox.height) / 2,
        rotationOriginX: (dataLabel.width || 0) / 2,
        rotationOriginY: (dataLabel.height || 0) / 2
      });
      if (justify && alignTo.height >= 0) {
        this.justifyDataLabel(dataLabel, options2, dataLabel.alignAttr, bBox, alignTo, isNew);
      } else if (pick$1t(options2.crop, true)) {
        const { x, y } = dataLabel.alignAttr, correction = 1;
        visible = chart.isInsidePlot(x, y, {
          paneCoordinates: true,
          series
        }) && chart.isInsidePlot(x + bBox.width - correction, y + bBox.height - correction, {
          paneCoordinates: true,
          series
        });
      }
      if (options2.shape && !rotation) {
        dataLabel[isNew ? "attr" : "animate"]({
          anchorX: pos[0],
          anchorY: pos[1]
        });
      }
    }
    if (isNew && enabledDataSorting) {
      dataLabel.placed = false;
    }
    if (!visible && (!enabledDataSorting || justify)) {
      dataLabel.hide();
      dataLabel.placed = false;
    } else {
      dataLabel.show();
      dataLabel.placed = true;
    }
  }
  function applyFilter(point, options2) {
    const filter = options2.filter;
    if (filter) {
      const op = filter.operator, prop = point[filter.property], val = filter.value;
      if (op === ">" && prop > val || op === "<" && prop < val || op === ">=" && prop >= val || op === "<=" && prop <= val || op === "==" && prop == val || // eslint-disable-line eqeqeq
      op === "===" && prop === val || op === "!=" && prop != val || // eslint-disable-line eqeqeq
      op === "!==" && prop !== val) {
        return true;
      }
      return false;
    }
    return true;
  }
  function compose2(SeriesClass) {
    const seriesProto2 = SeriesClass.prototype;
    if (!seriesProto2.initDataLabels) {
      seriesProto2.initDataLabels = initDataLabels2;
      seriesProto2.initDataLabelsGroup = initDataLabelsGroup;
      seriesProto2.alignDataLabel = alignDataLabel;
      seriesProto2.drawDataLabels = drawDataLabels;
      seriesProto2.justifyDataLabel = justifyDataLabel;
      seriesProto2.mergeArrays = mergeArrays;
      seriesProto2.setDataLabelStartPos = setDataLabelStartPos;
      seriesProto2.hasDataLabels = hasDataLabels;
    }
  }
  DataLabel2.compose = compose2;
  function initDataLabelsGroup() {
    return this.plotGroup(
      "dataLabelsGroup",
      "data-labels",
      this.hasRendered ? "inherit" : "hidden",
      // #5133, #10220
      this.options.dataLabels.zIndex || 6
    );
  }
  function initDataLabels2(animationConfig) {
    const series = this, hasRendered = series.hasRendered || 0;
    const dataLabelsGroup = this.initDataLabelsGroup().attr({ opacity: +hasRendered });
    if (!hasRendered && dataLabelsGroup) {
      if (series.visible) {
        dataLabelsGroup.show();
      }
      if (series.options.animation) {
        dataLabelsGroup.animate({ opacity: 1 }, animationConfig);
      } else {
        dataLabelsGroup.attr({ opacity: 1 });
      }
    }
    return dataLabelsGroup;
  }
  function drawDataLabels(points) {
    points = points || this.points;
    const series = this, chart = series.chart, seriesOptions = series.options, renderer = chart.renderer, { backgroundColor, plotBackgroundColor } = chart.options.chart, contrastColor = renderer.getContrast(
      isString$9(plotBackgroundColor) && plotBackgroundColor || isString$9(backgroundColor) && backgroundColor || "#000000"
      /* Palette.neutralColor100 */
    ), seriesDlOptions = mergedDataLabelOptions(series);
    let pointOptions, dataLabelsGroup;
    const { animation, defer } = seriesDlOptions[0], animationConfig = defer ? getDeferredAnimation$1(chart, animation, series) : { defer: 0, duration: 0 };
    fireEvent$w(this, "drawDataLabels");
    if (series.hasDataLabels?.()) {
      dataLabelsGroup = this.initDataLabels(animationConfig);
      points.forEach((point) => {
        const dataLabels = point.dataLabels || [], pointColor = point.color || series.color;
        pointOptions = splat$g(mergeArrays(
          seriesDlOptions,
          // The dlOptions prop is used in treemaps
          point.dlOptions || point.options?.dataLabels
        ));
        pointOptions.forEach((labelOptions, i) => {
          const labelEnabled = labelOptions.enabled && (point.visible || point.dataLabelOnHidden) && // #2282, #4641, #7112, #10049
          (!point.isNull || point.dataLabelOnNull) && applyFilter(point, labelOptions), { backgroundColor: backgroundColor2, borderColor, distance, style = {} } = labelOptions;
          let formatString, labelText, rotation, attr2 = {}, dataLabel = dataLabels[i], isNew = !dataLabel, labelBgColor;
          if (labelEnabled) {
            formatString = pick$1t(labelOptions[point.formatPrefix + "Format"], labelOptions.format);
            labelText = defined$Z(formatString) ? format$b(formatString, point, chart) : (labelOptions[point.formatPrefix + "Formatter"] || labelOptions.formatter).call(point, labelOptions);
            rotation = labelOptions.rotation;
            if (!chart.styledMode) {
              style.color = pick$1t(
                labelOptions.color,
                style.color,
                isString$9(series.color) ? series.color : void 0,
                "#000000"
                /* Palette.neutralColor100 */
              );
              if (style.color === "contrast") {
                if (backgroundColor2 !== "none") {
                  labelBgColor = backgroundColor2;
                }
                point.contrastColor = renderer.getContrast(labelBgColor !== "auto" && isString$9(labelBgColor) && labelBgColor || (isString$9(pointColor) ? pointColor : ""));
                style.color = labelBgColor || // #20007
                !defined$Z(distance) && labelOptions.inside || pInt$2(distance || 0) < 0 || seriesOptions.stacking ? point.contrastColor : contrastColor;
              } else {
                delete point.contrastColor;
              }
              if (seriesOptions.cursor) {
                style.cursor = seriesOptions.cursor;
              }
            }
            attr2 = {
              r: labelOptions.borderRadius || 0,
              rotation,
              padding: labelOptions.padding,
              zIndex: 1
            };
            if (!chart.styledMode) {
              attr2.fill = backgroundColor2 === "auto" ? point.color : backgroundColor2;
              attr2.stroke = borderColor === "auto" ? point.color : borderColor;
              attr2["stroke-width"] = labelOptions.borderWidth;
            }
            objectEach$h(attr2, (val, name) => {
              if (typeof val === "undefined") {
                delete attr2[name];
              }
            });
          }
          if (dataLabel && (!labelEnabled || !defined$Z(labelText) || // Changed useHTML value
          !!(dataLabel.div || dataLabel.text?.foreignObject) !== !!labelOptions.useHTML || // Change from no rotation to rotation and
          // vice versa. Don't use defined() because
          // rotation = 0 means also rotation = undefined
          (!dataLabel.rotation || !labelOptions.rotation) && dataLabel.rotation !== labelOptions.rotation)) {
            dataLabel = void 0;
            isNew = true;
          }
          if (labelEnabled && defined$Z(labelText)) {
            if (!dataLabel) {
              dataLabel = renderer.label(labelText, 0, 0, labelOptions.shape, void 0, void 0, labelOptions.useHTML, void 0, "data-label");
              dataLabel.addClass(" highcharts-data-label-color-" + point.colorIndex + " " + (labelOptions.className || "") + // #3398
              (labelOptions.useHTML ? " highcharts-tracker" : ""));
            } else {
              attr2.text = labelText;
            }
            if (dataLabel) {
              dataLabel.options = labelOptions;
              dataLabel.attr(attr2);
              if (!chart.styledMode) {
                dataLabel.css(style).shadow(labelOptions.shadow);
              } else if (style.width) {
                dataLabel.css({
                  width: style.width,
                  textOverflow: style.textOverflow,
                  whiteSpace: style.whiteSpace
                });
              }
              fireEvent$w(dataLabel, "beforeAddingDataLabel", { labelOptions, point });
              if (!dataLabel.added) {
                dataLabel.add(dataLabelsGroup);
              }
              series.alignDataLabel(point, dataLabel, labelOptions, void 0, isNew);
              dataLabel.isActive = true;
              if (dataLabels[i] && dataLabels[i] !== dataLabel) {
                dataLabels[i].destroy();
              }
              dataLabels[i] = dataLabel;
            }
          }
        });
        let j = dataLabels.length;
        while (j--) {
          if (!dataLabels[j]?.isActive) {
            dataLabels[j]?.destroy();
            dataLabels.splice(j, 1);
          } else {
            dataLabels[j].isActive = false;
          }
        }
        point.dataLabel = dataLabels[0];
        point.dataLabels = dataLabels;
      });
    }
    fireEvent$w(this, "afterDrawDataLabels");
  }
  function justifyDataLabel(dataLabel, options2, alignAttr, bBox, alignTo, isNew) {
    const chart = this.chart, align = options2.align, verticalAlign = options2.verticalAlign, padding = dataLabel.box ? 0 : dataLabel.padding || 0, horizontalAxis = chart.inverted ? this.yAxis : this.xAxis, horizontalAxisShift = horizontalAxis ? horizontalAxis.left - chart.plotLeft : 0, verticalAxis = chart.inverted ? this.xAxis : this.yAxis, verticalAxisShift = verticalAxis ? verticalAxis.top - chart.plotTop : 0;
    let { x = 0, y = 0 } = options2, off, justified;
    off = (alignAttr.x || 0) + padding + horizontalAxisShift;
    if (off < 0) {
      if (align === "right" && x >= 0) {
        options2.align = "left";
        options2.inside = true;
      } else {
        x -= off;
      }
      justified = true;
    }
    off = (alignAttr.x || 0) + bBox.width - padding + horizontalAxisShift;
    if (off > chart.plotWidth) {
      if (align === "left" && x <= 0) {
        options2.align = "right";
        options2.inside = true;
      } else {
        x += chart.plotWidth - off;
      }
      justified = true;
    }
    off = alignAttr.y + padding + verticalAxisShift;
    if (off < 0) {
      if (verticalAlign === "bottom" && y >= 0) {
        options2.verticalAlign = "top";
        options2.inside = true;
      } else {
        y -= off;
      }
      justified = true;
    }
    off = (alignAttr.y || 0) + bBox.height - padding + verticalAxisShift;
    if (off > chart.plotHeight) {
      if (verticalAlign === "top" && y <= 0) {
        options2.verticalAlign = "bottom";
        options2.inside = true;
      } else {
        y += chart.plotHeight - off;
      }
      justified = true;
    }
    if (justified) {
      options2.x = x;
      options2.y = y;
      dataLabel.placed = !isNew;
      dataLabel.align(options2, void 0, alignTo);
    }
    return justified;
  }
  function mergeArrays(one, two) {
    let res = [], i;
    if (isArray$h(one) && !isArray$h(two)) {
      res = one.map(function(el) {
        return merge$1m(el, two);
      });
    } else if (isArray$h(two) && !isArray$h(one)) {
      res = two.map(function(el) {
        return merge$1m(one, el);
      });
    } else if (!isArray$h(one) && !isArray$h(two)) {
      res = merge$1m(one, two);
    } else if (isArray$h(one) && isArray$h(two)) {
      i = Math.max(one.length, two.length);
      while (i--) {
        res[i] = merge$1m(one[i], two[i]);
      }
    }
    return res;
  }
  function mergedDataLabelOptions(series) {
    const plotOptions = series.chart.options.plotOptions;
    return splat$g(mergeArrays(mergeArrays(plotOptions?.series?.dataLabels, plotOptions?.[series.type]?.dataLabels), series.options.dataLabels));
  }
  function setDataLabelStartPos(point, dataLabel, isNew, isInside, alignOptions) {
    const chart = this.chart, inverted = chart.inverted, xAxis2 = this.xAxis, reversed = xAxis2.reversed, labelCenter = ((inverted ? dataLabel.height : dataLabel.width) || 0) / 2, pointWidth = point.pointWidth, halfWidth = pointWidth ? pointWidth / 2 : 0;
    dataLabel.startXPos = inverted ? alignOptions.x : reversed ? -labelCenter - halfWidth : xAxis2.width - labelCenter + halfWidth;
    dataLabel.startYPos = inverted ? reversed ? this.yAxis.height - labelCenter + halfWidth : -labelCenter - halfWidth : alignOptions.y;
    if (!isInside) {
      dataLabel.attr({ opacity: 1 }).animate({ opacity: 0 }, void 0, dataLabel.hide);
    } else if (dataLabel.visibility === "hidden") {
      dataLabel.show();
      dataLabel.attr({ opacity: 0 }).animate({ opacity: 1 });
    }
    if (!chart.hasRendered) {
      return;
    }
    if (isNew) {
      dataLabel.attr({ x: dataLabel.startXPos, y: dataLabel.startYPos });
    }
    dataLabel.placed = true;
  }
})(DataLabel || (DataLabel = {}));
const DataLabel$1 = DataLabel;
const { composed: composed$t } = Highcharts;
const { series: Series$7 } = SeriesRegistry$1;
const { merge: merge$1l, pushUnique: pushUnique$t } = Utilities;
var ColumnDataLabel$1;
(function(ColumnDataLabel2) {
  function alignDataLabel(point, dataLabel, dlOptions, alignTo, isNew) {
    const { chart, options: options2 } = this, inverted = chart.inverted, xLen = this.xAxis?.len || chart.plotSizeX || 0, yLen = this.yAxis?.len || chart.plotSizeY || 0, dlBox = point.dlBox || point.shapeArgs, below = point.below ?? // Range series
    (point.plotY || 0) > (this.translatedThreshold ?? yLen), inside = dlOptions.inside ?? !!options2.stacking;
    if (dlBox) {
      alignTo = merge$1l(dlBox);
      if (dlOptions.overflow !== "allow" || dlOptions.crop !== false || options2.clip !== false) {
        if (alignTo.y < 0) {
          alignTo.height += alignTo.y;
          alignTo.y = 0;
        }
        const overshoot = alignTo.y + alignTo.height - yLen;
        if (overshoot > 0 && overshoot < alignTo.height - 1) {
          alignTo.height -= overshoot;
        }
      }
      if (inverted) {
        alignTo = {
          x: yLen - alignTo.y - alignTo.height,
          y: xLen - alignTo.x - alignTo.width,
          width: alignTo.height,
          height: alignTo.width
        };
      }
      if (!inside) {
        if (inverted) {
          alignTo.x += below ? 0 : alignTo.width;
          alignTo.width = 0;
        } else {
          alignTo.y += below ? alignTo.height : 0;
          alignTo.height = 0;
        }
      }
    }
    dlOptions.align ?? (dlOptions.align = !inverted || inside ? "center" : below ? "right" : "left");
    dlOptions.verticalAlign ?? (dlOptions.verticalAlign = inverted || inside ? "middle" : below ? "top" : "bottom");
    Series$7.prototype.alignDataLabel.call(this, point, dataLabel, dlOptions, alignTo, isNew);
    if (dlOptions.inside && point.contrastColor) {
      dataLabel.css({
        color: point.contrastColor
      });
    }
  }
  function compose2(ColumnSeriesClass) {
    DataLabel$1.compose(Series$7);
    if (pushUnique$t(composed$t, "ColumnDataLabel")) {
      ColumnSeriesClass.prototype.alignDataLabel = alignDataLabel;
    }
  }
  ColumnDataLabel2.compose = compose2;
})(ColumnDataLabel$1 || (ColumnDataLabel$1 = {}));
const ColumnDataLabel$2 = ColumnDataLabel$1;
const { extend: extend$17, merge: merge$1k } = Utilities;
class BarSeries extends ColumnSeries$f {
}
BarSeries.defaultOptions = merge$1k(ColumnSeries$f.defaultOptions, {
  // Nothing here yet
});
extend$17(BarSeries.prototype, {
  inverted: true
});
SeriesRegistry$1.registerSeriesType("bar", BarSeries);
const ScatterSeriesDefaults = {
  /**
   * The width of the line connecting the data points.
   *
   * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-none/
   *         0 by default
   * @sample {highcharts} highcharts/plotoptions/scatter-linewidth-1/
   *         1px
   *
   * @product highcharts highstock
   */
  lineWidth: 0,
  findNearestPointBy: "xy",
  /**
   * Apply a jitter effect for the rendered markers. When plotting
   * discrete values, a little random noise may help telling the points
   * apart. The jitter setting applies a random displacement of up to `n`
   * axis units in either direction. So for example on a horizontal X
   * axis, setting the `jitter.x` to 0.24 will render the point in a
   * random position between 0.24 units to the left and 0.24 units to the
   * right of the true axis position. On a category axis, setting it to
   * 0.5 will fill up the bin and make the data appear continuous.
   *
   * When rendered on top of a box plot or a column series, a jitter value
   * of 0.24 will correspond to the underlying series' default
   * [groupPadding](
   * https://api.highcharts.com/highcharts/plotOptions.column.groupPadding)
   * and [pointPadding](
   * https://api.highcharts.com/highcharts/plotOptions.column.pointPadding)
   * settings.
   *
   * **Note:** With boost mode enabled, the jitter effect is not supported.
   *
   * @sample {highcharts} highcharts/demo/scatter-jitter
   *         Jitter on a scatter plot
   *
   * @sample {highcharts} highcharts/series-scatter/jitter-boxplot
   *         Jittered scatter plot on top of a box plot
   *
   * @product highcharts highstock
   * @since 7.0.2
   */
  jitter: {
    /**
     * The maximal X offset for the random jitter effect.
     */
    x: 0,
    /**
     * The maximal Y offset for the random jitter effect.
     */
    y: 0
  },
  marker: {
    enabled: true
    // Overrides auto-enabling in line series (#3647)
  },
  /**
   * Sticky tracking of mouse events. When true, the `mouseOut` event
   * on a series isn't triggered until the mouse moves over another
   * series, or out of the plot area. When false, the `mouseOut` event on
   * a series is triggered when the mouse leaves the area around the
   * series' graph or markers. This also implies the tooltip. When
   * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
   * will be hidden when moving the mouse between series.
   *
   * @type      {boolean}
   * @default   false
   * @product   highcharts highstock highmaps
   * @apioption plotOptions.scatter.stickyTracking
   */
  /**
   * A configuration object for the tooltip rendering of each single
   * series. Properties are inherited from [tooltip](#tooltip).
   * Overridable properties are `headerFormat`, `pointFormat`,
   * `yDecimals`, `xDateFormat`, `yPrefix` and `ySuffix`. Unlike other
   * series, in a scatter plot the series.name by default shows in the
   * headerFormat and point.x and point.y in the pointFormat.
   *
   * @product highcharts highstock highmaps
   */
  tooltip: {
    /**
     * @product highcharts highstock
     */
    headerFormat: '<span style="color:{point.color}">●</span> <span style="font-size: 0.8em"> {series.name}</span><br/>',
    pointFormat: "x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>"
  }
};
const { column: ColumnSeries$e, line: LineSeries$4 } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$1i, extend: extend$16, merge: merge$1j } = Utilities;
let ScatterSeries$4 = class ScatterSeries2 extends LineSeries$4 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Optionally add the jitter effect.
   * @private
   */
  applyJitter() {
    const series = this, jitter = this.options.jitter, len = this.points.length;
    function unrandom(seed) {
      const rand = Math.sin(seed) * 1e4;
      return rand - Math.floor(rand);
    }
    if (jitter) {
      this.points.forEach(function(point, i) {
        ["x", "y"].forEach(function(dim, j) {
          if (jitter[dim] && !point.isNull) {
            const plotProp = `plot${dim.toUpperCase()}`, axis = series[`${dim}Axis`], translatedJitter = jitter[dim] * axis.transA;
            if (axis && !axis.logarithmic) {
              const min2 = Math.max(0, (point[plotProp] || 0) - translatedJitter), max2 = Math.min(axis.len, (point[plotProp] || 0) + translatedJitter);
              point[plotProp] = min2 + (max2 - min2) * unrandom(i + j * len);
              if (dim === "x") {
                point.clientX = point.plotX;
              }
            }
          }
        });
      });
    }
  }
  /**
   * @private
   */
  drawGraph() {
    if (this.options.lineWidth) {
      super.drawGraph();
    } else if (this.graph) {
      this.graph = this.graph.destroy();
    }
  }
};
ScatterSeries$4.defaultOptions = merge$1j(LineSeries$4.defaultOptions, ScatterSeriesDefaults);
extend$16(ScatterSeries$4.prototype, {
  drawTracker: ColumnSeries$e.prototype.drawTracker,
  sorted: false,
  requireSorting: false,
  noSharedTooltip: true,
  trackerGroups: ["group", "markerGroup", "dataLabelsGroup"]
});
addEvent$1i(ScatterSeries$4, "afterTranslate", function() {
  this.applyJitter();
});
SeriesRegistry$1.registerSeriesType("scatter", ScatterSeries$4);
const { deg2rad: deg2rad$6 } = Highcharts;
const { fireEvent: fireEvent$v, isNumber: isNumber$S, pick: pick$1s, relativeLength: relativeLength$e } = Utilities;
var CenteredUtilities;
(function(CenteredUtilities2) {
  function getCenter2() {
    const options2 = this.options, chart = this.chart, slicingRoom = 2 * (options2.slicedOffset || 0), plotWidth = chart.plotWidth - 2 * slicingRoom, plotHeight = chart.plotHeight - 2 * slicingRoom, centerOption = options2.center, smallestSize = Math.min(plotWidth, plotHeight), thickness = options2.thickness;
    let handleSlicingRoom, size = options2.size, innerSize = options2.innerSize || 0, i, value;
    if (typeof size === "string") {
      size = parseFloat(size);
    }
    if (typeof innerSize === "string") {
      innerSize = parseFloat(innerSize);
    }
    const positions = [
      pick$1s(centerOption?.[0], "50%"),
      pick$1s(centerOption?.[1], "50%"),
      // Prevent from negative values
      pick$1s(size && size < 0 ? void 0 : options2.size, "100%"),
      pick$1s(innerSize && innerSize < 0 ? void 0 : options2.innerSize || 0, "0%")
    ];
    if (chart.angular && !(this instanceof Series$9)) {
      positions[3] = 0;
    }
    for (i = 0; i < 4; ++i) {
      value = positions[i];
      handleSlicingRoom = i < 2 || i === 2 && /%$/.test(value);
      positions[i] = relativeLength$e(value, [plotWidth, plotHeight, smallestSize, positions[2]][i]) + (handleSlicingRoom ? slicingRoom : 0);
    }
    if (positions[3] > positions[2]) {
      positions[3] = positions[2];
    }
    if (isNumber$S(thickness) && thickness * 2 < positions[2] && thickness > 0) {
      positions[3] = positions[2] - thickness * 2;
    }
    fireEvent$v(this, "afterGetCenter", { positions });
    return positions;
  }
  CenteredUtilities2.getCenter = getCenter2;
  function getStartAndEndRadians2(start2, end) {
    const startAngle = isNumber$S(start2) ? start2 : 0, endAngle = isNumber$S(end) && // Must be a number
    end > startAngle && // Must be larger than the start angle
    // difference must be less than 360 degrees
    end - startAngle < 360 ? end : startAngle + 360, correction = -90;
    return {
      start: deg2rad$6 * (startAngle + correction),
      end: deg2rad$6 * (endAngle + correction)
    };
  }
  CenteredUtilities2.getStartAndEndRadians = getStartAndEndRadians2;
})(CenteredUtilities || (CenteredUtilities = {}));
const CU = CenteredUtilities;
const { setAnimation: setAnimation$1 } = animationExports;
const { addEvent: addEvent$1h, defined: defined$Y, extend: extend$15, isNumber: isNumber$R, pick: pick$1r, relativeLength: relativeLength$d } = Utilities;
let PiePoint$3 = class PiePoint2 extends Point$3 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Extendable method for getting the path of the connector between the
   * data label and the pie slice.
   * @private
   */
  getConnectorPath(dataLabel) {
    const labelPosition = dataLabel.dataLabelPosition, options2 = dataLabel.options || {}, connectorShape = options2.connectorShape, shapeFunc = this.connectorShapes[connectorShape] || connectorShape;
    return labelPosition && shapeFunc.call(this, {
      // Pass simplified label position object for user's convenience
      ...labelPosition.computed,
      alignment: labelPosition.alignment
    }, labelPosition.connectorPosition, options2) || [];
  }
  /**
   * @private
   */
  getTranslate() {
    return this.sliced && this.slicedTranslation || {
      translateX: 0,
      translateY: 0
    };
  }
  /**
   * @private
   */
  haloPath(size) {
    const shapeArgs = this.shapeArgs;
    return this.sliced || !this.visible ? [] : this.series.chart.renderer.symbols.arc(shapeArgs.x, shapeArgs.y, shapeArgs.r + size, shapeArgs.r + size, {
      // Substract 1px to ensure the background is not bleeding
      // through between the halo and the slice (#7495).
      innerR: shapeArgs.r - 1,
      start: shapeArgs.start,
      end: shapeArgs.end,
      borderRadius: shapeArgs.borderRadius
    });
  }
  /**
   * Initialize the pie slice.
   * @private
   */
  constructor(series, options2, x) {
    super(series, options2, x);
    this.half = 0;
    this.name ?? (this.name = series.chart.options.lang.pieSliceName);
    const toggleSlice = (e) => {
      this.slice(e.type === "select");
    };
    addEvent$1h(this, "select", toggleSlice);
    addEvent$1h(this, "unselect", toggleSlice);
  }
  /**
   * Negative points are not valid (#1530, #3623, #5322)
   * @private
   */
  isValid() {
    return isNumber$R(this.y) && this.y >= 0;
  }
  /**
   * Toggle the visibility of a pie slice or other data point. Note that this
   * method is available only for some series, like pie, treemap and sunburst.
   *
   * @function Highcharts.Point#setVisible
   *
   * @param {boolean} [vis]
   * True to show the pie slice or other data point, false to hide. If
   * undefined, the visibility is toggled.
   *
   * @param {boolean} [redraw] Whether to redraw the chart after the point is
   * altered. If doing more operations on the chart, it is a good idea to set
   * redraw to false and call {@link Chart#redraw|chart.redraw()} after.
   *
   */
  setVisible(vis, redraw = true) {
    if (vis !== this.visible) {
      this.update({
        visible: vis ?? !this.visible
      }, redraw, void 0, false);
    }
  }
  /**
   * Set or toggle whether the slice is cut out from the pie.
   * @private
   *
   * @param {boolean} sliced
   * When undefined, the slice state is toggled.
   *
   * @param {boolean} [redraw]
   * Whether to redraw the chart. True by default.
   *
   * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
   * Animation options.
   */
  slice(sliced, redraw, animation) {
    const series = this.series, chart = series.chart;
    setAnimation$1(animation, chart);
    redraw = pick$1r(redraw, true);
    this.sliced = this.options.sliced = sliced = defined$Y(sliced) ? sliced : !this.sliced;
    series.options.data[series.data.indexOf(this)] = this.options;
    if (this.graphic) {
      this.graphic.animate(this.getTranslate());
    }
  }
};
extend$15(PiePoint$3.prototype, {
  connectorShapes: {
    // Only one available before v7.0.0
    fixedOffset: function(labelPosition, connectorPosition, options2) {
      const breakAt = connectorPosition.breakAt, touchingSliceAt = connectorPosition.touchingSliceAt, lineSegment = options2.softConnector ? [
        "C",
        // Soft break
        // 1st control point (of the curve)
        labelPosition.x + // 5 gives the connector a little horizontal bend
        (labelPosition.alignment === "left" ? -5 : 5),
        labelPosition.y,
        //
        2 * breakAt.x - touchingSliceAt.x,
        // 2nd control point
        2 * breakAt.y - touchingSliceAt.y,
        //
        breakAt.x,
        // End of the curve
        breakAt.y
        //
      ] : [
        "L",
        // Pointy break
        breakAt.x,
        breakAt.y
      ];
      return [
        ["M", labelPosition.x, labelPosition.y],
        lineSegment,
        ["L", touchingSliceAt.x, touchingSliceAt.y]
      ];
    },
    straight: function(labelPosition, connectorPosition) {
      const touchingSliceAt = connectorPosition.touchingSliceAt;
      return [
        ["M", labelPosition.x, labelPosition.y],
        ["L", touchingSliceAt.x, touchingSliceAt.y]
      ];
    },
    crookedLine: function(labelPosition, connectorPosition, options2) {
      const { angle = this.angle || 0, breakAt, touchingSliceAt } = connectorPosition, { series } = this, [cx, cy, diameter] = series.center, r = diameter / 2, { plotLeft, plotWidth } = series.chart, leftAligned = labelPosition.alignment === "left", { x, y } = labelPosition;
      let crookX = breakAt.x;
      if (options2.crookDistance) {
        const crookDistance = relativeLength$d(
          // % to fraction
          options2.crookDistance,
          1
        );
        crookX = leftAligned ? cx + r + (plotWidth + plotLeft - cx - r) * (1 - crookDistance) : plotLeft + (cx - r) * crookDistance;
      } else {
        crookX = cx + (cy - y) * Math.tan(angle - Math.PI / 2);
      }
      const path = [["M", x, y]];
      if (leftAligned ? crookX <= x && crookX >= breakAt.x : crookX >= x && crookX <= breakAt.x) {
        path.push(["L", crookX, y]);
      }
      path.push(["L", breakAt.x, breakAt.y], ["L", touchingSliceAt.x, touchingSliceAt.y]);
      return path;
    }
  }
});
const PieSeriesDefaults = {
  /**
   * The corner radius of the border surrounding each slice. A number
   * signifies pixels. A percentage string, like for example `50%`, signifies
   * a size relative to the radius and the inner radius.
   *
   * @sample  highcharts/plotoptions/series-border-radius
   *          Column and pie with rounded border
   *
   * @since   11.0.0
   *
   * @type      {number|string|Highcharts.BorderRadiusOptionsObject}
   */
  borderRadius: 3,
  /**
   * @excluding legendItemClick
   * @apioption plotOptions.pie.events
   */
  /**
   * Fires when the checkbox next to the point name in the legend is
   * clicked. One parameter, event, is passed to the function. The state
   * of the checkbox is found by event.checked. The checked item is found
   * by event.item. Return false to prevent the default action which is to
   * toggle the select state of the series.
   *
   * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
   *         Alert checkbox status
   *
   * @type      {Function}
   * @since     1.2.0
   * @product   highcharts highmaps
   * @context   Highcharts.Point
   * @apioption plotOptions.pie.events.checkboxClick
   */
  /**
   * Fires when the legend item belonging to the pie point (slice) is
   * clicked. The `this` keyword refers to the point itself. One
   * parameter, `event`, is passed to the function, containing common
   * event information. The default action is to toggle the visibility of
   * the point. This can be prevented by calling `event.preventDefault()`.
   *
   *  **Note:** This option is deprecated in favor of
   * [legend.events.itemClick](#legend.events.itemClick).
   *
   * @deprecated 11.4.4
   * @type       {Highcharts.PointLegendItemClickCallbackFunction}
   * @since      1.2.0
   * @product    highcharts highmaps
   * @apioption  plotOptions.pie.point.events.legendItemClick
   */
  /**
   * The center of the pie chart relative to the plot area. Can be
   * percentages or pixel values. The default behaviour (as of 3.0) is to
   * center the pie so that all slices and data labels are within the plot
   * area. As a consequence, the pie may actually jump around in a chart
   * with dynamic values, as the data labels move. In that case, the
   * center should be explicitly set, for example to `["50%", "50%"]`.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-center/
   *         Centered at 100, 100
   *
   * @type    {Array<(number|string|null),(number|string|null)>}
   * @default [null, null]
   * @product highcharts highmaps
   *
   * @private
   */
  center: [null, null],
  /**
   * The color of the pie series. A pie series is represented as an empty
   * circle if the total sum of its values is 0. Use this property to
   * define the color of its border.
   *
   * In styled mode, the color can be defined by the
   * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
   * color can be set with the `.highcharts-series`,
   * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
   * `.highcharts-series-{n}` class, or individual classes given by the
   * `className` option.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
   *         Empty pie series
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default   ${palette.neutralColor20}
   * @apioption plotOptions.pie.color
   */
  /**
   * @product highcharts
   *
   * @private
   */
  clip: false,
  /**
   * @ignore-option
   *
   * @private
   */
  colorByPoint: true,
  // Always true for pies
  /**
   * A series specific or series type specific color set to use instead
   * of the global [colors](#colors).
   *
   * @sample {highcharts} highcharts/demo/pie-monochrome/
   *         Set default colors for all pies
   *
   * @type      {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
   * @since     3.0
   * @product   highcharts highmaps
   * @apioption plotOptions.pie.colors
   */
  /**
   * @declare   Highcharts.SeriesPieDataLabelsOptionsObject
   * @extends   plotOptions.series.dataLabels
   * @excluding align, allowOverlap, inside, staggerLines, step
   * @private
   */
  dataLabels: {
    /**
     * Alignment method for data labels. Possible values are:
     *
     * - `plotEdges`: Each label touches the nearest vertical edge of
     *   the plot area.
     *
     * - `connectors`: Connectors have the same x position and the
     *   widest label of each half (left & right) touches the nearest
     *   vertical edge of the plot area.
     *
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-connectors/
     *         alignTo: connectors
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-alignto-plotedges/
     *         alignTo: plotEdges
     *
     * @type      {string}
     * @since     7.0.0
     * @product   highcharts highmaps
     * @apioption plotOptions.pie.dataLabels.alignTo
     */
    /**
     * The color of the line connecting the data label to the pie slice.
     * The default color is the same as the point's color.
     *
     * In styled mode, the connector stroke is given in the
     * `.highcharts-data-label-connector` class.
     *
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorcolor/
     *         Blue connectors
     * @sample {highcharts} highcharts/css/pie-point/
     *         Styled connectors
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     2.1
     * @product   highcharts highmaps
     * @apioption plotOptions.pie.dataLabels.connectorColor
     */
    /**
     * The distance from the data label to the connector. Note that
     * data labels also have a default `padding`, so in order for the
     * connector to touch the text, the `padding` must also be 0.
     *
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorpadding/
     *         No padding
     *
     * @since   2.1
     * @product highcharts highmaps
     */
    connectorPadding: 5,
    /**
     * Specifies the method that is used to generate the connector path.
     * Highcharts provides 3 built-in connector shapes: `'crookedLine'`
     * (default since v11), `'fixedOffset'` and `'straight'`.
     *
     * Users can provide their own method by passing a function instead of a
     * string. Three arguments are passed to the callback:
     *
     * - An object that holds the information about the coordinates of the
     *   label (`x` & `y` properties) and how the label is located in
     *   relation to the pie (`alignment` property). `alignment` can by one
     *   of the following: `'left'` (pie on the left side of the data
     *   label), `'right'` (pie on the right side of the data label) or
     *   `'center'` (data label overlaps the pie).
     *
     * - An object that holds the information about the position of the
     *   connector. Its `touchingSliceAt`  porperty tells the position of
     *   the place where the connector touches the slice.
     *
     * - Data label options
     *
     * The function has to return an SVG path definition in array form (see
     * the example).
     *
     * @sample {highcharts}
     *         highcharts/plotoptions/pie-datalabels-connectorshape-string/
     *         connectorShape is a String
     * @sample {highcharts}
     *         highcharts/plotoptions/pie-datalabels-connectorshape-function/
     *         connectorShape is a function
     *
     * @type    {string|Function}
     * @since   7.0.0
     * @product highcharts highmaps
     */
    connectorShape: "crookedLine",
    /**
     * The width of the line connecting the data label to the pie slice.
     *
     * In styled mode, the connector stroke width is given in the
     * `.highcharts-data-label-connector` class.
     *
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-connectorwidth-disabled/
     *         Disable the connector
     * @sample {highcharts} highcharts/css/pie-point/
     *         Styled connectors
     *
     * @type      {number}
     * @default   1
     * @since     2.1
     * @product   highcharts highmaps
     * @apioption plotOptions.pie.dataLabels.connectorWidth
     */
    /**
     * Works only if `connectorShape` is `'crookedLine'`. It defines how
     * far from the vertical plot edge the coonnector path should be
     * crooked. With the default, `undefined`, the crook is placed so that
     * the horizontal line from the label intersects with the radial line
     * extending through the center of the pie slice.
     *
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-crookdistance/
     *         crookDistance set to 90%
     *
     * @since   7.0.0
     * @product highcharts highmaps
     */
    crookDistance: void 0,
    /**
     * The distance of the data label from the pie's edge. Negative
     * numbers put the data label on top of the pie slices. Can also be
     * defined as a percentage of pie's radius. Connectors are only
     * shown for data labels outside the pie.
     *
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-distance/
     *         Data labels on top of the pie
     *
     * @type    {number|string}
     * @since   2.1
     * @product highcharts highmaps
     */
    distance: 30,
    enabled: true,
    /**
     * A
     * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * for the data label. Available variables are the same as for
     * `formatter`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
     *         Add a unit
     *
     * @type      {string}
     * @default   undefined
     * @since     3.0
     * @apioption plotOptions.pie.dataLabels.format
     */
    // eslint-disable-next-line valid-jsdoc
    /**
     * Callback JavaScript function to format the data label. Note that
     * if a `format` is defined, the format takes precedence and the
     * formatter is ignored.
     *
     * @type {Highcharts.DataLabelsFormatterCallbackFunction}
     * @default function () { return this.point.isNull ? void 0 : this.point.name; }
     */
    formatter: function() {
      return this.isNull ? void 0 : this.name;
    },
    /**
     * Whether to render the connector as a soft arc or a line with a sharp
     * break. Works only if `connectorShape` equals to `fixedOffset`.
     *
     * @sample {highcharts}
     *         highcharts/plotoptions/pie-datalabels-softconnector-true/
     *         Soft
     * @sample {highcharts}
     *         highcharts/plotoptions/pie-datalabels-softconnector-false/
     *         Non soft
     *
     * @since   2.1.7
     * @product highcharts highmaps
     */
    softConnector: true,
    /**
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow
     *         Long labels truncated with an ellipsis
     * @sample {highcharts} highcharts/plotoptions/pie-datalabels-overflow-wrap
     *         Long labels are wrapped
     *
     * @type      {Highcharts.CSSObject}
     * @apioption plotOptions.pie.dataLabels.style
     */
    x: 0
  },
  /**
   * If the total sum of the pie's values is 0, the series is represented
   * as an empty circle . The `fillColor` option defines the color of that
   * circle. Use [pie.borderWidth](#plotOptions.pie.borderWidth) to set
   * the border thickness.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-emptyseries/
   *         Empty pie series
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @private
   */
  fillColor: void 0,
  /**
   * The end angle of the pie in degrees where 0 is top and 90 is right.
   * Defaults to `startAngle` plus 360.
   *
   * @sample {highcharts} highcharts/demo/pie-semi-circle/
   *         Semi-circle donut
   *
   * @type      {number}
   * @since     1.3.6
   * @product   highcharts highmaps
   * @apioption plotOptions.pie.endAngle
   */
  /**
   * Thickness describing the ring size for a donut type chart,
   * overriding [innerSize](#plotOptions.pie.innerSize).
   *
   * @type      {number}
   * @default   undefined
   * @product   highcharts
   * @since 10.1.0
   * @apioption plotOptions.pie.thickness
   * @private
   */
  /**
   * Equivalent to [chart.ignoreHiddenSeries](#chart.ignoreHiddenSeries),
   * this option tells whether the series shall be redrawn as if the
   * hidden point were `null`.
   *
   * The default value changed from `false` to `true` with Highcharts
   * 3.0.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-ignorehiddenpoint/
   *         True, the hiddden point is ignored
   *
   * @since   2.3.0
   * @product highcharts highmaps
   *
   * @private
   */
  ignoreHiddenPoint: true,
  /**
   * @default   true
   * @extends   plotOptions.series.inactiveOtherPoints
   * @private
   */
  inactiveOtherPoints: true,
  /**
   * The size of the inner diameter for the pie. A size greater than 0
   * renders a donut chart. Can be a percentage or pixel value.
   * Percentages are relative to the pie size. Pixel values are given as
   * integers. Setting overridden by thickness.
   *
   *
   * Note: in Highcharts < 4.1.2, the percentage was relative to the plot
   * area, not the pie size.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-innersize-80px/
   *         80px inner size
   * @sample {highcharts} highcharts/plotoptions/pie-innersize-50percent/
   *         50% of the plot area
   * @sample {highcharts} highcharts/demo/3d-pie-donut/
   *         3D donut
   *
   * @type      {number|string}
   * @default   0
   * @since     2.0
   * @product   highcharts highmaps
   * @apioption plotOptions.pie.innerSize
   */
  /**
   * @ignore-option
   *
   * @private
   */
  legendType: "point",
  /**
   * @ignore-option
   *
   * @private
   */
  marker: null,
  // Point options are specified in the base options
  /**
   * The minimum size for a pie in response to auto margins. The pie will
   * try to shrink to make room for data labels in side the plot area,
   *  but only to this size.
   *
   * @type      {number|string}
   * @default   80
   * @since     3.0
   * @product   highcharts highmaps
   * @apioption plotOptions.pie.minSize
   */
  /**
   * The diameter of the pie relative to the plot area. Can be a
   * percentage or pixel value. Pixel values are given as integers. The
   * default behaviour (as of 3.0) is to scale to the plot area and give
   * room for data labels within the plot area.
   * [slicedOffset](#plotOptions.pie.slicedOffset) is also included in the
   * default size calculation. As a consequence, the size of the pie may
   * vary when points are updated and data labels more around. In that
   * case it is best to set a fixed value, for example `"75%"`.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-size/
   *         Smaller pie
   *
   * @type    {number|string|null}
   * @product highcharts highmaps
   *
   * @private
   */
  size: null,
  /**
   * Whether to display this particular series or series type in the
   * legend. Since 2.1, pies are not shown in the legend by default.
   *
   * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
   *         One series in the legend, one hidden
   *
   * @product highcharts highmaps
   *
   * @private
   */
  showInLegend: false,
  /**
   * If a point is sliced, moved out from the center, how many pixels
   * should it be moved?.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-slicedoffset-20/
   *         20px offset
   *
   * @product highcharts highmaps
   *
   * @private
   */
  slicedOffset: 10,
  /**
   * The start angle of the pie slices in degrees where 0 is top and 90
   * right.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-startangle-90/
   *         Start from right
   *
   * @type      {number}
   * @default   0
   * @since     2.3.4
   * @product   highcharts highmaps
   * @apioption plotOptions.pie.startAngle
   */
  /**
   * Sticky tracking of mouse events. When true, the `mouseOut` event
   * on a series isn't triggered until the mouse moves over another
   * series, or out of the plot area. When false, the `mouseOut` event on
   * a series is triggered when the mouse leaves the area around the
   * series'  graph or markers. This also implies the tooltip. When
   * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
   * will be hidden when moving the mouse between series.
   *
   * @product highcharts highmaps
   *
   * @private
   */
  stickyTracking: false,
  tooltip: {
    followPointer: true
  },
  /**
   * The color of the border surrounding each slice. When `null`, the
   * border takes the same color as the slice fill. This can be used
   * together with a `borderWidth` to fill drawing gaps created by
   * antialiazing artefacts in borderless pies.
   *
   * In styled mode, the border stroke is given in the `.highcharts-point`
   * class.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-bordercolor-black/
   *         Black border
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default #ffffff
   * @product highcharts highmaps
   *
   * @private
   */
  borderColor: "#ffffff",
  /**
   * The width of the border surrounding each slice.
   *
   * When setting the border width to 0, there may be small gaps between
   * the slices due to SVG antialiasing artefacts. To work around this,
   * keep the border width at 0.5 or 1, but set the `borderColor` to
   * `null` instead.
   *
   * In styled mode, the border stroke width is given in the
   * `.highcharts-point` class.
   *
   * @sample {highcharts} highcharts/plotoptions/pie-borderwidth/
   *         3px border
   *
   * @product highcharts highmaps
   *
   * @private
   */
  borderWidth: 1,
  /**
   * @ignore-option
   * @private
   */
  lineWidth: void 0,
  // #12222
  states: {
    /**
     * @extends   plotOptions.series.states.hover
     * @excluding marker, lineWidth, lineWidthPlus
     * @product   highcharts highmaps
     */
    hover: {
      /**
       * How much to brighten the point on interaction. Requires the
       * main color to be defined in hex or rgb(a) format.
       *
       * In styled mode, the hover brightness is by default replaced
       * by a fill-opacity given in the `.highcharts-point-hover`
       * class.
       *
       * @sample {highcharts} highcharts/plotoptions/pie-states-hover-brightness/
       *         Brightened by 0.5
       *
       * @product highcharts highmaps
       */
      brightness: 0.1
    }
  }
};
const { getStartAndEndRadians } = CU;
const { noop: noop$h } = Highcharts;
const { clamp: clamp$h, extend: extend$14, fireEvent: fireEvent$u, merge: merge$1i, pick: pick$1q } = Utilities;
let PieSeries$3 = class PieSeries2 extends Series$9 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Animates the pies in.
   * @private
   */
  animate(init2) {
    const series = this, points = series.points, startAngleRad = series.startAngleRad;
    if (!init2) {
      points.forEach(function(point) {
        const graphic = point.graphic, args = point.shapeArgs;
        if (graphic && args) {
          graphic.attr({
            // Animate from inner radius (#779)
            r: pick$1q(point.startR, series.center && series.center[3] / 2),
            start: startAngleRad,
            end: startAngleRad
          });
          graphic.animate({
            r: args.r,
            start: args.start,
            end: args.end
          }, series.options.animation);
        }
      });
    }
  }
  /**
   * Called internally to draw auxiliary graph in pie-like series in
   * situtation when the default graph is not sufficient enough to present
   * the data well. Auxiliary graph is saved in the same object as
   * regular graph.
   * @private
   */
  drawEmpty() {
    const start2 = this.startAngleRad, end = this.endAngleRad, options2 = this.options;
    let centerX, centerY;
    if (this.total === 0 && this.center) {
      centerX = this.center[0];
      centerY = this.center[1];
      if (!this.graph) {
        this.graph = this.chart.renderer.arc(centerX, centerY, this.center[1] / 2, 0, start2, end).addClass("highcharts-empty-series").add(this.group);
      }
      this.graph.attr({
        d: Symbols.arc(centerX, centerY, this.center[2] / 2, 0, {
          start: start2,
          end,
          innerR: this.center[3] / 2
        })
      });
      if (!this.chart.styledMode) {
        this.graph.attr({
          "stroke-width": options2.borderWidth,
          fill: options2.fillColor || "none",
          stroke: options2.color || "#cccccc"
          /* Palette.neutralColor20 */
        });
      }
    } else if (this.graph) {
      this.graph = this.graph.destroy();
    }
  }
  /**
   * Slices in pie chart are initialized in DOM, but it's shapes and
   * animations are normally run in `drawPoints()`.
   * @private
   */
  drawPoints() {
    const renderer = this.chart.renderer;
    this.points.forEach(function(point) {
      if (point.graphic && point.hasNewShapeType()) {
        point.graphic = point.graphic.destroy();
      }
      if (!point.graphic) {
        point.graphic = renderer[point.shapeType](point.shapeArgs).add(point.series.group);
        point.delayedRendering = true;
      }
    });
  }
  /**
   * Extend the generatePoints method by adding total and percentage
   * properties to each point
   * @private
   */
  generatePoints() {
    super.generatePoints();
    this.updateTotals();
  }
  /**
   * Utility for getting the x value from a given y, used for anticollision
   * logic in data labels.
   * @private
   */
  getX(y, left, point, dataLabel) {
    const center = this.center, radius = this.radii ? this.radii[point.index] || 0 : center[2] / 2, labelPosition = dataLabel.dataLabelPosition, distance = labelPosition?.distance || 0;
    const angle = Math.asin(clamp$h((y - center[1]) / (radius + distance), -1, 1));
    const x = center[0] + (left ? -1 : 1) * (Math.cos(angle) * (radius + distance)) + (distance > 0 ? (left ? -1 : 1) * (dataLabel.padding || 0) : 0);
    return x;
  }
  /**
   * Define hasData function for non-cartesian series. Returns true if the
   * series has points at all.
   * @private
   */
  hasData() {
    return !!this.dataTable.rowCount;
  }
  /**
   * Draw the data points
   * @private
   */
  redrawPoints() {
    const series = this, chart = series.chart;
    let groupTranslation, graphic, pointAttr, shapeArgs;
    this.drawEmpty();
    if (series.group && !chart.styledMode) {
      series.group.shadow(series.options.shadow);
    }
    series.points.forEach(function(point) {
      const animateTo = {};
      graphic = point.graphic;
      if (!point.isNull && graphic) {
        shapeArgs = point.shapeArgs;
        groupTranslation = point.getTranslate();
        if (!chart.styledMode) {
          pointAttr = series.pointAttribs(point, point.selected && "select");
        }
        if (!point.delayedRendering) {
          graphic.setRadialReference(series.center);
          if (!chart.styledMode) {
            merge$1i(true, animateTo, pointAttr);
          }
          merge$1i(true, animateTo, shapeArgs, groupTranslation);
          graphic.animate(animateTo);
        } else {
          graphic.setRadialReference(series.center).attr(shapeArgs).attr(groupTranslation);
          if (!chart.styledMode) {
            graphic.attr(pointAttr).attr({ "stroke-linejoin": "round" });
          }
          point.delayedRendering = false;
        }
        graphic.attr({
          visibility: point.visible ? "inherit" : "hidden"
        });
        graphic.addClass(point.getClassName(), true);
      } else if (graphic) {
        point.graphic = graphic.destroy();
      }
    });
  }
  /**
   * Utility for sorting data labels.
   * @private
   */
  sortByAngle(points, sign2) {
    points.sort(function(a, b) {
      return typeof a.angle !== "undefined" && (b.angle - a.angle) * sign2;
    });
  }
  /**
   * Do translation for pie slices
   * @private
   */
  translate(positions) {
    fireEvent$u(this, "translate");
    this.generatePoints();
    const series = this, precision = 1e3, options2 = series.options, slicedOffset = options2.slicedOffset, radians = getStartAndEndRadians(options2.startAngle, options2.endAngle), startAngleRad = series.startAngleRad = radians.start, endAngleRad = series.endAngleRad = radians.end, circ = endAngleRad - startAngleRad, points = series.points, ignoreHiddenPoint = options2.ignoreHiddenPoint, len = points.length;
    let start2, end, angle, radiusX, radiusY, i, point, cumulative = 0;
    if (!positions) {
      series.center = positions = series.getCenter();
    }
    for (i = 0; i < len; i++) {
      point = points[i];
      start2 = startAngleRad + cumulative * circ;
      if (point.isValid() && (!ignoreHiddenPoint || point.visible)) {
        cumulative += point.percentage / 100;
      }
      end = startAngleRad + cumulative * circ;
      const shapeArgs = {
        x: positions[0],
        y: positions[1],
        r: positions[2] / 2,
        innerR: positions[3] / 2,
        start: Math.round(start2 * precision) / precision,
        end: Math.round(end * precision) / precision
      };
      point.shapeType = "arc";
      point.shapeArgs = shapeArgs;
      angle = (end + start2) / 2;
      if (angle > 1.5 * Math.PI) {
        angle -= 2 * Math.PI;
      } else if (angle < -Math.PI / 2) {
        angle += 2 * Math.PI;
      }
      point.slicedTranslation = {
        translateX: Math.round(Math.cos(angle) * slicedOffset),
        translateY: Math.round(Math.sin(angle) * slicedOffset)
      };
      radiusX = Math.cos(angle) * positions[2] / 2;
      radiusY = Math.sin(angle) * positions[2] / 2;
      point.tooltipPos = [
        positions[0] + radiusX * 0.7,
        positions[1] + radiusY * 0.7
      ];
      point.half = angle < -Math.PI / 2 || angle > Math.PI / 2 ? 1 : 0;
      point.angle = angle;
    }
    fireEvent$u(series, "afterTranslate");
  }
  /**
   * Recompute total chart sum and update percentages of points.
   * @private
   */
  updateTotals() {
    const points = this.points, len = points.length, ignoreHiddenPoint = this.options.ignoreHiddenPoint;
    let i, point, total = 0;
    for (i = 0; i < len; i++) {
      point = points[i];
      if (point.isValid() && (!ignoreHiddenPoint || point.visible)) {
        total += point.y;
      }
    }
    this.total = total;
    for (i = 0; i < len; i++) {
      point = points[i];
      point.percentage = total > 0 && (point.visible || !ignoreHiddenPoint) ? point.y / total * 100 : 0;
      point.total = total;
    }
  }
};
PieSeries$3.defaultOptions = merge$1i(Series$9.defaultOptions, PieSeriesDefaults);
extend$14(PieSeries$3.prototype, {
  axisTypes: [],
  directTouch: true,
  drawGraph: void 0,
  drawTracker: ColumnSeries$f.prototype.drawTracker,
  getCenter: CU.getCenter,
  getSymbol: noop$h,
  invertible: false,
  isCartesian: false,
  noSharedTooltip: true,
  pointAttribs: ColumnSeries$f.prototype.pointAttribs,
  pointClass: PiePoint$3,
  requireSorting: false,
  searchPoint: noop$h,
  trackerGroups: ["group", "dataLabelsGroup"]
});
SeriesRegistry$1.registerSeriesType("pie", PieSeries$3);
const { composed: composed$s, noop: noop$g } = Highcharts;
const { distribute: distribute$1 } = R$1;
const { series: Series$6 } = SeriesRegistry$1;
const { arrayMax: arrayMax$7, clamp: clamp$g, defined: defined$X, pick: pick$1p, pushUnique: pushUnique$s, relativeLength: relativeLength$c } = Utilities;
var ColumnDataLabel;
(function(ColumnDataLabel2) {
  const dataLabelPositioners = {
    // Based on the value computed in Highcharts' distribute algorithm.
    radialDistributionY: function(point, dataLabel) {
      return (dataLabel.dataLabelPosition?.top || 0) + point.distributeBox.pos;
    },
    // Get the x - use the natural x position for labels near the top and
    // bottom, to prevent the top and botton slice connectors from touching
    // each other on either side. Based on the value computed in Highcharts'
    // distribute algorithm.
    radialDistributionX: function(series, point, y, naturalY, dataLabel) {
      const pos = dataLabel.dataLabelPosition;
      return series.getX(y < (pos?.top || 0) + 2 || y > (pos?.bottom || 0) - 2 ? naturalY : y, point.half, point, dataLabel);
    },
    // The dataLabels.distance determines the x position of the label
    justify: function(point, dataLabel, radius, seriesCenter) {
      return seriesCenter[0] + (point.half ? -1 : 1) * (radius + (dataLabel.dataLabelPosition?.distance || 0));
    },
    // Left edges of the left-half labels touch the left edge of the plot
    // area. Right edges of the right-half labels touch the right edge of
    // the plot area.
    alignToPlotEdges: function(dataLabel, half, plotWidth, plotLeft) {
      const dataLabelWidth = dataLabel.getBBox().width;
      return half ? dataLabelWidth + plotLeft : plotWidth - dataLabelWidth - plotLeft;
    },
    // Connectors of each side end in the same x position. Labels are
    // aligned to them. Left edge of the widest left-half label touches the
    // left edge of the plot area. Right edge of the widest right-half label
    // touches the right edge of the plot area.
    alignToConnectors: function(points, half, plotWidth, plotLeft) {
      let maxDataLabelWidth = 0, dataLabelWidth;
      points.forEach(function(point) {
        dataLabelWidth = point.dataLabel.getBBox().width;
        if (dataLabelWidth > maxDataLabelWidth) {
          maxDataLabelWidth = dataLabelWidth;
        }
      });
      return half ? maxDataLabelWidth + plotLeft : plotWidth - maxDataLabelWidth - plotLeft;
    }
  };
  function compose2(PieSeriesClass) {
    DataLabel$1.compose(Series$6);
    if (pushUnique$s(composed$s, "PieDataLabel")) {
      const pieProto = PieSeriesClass.prototype;
      pieProto.dataLabelPositioners = dataLabelPositioners;
      pieProto.alignDataLabel = noop$g;
      pieProto.drawDataLabels = drawDataLabels;
      pieProto.getDataLabelPosition = getDataLabelPosition;
      pieProto.placeDataLabels = placeDataLabels;
      pieProto.verifyDataLabelOverflow = verifyDataLabelOverflow;
    }
  }
  ColumnDataLabel2.compose = compose2;
  function getDataLabelPosition(point, distance) {
    const halfPI = Math.PI / 2, { start: start2 = 0, end = 0 } = point.shapeArgs || {};
    let angle = point.angle || 0;
    if (distance > 0 && // Crossing the bottom
    start2 < halfPI && end > halfPI && // Angle within the bottom quadrant
    angle > halfPI / 2 && angle < halfPI * 1.5) {
      angle = angle <= halfPI ? Math.max(halfPI / 2, (start2 + halfPI) / 2) : Math.min(halfPI * 1.5, (halfPI + end) / 2);
    }
    const { center, options: options2 } = this, r = center[2] / 2, cosAngle = Math.cos(angle), sinAngle = Math.sin(angle), x = center[0] + cosAngle * r, y = center[1] + sinAngle * r, finalConnectorOffset = Math.min((options2.slicedOffset || 0) + (options2.borderWidth || 0), distance / 5);
    return {
      natural: {
        // Initial position of the data label - it's utilized for
        // finding the final position for the label
        x: x + cosAngle * distance,
        y: y + sinAngle * distance
      },
      computed: {
        // Used for generating connector path - initialized later in
        // drawDataLabels function x: undefined, y: undefined
      },
      // Left - pie on the left side of the data label
      // Right - pie on the right side of the data label
      // Center - data label overlaps the pie
      alignment: distance < 0 ? "center" : point.half ? "right" : "left",
      connectorPosition: {
        angle,
        breakAt: {
          x: x + cosAngle * finalConnectorOffset,
          y: y + sinAngle * finalConnectorOffset
        },
        touchingSliceAt: {
          x,
          y
        }
      },
      distance
    };
  }
  function drawDataLabels() {
    const series = this, points = series.points, chart = series.chart, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, plotLeft = chart.plotLeft, maxWidth = Math.round(chart.chartWidth / 3), seriesCenter = series.center, radius = seriesCenter[2] / 2, centerY = seriesCenter[1], halves = [
      [],
      // Right
      []
      // Left
    ], overflow = [0, 0, 0, 0], dataLabelPositioners2 = series.dataLabelPositioners;
    let connector, dataLabelWidth, labelHeight, maxLabelDistance = 0;
    if (!series.visible || !series.hasDataLabels?.()) {
      return;
    }
    points.forEach((point) => {
      (point.dataLabels || []).forEach((dataLabel) => {
        if (dataLabel.shortened) {
          dataLabel.attr({
            width: "auto"
          }).css({
            width: "auto",
            textOverflow: "clip"
          });
          dataLabel.shortened = false;
        }
      });
    });
    Series$6.prototype.drawDataLabels.apply(series);
    points.forEach((point) => {
      (point.dataLabels || []).forEach((dataLabel, i) => {
        const r = seriesCenter[2] / 2, dataLabelOptions = dataLabel.options, distance = relativeLength$c(dataLabelOptions?.distance || 0, r);
        if (i === 0) {
          halves[point.half].push(point);
        }
        if (!defined$X(dataLabelOptions?.style?.width)) {
          if (dataLabel.getBBox().width > maxWidth) {
            dataLabel.css({
              // Use a fraction of the maxWidth to avoid wrapping
              // close to the end of the string.
              width: Math.round(maxWidth * 0.7) + "px"
            });
            dataLabel.shortened = true;
          }
        }
        dataLabel.dataLabelPosition = this.getDataLabelPosition(point, distance);
        maxLabelDistance = Math.max(maxLabelDistance, distance);
      });
    });
    halves.forEach((points2, halfIdx) => {
      const length = points2.length, positions = [];
      let top, bottom, size = 0, distributionLength;
      if (!length) {
        return;
      }
      series.sortByAngle(points2, halfIdx - 0.5);
      if (maxLabelDistance > 0) {
        top = Math.max(0, centerY - radius - maxLabelDistance);
        bottom = Math.min(centerY + radius + maxLabelDistance, chart.plotHeight);
        points2.forEach((point) => {
          (point.dataLabels || []).forEach((dataLabel) => {
            const labelPosition = dataLabel.dataLabelPosition;
            if (labelPosition && labelPosition.distance > 0) {
              labelPosition.top = Math.max(0, centerY - radius - labelPosition.distance);
              labelPosition.bottom = Math.min(centerY + radius + labelPosition.distance, chart.plotHeight);
              size = dataLabel.getBBox().height || 21;
              dataLabel.lineHeight = chart.renderer.fontMetrics(dataLabel.text || dataLabel).h + 2 * dataLabel.padding;
              point.distributeBox = {
                target: (dataLabel.dataLabelPosition?.natural.y || 0) - labelPosition.top + dataLabel.lineHeight / 2,
                size,
                rank: point.y
              };
              positions.push(point.distributeBox);
            }
          });
        });
        distributionLength = bottom + size - top;
        distribute$1(positions, distributionLength, distributionLength / 5);
      }
      points2.forEach((point) => {
        (point.dataLabels || []).forEach((dataLabel) => {
          const dataLabelOptions = dataLabel.options || {}, distributeBox = point.distributeBox, labelPosition = dataLabel.dataLabelPosition, naturalY = labelPosition?.natural.y || 0, connectorPadding = dataLabelOptions.connectorPadding || 0, lineHeight = dataLabel.lineHeight || 21, bBox = dataLabel.getBBox(), topOffset = (lineHeight - bBox.height) / 2;
          let x = 0, y = naturalY, visibility = "inherit";
          if (labelPosition) {
            if (positions && defined$X(distributeBox) && labelPosition.distance > 0) {
              if (typeof distributeBox.pos === "undefined") {
                visibility = "hidden";
              } else {
                labelHeight = distributeBox.size;
                y = dataLabelPositioners2.radialDistributionY(point, dataLabel);
              }
            }
            if (dataLabelOptions.justify) {
              x = dataLabelPositioners2.justify(point, dataLabel, radius, seriesCenter);
            } else {
              switch (dataLabelOptions.alignTo) {
                case "connectors":
                  x = dataLabelPositioners2.alignToConnectors(points2, halfIdx, plotWidth, plotLeft);
                  break;
                case "plotEdges":
                  x = dataLabelPositioners2.alignToPlotEdges(dataLabel, halfIdx, plotWidth, plotLeft);
                  break;
                default:
                  x = dataLabelPositioners2.radialDistributionX(series, point, y - topOffset, naturalY, dataLabel);
              }
            }
            labelPosition.attribs = {
              visibility,
              align: labelPosition.alignment
            };
            labelPosition.posAttribs = {
              x: x + (dataLabelOptions.x || 0) + // (#12985)
              ({
                left: connectorPadding,
                right: -connectorPadding
              }[labelPosition.alignment] || 0),
              y: y + (dataLabelOptions.y || 0) - // (#12985)
              // Vertically center
              lineHeight / 2
            };
            labelPosition.computed.x = x;
            labelPosition.computed.y = y - topOffset;
            if (pick$1p(dataLabelOptions.crop, true)) {
              dataLabelWidth = dataLabel.getBBox().width;
              let sideOverflow;
              if (x - dataLabelWidth < connectorPadding && halfIdx === 1) {
                sideOverflow = Math.round(dataLabelWidth - x + connectorPadding);
                overflow[3] = Math.max(sideOverflow, overflow[3]);
              } else if (x + dataLabelWidth > plotWidth - connectorPadding && halfIdx === 0) {
                sideOverflow = Math.round(x + dataLabelWidth - plotWidth + connectorPadding);
                overflow[1] = Math.max(sideOverflow, overflow[1]);
              }
              if (y - labelHeight / 2 < 0) {
                overflow[0] = Math.max(Math.round(-y + labelHeight / 2), overflow[0]);
              } else if (y + labelHeight / 2 > plotHeight) {
                overflow[2] = Math.max(Math.round(y + labelHeight / 2 - plotHeight), overflow[2]);
              }
              labelPosition.sideOverflow = sideOverflow;
            }
          }
        });
      });
    });
    if (arrayMax$7(overflow) === 0 || this.verifyDataLabelOverflow(overflow)) {
      this.placeDataLabels();
      this.points.forEach((point) => {
        (point.dataLabels || []).forEach((dataLabel) => {
          const { connectorColor, connectorWidth = 1 } = dataLabel.options || {}, labelPosition = dataLabel.dataLabelPosition;
          if (connectorWidth) {
            let isNew;
            connector = dataLabel.connector;
            if (labelPosition && labelPosition.distance > 0) {
              isNew = !connector;
              if (!connector) {
                dataLabel.connector = connector = chart.renderer.path().addClass("highcharts-data-label-connector  highcharts-color-" + point.colorIndex + (point.className ? " " + point.className : "")).add(series.dataLabelsGroup);
              }
              if (!chart.styledMode) {
                connector.attr({
                  "stroke-width": connectorWidth,
                  "stroke": connectorColor || point.color || "#666666"
                });
              }
              connector[isNew ? "attr" : "animate"]({
                d: point.getConnectorPath(dataLabel)
              });
              connector.attr({
                visibility: labelPosition.attribs?.visibility
              });
            } else if (connector) {
              dataLabel.connector = connector.destroy();
            }
          }
        });
      });
    }
  }
  function placeDataLabels() {
    this.points.forEach((point) => {
      (point.dataLabels || []).forEach((dataLabel) => {
        const labelPosition = dataLabel.dataLabelPosition;
        if (labelPosition) {
          if (labelPosition.sideOverflow) {
            dataLabel.css({
              width: Math.max(dataLabel.getBBox().width - labelPosition.sideOverflow, 0) + "px",
              textOverflow: dataLabel.options?.style?.textOverflow || "ellipsis"
            });
            dataLabel.shortened = true;
          }
          dataLabel.attr(labelPosition.attribs);
          dataLabel[dataLabel.moved ? "animate" : "attr"](labelPosition.posAttribs);
          dataLabel.moved = true;
        } else if (dataLabel) {
          dataLabel.attr({ y: -9999 });
        }
      });
      delete point.distributeBox;
    }, this);
  }
  function verifyDataLabelOverflow(overflow) {
    const center = this.center, options2 = this.options, centerOption = options2.center, minSize = options2.minSize || 80;
    let newSize = minSize, ret = options2.size !== null;
    if (!ret) {
      if (centerOption[0] !== null) {
        newSize = Math.max(center[2] - Math.max(overflow[1], overflow[3]), minSize);
      } else {
        newSize = Math.max(
          // Horizontal overflow
          center[2] - overflow[1] - overflow[3],
          minSize
        );
        center[0] += (overflow[3] - overflow[1]) / 2;
      }
      if (centerOption[1] !== null) {
        newSize = clamp$g(newSize, minSize, center[2] - Math.max(overflow[0], overflow[2]));
      } else {
        newSize = clamp$g(
          newSize,
          minSize,
          // Vertical overflow
          center[2] - overflow[0] - overflow[2]
        );
        center[1] += (overflow[0] - overflow[2]) / 2;
      }
      if (newSize < center[2]) {
        center[2] = newSize;
        center[3] = Math.min(
          // #3632
          options2.thickness ? Math.max(0, newSize - options2.thickness * 2) : Math.max(0, relativeLength$c(options2.innerSize || 0, newSize)),
          newSize
        );
        this.translate(center);
        if (this.drawDataLabels) {
          this.drawDataLabels();
        }
      } else {
        ret = true;
      }
    }
    return ret;
  }
})(ColumnDataLabel || (ColumnDataLabel = {}));
const PieDataLabel = ColumnDataLabel;
var GeometryUtilities;
(function(GeometryUtilities2) {
  function getCenterOfPoints(points) {
    const sum2 = points.reduce((sum3, point) => {
      sum3.x += point.x;
      sum3.y += point.y;
      return sum3;
    }, { x: 0, y: 0 });
    return {
      x: sum2.x / points.length,
      y: sum2.y / points.length
    };
  }
  GeometryUtilities2.getCenterOfPoints = getCenterOfPoints;
  function getDistanceBetweenPoints(p12, p22) {
    return Math.sqrt(Math.pow(p22.x - p12.x, 2) + Math.pow(p22.y - p12.y, 2));
  }
  GeometryUtilities2.getDistanceBetweenPoints = getDistanceBetweenPoints;
  function getAngleBetweenPoints(p12, p22) {
    return Math.atan2(p22.x - p12.x, p22.y - p12.y);
  }
  GeometryUtilities2.getAngleBetweenPoints = getAngleBetweenPoints;
  function pointInPolygon2({ x, y }, polygon) {
    const len = polygon.length;
    let i, j, inside = false;
    for (i = 0, j = len - 1; i < len; j = i++) {
      const [x1, y1] = polygon[i], [x2, y2] = polygon[j];
      if (y1 > y !== y2 > y && x < (x2 - x1) * (y - y1) / (y2 - y1) + x1) {
        inside = !inside;
      }
    }
    return inside;
  }
  GeometryUtilities2.pointInPolygon = pointInPolygon2;
})(GeometryUtilities || (GeometryUtilities = {}));
const GeometryUtilities$1 = GeometryUtilities;
const { pointInPolygon } = GeometryUtilities$1;
const { addEvent: addEvent$1g, getAlignFactor: getAlignFactor$2, fireEvent: fireEvent$t, objectEach: objectEach$g, pick: pick$1o } = Utilities;
function chartHideOverlappingLabels(labels) {
  const chart = this, len = labels.length, isIntersectRect = (box12, box22) => !(box22.x >= box12.x + box12.width || box22.x + box22.width <= box12.x || box22.y >= box12.y + box12.height || box22.y + box22.height <= box12.y), isPolygonOverlap = (box1Poly, box2Poly) => {
    for (const p of box1Poly) {
      if (pointInPolygon({ x: p[0], y: p[1] }, box2Poly)) {
        return true;
      }
    }
    return false;
  };
  function getAbsoluteBox(label3) {
    if (label3 && (!label3.alignAttr || label3.placed)) {
      const padding = label3.box ? 0 : label3.padding || 0, pos = label3.alignAttr || {
        x: label3.attr("x"),
        y: label3.attr("y")
      }, { height, polygon, width } = label3.getBBox(), alignOffset = getAlignFactor$2(label3.alignValue) * width;
      label3.width = width;
      label3.height = height;
      return {
        x: pos.x + (label3.parentGroup?.translateX || 0) + padding - alignOffset,
        y: pos.y + (label3.parentGroup?.translateY || 0) + padding,
        width: width - 2 * padding,
        height: height - 2 * padding,
        polygon
      };
    }
  }
  let label, label1, label2, box1, box2, isLabelAffected = false;
  for (let i = 0; i < len; i++) {
    label = labels[i];
    if (label) {
      label.oldOpacity = label.opacity;
      label.newOpacity = 1;
      label.absoluteBox = getAbsoluteBox(label);
    }
  }
  labels.sort((a, b) => (b.labelrank || 0) - (a.labelrank || 0));
  for (let i = 0; i < len; ++i) {
    label1 = labels[i];
    box1 = label1 && label1.absoluteBox;
    const box1Poly = box1?.polygon;
    for (let j = i + 1; j < len; ++j) {
      label2 = labels[j];
      box2 = label2 && label2.absoluteBox;
      let toHide = false;
      if (box1 && box2 && label1 !== label2 && // #6465, polar chart with connectEnds
      label1.newOpacity !== 0 && label2.newOpacity !== 0 && // #15863 dataLabels are no longer hidden by translation
      label1.visibility !== "hidden" && label2.visibility !== "hidden") {
        const box2Poly = box2.polygon;
        if (box1Poly && box2Poly && box1Poly !== box2Poly) {
          if (isPolygonOverlap(box1Poly, box2Poly)) {
            toHide = true;
          }
        } else if (isIntersectRect(box1, box2)) {
          toHide = true;
        }
        if (toHide) {
          const overlappingLabel = label1.labelrank < label2.labelrank ? label1 : label2, labelText = overlappingLabel.text;
          overlappingLabel.newOpacity = 0;
          if (labelText?.element.querySelector("textPath")) {
            labelText.hide();
          }
        }
      }
    }
  }
  for (const label3 of labels) {
    if (hideOrShow(label3, chart)) {
      isLabelAffected = true;
    }
  }
  if (isLabelAffected) {
    fireEvent$t(chart, "afterHideAllOverlappingLabels");
  }
}
function compose$q(ChartClass) {
  const chartProto = ChartClass.prototype;
  if (!chartProto.hideOverlappingLabels) {
    chartProto.hideOverlappingLabels = chartHideOverlappingLabels;
    addEvent$1g(ChartClass, "render", onChartRender$4);
  }
}
function hideOrShow(label, chart) {
  let complete, newOpacity, isLabelAffected = false;
  if (label) {
    newOpacity = label.newOpacity;
    if (label.oldOpacity !== newOpacity) {
      if (label.hasClass("highcharts-data-label")) {
        label[newOpacity ? "removeClass" : "addClass"]("highcharts-data-label-hidden");
        complete = function() {
          if (!chart.styledMode) {
            label.css({
              pointerEvents: newOpacity ? "auto" : "none"
            });
          }
        };
        isLabelAffected = true;
        label[label.isOld ? "animate" : "attr"]({ opacity: newOpacity }, void 0, complete);
        fireEvent$t(chart, "afterHideOverlappingLabel");
      } else {
        label.attr({
          opacity: newOpacity
        });
      }
    }
    label.isOld = true;
  }
  return isLabelAffected;
}
function onChartRender$4() {
  const chart = this;
  let labels = [];
  for (const collector of chart.labelCollectors || []) {
    labels = labels.concat(collector());
  }
  for (const yAxis2 of chart.yAxis || []) {
    if (yAxis2.stacking && yAxis2.options.stackLabels && !yAxis2.options.stackLabels.allowOverlap) {
      objectEach$g(yAxis2.stacking.stacks, (stack) => {
        objectEach$g(stack, (stackItem) => {
          if (stackItem.label) {
            labels.push(stackItem.label);
          }
        });
      });
    }
  }
  for (const series of chart.series || []) {
    if (series.visible && series.hasDataLabels?.()) {
      const push = (points) => {
        for (const point of points) {
          if (point.visible) {
            (point.dataLabels || []).forEach((label) => {
              const options2 = label.options || {};
              label.labelrank = pick$1o(options2.labelrank, point.labelrank, point.shapeArgs?.height);
              if (
                // #13449
                options2.allowOverlap ?? // Pie labels outside have a separate placement
                // logic, skip the overlap logic
                Number(options2.distance) > 0
              ) {
                label.oldOpacity = label.opacity;
                label.newOpacity = 1;
                hideOrShow(label, chart);
              } else {
                labels.push(label);
              }
            });
          }
        }
      };
      push(series.nodes || []);
      push(series.points);
    }
  }
  this.hideOverlappingLabels(labels);
}
const OverlappingDataLabels = {
  compose: compose$q
};
const { defaultOptions: defaultOptions$f } = DefaultOptions;
const { noop: noop$f } = Highcharts;
const { addEvent: addEvent$1f, extend: extend$13, isObject: isObject$e, merge: merge$1h, relativeLength: relativeLength$b } = Utilities;
const defaultBorderRadiusOptions = {
  radius: 0,
  scope: "stack",
  where: void 0
};
let oldArc = noop$f;
let oldRoundedRect = noop$f;
function applyBorderRadius(path, i, r) {
  const a = path[i];
  let b = path[i + 1];
  if (b[0] === "Z") {
    b = path[0];
  }
  let line2, arc2, fromLineToArc;
  if ((a[0] === "M" || a[0] === "L") && b[0] === "A") {
    line2 = a;
    arc2 = b;
    fromLineToArc = true;
  } else if (a[0] === "A" && (b[0] === "M" || b[0] === "L")) {
    line2 = b;
    arc2 = a;
  }
  if (line2 && arc2 && arc2.params) {
    const bigR = arc2[1], clockwise = arc2[5], params2 = arc2.params, { start: start2, end, cx, cy } = params2;
    const relativeR = clockwise ? bigR - r : bigR + r, angleOfBorderRadius = relativeR ? Math.asin(r / relativeR) : 0, angleOffset = clockwise ? angleOfBorderRadius : -angleOfBorderRadius, distanceBigCenterToStartArc = Math.cos(angleOfBorderRadius) * relativeR;
    if (fromLineToArc) {
      params2.start = start2 + angleOffset;
      line2[1] = cx + distanceBigCenterToStartArc * Math.cos(start2);
      line2[2] = cy + distanceBigCenterToStartArc * Math.sin(start2);
      path.splice(i + 1, 0, [
        "A",
        r,
        r,
        0,
        // Slanting,
        0,
        // Long arc
        1,
        // Clockwise
        cx + bigR * Math.cos(params2.start),
        cy + bigR * Math.sin(params2.start)
      ]);
    } else {
      params2.end = end - angleOffset;
      arc2[6] = cx + bigR * Math.cos(params2.end);
      arc2[7] = cy + bigR * Math.sin(params2.end);
      path.splice(i + 1, 0, [
        "A",
        r,
        r,
        0,
        0,
        1,
        cx + distanceBigCenterToStartArc * Math.cos(end),
        cy + distanceBigCenterToStartArc * Math.sin(end)
      ]);
    }
    arc2[4] = Math.abs(params2.end - params2.start) < Math.PI ? 0 : 1;
  }
}
function arc(x, y, w, h, options2 = {}) {
  const path = oldArc(x, y, w, h, options2), { innerR = 0, r = w, start: start2 = 0, end = 0 } = options2;
  if (options2.open || !options2.borderRadius) {
    return path;
  }
  const alpha = end - start2, sinHalfAlpha = Math.sin(alpha / 2), borderRadius = Math.max(Math.min(
    relativeLength$b(options2.borderRadius || 0, r - innerR),
    // Cap to half the sector radius
    (r - innerR) / 2,
    // For smaller pie slices, cap to the largest small circle that
    // can be fitted within the sector
    r * sinHalfAlpha / (1 + sinHalfAlpha)
  ), 0), innerBorderRadius = Math.min(borderRadius, 2 * (alpha / Math.PI) * innerR);
  let i = path.length - 1;
  while (i--) {
    applyBorderRadius(path, i, i > 1 ? innerBorderRadius : borderRadius);
  }
  return path;
}
function seriesOnAfterColumnTranslate() {
  if (this.options.borderRadius && !(this.chart.is3d && this.chart.is3d())) {
    const { options: options2, yAxis: yAxis2 } = this, percent = options2.stacking === "percent", seriesDefault = defaultOptions$f.plotOptions?.[this.type]?.borderRadius, borderRadius = optionsToObject$1(options2.borderRadius, isObject$e(seriesDefault) ? seriesDefault : {}), reversed = yAxis2.options.reversed;
    for (const point of this.points) {
      const { shapeArgs } = point;
      if (point.shapeType === "roundedRect" && shapeArgs) {
        const { width = 0, height = 0, y = 0 } = shapeArgs;
        let brBoxY = y, brBoxHeight = height;
        if (borderRadius.scope === "stack" && point.stackTotal) {
          const stackEnd = yAxis2.translate(percent ? 100 : point.stackTotal, false, true, false, true), stackThreshold = yAxis2.translate(options2.threshold || 0, false, true, false, true), box = this.crispCol(0, Math.min(stackEnd, stackThreshold), 0, Math.abs(stackEnd - stackThreshold));
          brBoxY = box.y;
          brBoxHeight = box.height;
        }
        const flip = (point.negative ? -1 : 1) * (reversed ? -1 : 1) === -1;
        let where = borderRadius.where;
        if (!where && this.is("waterfall") && Math.abs((point.yBottom || 0) - (this.translatedThreshold || 0)) > this.borderWidth) {
          where = "all";
        }
        if (!where) {
          where = "end";
        }
        const r = Math.min(
          relativeLength$b(borderRadius.radius, width),
          width / 2,
          // Cap to the height, but not if where is `end`
          where === "all" ? height / 2 : Infinity
        ) || 0;
        if (where === "end") {
          if (flip) {
            brBoxY -= r;
            brBoxHeight += r;
          } else {
            brBoxHeight += r;
          }
        }
        extend$13(shapeArgs, { brBoxHeight, brBoxY, r });
      }
    }
  }
}
function compose$p(SeriesClass, SVGElementClass, SVGRendererClass) {
  const PieSeriesClass = SeriesClass.types.pie;
  if (!SVGElementClass.symbolCustomAttribs.includes("borderRadius")) {
    const symbols2 = SVGRendererClass.prototype.symbols;
    addEvent$1f(SeriesClass, "afterColumnTranslate", seriesOnAfterColumnTranslate, {
      // After columnrange and polar column modifications
      order: 9
    });
    addEvent$1f(PieSeriesClass, "afterTranslate", pieSeriesOnAfterTranslate);
    SVGElementClass.symbolCustomAttribs.push("borderRadius", "brBoxHeight", "brBoxY");
    oldArc = symbols2.arc;
    oldRoundedRect = symbols2.roundedRect;
    symbols2.arc = arc;
    symbols2.roundedRect = roundedRect;
  }
}
function optionsToObject$1(options2, seriesBROptions) {
  if (!isObject$e(options2)) {
    options2 = { radius: options2 || 0 };
  }
  return merge$1h(defaultBorderRadiusOptions, seriesBROptions, options2);
}
function pieSeriesOnAfterTranslate() {
  const borderRadius = optionsToObject$1(this.options.borderRadius);
  for (const point of this.points) {
    const shapeArgs = point.shapeArgs;
    if (shapeArgs) {
      shapeArgs.borderRadius = relativeLength$b(borderRadius.radius, (shapeArgs.r || 0) - (shapeArgs.innerR || 0));
    }
  }
}
function roundedRect(x, y, width, height, options2 = {}) {
  const path = oldRoundedRect(x, y, width, height, options2), { r = 0, brBoxHeight = height, brBoxY = y } = options2, brOffsetTop = y - brBoxY, brOffsetBtm = brBoxY + brBoxHeight - (y + height), rTop = brOffsetTop - r > -0.1 ? 0 : r, rBtm = brOffsetBtm - r > -0.1 ? 0 : r, cutTop = Math.max(rTop && brOffsetTop, 0), cutBtm = Math.max(rBtm && brOffsetBtm, 0);
  const a = [x + rTop, y], b = [x + width - rTop, y], c = [x + width, y + rTop], d = [
    x + width,
    y + height - rBtm
  ], e = [
    x + width - rBtm,
    y + height
  ], f = [x + rBtm, y + height], g = [x, y + height - rBtm], h = [x, y + rTop];
  const applyPythagoras = (r2, altitude) => Math.sqrt(Math.pow(r2, 2) - Math.pow(altitude, 2));
  if (cutTop) {
    const base2 = applyPythagoras(rTop, rTop - cutTop);
    a[0] -= base2;
    b[0] += base2;
    c[1] = h[1] = y + rTop - cutTop;
  }
  if (height < rTop - cutTop) {
    const base2 = applyPythagoras(rTop, rTop - cutTop - height);
    c[0] = d[0] = x + width - rTop + base2;
    e[0] = Math.min(c[0], e[0]);
    f[0] = Math.max(d[0], f[0]);
    g[0] = h[0] = x + rTop - base2;
    c[1] = h[1] = y + height;
  }
  if (cutBtm) {
    const base2 = applyPythagoras(rBtm, rBtm - cutBtm);
    e[0] += base2;
    f[0] -= base2;
    d[1] = g[1] = y + height - rBtm + cutBtm;
  }
  if (height < rBtm - cutBtm) {
    const base2 = applyPythagoras(rBtm, rBtm - cutBtm - height);
    c[0] = d[0] = x + width - rBtm + base2;
    b[0] = Math.min(c[0], b[0]);
    a[0] = Math.max(d[0], a[0]);
    g[0] = h[0] = x + rBtm - base2;
    d[1] = g[1] = y;
  }
  path.length = 0;
  path.push(
    ["M", ...a],
    // Top side
    ["L", ...b],
    // Top right corner
    ["A", rTop, rTop, 0, 0, 1, ...c],
    // Right side
    ["L", ...d],
    // Bottom right corner
    ["A", rBtm, rBtm, 0, 0, 1, ...e],
    // Bottom side
    ["L", ...f],
    // Bottom left corner
    ["A", rBtm, rBtm, 0, 0, 1, ...g],
    // Left side
    ["L", ...h],
    // Top left corner
    ["A", rTop, rTop, 0, 0, 1, ...a],
    ["Z"]
  );
  return path;
}
const BorderRadius = {
  compose: compose$p,
  optionsToObject: optionsToObject$1
};
const { diffObjects: diffObjects$2, extend: extend$12, find: find$e, merge: merge$1g, pick: pick$1n, uniqueKey: uniqueKey$4 } = Utilities;
var Responsive;
(function(Responsive2) {
  function compose2(ChartClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.matchResponsiveRule) {
      extend$12(chartProto, {
        matchResponsiveRule,
        setResponsive
      });
    }
    return ChartClass;
  }
  Responsive2.compose = compose2;
  function matchResponsiveRule(rule, matches) {
    const condition = rule.condition, fn = condition.callback || function() {
      return this.chartWidth <= pick$1n(condition.maxWidth, Number.MAX_VALUE) && this.chartHeight <= pick$1n(condition.maxHeight, Number.MAX_VALUE) && this.chartWidth >= pick$1n(condition.minWidth, 0) && this.chartHeight >= pick$1n(condition.minHeight, 0);
    };
    if (fn.call(this)) {
      matches.push(rule._id);
    }
  }
  function setResponsive(redraw, reset) {
    const options2 = this.options.responsive, currentResponsive = this.currentResponsive;
    let ruleIds = [], undoOptions;
    if (!reset && options2 && options2.rules) {
      options2.rules.forEach((rule) => {
        if (typeof rule._id === "undefined") {
          rule._id = uniqueKey$4();
        }
        this.matchResponsiveRule(
          rule,
          ruleIds
          /* , redraw */
        );
      }, this);
    }
    const mergedOptions = merge$1g(...ruleIds.map((ruleId) => find$e(options2?.rules || [], (rule) => rule._id === ruleId)).map((rule) => rule?.chartOptions));
    mergedOptions.isResponsiveOptions = true;
    ruleIds = ruleIds.toString() || void 0;
    const currentRuleIds = currentResponsive?.ruleIds;
    if (ruleIds !== currentRuleIds) {
      if (currentResponsive) {
        this.currentResponsive = void 0;
        this.updatingResponsive = true;
        this.update(currentResponsive.undoOptions, redraw, true);
        this.updatingResponsive = false;
      }
      if (ruleIds) {
        undoOptions = diffObjects$2(mergedOptions, this.options, true, this.collectionsWithUpdate);
        undoOptions.isResponsiveOptions = true;
        this.currentResponsive = {
          ruleIds,
          mergedOptions,
          undoOptions
        };
        if (!this.updatingResponsive) {
          this.update(mergedOptions, redraw, true);
        }
      } else {
        this.currentResponsive = void 0;
      }
    }
  }
})(Responsive || (Responsive = {}));
const Responsive$1 = Responsive;
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/highcharts
 *
 * (c) 2009-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$k = Highcharts;
G$k.AST = AST;
G$k.Axis = Axis;
G$k.Chart = Chart$1;
G$k.Color = Color;
G$k.DataLabel = DataLabel$1;
G$k.DataTableCore = DataTableCore;
G$k.Fx = Fx;
G$k.HTMLElement = HTMLElement$1;
G$k.Legend = Legend$1;
G$k.LegendSymbol = LegendSymbol$1;
G$k.OverlappingDataLabels = G$k.OverlappingDataLabels || OverlappingDataLabels;
G$k.PlotLineOrBand = PlotLineOrBand;
G$k.Point = Point$3;
G$k.Pointer = Pointer$1;
G$k.RendererRegistry = RendererRegistry$1;
G$k.Series = Series$9;
G$k.SeriesRegistry = SeriesRegistry$1;
G$k.StackItem = StackItem;
G$k.SVGElement = SVGElement$1;
G$k.SVGRenderer = SVGRenderer;
G$k.Templating = Templating;
G$k.Tick = Tick;
G$k.Time = Time;
G$k.Tooltip = Tooltip$1;
G$k.animate = animationExports.animate;
G$k.animObject = animationExports.animObject;
G$k.chart = Chart$1.chart;
G$k.color = Color.parse;
G$k.dateFormat = Templating.dateFormat;
G$k.defaultOptions = DefaultOptions.defaultOptions;
G$k.distribute = R$1.distribute;
G$k.format = Templating.format;
G$k.getDeferredAnimation = animationExports.getDeferredAnimation;
G$k.getOptions = DefaultOptions.getOptions;
G$k.numberFormat = Templating.numberFormat;
G$k.seriesType = SeriesRegistry$1.seriesType;
G$k.setAnimation = animationExports.setAnimation;
G$k.setOptions = DefaultOptions.setOptions;
G$k.stop = animationExports.stop;
G$k.time = DefaultOptions.defaultTime;
G$k.timers = Fx.timers;
BorderRadius.compose(G$k.Series, G$k.SVGElement, G$k.SVGRenderer);
ColumnDataLabel$2.compose(G$k.Series.types.column);
DataLabel$1.compose(G$k.Series);
DateTimeAxis$1.compose(G$k.Axis);
HTMLElement$1.compose(G$k.SVGRenderer);
Legend$1.compose(G$k.Chart);
LogarithmicAxis$1.compose(G$k.Axis);
OverlappingDataLabels.compose(G$k.Chart);
PieDataLabel.compose(G$k.Series.types.pie);
PlotLineOrBand.compose(G$k.Chart, G$k.Axis);
Pointer$1.compose(G$k.Chart);
Responsive$1.compose(G$k.Chart);
ScrollablePlotArea.compose(G$k.Axis, G$k.Chart, G$k.Series);
StackingAxis$1.compose(G$k.Axis, G$k.Chart, G$k.Series);
Tooltip$1.compose(G$k.Pointer);
Utilities.extend(G$k, Utilities);
const { tooltipFormatter: pointTooltipFormatter } = Point$3.prototype;
const { addEvent: addEvent$1e, arrayMax: arrayMax$6, arrayMin: arrayMin$5, correctFloat: correctFloat$b, defined: defined$W, isArray: isArray$g, isNumber: isNumber$Q, isString: isString$8, pick: pick$1m } = Utilities;
var DataModifyComposition;
(function(DataModifyComposition2) {
  function compose2(SeriesClass, AxisClass, PointClass) {
    const axisProto = AxisClass.prototype, pointProto2 = PointClass.prototype, seriesProto2 = SeriesClass.prototype;
    if (!seriesProto2.setCompare) {
      seriesProto2.setCompare = seriesSetCompare;
      seriesProto2.setCumulative = seriesSetCumulative;
      addEvent$1e(SeriesClass, "afterInit", afterInit);
      addEvent$1e(SeriesClass, "afterGetExtremes", afterGetExtremes);
      addEvent$1e(SeriesClass, "afterProcessData", afterProcessData);
    }
    if (!axisProto.setCompare) {
      axisProto.setCompare = axisSetCompare;
      axisProto.setModifier = setModifier;
      axisProto.setCumulative = axisSetCumulative;
      pointProto2.tooltipFormatter = tooltipFormatter;
    }
    return SeriesClass;
  }
  DataModifyComposition2.compose = compose2;
  function setModifier(mode2, modeState, redraw) {
    if (!this.isXAxis) {
      this.series.forEach(function(series) {
        if (mode2 === "compare" && typeof modeState !== "boolean") {
          series.setCompare(modeState, false);
        } else if (mode2 === "cumulative" && !isString$8(modeState)) {
          series.setCumulative(modeState, false);
        }
      });
      if (pick$1m(redraw, true)) {
        this.chart.redraw();
      }
    }
  }
  function tooltipFormatter(pointFormat) {
    const point = this, { numberFormatter } = point.series.chart, replace = function(value) {
      pointFormat = pointFormat.replace("{point." + value + "}", (point[value] > 0 && value === "change" ? "+" : "") + numberFormatter(point[value], pick$1m(point.series.tooltipOptions.changeDecimals, 2)));
    };
    if (defined$W(point.change)) {
      replace("change");
    }
    if (defined$W(point.cumulativeSum)) {
      replace("cumulativeSum");
    }
    return pointTooltipFormatter.apply(this, [pointFormat]);
  }
  function afterInit() {
    const compare = this.options.compare;
    let dataModify;
    if (compare === "percent" || compare === "value" || this.options.cumulative) {
      dataModify = new Additions(this);
      if (compare === "percent" || compare === "value") {
        dataModify.initCompare(compare);
      } else {
        dataModify.initCumulative();
      }
    }
    this.dataModify = dataModify;
  }
  function afterGetExtremes(e) {
    const dataExtremes = e.dataExtremes, activeYData = dataExtremes.activeYData;
    if (this.dataModify && dataExtremes) {
      let extremes;
      if (this.options.compare) {
        extremes = [
          this.dataModify.modifyValue(dataExtremes.dataMin),
          this.dataModify.modifyValue(dataExtremes.dataMax)
        ];
      } else if (this.options.cumulative && isArray$g(activeYData) && // If only one y visible, sum doesn't change
      // so no need to change extremes
      activeYData.length >= 2) {
        extremes = Additions.getCumulativeExtremes(activeYData);
      }
      if (extremes) {
        dataExtremes.dataMin = arrayMin$5(extremes);
        dataExtremes.dataMax = arrayMax$6(extremes);
      }
    }
  }
  function seriesSetCompare(compare, redraw) {
    this.options.compare = this.userOptions.compare = compare;
    this.update({}, pick$1m(redraw, true));
    if (this.dataModify && (compare === "value" || compare === "percent")) {
      this.dataModify.initCompare(compare);
    } else {
      this.points.forEach((point) => {
        delete point.change;
      });
    }
  }
  function afterProcessData() {
    const series = this, compareColumn = this.getColumn(series.pointArrayMap && (series.options.pointValKey || series.pointValKey) || "y", true);
    if (series.xAxis && // Not pies
    compareColumn.length && series.dataModify) {
      const processedXData = series.getColumn("x", true), length = series.dataTable.rowCount, compareStart = series.options.compareStart === true ? 0 : 1;
      for (let i = 0; i < length - compareStart; i++) {
        const compareValue = compareColumn[i];
        if (isNumber$Q(compareValue) && compareValue !== 0 && processedXData[i + compareStart] >= (series.xAxis.min || 0)) {
          series.dataModify.compareValue = compareValue;
          break;
        }
      }
    }
  }
  function axisSetCompare(compare, redraw) {
    this.setModifier("compare", compare, redraw);
  }
  function seriesSetCumulative(cumulative, redraw) {
    cumulative = pick$1m(cumulative, false);
    this.options.cumulative = this.userOptions.cumulative = cumulative;
    this.update({}, pick$1m(redraw, true));
    if (this.dataModify) {
      this.dataModify.initCumulative();
    } else {
      this.points.forEach((point) => {
        delete point.cumulativeSum;
      });
    }
  }
  function axisSetCumulative(cumulative, redraw) {
    this.setModifier("cumulative", cumulative, redraw);
  }
  class Additions {
    /* *
     *
     *  Constructors
     *
     * */
    /**
     * @private
     */
    constructor(series) {
      this.series = series;
    }
    /* *
    *
    *  Functions
    *
    * */
    /**
     * @private
     */
    modifyValue() {
      return 0;
    }
    /**
     * @ignore
     * @function Highcharts.Series#getCumulativeExtremes
     *
     * @param {Array} [activeYData]
     *        An array cointaining all the points' y values
     *        in a visible range.
     */
    static getCumulativeExtremes(activeYData) {
      let cumulativeDataMin = Infinity, cumulativeDataMax = -Infinity;
      activeYData.reduce((prev, cur) => {
        const sum2 = prev + cur;
        cumulativeDataMin = Math.min(cumulativeDataMin, sum2, prev);
        cumulativeDataMax = Math.max(cumulativeDataMax, sum2, prev);
        return sum2;
      });
      return [cumulativeDataMin, cumulativeDataMax];
    }
    /**
     * @ignore
     * @function Highcharts.Series#initCompare
     *
     * @param {string} [compare]
     *        Can be one of `"percent"` or `"value"`.
     */
    initCompare(compare) {
      this.modifyValue = function(value, index) {
        if (value === null) {
          value = 0;
        }
        const compareValue = this.compareValue;
        if (typeof value !== "undefined" && typeof compareValue !== "undefined") {
          if (compare === "value") {
            value -= compareValue;
          } else {
            const compareBase = this.series.options.compareBase;
            value = 100 * (value / compareValue) - (compareBase === 100 ? 0 : 100);
          }
          if (typeof index !== "undefined") {
            const point = this.series.points[index];
            if (point) {
              point.change = value;
            }
          }
          return value;
        }
        return 0;
      };
    }
    /**
     * @ignore
     * @function Highcharts.Series#initCumulative
     */
    initCumulative() {
      this.modifyValue = function(value, index) {
        if (value === null) {
          value = 0;
        }
        if (value !== void 0 && index !== void 0) {
          const prevPoint = index > 0 ? this.series.points[index - 1] : null;
          if (prevPoint && prevPoint.cumulativeSum) {
            value = correctFloat$b(prevPoint.cumulativeSum + value);
          }
          const point = this.series.points[index];
          const cumulativeStart = point.series.options.cumulativeStart, withinRange = point.x <= this.series.xAxis.max && point.x >= this.series.xAxis.min;
          if (point) {
            if (!cumulativeStart || withinRange) {
              point.cumulativeSum = value;
            } else {
              point.cumulativeSum = void 0;
            }
          }
          return value;
        }
        return 0;
      };
    }
  }
  DataModifyComposition2.Additions = Additions;
})(DataModifyComposition || (DataModifyComposition = {}));
const DataModifyComposition$1 = DataModifyComposition;
const { isTouchDevice: isTouchDevice$4 } = Highcharts;
const { addEvent: addEvent$1d, merge: merge$1f, pick: pick$1l } = Utilities;
const composedMembers = [];
let NavigatorConstructor;
function compose$o(ChartClass, NavigatorClass) {
  if (Utilities.pushUnique(composedMembers, ChartClass)) {
    const chartProto = ChartClass.prototype;
    NavigatorConstructor = NavigatorClass;
    chartProto.callbacks.push(onChartCallback);
    addEvent$1d(ChartClass, "afterAddSeries", onChartAfterAddSeries);
    addEvent$1d(ChartClass, "afterSetChartSize", onChartAfterSetChartSize$1);
    addEvent$1d(ChartClass, "afterUpdate", onChartAfterUpdate);
    addEvent$1d(ChartClass, "beforeRender", onChartBeforeRender$2);
    addEvent$1d(ChartClass, "beforeShowResetZoom", onChartBeforeShowResetZoom);
    addEvent$1d(ChartClass, "update", onChartUpdate$1);
  }
}
function onChartAfterAddSeries() {
  if (this.navigator) {
    this.navigator.setBaseSeries(null, false);
  }
}
function onChartAfterSetChartSize$1() {
  const legend = this.legend, navigator2 = this.navigator;
  let legendOptions, xAxis2, yAxis2;
  if (navigator2) {
    legendOptions = legend && legend.options;
    xAxis2 = navigator2.xAxis;
    yAxis2 = navigator2.yAxis;
    const { scrollbarHeight, scrollButtonSize } = navigator2;
    if (this.inverted) {
      navigator2.left = navigator2.opposite ? this.chartWidth - scrollbarHeight - navigator2.height : this.spacing[3] + scrollbarHeight;
      navigator2.top = this.plotTop + scrollButtonSize;
    } else {
      navigator2.left = pick$1l(xAxis2.left, this.plotLeft + scrollButtonSize);
      navigator2.top = navigator2.navigatorOptions.top || this.chartHeight - navigator2.height - scrollbarHeight - (this.scrollbar?.options.margin || 0) - this.spacing[2] - (this.rangeSelector && this.extraBottomMargin ? this.rangeSelector.getHeight() : 0) - (legendOptions && legendOptions.verticalAlign === "bottom" && legendOptions.layout !== "proximate" && // #13392
      legendOptions.enabled && !legendOptions.floating ? legend.legendHeight + pick$1l(legendOptions.margin, 10) : 0) - (this.titleOffset ? this.titleOffset[2] : 0);
    }
    if (xAxis2 && yAxis2) {
      if (this.inverted) {
        xAxis2.options.left = yAxis2.options.left = navigator2.left;
      } else {
        xAxis2.options.top = yAxis2.options.top = navigator2.top;
      }
      xAxis2.setAxisSize();
      yAxis2.setAxisSize();
    }
  }
}
function onChartAfterUpdate(event) {
  if (!this.navigator && !this.scroller && (this.options.navigator.enabled || this.options.scrollbar.enabled)) {
    this.scroller = this.navigator = new NavigatorConstructor(this);
    if (pick$1l(event.redraw, true)) {
      this.redraw(event.animation);
    }
  }
}
function onChartBeforeRender$2() {
  const options2 = this.options;
  if (options2.navigator.enabled || options2.scrollbar.enabled) {
    this.scroller = this.navigator = new NavigatorConstructor(this);
  }
}
function onChartBeforeShowResetZoom() {
  const chartOptions = this.options, navigator2 = chartOptions.navigator, rangeSelector2 = chartOptions.rangeSelector;
  if ((navigator2 && navigator2.enabled || rangeSelector2 && rangeSelector2.enabled) && (!isTouchDevice$4 && this.zooming.type === "x" || isTouchDevice$4 && this.zooming.pinchType === "x")) {
    return false;
  }
}
function onChartCallback(chart) {
  const navigator2 = chart.navigator;
  if (navigator2 && chart.xAxis[0]) {
    const extremes = chart.xAxis[0].getExtremes();
    navigator2.render(extremes.min, extremes.max);
  }
}
function onChartUpdate$1(e) {
  const navigatorOptions = e.options.navigator || {}, scrollbarOptions = e.options.scrollbar || {};
  if (!this.navigator && !this.scroller && (navigatorOptions.enabled || scrollbarOptions.enabled)) {
    merge$1f(true, this.options.navigator, navigatorOptions);
    merge$1f(true, this.options.scrollbar, scrollbarOptions);
    delete e.options.navigator;
    delete e.options.scrollbar;
  }
}
const ChartNavigatorComposition = {
  compose: compose$o
};
const { isTouchDevice: isTouchDevice$3 } = Highcharts;
const { addEvent: addEvent$1c, correctFloat: correctFloat$a, defined: defined$V, isNumber: isNumber$P, pick: pick$1k } = Utilities;
function onAxisInit$1() {
  const axis = this;
  if (!axis.navigatorAxis) {
    axis.navigatorAxis = new NavigatorAxisAdditions(axis);
  }
}
function onAxisSetExtremes(e) {
  const axis = this, chart = axis.chart, chartOptions = chart.options, navigator2 = chartOptions.navigator, navigatorAxis = axis.navigatorAxis, pinchType = chart.zooming.pinchType, rangeSelector2 = chartOptions.rangeSelector, zoomType = chart.zooming.type;
  let zoomed;
  if (axis.isXAxis && (navigator2?.enabled || rangeSelector2?.enabled)) {
    if (zoomType === "y" && e.trigger === "zoom") {
      zoomed = false;
    } else if ((e.trigger === "zoom" && zoomType === "xy" || isTouchDevice$3 && pinchType === "xy") && axis.options.range) {
      const previousZoom = navigatorAxis.previousZoom;
      if (defined$V(e.min)) {
        navigatorAxis.previousZoom = [axis.min, axis.max];
      } else if (previousZoom) {
        e.min = previousZoom[0];
        e.max = previousZoom[1];
        navigatorAxis.previousZoom = void 0;
      }
    }
  }
  if (typeof zoomed !== "undefined") {
    e.preventDefault();
  }
}
class NavigatorAxisAdditions {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static compose(AxisClass) {
    if (!AxisClass.keepProps.includes("navigatorAxis")) {
      AxisClass.keepProps.push("navigatorAxis");
      addEvent$1c(AxisClass, "init", onAxisInit$1);
      addEvent$1c(AxisClass, "setExtremes", onAxisSetExtremes);
    }
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(axis) {
    this.axis = axis;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  destroy() {
    this.axis = void 0;
  }
  /**
   * Add logic to normalize the zoomed range in order to preserve the pressed
   * state of range selector buttons
   *
   * @private
   * @function Highcharts.Axis#toFixedRange
   */
  toFixedRange(pxMin, pxMax, fixedMin, fixedMax) {
    const axis = this.axis, halfPointRange = (axis.pointRange || 0) / 2;
    let newMin = pick$1k(fixedMin, axis.translate(pxMin, true, !axis.horiz)), newMax = pick$1k(fixedMax, axis.translate(pxMax, true, !axis.horiz));
    if (!defined$V(fixedMin)) {
      newMin = correctFloat$a(newMin + halfPointRange);
    }
    if (!defined$V(fixedMax)) {
      newMax = correctFloat$a(newMax - halfPointRange);
    }
    if (!isNumber$P(newMin) || !isNumber$P(newMax)) {
      newMin = newMax = void 0;
    }
    return {
      min: newMin,
      max: newMax
    };
  }
}
const { parse: color$9 } = Color;
const { seriesTypes: seriesTypes$3 } = SeriesRegistry$1;
const NavigatorDefaults = {
  /**
   * Whether the navigator and scrollbar should adapt to updated data
   * in the base X axis. When loading data async, as in the demo below,
   * this should be `false`. Otherwise new data will trigger navigator
   * redraw, which will cause unwanted looping. In the demo below, the
   * data in the navigator is set only once. On navigating, only the main
   * chart content is updated.
   *
   * @sample {highstock} stock/demo/lazy-loading/
   *         Set to false with async data loading
   *
   * @type      {boolean}
   * @default   true
   * @apioption navigator.adaptToUpdatedData
   */
  /**
   * An integer identifying the index to use for the base series, or a
   * string representing the id of the series.
   *
   * **Note**: As of Highcharts 5.0, this is now a deprecated option.
   * Prefer [series.showInNavigator](#plotOptions.series.showInNavigator).
   *
   * @see [series.showInNavigator](#plotOptions.series.showInNavigator)
   *
   * @deprecated
   * @type      {number|string}
   * @default   0
   * @apioption navigator.baseSeries
   */
  /**
   * Enable or disable the navigator.
   *
   * @sample {highstock} stock/navigator/enabled/
   *         Disable the navigator
   *
   * @type      {boolean}
   * @default   true
   * @apioption navigator.enabled
   */
  /**
   * When the chart is inverted, whether to draw the navigator on the
   * opposite side.
   *
   * @type      {boolean}
   * @default   false
   * @since     5.0.8
   * @apioption navigator.opposite
   */
  /**
   * The height of the navigator.
   *
   * @sample {highstock} stock/navigator/height/
   *         A higher navigator
   */
  height: 40,
  /**
   * The distance from the nearest element, the X axis or X axis labels.
   *
   * @sample {highstock} stock/navigator/margin/
   *         A margin of 2 draws the navigator closer to the X axis labels
   */
  margin: 22,
  /**
   * Whether the mask should be inside the range marking the zoomed
   * range, or outside. In Highcharts Stock 1.x it was always `false`.
   *
   * @sample {highstock} stock/demo/maskinside-false/
   *         False, mask outside
   *
   * @since   2.0
   */
  maskInside: true,
  /**
   * Options for the handles for dragging the zoomed area.
   *
   * @sample {highstock} stock/navigator/handles/
   *         Colored handles
   */
  handles: {
    /**
     * Width for handles.
     *
     * @sample {highstock} stock/navigator/styled-handles/
     *         Styled handles
     *
     * @since   6.0.0
     */
    width: 7,
    /**
     * Border radius of the handles.
     *
     * @sample {highstock} stock/navigator/handles-border-radius/
     *      Border radius on the navigator handles.
     *
     * @since 11.4.2
     */
    borderRadius: 0,
    /**
     * Height for handles.
     *
     * @sample {highstock} stock/navigator/styled-handles/
     *         Styled handles
     *
     * @since   6.0.0
     */
    height: 15,
    /**
     * Array to define shapes of handles. 0-index for left, 1-index for
     * right.
     *
     * Additionally, the URL to a graphic can be given on this form:
     * `url(graphic.png)`. Note that for the image to be applied to
     * exported charts, its URL needs to be accessible by the export
     * server.
     *
     * Custom callbacks for symbol path generation can also be added to
     * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
     * used by its method name, as shown in the demo.
     *
     * @sample {highstock} stock/navigator/styled-handles/
     *         Styled handles
     *
     * @type    {Array<string>}
     * @default ["navigator-handle", "navigator-handle"]
     * @since   6.0.0
     */
    symbols: ["navigator-handle", "navigator-handle"],
    /**
     * Allows to enable/disable handles.
     *
     * @since   6.0.0
     */
    enabled: true,
    /**
     * The width for the handle border and the stripes inside.
     *
     * @sample {highstock} stock/navigator/styled-handles/
     *         Styled handles
     *
     * @since     6.0.0
     * @apioption navigator.handles.lineWidth
     */
    lineWidth: 1,
    /**
     * The fill for the handle.
     *
     * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    backgroundColor: "#f2f2f2",
    /**
     * The stroke for the handle border and the stripes inside.
     *
     * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    borderColor: "#999999"
    /* Palette.neutralColor40 */
  },
  /**
   * The color of the mask covering the areas of the navigator series
   * that are currently not visible in the main series. The default
   * color is bluish with an opacity of 0.3 to see the series below.
   *
   * @see In styled mode, the mask is styled with the
   *      `.highcharts-navigator-mask` and
   *      `.highcharts-navigator-mask-inside` classes.
   *
   * @sample {highstock} stock/navigator/maskfill/
   *         Blue, semi transparent mask
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default rgba(102,133,194,0.3)
   */
  maskFill: color$9(
    "#667aff"
    /* Palette.highlightColor60 */
  ).setOpacity(0.3).get(),
  /**
   * The color of the line marking the currently zoomed area in the
   * navigator.
   *
   * @sample {highstock} stock/navigator/outline/
   *         2px blue outline
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default #cccccc
   */
  outlineColor: "#999999",
  /**
   * The width of the line marking the currently zoomed area in the
   * navigator.
   *
   * @see In styled mode, the outline stroke width is set with the
   *      `.highcharts-navigator-outline` class.
   *
   * @sample {highstock} stock/navigator/outline/
   *         2px blue outline
   *
   * @type    {number}
   */
  outlineWidth: 1,
  /**
   * Options for the navigator series. Available options are the same
   * as any series, documented at [plotOptions](#plotOptions.series)
   * and [series](#series).
   *
   * Unless data is explicitly defined on navigator.series, the data
   * is borrowed from the first series in the chart.
   *
   * Default series options for the navigator series are:
   * ```js
   * series: {
   *     type: 'areaspline',
   *     fillOpacity: 0.05,
   *     dataGrouping: {
   *         smoothed: true
   *     },
   *     lineWidth: 1,
   *     marker: {
   *         enabled: false
   *     }
   * }
   * ```
   *
   * @see In styled mode, the navigator series is styled with the
   *      `.highcharts-navigator-series` class.
   *
   * @sample {highstock} stock/navigator/series-data/
   *         Using a separate data set for the navigator
   * @sample {highstock} stock/navigator/series/
   *         A green navigator series
   *
   * @type {*|Array<*>|Highcharts.SeriesOptionsType|Array<Highcharts.SeriesOptionsType>}
   */
  series: {
    /**
     * The type of the navigator series.
     *
     * Heads up:
     * In column-type navigator, zooming is limited to at least one
     * point with its `pointRange`.
     *
     * @sample {highstock} stock/navigator/column/
     *         Column type navigator
     *
     * @type    {string}
     * @default {highstock} `areaspline` if defined, otherwise `line`
     * @default {gantt} gantt
     */
    type: typeof seriesTypes$3.areaspline === "undefined" ? "line" : "areaspline",
    /**
     * The fill opacity of the navigator series.
     */
    fillOpacity: 0.05,
    /**
     * The pixel line width of the navigator series.
     */
    lineWidth: 1,
    /**
     * @ignore-option
     */
    compare: null,
    /**
     * @ignore-option
     */
    sonification: {
      enabled: false
    },
    /**
     * Unless data is explicitly defined, the data is borrowed from the
     * first series in the chart.
     *
     * @type      {Array<number|Array<number|string|null>|object|null>}
     * @product   highstock
     * @apioption navigator.series.data
     */
    /**
     * Data grouping options for the navigator series.
     *
     * @extends plotOptions.series.dataGrouping
     */
    dataGrouping: {
      approximation: "average",
      enabled: true,
      groupPixelWidth: 2,
      // Replace smoothed property by anchors, #12455.
      firstAnchor: "firstPoint",
      anchor: "middle",
      lastAnchor: "lastPoint",
      // Day and week differs from plotOptions.series.dataGrouping
      units: [
        ["millisecond", [1, 2, 5, 10, 20, 25, 50, 100, 200, 500]],
        ["second", [1, 2, 5, 10, 15, 30]],
        ["minute", [1, 2, 5, 10, 15, 30]],
        ["hour", [1, 2, 3, 4, 6, 8, 12]],
        ["day", [1, 2, 3, 4]],
        ["week", [1, 2, 3]],
        ["month", [1, 3, 6]],
        ["year", null]
      ]
    },
    /**
     * Data label options for the navigator series. Data labels are
     * disabled by default on the navigator series.
     *
     * @extends plotOptions.series.dataLabels
     */
    dataLabels: {
      enabled: false,
      zIndex: 2
      // #1839
    },
    id: "highcharts-navigator-series",
    className: "highcharts-navigator-series",
    /**
     * Sets the fill color of the navigator series.
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption navigator.series.color
     */
    /**
     * Line color for the navigator series. Allows setting the color
     * while disallowing the default candlestick setting.
     *
     * @type {Highcharts.ColorString|null}
     */
    lineColor: null,
    // #4602
    marker: {
      enabled: false
    },
    /**
     * Since Highcharts Stock v8, default value is the same as default
     * `pointRange` defined for a specific type (e.g. `null` for
     * column type).
     *
     * In Highcharts Stock version < 8, defaults to 0.
     *
     * @extends plotOptions.series.pointRange
     * @type {number|null}
     * @apioption navigator.series.pointRange
     */
    /**
     * The threshold option. Setting it to 0 will make the default
     * navigator area series draw its area from the 0 value and up.
     *
     * @type {number|null}
     */
    threshold: null
  },
  /**
   * Enable or disable navigator sticking to right, while adding new
   * points. If `undefined`, the navigator sticks to the axis maximum only
   * if it was already at the maximum prior to adding points.
   *
   * @type      {boolean}
   * @default   undefined
   * @since 10.2.1
   * @sample {highstock} stock/navigator/sticktomax-false/
   * stickToMax set to false
   * @apioption navigator.stickToMax
   */
  /**
   * Options for the navigator X axis. Default series options for the
   * navigator xAxis are:
   * ```js
   * xAxis: {
   *     tickWidth: 0,
   *     lineWidth: 0,
   *     gridLineWidth: 1,
   *     tickPixelInterval: 200,
   *     labels: {
   *            align: 'left',
   *         style: {
   *             color: '#888'
   *         },
   *         x: 3,
   *         y: -4
   *     }
   * }
   * ```
   *
   * @extends   xAxis
   * @excluding linkedTo, maxZoom, minRange, opposite, range, scrollbar,
   *            showEmpty, maxRange
   */
  xAxis: {
    /**
     * Additional range on the right side of the xAxis. Works similar to
     * `xAxis.maxPadding`, but the value is set in terms of axis values,
     * percentage or pixels.
     *
     * If it's a number, it is interpreted as axis values, which in a
     * datetime axis equals milliseconds.
     *
     * If it's a percentage string, is interpreted as percentages of the
     * axis length. An overscroll of 50% will make a 100px axis 50px longer.
     *
     * If it's a pixel string, it is interpreted as a fixed pixel value, but
     * limited to 90% of the axis length.
     *
     * If it's undefined, the value is inherited from `xAxis.overscroll`.
     *
     * Can be set for both, main xAxis and navigator's xAxis.
     *
     * @type    {number | string | undefined}
     * @since   6.0.0
     * @apioption navigator.xAxis.overscroll
     */
    className: "highcharts-navigator-xaxis",
    tickLength: 0,
    lineWidth: 0,
    gridLineColor: "#e6e6e6",
    id: "navigator-x-axis",
    gridLineWidth: 1,
    tickPixelInterval: 200,
    labels: {
      align: "left",
      /**
       * @type {Highcharts.CSSObject}
       */
      style: {
        /** @ignore */
        color: "#000000",
        /** @ignore */
        fontSize: "0.7em",
        /** @ignore */
        opacity: 0.6,
        /** @ignore */
        textOutline: "2px contrast"
      },
      x: 3,
      y: -4
    },
    crosshair: false
  },
  /**
   * Options for the navigator Y axis. Default series options for the
   * navigator yAxis are:
   * ```js
   * yAxis: {
   *     gridLineWidth: 0,
   *     startOnTick: false,
   *     endOnTick: false,
   *     minPadding: 0.1,
   *     maxPadding: 0.1,
   *     labels: {
   *         enabled: false
   *     },
   *     title: {
   *         text: null
   *     },
   *     tickWidth: 0
   * }
   * ```
   *
   * @extends   yAxis
   * @excluding height, linkedTo, maxZoom, minRange, ordinal, range,
   *            showEmpty, scrollbar, top, units, maxRange, minLength,
   *            maxLength, resize
   */
  yAxis: {
    className: "highcharts-navigator-yaxis",
    gridLineWidth: 0,
    startOnTick: false,
    endOnTick: false,
    minPadding: 0.1,
    id: "navigator-y-axis",
    maxPadding: 0.1,
    labels: {
      enabled: false
    },
    crosshair: false,
    title: {
      text: void 0
    },
    tickLength: 0,
    tickWidth: 0
  }
};
const { relativeLength: relativeLength$a } = Utilities;
function navigatorHandle(_x, _y, width, height, options2 = {}) {
  const halfWidth = options2.width ? options2.width / 2 : width, markerPosition = 1.5, r = relativeLength$a(options2.borderRadius || 0, Math.min(halfWidth * 2, height));
  height = options2.height || height;
  return [
    ["M", -markerPosition, height / 2 - 3.5],
    ["L", -markerPosition, height / 2 + 4.5],
    ["M", markerPosition - 1, height / 2 - 3.5],
    ["L", markerPosition - 1, height / 2 + 4.5],
    ...Symbols.rect(-halfWidth - 1, 0.5, halfWidth * 2 + 1, height, { r })
  ];
}
const NavigatorSymbols = {
  "navigator-handle": navigatorHandle
};
const { defined: defined$U } = Utilities;
function setFixedRange$2(range2) {
  const xAxis2 = this.xAxis[0];
  if (defined$U(xAxis2.dataMax) && defined$U(xAxis2.dataMin) && range2) {
    this.fixedRange = Math.min(range2, xAxis2.dataMax - xAxis2.dataMin);
  } else {
    this.fixedRange = range2;
  }
}
const StockUtilities = {
  setFixedRange: setFixedRange$2
};
const { setOptions: setOptions$3 } = DefaultOptions;
const { composed: composed$r } = Highcharts;
const { getRendererType } = RendererRegistry$1;
const { setFixedRange: setFixedRange$1 } = StockUtilities;
const { addEvent: addEvent$1b, extend: extend$11, pushUnique: pushUnique$r } = Utilities;
function compose$n(ChartClass, AxisClass, SeriesClass) {
  NavigatorAxisAdditions.compose(AxisClass);
  if (pushUnique$r(composed$r, "Navigator")) {
    ChartClass.prototype.setFixedRange = setFixedRange$1;
    extend$11(getRendererType().prototype.symbols, NavigatorSymbols);
    addEvent$1b(SeriesClass, "afterUpdate", onSeriesAfterUpdate);
    setOptions$3({ navigator: NavigatorDefaults });
  }
}
function onSeriesAfterUpdate() {
  if (this.chart.navigator && !this.options.isInternal) {
    this.chart.navigator.setBaseSeries(null, false);
  }
}
const NavigatorComposition = {
  compose: compose$n
};
const { composed: composed$q } = Highcharts;
const { addEvent: addEvent$1a, defined: defined$T, pick: pick$1j, pushUnique: pushUnique$q } = Utilities;
var ScrollbarAxis;
(function(ScrollbarAxis2) {
  let Scrollbar2;
  function compose2(AxisClass, ScrollbarClass) {
    if (pushUnique$q(composed$q, "Axis.Scrollbar")) {
      Scrollbar2 = ScrollbarClass;
      addEvent$1a(AxisClass, "afterGetOffset", onAxisAfterGetOffset);
      addEvent$1a(AxisClass, "afterInit", onAxisAfterInit);
      addEvent$1a(AxisClass, "afterRender", onAxisAfterRender2);
    }
  }
  ScrollbarAxis2.compose = compose2;
  function getExtremes(axis) {
    const axisMin = pick$1j(axis.options?.min, axis.min);
    const axisMax2 = pick$1j(axis.options?.max, axis.max);
    return {
      axisMin,
      axisMax: axisMax2,
      scrollMin: defined$T(axis.dataMin) ? Math.min(axisMin, axis.min, axis.dataMin, pick$1j(axis.threshold, Infinity)) : axisMin,
      scrollMax: defined$T(axis.dataMax) ? Math.max(axisMax2, axis.max, axis.dataMax, pick$1j(axis.threshold, -Infinity)) : axisMax2
    };
  }
  function onAxisAfterGetOffset() {
    const axis = this, scrollbar = axis.scrollbar, opposite = scrollbar && !scrollbar.options.opposite, index = axis.horiz ? 2 : opposite ? 3 : 1;
    if (scrollbar) {
      axis.chart.scrollbarsOffsets = [0, 0];
      axis.chart.axisOffset[index] += scrollbar.size + (scrollbar.options.margin || 0);
    }
  }
  function onAxisAfterInit() {
    const axis = this;
    if (axis.options?.scrollbar?.enabled) {
      axis.options.scrollbar.vertical = !axis.horiz;
      axis.options.startOnTick = axis.options.endOnTick = false;
      axis.scrollbar = new Scrollbar2(axis.chart.renderer, axis.options.scrollbar, axis.chart);
      addEvent$1a(axis.scrollbar, "changed", function(e) {
        const { axisMin, axisMax: axisMax2, scrollMin: unitedMin, scrollMax: unitedMax } = getExtremes(axis), range2 = unitedMax - unitedMin;
        let to, from;
        if (!defined$T(axisMin) || !defined$T(axisMax2)) {
          return;
        }
        if (axis.horiz && !axis.reversed || !axis.horiz && axis.reversed) {
          to = unitedMin + range2 * this.to;
          from = unitedMin + range2 * this.from;
        } else {
          to = unitedMin + range2 * (1 - this.from);
          from = unitedMin + range2 * (1 - this.to);
        }
        if (this.shouldUpdateExtremes(e.DOMType)) {
          const animate2 = e.DOMType === "mousemove" || e.DOMType === "touchmove" ? false : void 0;
          axis.setExtremes(from, to, true, animate2, e);
        } else {
          this.setRange(this.from, this.to);
        }
      });
    }
  }
  function onAxisAfterRender2() {
    const axis = this, { scrollMin, scrollMax } = getExtremes(axis), scrollbar = axis.scrollbar, offset2 = axis.axisTitleMargin + (axis.titleOffset || 0), scrollbarsOffsets = axis.chart.scrollbarsOffsets, axisMargin = axis.options.margin || 0;
    let offsetsIndex, from, to;
    if (scrollbar && scrollbarsOffsets) {
      if (axis.horiz) {
        if (!axis.opposite) {
          scrollbarsOffsets[1] += offset2;
        }
        scrollbar.position(axis.left, axis.top + axis.height + 2 + scrollbarsOffsets[1] - (axis.opposite ? axisMargin : 0), axis.width, axis.height);
        if (!axis.opposite) {
          scrollbarsOffsets[1] += axisMargin;
        }
        offsetsIndex = 1;
      } else {
        if (axis.opposite) {
          scrollbarsOffsets[0] += offset2;
        }
        let xPosition;
        if (!scrollbar.options.opposite) {
          xPosition = axis.opposite ? 0 : axisMargin;
        } else {
          xPosition = axis.left + axis.width + 2 + scrollbarsOffsets[0] - (axis.opposite ? 0 : axisMargin);
        }
        scrollbar.position(xPosition, axis.top, axis.width, axis.height);
        if (axis.opposite) {
          scrollbarsOffsets[0] += axisMargin;
        }
        offsetsIndex = 0;
      }
      scrollbarsOffsets[offsetsIndex] += scrollbar.size + (scrollbar.options.margin || 0);
      if (isNaN(scrollMin) || isNaN(scrollMax) || !defined$T(axis.min) || !defined$T(axis.max) || axis.dataMin === axis.dataMax) {
        scrollbar.setRange(0, 1);
      } else if (axis.min === axis.max) {
        const interval = axis.pointRange / (axis.dataMax + 1);
        from = interval * axis.min;
        to = interval * (axis.max + 1);
        scrollbar.setRange(from, to);
      } else {
        from = (axis.min - scrollMin) / (scrollMax - scrollMin);
        to = (axis.max - scrollMin) / (scrollMax - scrollMin);
        if (axis.horiz && !axis.reversed || !axis.horiz && axis.reversed) {
          scrollbar.setRange(from, to);
        } else {
          scrollbar.setRange(1 - to, 1 - from);
        }
      }
    }
  }
})(ScrollbarAxis || (ScrollbarAxis = {}));
const ScrollbarAxis$1 = ScrollbarAxis;
const ScrollbarDefaults = {
  /**
   * The height of the scrollbar. If `buttonsEnabled` is true , the height
   * also applies to the width of the scroll arrows so that they are always
   * squares.
   *
   * @sample stock/scrollbar/style/
   *         Non-default height
   *
   * @type    {number}
   */
  height: 10,
  /**
   * The border rounding radius of the bar.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   */
  barBorderRadius: 5,
  /**
   * The corner radius of the scrollbar buttons.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   */
  buttonBorderRadius: 0,
  /**
   * Enable or disable the buttons at the end of the scrollbar.
   *
   * @since 11.0.0
   */
  buttonsEnabled: false,
  /**
   * Enable or disable the scrollbar.
   *
   * @sample stock/scrollbar/enabled/
   *         Disable the scrollbar, only use navigator
   *
   * @type      {boolean}
   * @default   true
   * @apioption scrollbar.enabled
   */
  /**
   * Whether to redraw the main chart as the scrollbar or the navigator
   * zoomed window is moved. Defaults to `true` for modern browsers and
   * `false` for legacy IE browsers as well as mobile devices.
   *
   * @sample stock/scrollbar/liveredraw
   *         Setting live redraw to false
   *
   * @type  {boolean}
   * @since 1.3
   */
  liveRedraw: void 0,
  /**
   * The margin between the scrollbar and its axis when the scrollbar is
   * applied directly to an axis, or the navigator in case that is enabled.
   * Defaults to 10 for axis, 3 for navigator.
   *
   * @type {number|undefined}
   */
  margin: void 0,
  /**
   * The minimum width of the scrollbar.
   *
   * @since 1.2.5
   */
  minWidth: 6,
  /** @ignore-option */
  opposite: true,
  /**
   * Whether to show or hide the scrollbar when the scrolled content is
   * zoomed out to it full extent.
   *
   * @type      {boolean}
   * @default   true
   * @apioption scrollbar.showFull
   */
  step: 0.2,
  /**
   * The z index of the scrollbar group.
   */
  zIndex: 3,
  /**
   * The background color of the scrollbar itself.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  barBackgroundColor: "#cccccc",
  /**
   * The width of the bar's border.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   */
  barBorderWidth: 0,
  /**
   * The color of the scrollbar's border.
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  barBorderColor: "#cccccc",
  /**
   * The color of the small arrow inside the scrollbar buttons.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  buttonArrowColor: "#333333",
  /**
   * The color of scrollbar buttons.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  buttonBackgroundColor: "#e6e6e6",
  /**
   * The color of the border of the scrollbar buttons.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  buttonBorderColor: "#cccccc",
  /**
   * The border width of the scrollbar buttons.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   */
  buttonBorderWidth: 1,
  /**
   * The color of the small rifles in the middle of the scrollbar.
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  rifleColor: "none",
  /**
   * The color of the track background.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  trackBackgroundColor: "rgba(255, 255, 255, 0.001)",
  // #18922
  /**
   * The color of the border of the scrollbar track.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  trackBorderColor: "#cccccc",
  /**
   * The corner radius of the border of the scrollbar track.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   */
  trackBorderRadius: 5,
  /**
   * The width of the border of the scrollbar track.
   *
   * @sample stock/scrollbar/style/
   *         Scrollbar styling
   */
  trackBorderWidth: 1
};
const { defaultOptions: defaultOptions$e } = DefaultOptions;
const { addEvent: addEvent$19, correctFloat: correctFloat$9, crisp: crisp$a, defined: defined$S, destroyObjectProperties: destroyObjectProperties$3, fireEvent: fireEvent$s, merge: merge$1e, pick: pick$1i, removeEvent: removeEvent$6 } = Utilities;
class Scrollbar {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AxisClass) {
    ScrollbarAxis$1.compose(AxisClass, Scrollbar);
  }
  /**
   * When we have vertical scrollbar, rifles and arrow in buttons should be
   * rotated. The same method is used in Navigator's handles, to rotate them.
   *
   * @function Highcharts.swapXY
   *
   * @param {Highcharts.SVGPathArray} path
   * Path to be rotated.
   *
   * @param {boolean} [vertical]
   * If vertical scrollbar, swap x-y values.
   *
   * @return {Highcharts.SVGPathArray}
   * Rotated path.
   *
   * @requires modules/stock
   */
  static swapXY(path, vertical) {
    if (vertical) {
      path.forEach((seg) => {
        const len = seg.length;
        let temp;
        for (let i = 0; i < len; i += 2) {
          temp = seg[i + 1];
          if (typeof temp === "number") {
            seg[i + 1] = seg[i + 2];
            seg[i + 2] = temp;
          }
        }
      });
    }
    return path;
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(renderer, options2, chart) {
    this._events = [];
    this.chartX = 0;
    this.chartY = 0;
    this.from = 0;
    this.scrollbarButtons = [];
    this.scrollbarLeft = 0;
    this.scrollbarStrokeWidth = 1;
    this.scrollbarTop = 0;
    this.size = 0;
    this.to = 0;
    this.trackBorderWidth = 1;
    this.x = 0;
    this.y = 0;
    this.init(renderer, options2, chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Set up the mouse and touch events for the Scrollbar
   *
   * @private
   * @function Highcharts.Scrollbar#addEvents
   */
  addEvents() {
    const buttonsOrder = this.options.inverted ? [1, 0] : [0, 1], buttons = this.scrollbarButtons, bar = this.scrollbarGroup.element, track = this.track.element, mouseDownHandler = this.mouseDownHandler.bind(this), mouseMoveHandler = this.mouseMoveHandler.bind(this), mouseUpHandler = this.mouseUpHandler.bind(this);
    const _events = [
      // Mouse events
      [
        buttons[buttonsOrder[0]].element,
        "click",
        this.buttonToMinClick.bind(this)
      ],
      [
        buttons[buttonsOrder[1]].element,
        "click",
        this.buttonToMaxClick.bind(this)
      ],
      [track, "click", this.trackClick.bind(this)],
      [bar, "mousedown", mouseDownHandler],
      [bar.ownerDocument, "mousemove", mouseMoveHandler],
      [bar.ownerDocument, "mouseup", mouseUpHandler],
      // Touch events
      [bar, "touchstart", mouseDownHandler],
      [bar.ownerDocument, "touchmove", mouseMoveHandler],
      [bar.ownerDocument, "touchend", mouseUpHandler]
    ];
    _events.forEach(function(args) {
      addEvent$19.apply(null, args);
    });
    this._events = _events;
  }
  buttonToMaxClick(e) {
    const scroller = this;
    const range2 = (scroller.to - scroller.from) * pick$1i(scroller.options.step, 0.2);
    scroller.updatePosition(scroller.from + range2, scroller.to + range2);
    fireEvent$s(scroller, "changed", {
      from: scroller.from,
      to: scroller.to,
      trigger: "scrollbar",
      DOMEvent: e
    });
  }
  buttonToMinClick(e) {
    const scroller = this;
    const range2 = correctFloat$9(scroller.to - scroller.from) * pick$1i(scroller.options.step, 0.2);
    scroller.updatePosition(correctFloat$9(scroller.from - range2), correctFloat$9(scroller.to - range2));
    fireEvent$s(scroller, "changed", {
      from: scroller.from,
      to: scroller.to,
      trigger: "scrollbar",
      DOMEvent: e
    });
  }
  /**
   * Get normalized (0-1) cursor position over the scrollbar
   *
   * @private
   * @function Highcharts.Scrollbar#cursorToScrollbarPosition
   *
   * @param  {*} normalizedEvent
   *         normalized event, with chartX and chartY values
   *
   * @return {Highcharts.Dictionary<number>}
   *         Local position {chartX, chartY}
   */
  cursorToScrollbarPosition(normalizedEvent) {
    const scroller = this, options2 = scroller.options, minWidthDifference = options2.minWidth > scroller.calculatedWidth ? options2.minWidth : 0;
    return {
      chartX: (normalizedEvent.chartX - scroller.x - scroller.xOffset) / (scroller.barWidth - minWidthDifference),
      chartY: (normalizedEvent.chartY - scroller.y - scroller.yOffset) / (scroller.barWidth - minWidthDifference)
    };
  }
  /**
   * Destroys allocated elements.
   *
   * @private
   * @function Highcharts.Scrollbar#destroy
   */
  destroy() {
    const scroller = this, navigator2 = scroller.chart.scroller;
    scroller.removeEvents();
    [
      "track",
      "scrollbarRifles",
      "scrollbar",
      "scrollbarGroup",
      "group"
    ].forEach(function(prop) {
      if (scroller[prop] && scroller[prop].destroy) {
        scroller[prop] = scroller[prop].destroy();
      }
    });
    if (navigator2 && scroller === navigator2.scrollbar) {
      navigator2.scrollbar = null;
      destroyObjectProperties$3(navigator2.scrollbarButtons);
    }
  }
  /**
   * Draw the scrollbar buttons with arrows
   *
   * @private
   * @function Highcharts.Scrollbar#drawScrollbarButton
   * @param {number} index
   *        0 is left, 1 is right
   */
  drawScrollbarButton(index) {
    const scroller = this, renderer = scroller.renderer, scrollbarButtons = scroller.scrollbarButtons, options2 = scroller.options, size = scroller.size, group2 = renderer.g().add(scroller.group);
    scrollbarButtons.push(group2);
    if (options2.buttonsEnabled) {
      const rect2 = renderer.rect().addClass("highcharts-scrollbar-button").add(group2);
      if (!scroller.chart.styledMode) {
        rect2.attr({
          stroke: options2.buttonBorderColor,
          "stroke-width": options2.buttonBorderWidth,
          fill: options2.buttonBackgroundColor
        });
      }
      rect2.attr(rect2.crisp({
        x: -0.5,
        y: -0.5,
        width: size,
        height: size,
        r: options2.buttonBorderRadius
      }, rect2.strokeWidth()));
      const arrow2 = renderer.path(Scrollbar.swapXY([[
        "M",
        size / 2 + (index ? -1 : 1),
        size / 2 - 3
      ], [
        "L",
        size / 2 + (index ? -1 : 1),
        size / 2 + 3
      ], [
        "L",
        size / 2 + (index ? 2 : -2),
        size / 2
      ]], options2.vertical)).addClass("highcharts-scrollbar-arrow").add(scrollbarButtons[index]);
      if (!scroller.chart.styledMode) {
        arrow2.attr({
          fill: options2.buttonArrowColor
        });
      }
    }
  }
  /**
   * @private
   * @function Highcharts.Scrollbar#init
   * @param {Highcharts.SVGRenderer} renderer
   * @param {Highcharts.ScrollbarOptions} options
   * @param {Highcharts.Chart} chart
   */
  init(renderer, options2, chart) {
    const scroller = this;
    scroller.scrollbarButtons = [];
    scroller.renderer = renderer;
    scroller.userOptions = options2;
    scroller.options = merge$1e(ScrollbarDefaults, defaultOptions$e.scrollbar, options2);
    scroller.options.margin = pick$1i(scroller.options.margin, 10);
    scroller.chart = chart;
    scroller.size = pick$1i(scroller.options.size, scroller.options.height);
    if (options2.enabled) {
      scroller.render();
      scroller.addEvents();
    }
  }
  mouseDownHandler(e) {
    const scroller = this, normalizedEvent = scroller.chart.pointer?.normalize(e) || e, mousePosition = scroller.cursorToScrollbarPosition(normalizedEvent);
    scroller.chartX = mousePosition.chartX;
    scroller.chartY = mousePosition.chartY;
    scroller.initPositions = [scroller.from, scroller.to];
    scroller.grabbedCenter = true;
  }
  /**
   * Event handler for the mouse move event.
   * @private
   */
  mouseMoveHandler(e) {
    const scroller = this, normalizedEvent = scroller.chart.pointer?.normalize(e) || e, options2 = scroller.options, direction = options2.vertical ? "chartY" : "chartX", initPositions = scroller.initPositions || [];
    let scrollPosition, chartPosition, change;
    if (scroller.grabbedCenter && // #4696, scrollbar failed on Android
    (!e.touches || e.touches[0][direction] !== 0)) {
      chartPosition = scroller.cursorToScrollbarPosition(normalizedEvent)[direction];
      scrollPosition = scroller[direction];
      change = chartPosition - scrollPosition;
      scroller.hasDragged = true;
      scroller.updatePosition(initPositions[0] + change, initPositions[1] + change);
      if (scroller.hasDragged) {
        fireEvent$s(scroller, "changed", {
          from: scroller.from,
          to: scroller.to,
          trigger: "scrollbar",
          DOMType: e.type,
          DOMEvent: e
        });
      }
    }
  }
  /**
   * Event handler for the mouse up event.
   * @private
   */
  mouseUpHandler(e) {
    const scroller = this;
    if (scroller.hasDragged) {
      fireEvent$s(scroller, "changed", {
        from: scroller.from,
        to: scroller.to,
        trigger: "scrollbar",
        DOMType: e.type,
        DOMEvent: e
      });
    }
    scroller.grabbedCenter = scroller.hasDragged = scroller.chartX = scroller.chartY = null;
  }
  /**
   * Position the scrollbar, method called from a parent with defined
   * dimensions.
   *
   * @private
   * @function Highcharts.Scrollbar#position
   * @param {number} x
   *        x-position on the chart
   * @param {number} y
   *        y-position on the chart
   * @param {number} width
   *        width of the scrollbar
   * @param {number} height
   *        height of the scrollbar
   */
  position(x, y, width, height) {
    const scroller = this, options2 = scroller.options, { buttonsEnabled, margin = 0, vertical } = options2, method = scroller.rendered ? "animate" : "attr";
    let xOffset = height, yOffset = 0;
    scroller.group.show();
    scroller.x = x;
    scroller.y = y + this.trackBorderWidth;
    scroller.width = width;
    scroller.height = height;
    scroller.xOffset = xOffset;
    scroller.yOffset = yOffset;
    if (vertical) {
      scroller.width = scroller.yOffset = width = yOffset = scroller.size;
      scroller.xOffset = xOffset = 0;
      scroller.yOffset = yOffset = buttonsEnabled ? scroller.size : 0;
      scroller.barWidth = height - (buttonsEnabled ? width * 2 : 0);
      scroller.x = x = x + margin;
    } else {
      scroller.height = height = scroller.size;
      scroller.xOffset = xOffset = buttonsEnabled ? scroller.size : 0;
      scroller.barWidth = width - (buttonsEnabled ? height * 2 : 0);
      scroller.y = scroller.y + margin;
    }
    scroller.group[method]({
      translateX: x,
      translateY: scroller.y
    });
    scroller.track[method]({
      width,
      height
    });
    scroller.scrollbarButtons[1][method]({
      translateX: vertical ? 0 : width - xOffset,
      translateY: vertical ? height - yOffset : 0
    });
  }
  /**
   * Removes the event handlers attached previously with addEvents.
   *
   * @private
   * @function Highcharts.Scrollbar#removeEvents
   */
  removeEvents() {
    this._events.forEach(function(args) {
      removeEvent$6.apply(null, args);
    });
    this._events.length = 0;
  }
  /**
   * Render scrollbar with all required items.
   *
   * @private
   * @function Highcharts.Scrollbar#render
   */
  render() {
    const scroller = this, renderer = scroller.renderer, options2 = scroller.options, size = scroller.size, styledMode = scroller.chart.styledMode, group2 = renderer.g("scrollbar").attr({
      zIndex: options2.zIndex
    }).hide().add();
    scroller.group = group2;
    scroller.track = renderer.rect().addClass("highcharts-scrollbar-track").attr({
      r: options2.trackBorderRadius || 0,
      height: size,
      width: size
    }).add(group2);
    if (!styledMode) {
      scroller.track.attr({
        fill: options2.trackBackgroundColor,
        stroke: options2.trackBorderColor,
        "stroke-width": options2.trackBorderWidth
      });
    }
    const trackBorderWidth = scroller.trackBorderWidth = scroller.track.strokeWidth();
    scroller.track.attr({
      x: -crisp$a(0, trackBorderWidth),
      y: -crisp$a(0, trackBorderWidth)
    });
    scroller.scrollbarGroup = renderer.g().add(group2);
    scroller.scrollbar = renderer.rect().addClass("highcharts-scrollbar-thumb").attr({
      height: size - trackBorderWidth,
      width: size - trackBorderWidth,
      r: options2.barBorderRadius || 0
    }).add(scroller.scrollbarGroup);
    scroller.scrollbarRifles = renderer.path(Scrollbar.swapXY([
      ["M", -3, size / 4],
      ["L", -3, 2 * size / 3],
      ["M", 0, size / 4],
      ["L", 0, 2 * size / 3],
      ["M", 3, size / 4],
      ["L", 3, 2 * size / 3]
    ], options2.vertical)).addClass("highcharts-scrollbar-rifles").add(scroller.scrollbarGroup);
    if (!styledMode) {
      scroller.scrollbar.attr({
        fill: options2.barBackgroundColor,
        stroke: options2.barBorderColor,
        "stroke-width": options2.barBorderWidth
      });
      scroller.scrollbarRifles.attr({
        stroke: options2.rifleColor,
        "stroke-width": 1
      });
    }
    scroller.scrollbarStrokeWidth = scroller.scrollbar.strokeWidth();
    scroller.scrollbarGroup.translate(-crisp$a(0, scroller.scrollbarStrokeWidth), -crisp$a(0, scroller.scrollbarStrokeWidth));
    scroller.drawScrollbarButton(0);
    scroller.drawScrollbarButton(1);
  }
  /**
   * Set scrollbar size, with a given scale.
   *
   * @private
   * @function Highcharts.Scrollbar#setRange
   * @param {number} from
   *        scale (0-1) where bar should start
   * @param {number} to
   *        scale (0-1) where bar should end
   */
  setRange(from, to) {
    const scroller = this, options2 = scroller.options, vertical = options2.vertical, minWidth = options2.minWidth, fullWidth = scroller.barWidth, method = this.rendered && !this.hasDragged && !(this.chart.navigator && this.chart.navigator.hasDragged) ? "animate" : "attr";
    if (!defined$S(fullWidth)) {
      return;
    }
    const toPX = fullWidth * Math.min(to, 1);
    let fromPX, newSize;
    from = Math.max(from, 0);
    fromPX = Math.ceil(fullWidth * from);
    scroller.calculatedWidth = newSize = correctFloat$9(toPX - fromPX);
    if (newSize < minWidth) {
      fromPX = (fullWidth - minWidth + newSize) * from;
      newSize = minWidth;
    }
    const newPos = Math.floor(fromPX + scroller.xOffset + scroller.yOffset);
    const newRiflesPos = newSize / 2 - 0.5;
    scroller.from = from;
    scroller.to = to;
    if (!vertical) {
      scroller.scrollbarGroup[method]({
        translateX: newPos
      });
      scroller.scrollbar[method]({
        width: newSize
      });
      scroller.scrollbarRifles[method]({
        translateX: newRiflesPos
      });
      scroller.scrollbarLeft = newPos;
      scroller.scrollbarTop = 0;
    } else {
      scroller.scrollbarGroup[method]({
        translateY: newPos
      });
      scroller.scrollbar[method]({
        height: newSize
      });
      scroller.scrollbarRifles[method]({
        translateY: newRiflesPos
      });
      scroller.scrollbarTop = newPos;
      scroller.scrollbarLeft = 0;
    }
    if (newSize <= 12) {
      scroller.scrollbarRifles.hide();
    } else {
      scroller.scrollbarRifles.show();
    }
    if (options2.showFull === false) {
      if (from <= 0 && to >= 1) {
        scroller.group.hide();
      } else {
        scroller.group.show();
      }
    }
    scroller.rendered = true;
  }
  /**
   * Checks if the extremes should be updated in response to a scrollbar
   * change event.
   *
   * @private
   * @function Highcharts.Scrollbar#shouldUpdateExtremes
   */
  shouldUpdateExtremes(eventType) {
    return pick$1i(this.options.liveRedraw, Highcharts.svg && !Highcharts.isTouchDevice && !this.chart.boosted) || // Mouseup always should change extremes
    eventType === "mouseup" || eventType === "touchend" || // Internal events
    !defined$S(eventType);
  }
  trackClick(e) {
    const scroller = this;
    const normalizedEvent = scroller.chart.pointer?.normalize(e) || e, range2 = scroller.to - scroller.from, top = scroller.y + scroller.scrollbarTop, left = scroller.x + scroller.scrollbarLeft;
    if (scroller.options.vertical && normalizedEvent.chartY > top || !scroller.options.vertical && normalizedEvent.chartX > left) {
      scroller.updatePosition(scroller.from + range2, scroller.to + range2);
    } else {
      scroller.updatePosition(scroller.from - range2, scroller.to - range2);
    }
    fireEvent$s(scroller, "changed", {
      from: scroller.from,
      to: scroller.to,
      trigger: "scrollbar",
      DOMEvent: e
    });
  }
  /**
   * Update the scrollbar with new options
   *
   * @private
   * @function Highcharts.Scrollbar#update
   * @param  {Highcharts.ScrollbarOptions} options
   */
  update(options2) {
    this.destroy();
    this.init(this.chart.renderer, merge$1e(true, this.options, options2), this.chart);
  }
  /**
   * Update position option in the Scrollbar, with normalized 0-1 scale
   *
   * @private
   * @function Highcharts.Scrollbar#updatePosition
   * @param  {number} from
   * @param  {number} to
   */
  updatePosition(from, to) {
    if (to > 1) {
      from = correctFloat$9(1 - correctFloat$9(to - from));
      to = 1;
    }
    if (from < 0) {
      to = correctFloat$9(to - from);
      from = 0;
    }
    this.from = from;
    this.to = to;
  }
}
Scrollbar.defaultOptions = ScrollbarDefaults;
defaultOptions$e.scrollbar = merge$1e(true, Scrollbar.defaultOptions, defaultOptions$e.scrollbar);
const { defaultOptions: defaultOptions$d } = DefaultOptions;
const { isTouchDevice: isTouchDevice$2 } = Highcharts;
const { prototype: { symbols: symbols$1 } } = SVGRenderer;
const { addEvent: addEvent$18, clamp: clamp$f, correctFloat: correctFloat$8, defined: defined$R, destroyObjectProperties: destroyObjectProperties$2, erase: erase$3, extend: extend$10, find: find$d, fireEvent: fireEvent$r, isArray: isArray$f, isNumber: isNumber$O, merge: merge$1d, pick: pick$1h, removeEvent: removeEvent$5, splat: splat$f } = Utilities;
function numExt(extreme, ...args) {
  const numbers = [].filter.call(args, isNumber$O);
  if (numbers.length) {
    return Math[extreme].apply(0, numbers);
  }
}
class Navigator {
  /* *
   *
   *  Static Properties
   *
   * */
  static compose(ChartClass, AxisClass, SeriesClass) {
    ChartNavigatorComposition.compose(ChartClass, Navigator);
    NavigatorComposition.compose(ChartClass, AxisClass, SeriesClass);
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.isDirty = false;
    this.scrollbarHeight = 0;
    this.init(chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Draw one of the handles on the side of the zoomed range in the navigator.
   *
   * @private
   * @function Highcharts.Navigator#drawHandle
   *
   * @param {number} x
   *        The x center for the handle
   *
   * @param {number} index
   *        0 for left and 1 for right
   *
   * @param {boolean|undefined} inverted
   *        Flag for chart.inverted
   *
   * @param {string} verb
   *        Use 'animate' or 'attr'
   */
  drawHandle(x, index, inverted, verb) {
    const navigator2 = this, height = navigator2.navigatorOptions.handles.height;
    navigator2.handles[index][verb](inverted ? {
      translateX: Math.round(navigator2.left + navigator2.height / 2),
      translateY: Math.round(navigator2.top + parseInt(x, 10) + 0.5 - height)
    } : {
      translateX: Math.round(navigator2.left + parseInt(x, 10)),
      translateY: Math.round(navigator2.top + navigator2.height / 2 - height / 2 - 1)
    });
  }
  /**
   * Render outline around the zoomed range
   *
   * @private
   * @function Highcharts.Navigator#drawOutline
   *
   * @param {number} zoomedMin
   *        in pixels position where zoomed range starts
   *
   * @param {number} zoomedMax
   *        in pixels position where zoomed range ends
   *
   * @param {boolean|undefined} inverted
   *        flag if chart is inverted
   *
   * @param {string} verb
   *        use 'animate' or 'attr'
   */
  drawOutline(zoomedMin, zoomedMax, inverted, verb) {
    const navigator2 = this, maskInside = navigator2.navigatorOptions.maskInside, outlineWidth = navigator2.outline.strokeWidth(), halfOutline = outlineWidth / 2, outlineCorrection = outlineWidth % 2 / 2, scrollButtonSize = navigator2.scrollButtonSize, navigatorSize = navigator2.size, navigatorTop = navigator2.top, height = navigator2.height, lineTop = navigatorTop - halfOutline, lineBtm = navigatorTop + height;
    let left = navigator2.left, verticalMin, path;
    if (inverted) {
      verticalMin = navigatorTop + zoomedMax + outlineCorrection;
      zoomedMax = navigatorTop + zoomedMin + outlineCorrection;
      path = [
        [
          "M",
          left + height,
          navigatorTop - scrollButtonSize - outlineCorrection
        ],
        // Top right of zoomed range
        ["L", left + height, verticalMin],
        ["L", left, verticalMin],
        // Top left of z.r.
        ["M", left, zoomedMax],
        // Bottom left of z.r.
        ["L", left + height, zoomedMax],
        // Bottom right of z.r.
        [
          "L",
          left + height,
          navigatorTop + navigatorSize + scrollButtonSize
        ]
      ];
      if (maskInside) {
        path.push(
          // Upper left of zoomed range
          ["M", left + height, verticalMin - halfOutline],
          // Upper right of z.r.
          [
            "L",
            left + height,
            zoomedMax + halfOutline
          ]
        );
      }
    } else {
      left -= scrollButtonSize;
      zoomedMin += left + scrollButtonSize - outlineCorrection;
      zoomedMax += left + scrollButtonSize - outlineCorrection;
      path = [
        // Left
        ["M", left, lineTop],
        // Upper left of zoomed range
        ["L", zoomedMin, lineTop],
        // Lower left of z.r.
        ["L", zoomedMin, lineBtm],
        // Lower right of z.r.
        ["M", zoomedMax, lineBtm],
        // Upper right of z.r.
        ["L", zoomedMax, lineTop],
        // Right
        [
          "L",
          left + navigatorSize + scrollButtonSize * 2,
          lineTop
        ]
      ];
      if (maskInside) {
        path.push(
          // Upper left of zoomed range
          ["M", zoomedMin - halfOutline, lineTop],
          // Upper right of z.r.
          ["L", zoomedMax + halfOutline, lineTop]
        );
      }
    }
    navigator2.outline[verb]({
      d: path
    });
  }
  /**
   * Render outline around the zoomed range
   *
   * @private
   * @function Highcharts.Navigator#drawMasks
   *
   * @param {number} zoomedMin
   *        in pixels position where zoomed range starts
   *
   * @param {number} zoomedMax
   *        in pixels position where zoomed range ends
   *
   * @param {boolean|undefined} inverted
   *        flag if chart is inverted
   *
   * @param {string} verb
   *        use 'animate' or 'attr'
   */
  drawMasks(zoomedMin, zoomedMax, inverted, verb) {
    const navigator2 = this, left = navigator2.left, top = navigator2.top, navigatorHeight = navigator2.height;
    let height, width, x, y;
    if (inverted) {
      x = [left, left, left];
      y = [top, top + zoomedMin, top + zoomedMax];
      width = [navigatorHeight, navigatorHeight, navigatorHeight];
      height = [
        zoomedMin,
        zoomedMax - zoomedMin,
        navigator2.size - zoomedMax
      ];
    } else {
      x = [left, left + zoomedMin, left + zoomedMax];
      y = [top, top, top];
      width = [
        zoomedMin,
        zoomedMax - zoomedMin,
        navigator2.size - zoomedMax
      ];
      height = [navigatorHeight, navigatorHeight, navigatorHeight];
    }
    navigator2.shades.forEach((shade, i) => {
      shade[verb]({
        x: x[i],
        y: y[i],
        width: width[i],
        height: height[i]
      });
    });
  }
  /**
   * Generate and update DOM elements for a navigator:
   *
   * - main navigator group
   *
   * - all shades
   *
   * - outline
   *
   * - handles
   *
   * @private
   * @function Highcharts.Navigator#renderElements
   */
  renderElements() {
    const navigator2 = this, navigatorOptions = navigator2.navigatorOptions, maskInside = navigatorOptions.maskInside, chart = navigator2.chart, inverted = chart.inverted, renderer = chart.renderer, mouseCursor = {
      cursor: inverted ? "ns-resize" : "ew-resize"
    }, navigatorGroup = navigator2.navigatorGroup ?? (navigator2.navigatorGroup = renderer.g("navigator").attr({
      zIndex: 8,
      visibility: "hidden"
    }).add());
    [
      !maskInside,
      maskInside,
      !maskInside
    ].forEach((hasMask, index) => {
      const shade = navigator2.shades[index] ?? (navigator2.shades[index] = renderer.rect().addClass("highcharts-navigator-mask" + (index === 1 ? "-inside" : "-outside")).add(navigatorGroup));
      if (!chart.styledMode) {
        shade.attr({
          fill: hasMask ? navigatorOptions.maskFill : "rgba(0,0,0,0)"
        });
        if (index === 1) {
          shade.css(mouseCursor);
        }
      }
    });
    if (!navigator2.outline) {
      navigator2.outline = renderer.path().addClass("highcharts-navigator-outline").add(navigatorGroup);
    }
    if (!chart.styledMode) {
      navigator2.outline.attr({
        "stroke-width": navigatorOptions.outlineWidth,
        stroke: navigatorOptions.outlineColor
      });
    }
    if (navigatorOptions.handles?.enabled) {
      const handlesOptions = navigatorOptions.handles, { height, width } = handlesOptions;
      [0, 1].forEach((index) => {
        const symbolName = handlesOptions.symbols[index];
        if (!navigator2.handles[index] || navigator2.handles[index].symbolUrl !== symbolName) {
          navigator2.handles[index]?.destroy();
          navigator2.handles[index] = renderer.symbol(symbolName, -width / 2 - 1, 0, width, height, handlesOptions);
          navigator2.handles[index].attr({ zIndex: 7 - index }).addClass("highcharts-navigator-handle highcharts-navigator-handle-" + ["left", "right"][index]).add(navigatorGroup);
          navigator2.addMouseEvents();
        } else if (!navigator2.handles[index].isImg && navigator2.handles[index].symbolName !== symbolName) {
          const symbolFn = symbols$1[symbolName], path = symbolFn.call(symbols$1, -width / 2 - 1, 0, width, height);
          navigator2.handles[index].attr({
            d: path
          });
          navigator2.handles[index].symbolName = symbolName;
        }
        if (chart.inverted) {
          navigator2.handles[index].attr({
            rotation: 90,
            rotationOriginX: Math.floor(-width / 2),
            rotationOriginY: (height + width) / 2
          });
        }
        if (!chart.styledMode) {
          navigator2.handles[index].attr({
            fill: handlesOptions.backgroundColor,
            stroke: handlesOptions.borderColor,
            "stroke-width": handlesOptions.lineWidth,
            width: handlesOptions.width,
            height: handlesOptions.height,
            x: -width / 2 - 1,
            y: 0
          }).css(mouseCursor);
        }
      });
    }
  }
  /**
   * Update navigator
   *
   * @private
   * @function Highcharts.Navigator#update
   *
   * @param {Highcharts.NavigatorOptions} options
   *        Options to merge in when updating navigator
   */
  update(options2, redraw = false) {
    const chart = this.chart, invertedUpdate = chart.options.chart.inverted !== chart.scrollbar?.options.vertical;
    merge$1d(true, chart.options.navigator, options2);
    this.navigatorOptions = chart.options.navigator || {};
    this.setOpposite();
    if (defined$R(options2.enabled) || invertedUpdate) {
      this.destroy();
      this.navigatorEnabled = options2.enabled || this.navigatorEnabled;
      return this.init(chart);
    }
    if (this.navigatorEnabled) {
      this.isDirty = true;
      if (options2.adaptToUpdatedData === false) {
        this.baseSeries.forEach((series) => {
          removeEvent$5(series, "updatedData", this.updatedDataHandler);
        }, this);
      }
      if (options2.adaptToUpdatedData) {
        this.baseSeries.forEach((series) => {
          series.eventsToUnbind.push(addEvent$18(series, "updatedData", this.updatedDataHandler));
        }, this);
      }
      if (options2.series || options2.baseSeries) {
        this.setBaseSeries(void 0, false);
      }
      if (options2.height || options2.xAxis || options2.yAxis) {
        this.height = options2.height ?? this.height;
        const offsets = this.getXAxisOffsets();
        this.xAxis.update({
          ...options2.xAxis,
          offsets,
          [chart.inverted ? "width" : "height"]: this.height,
          [chart.inverted ? "height" : "width"]: void 0
        }, false);
        this.yAxis.update({
          ...options2.yAxis,
          [chart.inverted ? "width" : "height"]: this.height
        }, false);
      }
    }
    if (redraw) {
      chart.redraw();
    }
  }
  /**
   * Render the navigator
   *
   * @private
   * @function Highcharts.Navigator#render
   * @param {number} min
   *        X axis value minimum
   * @param {number} max
   *        X axis value maximum
   * @param {number} [pxMin]
   *        Pixel value minimum
   * @param {number} [pxMax]
   *        Pixel value maximum
   */
  render(min2, max2, pxMin, pxMax) {
    const navigator2 = this, chart = navigator2.chart, xAxis2 = navigator2.xAxis, pointRange = xAxis2.pointRange || 0, scrollbarXAxis = xAxis2.navigatorAxis.fake ? chart.xAxis[0] : xAxis2, navigatorEnabled = navigator2.navigatorEnabled, rendered = navigator2.rendered, inverted = chart.inverted, minRange = chart.xAxis[0].minRange, maxRange = chart.xAxis[0].options.maxRange, scrollButtonSize = navigator2.scrollButtonSize;
    let navigatorWidth, scrollbarLeft, scrollbarTop, scrollbarHeight = navigator2.scrollbarHeight, navigatorSize, verb;
    if (this.hasDragged && !defined$R(pxMin)) {
      return;
    }
    if (this.isDirty) {
      this.renderElements();
    }
    min2 = correctFloat$8(min2 - pointRange / 2);
    max2 = correctFloat$8(max2 + pointRange / 2);
    if (!isNumber$O(min2) || !isNumber$O(max2)) {
      if (rendered) {
        pxMin = 0;
        pxMax = pick$1h(xAxis2.width, scrollbarXAxis.width);
      } else {
        return;
      }
    }
    navigator2.left = pick$1h(
      xAxis2.left,
      // In case of scrollbar only, without navigator
      chart.plotLeft + scrollButtonSize + (inverted ? chart.plotWidth : 0)
    );
    let zoomedMax = navigator2.size = navigatorSize = pick$1h(xAxis2.len, (inverted ? chart.plotHeight : chart.plotWidth) - 2 * scrollButtonSize);
    if (inverted) {
      navigatorWidth = scrollbarHeight;
    } else {
      navigatorWidth = navigatorSize + 2 * scrollButtonSize;
    }
    pxMin = pick$1h(pxMin, xAxis2.toPixels(min2, true));
    pxMax = pick$1h(pxMax, xAxis2.toPixels(max2, true));
    if (!isNumber$O(pxMin) || Math.abs(pxMin) === Infinity) {
      pxMin = 0;
      pxMax = navigatorWidth;
    }
    const newMin = xAxis2.toValue(pxMin, true), newMax = xAxis2.toValue(pxMax, true), currentRange = Math.abs(correctFloat$8(newMax - newMin));
    if (currentRange < minRange) {
      if (this.grabbedLeft) {
        pxMin = xAxis2.toPixels(newMax - minRange - pointRange, true);
      } else if (this.grabbedRight) {
        pxMax = xAxis2.toPixels(newMin + minRange + pointRange, true);
      }
    } else if (defined$R(maxRange) && correctFloat$8(currentRange - pointRange) > maxRange) {
      if (this.grabbedLeft) {
        pxMin = xAxis2.toPixels(newMax - maxRange - pointRange, true);
      } else if (this.grabbedRight) {
        pxMax = xAxis2.toPixels(newMin + maxRange + pointRange, true);
      }
    }
    navigator2.zoomedMax = clamp$f(Math.max(pxMin, pxMax), 0, zoomedMax);
    navigator2.zoomedMin = clamp$f(navigator2.fixedWidth ? navigator2.zoomedMax - navigator2.fixedWidth : Math.min(pxMin, pxMax), 0, zoomedMax);
    navigator2.range = navigator2.zoomedMax - navigator2.zoomedMin;
    zoomedMax = Math.round(navigator2.zoomedMax);
    const zoomedMin = Math.round(navigator2.zoomedMin);
    if (navigatorEnabled) {
      navigator2.navigatorGroup.attr({
        visibility: "inherit"
      });
      verb = rendered && !navigator2.hasDragged ? "animate" : "attr";
      navigator2.drawMasks(zoomedMin, zoomedMax, inverted, verb);
      navigator2.drawOutline(zoomedMin, zoomedMax, inverted, verb);
      if (navigator2.navigatorOptions.handles.enabled) {
        navigator2.drawHandle(zoomedMin, 0, inverted, verb);
        navigator2.drawHandle(zoomedMax, 1, inverted, verb);
      }
    }
    if (navigator2.scrollbar) {
      if (inverted) {
        scrollbarTop = navigator2.top - scrollButtonSize;
        scrollbarLeft = navigator2.left - scrollbarHeight + (navigatorEnabled || !scrollbarXAxis.opposite ? 0 : (
          // Multiple axes has offsets:
          (scrollbarXAxis.titleOffset || 0) + // Self margin from the axis.title
          scrollbarXAxis.axisTitleMargin
        ));
        scrollbarHeight = navigatorSize + 2 * scrollButtonSize;
      } else {
        scrollbarTop = navigator2.top + (navigatorEnabled ? navigator2.height : -scrollbarHeight);
        scrollbarLeft = navigator2.left - scrollButtonSize;
      }
      navigator2.scrollbar.position(scrollbarLeft, scrollbarTop, navigatorWidth, scrollbarHeight);
      navigator2.scrollbar.setRange(
        // Use real value, not rounded because range can be very small
        // (#1716)
        navigator2.zoomedMin / (navigatorSize || 1),
        navigator2.zoomedMax / (navigatorSize || 1)
      );
    }
    navigator2.rendered = true;
    this.isDirty = false;
    fireEvent$r(this, "afterRender");
  }
  /**
   * Set up the mouse and touch events for the navigator
   *
   * @private
   * @function Highcharts.Navigator#addMouseEvents
   */
  addMouseEvents() {
    const navigator2 = this, chart = navigator2.chart, container = chart.container;
    let eventsToUnbind = [], mouseMoveHandler, mouseUpHandler;
    navigator2.mouseMoveHandler = mouseMoveHandler = function(e) {
      navigator2.onMouseMove(e);
    };
    navigator2.mouseUpHandler = mouseUpHandler = function(e) {
      navigator2.onMouseUp(e);
    };
    eventsToUnbind = navigator2.getPartsEvents("mousedown");
    eventsToUnbind.push(
      // Add mouse move and mouseup events. These are bind to doc/div,
      // because Navigator.grabbedSomething flags are stored in mousedown
      // events
      addEvent$18(chart.renderTo, "mousemove", mouseMoveHandler),
      addEvent$18(container.ownerDocument, "mouseup", mouseUpHandler),
      // Touch events
      addEvent$18(chart.renderTo, "touchmove", mouseMoveHandler),
      addEvent$18(container.ownerDocument, "touchend", mouseUpHandler)
    );
    eventsToUnbind.concat(navigator2.getPartsEvents("touchstart"));
    navigator2.eventsToUnbind = eventsToUnbind;
    if (navigator2.series && navigator2.series[0]) {
      eventsToUnbind.push(addEvent$18(navigator2.series[0].xAxis, "foundExtremes", function() {
        chart.navigator.modifyNavigatorAxisExtremes();
      }));
    }
  }
  /**
   * Generate events for handles and masks
   *
   * @private
   * @function Highcharts.Navigator#getPartsEvents
   *
   * @param {string} eventName
   *        Event name handler, 'mousedown' or 'touchstart'
   *
   * @return {Array<Function>}
   *         An array of functions to remove navigator functions from the
   *         events again.
   */
  getPartsEvents(eventName) {
    const navigator2 = this, events = [];
    ["shades", "handles"].forEach(function(name) {
      navigator2[name].forEach(function(navigatorItem, index) {
        events.push(addEvent$18(navigatorItem.element, eventName, function(e) {
          navigator2[name + "Mousedown"](e, index);
        }));
      });
    });
    return events;
  }
  /**
   * Mousedown on a shaded mask, either:
   *
   * - will be stored for future drag&drop
   *
   * - will directly shift to a new range
   *
   * @private
   * @function Highcharts.Navigator#shadesMousedown
   *
   * @param {Highcharts.PointerEventObject} e
   *        Mouse event
   *
   * @param {number} index
   *        Index of a mask in Navigator.shades array
   */
  shadesMousedown(e, index) {
    e = this.chart.pointer?.normalize(e) || e;
    const navigator2 = this, chart = navigator2.chart, xAxis2 = navigator2.xAxis, zoomedMin = navigator2.zoomedMin, navigatorSize = navigator2.size, range2 = navigator2.range;
    let navigatorPosition = navigator2.left, chartX = e.chartX, fixedMax, fixedMin, ext, left;
    if (chart.inverted) {
      chartX = e.chartY;
      navigatorPosition = navigator2.top;
    }
    if (index === 1) {
      navigator2.grabbedCenter = chartX;
      navigator2.fixedWidth = range2;
      navigator2.dragOffset = chartX - zoomedMin;
    } else {
      left = chartX - navigatorPosition - range2 / 2;
      if (index === 0) {
        left = Math.max(0, left);
      } else if (index === 2 && left + range2 >= navigatorSize) {
        left = navigatorSize - range2;
        if (navigator2.reversedExtremes) {
          left -= range2;
          fixedMin = navigator2.getUnionExtremes().dataMin;
        } else {
          fixedMax = navigator2.getUnionExtremes().dataMax;
        }
      }
      if (left !== zoomedMin) {
        navigator2.fixedWidth = range2;
        ext = xAxis2.navigatorAxis.toFixedRange(left, left + range2, fixedMin, fixedMax);
        if (defined$R(ext.min)) {
          fireEvent$r(this, "setRange", {
            min: Math.min(ext.min, ext.max),
            max: Math.max(ext.min, ext.max),
            redraw: true,
            eventArguments: {
              trigger: "navigator"
            }
          });
        }
      }
    }
  }
  /**
   * Mousedown on a handle mask.
   * Will store necessary information for drag&drop.
   *
   * @private
   * @function Highcharts.Navigator#handlesMousedown
   * @param {Highcharts.PointerEventObject} e
   *        Mouse event
   * @param {number} index
   *        Index of a handle in Navigator.handles array
   */
  handlesMousedown(e, index) {
    e = this.chart.pointer?.normalize(e) || e;
    const navigator2 = this, chart = navigator2.chart, baseXAxis = chart.xAxis[0], reverse = navigator2.reversedExtremes;
    if (index === 0) {
      navigator2.grabbedLeft = true;
      navigator2.otherHandlePos = navigator2.zoomedMax;
      navigator2.fixedExtreme = reverse ? baseXAxis.min : baseXAxis.max;
    } else {
      navigator2.grabbedRight = true;
      navigator2.otherHandlePos = navigator2.zoomedMin;
      navigator2.fixedExtreme = reverse ? baseXAxis.max : baseXAxis.min;
    }
    chart.setFixedRange(void 0);
  }
  /**
   * Mouse move event based on x/y mouse position.
   *
   * @private
   * @function Highcharts.Navigator#onMouseMove
   *
   * @param {Highcharts.PointerEventObject} e
   *        Mouse event
   */
  onMouseMove(e) {
    const navigator2 = this, chart = navigator2.chart, navigatorSize = navigator2.navigatorSize, range2 = navigator2.range, dragOffset = navigator2.dragOffset, inverted = chart.inverted;
    let left = navigator2.left, chartX;
    if (!e.touches || e.touches[0].pageX !== 0) {
      e = chart.pointer?.normalize(e) || e;
      chartX = e.chartX;
      if (inverted) {
        left = navigator2.top;
        chartX = e.chartY;
      }
      if (navigator2.grabbedLeft) {
        navigator2.hasDragged = true;
        navigator2.render(0, 0, chartX - left, navigator2.otherHandlePos);
      } else if (navigator2.grabbedRight) {
        navigator2.hasDragged = true;
        navigator2.render(0, 0, navigator2.otherHandlePos, chartX - left);
      } else if (navigator2.grabbedCenter) {
        navigator2.hasDragged = true;
        if (chartX < dragOffset) {
          chartX = dragOffset;
        } else if (chartX > navigatorSize + dragOffset - range2) {
          chartX = navigatorSize + dragOffset - range2;
        }
        navigator2.render(0, 0, chartX - dragOffset, chartX - dragOffset + range2);
      }
      if (navigator2.hasDragged && navigator2.scrollbar && pick$1h(
        navigator2.scrollbar.options.liveRedraw,
        // By default, don't run live redraw on touch
        // devices or if the chart is in boost.
        !isTouchDevice$2 && !this.chart.boosted
      )) {
        e.DOMType = e.type;
        setTimeout(function() {
          navigator2.onMouseUp(e);
        }, 0);
      }
    }
  }
  /**
   * Mouse up event based on x/y mouse position.
   *
   * @private
   * @function Highcharts.Navigator#onMouseUp
   * @param {Highcharts.PointerEventObject} e
   *        Mouse event
   */
  onMouseUp(e) {
    const navigator2 = this, chart = navigator2.chart, xAxis2 = navigator2.xAxis, scrollbar = navigator2.scrollbar, DOMEvent = e.DOMEvent || e, inverted = chart.inverted, verb = navigator2.rendered && !navigator2.hasDragged ? "animate" : "attr";
    let zoomedMax, zoomedMin, unionExtremes, fixedMin, fixedMax, ext;
    if (
      // MouseUp is called for both, navigator and scrollbar (that order),
      // which causes calling afterSetExtremes twice. Prevent first call
      // by checking if scrollbar is going to set new extremes (#6334)
      navigator2.hasDragged && (!scrollbar || !scrollbar.hasDragged) || e.trigger === "scrollbar"
    ) {
      unionExtremes = navigator2.getUnionExtremes();
      if (navigator2.zoomedMin === navigator2.otherHandlePos) {
        fixedMin = navigator2.fixedExtreme;
      } else if (navigator2.zoomedMax === navigator2.otherHandlePos) {
        fixedMax = navigator2.fixedExtreme;
      }
      if (navigator2.zoomedMax === navigator2.size) {
        fixedMax = navigator2.reversedExtremes ? unionExtremes.dataMin : unionExtremes.dataMax;
      }
      if (navigator2.zoomedMin === 0) {
        fixedMin = navigator2.reversedExtremes ? unionExtremes.dataMax : unionExtremes.dataMin;
      }
      ext = xAxis2.navigatorAxis.toFixedRange(navigator2.zoomedMin, navigator2.zoomedMax, fixedMin, fixedMax);
      if (defined$R(ext.min)) {
        fireEvent$r(this, "setRange", {
          min: Math.min(ext.min, ext.max),
          max: Math.max(ext.min, ext.max),
          redraw: true,
          animation: navigator2.hasDragged ? false : null,
          eventArguments: {
            trigger: "navigator",
            triggerOp: "navigator-drag",
            DOMEvent
            // #1838
          }
        });
      }
    }
    if (e.DOMType !== "mousemove" && e.DOMType !== "touchmove") {
      navigator2.grabbedLeft = navigator2.grabbedRight = navigator2.grabbedCenter = navigator2.fixedWidth = navigator2.fixedExtreme = navigator2.otherHandlePos = navigator2.hasDragged = navigator2.dragOffset = null;
    }
    if (navigator2.navigatorEnabled && isNumber$O(navigator2.zoomedMin) && isNumber$O(navigator2.zoomedMax)) {
      zoomedMin = Math.round(navigator2.zoomedMin);
      zoomedMax = Math.round(navigator2.zoomedMax);
      if (navigator2.shades) {
        navigator2.drawMasks(zoomedMin, zoomedMax, inverted, verb);
      }
      if (navigator2.outline) {
        navigator2.drawOutline(zoomedMin, zoomedMax, inverted, verb);
      }
      if (navigator2.navigatorOptions.handles.enabled && Object.keys(navigator2.handles).length === navigator2.handles.length) {
        navigator2.drawHandle(zoomedMin, 0, inverted, verb);
        navigator2.drawHandle(zoomedMax, 1, inverted, verb);
      }
    }
  }
  /**
   * Removes the event handlers attached previously with addEvents.
   *
   * @private
   * @function Highcharts.Navigator#removeEvents
   */
  removeEvents() {
    if (this.eventsToUnbind) {
      this.eventsToUnbind.forEach(function(unbind) {
        unbind();
      });
      this.eventsToUnbind = void 0;
    }
    this.removeBaseSeriesEvents();
  }
  /**
   * Remove data events.
   *
   * @private
   * @function Highcharts.Navigator#removeBaseSeriesEvents
   */
  removeBaseSeriesEvents() {
    const baseSeries = this.baseSeries || [];
    if (this.navigatorEnabled && baseSeries[0]) {
      if (this.navigatorOptions.adaptToUpdatedData !== false) {
        baseSeries.forEach(function(series) {
          removeEvent$5(series, "updatedData", this.updatedDataHandler);
        }, this);
      }
      if (baseSeries[0].xAxis) {
        removeEvent$5(baseSeries[0].xAxis, "foundExtremes", this.modifyBaseAxisExtremes);
      }
    }
  }
  /**
   * Calculate the navigator xAxis offsets
   *
   * @private
   */
  getXAxisOffsets() {
    return this.chart.inverted ? [this.scrollButtonSize, 0, -this.scrollButtonSize, 0] : [0, -this.scrollButtonSize, 0, this.scrollButtonSize];
  }
  /**
   * Initialize the Navigator object
   *
   * @private
   * @function Highcharts.Navigator#init
   */
  init(chart) {
    const chartOptions = chart.options, navigatorOptions = chartOptions.navigator || {}, navigatorEnabled = navigatorOptions.enabled, scrollbarOptions = chartOptions.scrollbar || {}, scrollbarEnabled = scrollbarOptions.enabled, height = navigatorEnabled && navigatorOptions.height || 0, scrollbarHeight = scrollbarEnabled && scrollbarOptions.height || 0, scrollButtonSize = scrollbarOptions.buttonsEnabled && scrollbarHeight || 0;
    this.handles = [];
    this.shades = [];
    this.chart = chart;
    this.setBaseSeries();
    this.height = height;
    this.scrollbarHeight = scrollbarHeight;
    this.scrollButtonSize = scrollButtonSize;
    this.scrollbarEnabled = scrollbarEnabled;
    this.navigatorEnabled = navigatorEnabled;
    this.navigatorOptions = navigatorOptions;
    this.scrollbarOptions = scrollbarOptions;
    this.setOpposite();
    const navigator2 = this, baseSeries = navigator2.baseSeries, xAxisIndex = chart.xAxis.length, yAxisIndex = chart.yAxis.length, baseXaxis = baseSeries && baseSeries[0] && baseSeries[0].xAxis || chart.xAxis[0] || { options: {} };
    chart.isDirtyBox = true;
    if (navigator2.navigatorEnabled) {
      const offsets = this.getXAxisOffsets();
      navigator2.xAxis = new Axis(chart, merge$1d({
        // Inherit base xAxis' break, ordinal options and overscroll
        breaks: baseXaxis.options.breaks,
        ordinal: baseXaxis.options.ordinal,
        overscroll: baseXaxis.options.overscroll
      }, navigatorOptions.xAxis, {
        type: "datetime",
        yAxis: navigatorOptions.yAxis?.id,
        index: xAxisIndex,
        isInternal: true,
        offset: 0,
        keepOrdinalPadding: true,
        // #2436
        startOnTick: false,
        endOnTick: false,
        // Inherit base xAxis' padding when ordinal is false (#16915).
        minPadding: baseXaxis.options.ordinal ? 0 : baseXaxis.options.minPadding,
        maxPadding: baseXaxis.options.ordinal ? 0 : baseXaxis.options.maxPadding,
        zoomEnabled: false
      }, chart.inverted ? {
        offsets,
        width: height
      } : {
        offsets,
        height
      }), "xAxis");
      navigator2.yAxis = new Axis(chart, merge$1d(navigatorOptions.yAxis, {
        alignTicks: false,
        offset: 0,
        index: yAxisIndex,
        isInternal: true,
        reversed: pick$1h(navigatorOptions.yAxis && navigatorOptions.yAxis.reversed, chart.yAxis[0] && chart.yAxis[0].reversed, false),
        // #14060
        zoomEnabled: false
      }, chart.inverted ? {
        width: height
      } : {
        height
      }), "yAxis");
      if (baseSeries || navigatorOptions.series.data) {
        navigator2.updateNavigatorSeries(false);
      } else if (chart.series.length === 0) {
        navigator2.unbindRedraw = addEvent$18(chart, "beforeRedraw", function() {
          if (chart.series.length > 0 && !navigator2.series) {
            navigator2.setBaseSeries();
            navigator2.unbindRedraw();
          }
        });
      }
      navigator2.reversedExtremes = chart.inverted && !navigator2.xAxis.reversed || !chart.inverted && navigator2.xAxis.reversed;
      navigator2.renderElements();
      navigator2.addMouseEvents();
    } else {
      navigator2.xAxis = {
        chart,
        navigatorAxis: {
          fake: true
        },
        translate: function(value, reverse) {
          const axis = chart.xAxis[0], ext = axis.getExtremes(), scrollTrackWidth = axis.len - 2 * scrollButtonSize, min2 = numExt("min", axis.options.min, ext.dataMin), valueRange = numExt("max", axis.options.max, ext.dataMax) - min2;
          return reverse ? (
            // From pixel to value
            value * valueRange / scrollTrackWidth + min2
          ) : (
            // From value to pixel
            scrollTrackWidth * (value - min2) / valueRange
          );
        },
        toPixels: function(value) {
          return this.translate(value);
        },
        toValue: function(value) {
          return this.translate(value, true);
        }
      };
      navigator2.xAxis.navigatorAxis.axis = navigator2.xAxis;
      navigator2.xAxis.navigatorAxis.toFixedRange = NavigatorAxisAdditions.prototype.toFixedRange.bind(navigator2.xAxis.navigatorAxis);
    }
    if (chart.options.scrollbar?.enabled) {
      const options2 = merge$1d(chart.options.scrollbar, { vertical: chart.inverted });
      if (!isNumber$O(options2.margin)) {
        options2.margin = chart.inverted ? -3 : 3;
      }
      chart.scrollbar = navigator2.scrollbar = new Scrollbar(chart.renderer, options2, chart);
      addEvent$18(navigator2.scrollbar, "changed", function(e) {
        const range2 = navigator2.size, to = range2 * this.to, from = range2 * this.from;
        navigator2.hasDragged = navigator2.scrollbar.hasDragged;
        navigator2.render(0, 0, from, to);
        if (this.shouldUpdateExtremes(e.DOMType)) {
          setTimeout(function() {
            navigator2.onMouseUp(e);
          });
        }
      });
    }
    navigator2.addBaseSeriesEvents();
    navigator2.addChartEvents();
  }
  /**
   * Set the opposite property on navigator
   *
   * @private
   */
  setOpposite() {
    const navigatorOptions = this.navigatorOptions, navigatorEnabled = this.navigatorEnabled, chart = this.chart;
    this.opposite = pick$1h(navigatorOptions.opposite, Boolean(!navigatorEnabled && chart.inverted));
  }
  /**
   * Get the union data extremes of the chart - the outer data extremes of the
   * base X axis and the navigator axis.
   *
   * @private
   * @function Highcharts.Navigator#getUnionExtremes
   */
  getUnionExtremes(returnFalseOnNoBaseSeries) {
    const baseAxis = this.chart.xAxis[0], time = this.chart.time, navAxis = this.xAxis, navAxisOptions = navAxis.options, baseAxisOptions = baseAxis.options;
    let ret;
    if (!returnFalseOnNoBaseSeries || baseAxis.dataMin !== null) {
      ret = {
        dataMin: pick$1h(
          // #4053
          time.parse(navAxisOptions?.min),
          numExt("min", time.parse(baseAxisOptions.min), baseAxis.dataMin, navAxis.dataMin, navAxis.min)
        ),
        dataMax: pick$1h(time.parse(navAxisOptions?.max), numExt("max", time.parse(baseAxisOptions.max), baseAxis.dataMax, navAxis.dataMax, navAxis.max))
      };
    }
    return ret;
  }
  /**
   * Set the base series and update the navigator series from this. With a bit
   * of modification we should be able to make this an API method to be called
   * from the outside
   *
   * @private
   * @function Highcharts.Navigator#setBaseSeries
   * @param {Highcharts.SeriesOptionsType} [baseSeriesOptions]
   *        Additional series options for a navigator
   * @param {boolean} [redraw]
   *        Whether to redraw after update.
   */
  setBaseSeries(baseSeriesOptions, redraw) {
    const chart = this.chart, baseSeries = this.baseSeries = [];
    baseSeriesOptions = baseSeriesOptions || chart.options && chart.options.navigator.baseSeries || (chart.series.length ? (
      // Find the first non-navigator series (#8430)
      find$d(chart.series, (s) => !s.options.isInternal).index
    ) : 0);
    (chart.series || []).forEach((series, i) => {
      if (
        // Don't include existing nav series
        !series.options.isInternal && (series.options.showInNavigator || (i === baseSeriesOptions || series.options.id === baseSeriesOptions) && series.options.showInNavigator !== false)
      ) {
        baseSeries.push(series);
      }
    });
    if (this.xAxis && !this.xAxis.navigatorAxis.fake) {
      this.updateNavigatorSeries(true, redraw);
    }
  }
  /**
   * Update series in the navigator from baseSeries, adding new if does not
   * exist.
   *
   * @private
   * @function Highcharts.Navigator.updateNavigatorSeries
   */
  updateNavigatorSeries(addEvents2, redraw) {
    const navigator2 = this, chart = navigator2.chart, baseSeries = navigator2.baseSeries, navSeriesMixin = {
      enableMouseTracking: false,
      index: null,
      // #6162
      linkedTo: null,
      // #6734
      group: "nav",
      // For columns
      padXAxis: false,
      xAxis: this.navigatorOptions.xAxis?.id,
      yAxis: this.navigatorOptions.yAxis?.id,
      showInLegend: false,
      stacking: void 0,
      // #4823
      isInternal: true,
      states: {
        inactive: {
          opacity: 1
        }
      }
    }, navigatorSeries = navigator2.series = (navigator2.series || []).filter((navSeries) => {
      const base2 = navSeries.baseSeries;
      if (baseSeries.indexOf(base2) < 0) {
        if (base2) {
          removeEvent$5(base2, "updatedData", navigator2.updatedDataHandler);
          delete base2.navigatorSeries;
        }
        if (navSeries.chart) {
          navSeries.destroy();
        }
        return false;
      }
      return true;
    });
    let baseOptions, mergedNavSeriesOptions, chartNavigatorSeriesOptions = navigator2.navigatorOptions.series, baseNavigatorOptions;
    if (baseSeries && baseSeries.length) {
      baseSeries.forEach((base2) => {
        const linkedNavSeries = base2.navigatorSeries, userNavOptions = extend$10(
          // Grab color and visibility from base as default
          {
            color: base2.color,
            visible: base2.visible
          },
          !isArray$f(chartNavigatorSeriesOptions) ? chartNavigatorSeriesOptions : defaultOptions$d.navigator.series
        );
        if (linkedNavSeries && navigator2.navigatorOptions.adaptToUpdatedData === false) {
          return;
        }
        navSeriesMixin.name = "Navigator " + baseSeries.length;
        baseOptions = base2.options || {};
        baseNavigatorOptions = baseOptions.navigatorOptions || {};
        userNavOptions.dataLabels = splat$f(userNavOptions.dataLabels);
        mergedNavSeriesOptions = merge$1d(baseOptions, navSeriesMixin, userNavOptions, baseNavigatorOptions);
        mergedNavSeriesOptions.pointRange = pick$1h(
          // Stricte set pointRange in options
          userNavOptions.pointRange,
          baseNavigatorOptions.pointRange,
          // Fallback to default values, e.g. `null` for column
          defaultOptions$d.plotOptions[mergedNavSeriesOptions.type || "line"].pointRange
        );
        const navigatorSeriesData = baseNavigatorOptions.data || userNavOptions.data;
        navigator2.hasNavigatorData = navigator2.hasNavigatorData || !!navigatorSeriesData;
        mergedNavSeriesOptions.data = navigatorSeriesData || baseOptions.data?.slice(0);
        if (linkedNavSeries && linkedNavSeries.options) {
          linkedNavSeries.update(mergedNavSeriesOptions, redraw);
        } else {
          base2.navigatorSeries = chart.initSeries(mergedNavSeriesOptions);
          chart.setSortedData();
          base2.navigatorSeries.baseSeries = base2;
          navigatorSeries.push(base2.navigatorSeries);
        }
      });
    }
    if (chartNavigatorSeriesOptions.data && !(baseSeries && baseSeries.length) || isArray$f(chartNavigatorSeriesOptions)) {
      navigator2.hasNavigatorData = false;
      chartNavigatorSeriesOptions = splat$f(chartNavigatorSeriesOptions);
      chartNavigatorSeriesOptions.forEach((userSeriesOptions, i) => {
        navSeriesMixin.name = "Navigator " + (navigatorSeries.length + 1);
        mergedNavSeriesOptions = merge$1d(defaultOptions$d.navigator.series, {
          // Since we don't have a base series to pull color from,
          // try to fake it by using color from series with same
          // index. Otherwise pull from the colors array. We need
          // an explicit color as otherwise updates will increment
          // color counter and we'll get a new color for each
          // update of the nav series.
          color: chart.series[i] && !chart.series[i].options.isInternal && chart.series[i].color || chart.options.colors[i] || chart.options.colors[0]
        }, navSeriesMixin, userSeriesOptions);
        mergedNavSeriesOptions.data = userSeriesOptions.data;
        if (mergedNavSeriesOptions.data) {
          navigator2.hasNavigatorData = true;
          navigatorSeries.push(chart.initSeries(mergedNavSeriesOptions));
        }
      });
    }
    if (addEvents2) {
      this.addBaseSeriesEvents();
    }
  }
  /**
   * Add data events.
   * For example when main series is updated we need to recalculate extremes
   *
   * @private
   * @function Highcharts.Navigator#addBaseSeriesEvent
   */
  addBaseSeriesEvents() {
    const navigator2 = this, baseSeries = navigator2.baseSeries || [];
    if (baseSeries[0] && baseSeries[0].xAxis) {
      baseSeries[0].eventsToUnbind.push(addEvent$18(baseSeries[0].xAxis, "foundExtremes", this.modifyBaseAxisExtremes));
    }
    baseSeries.forEach((base2) => {
      base2.eventsToUnbind.push(addEvent$18(base2, "show", function() {
        if (this.navigatorSeries) {
          this.navigatorSeries.setVisible(true, false);
        }
      }));
      base2.eventsToUnbind.push(addEvent$18(base2, "hide", function() {
        if (this.navigatorSeries) {
          this.navigatorSeries.setVisible(false, false);
        }
      }));
      if (this.navigatorOptions.adaptToUpdatedData !== false) {
        if (base2.xAxis) {
          base2.eventsToUnbind.push(addEvent$18(base2, "updatedData", this.updatedDataHandler));
        }
      }
      base2.eventsToUnbind.push(addEvent$18(base2, "remove", function() {
        if (baseSeries) {
          erase$3(baseSeries, base2);
        }
        if (this.navigatorSeries && navigator2.series) {
          erase$3(navigator2.series, this.navigatorSeries);
          if (defined$R(this.navigatorSeries.options)) {
            this.navigatorSeries.remove(false);
          }
          delete this.navigatorSeries;
        }
      }));
    });
  }
  /**
   * Get minimum from all base series connected to the navigator
   * @private
   * @param {number} currentSeriesMin
   *        Minium from the current series
   * @return {number}
   *         Minimum from all series
   */
  getBaseSeriesMin(currentSeriesMin) {
    return this.baseSeries.reduce(function(min2, series) {
      return Math.min(min2, series.getColumn("x")[0] ?? min2);
    }, currentSeriesMin);
  }
  /**
   * Set the navigator x axis extremes to reflect the total. The navigator
   * extremes should always be the extremes of the union of all series in the
   * chart as well as the navigator series.
   *
   * @private
   * @function Highcharts.Navigator#modifyNavigatorAxisExtremes
   */
  modifyNavigatorAxisExtremes() {
    const xAxis2 = this.xAxis;
    if (typeof xAxis2.getExtremes !== "undefined") {
      const unionExtremes = this.getUnionExtremes(true);
      if (unionExtremes && (unionExtremes.dataMin !== xAxis2.min || unionExtremes.dataMax !== xAxis2.max)) {
        xAxis2.min = unionExtremes.dataMin;
        xAxis2.max = unionExtremes.dataMax;
      }
    }
  }
  /**
   * Hook to modify the base axis extremes with information from the Navigator
   *
   * @private
   * @function Highcharts.Navigator#modifyBaseAxisExtremes
   */
  modifyBaseAxisExtremes() {
    const baseXAxis = this, navigator2 = baseXAxis.chart.navigator, baseExtremes = baseXAxis.getExtremes(), baseMin = baseExtremes.min, baseMax = baseExtremes.max, baseDataMin = baseExtremes.dataMin, baseDataMax = baseExtremes.dataMax, range2 = baseMax - baseMin, stickToMin = navigator2.stickToMin, stickToMax = navigator2.stickToMax, overscroll = pick$1h(baseXAxis.ordinal?.convertOverscroll(baseXAxis.options.overscroll), 0), navigatorSeries = navigator2.series && navigator2.series[0], hasSetExtremes = !!baseXAxis.setExtremes, unmutable = baseXAxis.eventArgs && baseXAxis.eventArgs.trigger === "rangeSelectorButton";
    let newMax, newMin;
    if (!unmutable) {
      if (stickToMin) {
        newMin = baseDataMin;
        newMax = newMin + range2;
      }
      if (stickToMax) {
        newMax = baseDataMax + overscroll;
        if (!stickToMin) {
          newMin = Math.max(
            baseDataMin,
            // Don't go below data extremes (#13184)
            newMax - range2,
            navigator2.getBaseSeriesMin(navigatorSeries && navigatorSeries.xData ? navigatorSeries.xData[0] : -Number.MAX_VALUE)
          );
        }
      }
      if (hasSetExtremes && (stickToMin || stickToMax)) {
        if (isNumber$O(newMin)) {
          baseXAxis.min = baseXAxis.userMin = newMin;
          baseXAxis.max = baseXAxis.userMax = newMax;
        }
      }
    }
    navigator2.stickToMin = navigator2.stickToMax = null;
  }
  /**
   * Handler for updated data on the base series. When data is modified, the
   * navigator series must reflect it. This is called from the Chart.redraw
   * function before axis and series extremes are computed.
   *
   * @private
   * @function Highcharts.Navigator#updateDataHandler
   */
  updatedDataHandler() {
    const navigator2 = this.chart.navigator, baseSeries = this, navigatorSeries = this.navigatorSeries, shouldStickToMax = navigator2.reversedExtremes ? Math.round(navigator2.zoomedMin) === 0 : Math.round(navigator2.zoomedMax) >= Math.round(navigator2.size);
    navigator2.stickToMax = pick$1h(this.chart.options.navigator && this.chart.options.navigator.stickToMax, shouldStickToMax);
    navigator2.stickToMin = navigator2.shouldStickToMin(baseSeries, navigator2);
    if (navigatorSeries && !navigator2.hasNavigatorData) {
      navigatorSeries.options.pointStart = baseSeries.getColumn("x")[0];
      navigatorSeries.setData(baseSeries.options.data, false, null, false);
    }
  }
  /**
   * Detect if the zoomed area should stick to the minimum, #14742.
   *
   * @private
   * @function Highcharts.Navigator#shouldStickToMin
   */
  shouldStickToMin(baseSeries, navigator2) {
    const xDataMin = navigator2.getBaseSeriesMin(baseSeries.getColumn("x")[0]), xAxis2 = baseSeries.xAxis, max2 = xAxis2.max, min2 = xAxis2.min, range2 = xAxis2.options.range;
    let stickToMin = true;
    if (isNumber$O(max2) && isNumber$O(min2)) {
      if (range2 && max2 - xDataMin > 0) {
        stickToMin = max2 - xDataMin < range2;
      } else {
        stickToMin = min2 <= xDataMin;
      }
    } else {
      stickToMin = false;
    }
    return stickToMin;
  }
  /**
   * Add chart events, like redrawing navigator, when chart requires that.
   *
   * @private
   * @function Highcharts.Navigator#addChartEvents
   */
  addChartEvents() {
    if (!this.eventsToUnbind) {
      this.eventsToUnbind = [];
    }
    this.eventsToUnbind.push(
      // Move the scrollbar after redraw, like after data updata even if
      // axes don't redraw
      addEvent$18(this.chart, "redraw", function() {
        const navigator2 = this.navigator, xAxis2 = navigator2 && (navigator2.baseSeries && navigator2.baseSeries[0] && navigator2.baseSeries[0].xAxis || this.xAxis[0]);
        if (xAxis2) {
          navigator2.render(xAxis2.min, xAxis2.max);
        }
      }),
      // Make room for the navigator, can be placed around the chart:
      addEvent$18(this.chart, "getMargins", function() {
        const chart = this, navigator2 = chart.navigator;
        let marginName = navigator2.opposite ? "plotTop" : "marginBottom";
        if (chart.inverted) {
          marginName = navigator2.opposite ? "marginRight" : "plotLeft";
        }
        chart[marginName] = (chart[marginName] || 0) + (navigator2.navigatorEnabled || !chart.inverted ? navigator2.height + (this.scrollbar?.options.margin || 0) + navigator2.scrollbarHeight : 0) + (navigator2.navigatorOptions.margin || 0);
      }),
      addEvent$18(Navigator, "setRange", function(e) {
        this.chart.xAxis[0].setExtremes(e.min, e.max, e.redraw, e.animation, e.eventArguments);
      })
    );
  }
  /**
   * Destroys allocated elements.
   *
   * @private
   * @function Highcharts.Navigator#destroy
   */
  destroy() {
    this.removeEvents();
    if (this.xAxis) {
      erase$3(this.chart.xAxis, this.xAxis);
      erase$3(this.chart.axes, this.xAxis);
    }
    if (this.yAxis) {
      erase$3(this.chart.yAxis, this.yAxis);
      erase$3(this.chart.axes, this.yAxis);
    }
    (this.series || []).forEach((s) => {
      if (s.destroy) {
        s.destroy();
      }
    });
    [
      "series",
      "xAxis",
      "yAxis",
      "shades",
      "outline",
      "scrollbarTrack",
      "scrollbarRifles",
      "scrollbarGroup",
      "scrollbar",
      "navigatorGroup",
      "rendered"
    ].forEach((prop) => {
      if (this[prop] && this[prop].destroy) {
        this[prop].destroy();
      }
      this[prop] = null;
    });
    [this.handles].forEach((coll) => {
      destroyObjectProperties$2(coll);
    });
    this.baseSeries.forEach((s) => {
      s.navigatorSeries = void 0;
    });
    this.navigatorEnabled = false;
  }
}
const { addEvent: addEvent$17, correctFloat: correctFloat$7, css: css$6, defined: defined$Q, error: error$5, isNumber: isNumber$N, pick: pick$1g, timeUnits: timeUnits$1, isString: isString$7 } = Utilities;
var OrdinalAxis;
(function(OrdinalAxis2) {
  function compose2(AxisClass, SeriesClass, ChartClass) {
    const axisProto = AxisClass.prototype;
    if (!axisProto.ordinal2lin) {
      axisProto.getTimeTicks = getTimeTicks;
      axisProto.index2val = index2val;
      axisProto.lin2val = lin2val;
      axisProto.val2lin = val2lin;
      axisProto.ordinal2lin = axisProto.val2lin;
      addEvent$17(AxisClass, "afterInit", onAxisAfterInit);
      addEvent$17(AxisClass, "foundExtremes", onAxisFoundExtremes2);
      addEvent$17(AxisClass, "afterSetScale", onAxisAfterSetScale);
      addEvent$17(AxisClass, "initialAxisTranslation", onAxisInitialAxisTranslation);
      addEvent$17(ChartClass, "pan", onChartPan);
      addEvent$17(ChartClass, "touchpan", onChartPan);
      addEvent$17(SeriesClass, "updatedData", onSeriesUpdatedData);
    }
    return AxisClass;
  }
  OrdinalAxis2.compose = compose2;
  function getTimeTicks(normalizedInterval, min2, max2, startOfWeek2, positions = [], closestDistance = 0, findHigherRanks) {
    const higherRanks = {}, tickPixelIntervalOption = this.options.tickPixelInterval, time = this.chart.time, segmentStarts = [];
    let end, segmentPositions, hasCrossedHigherRank, info, outsideMax, start2 = 0, groupPositions = [], lastGroupPosition = -Number.MAX_VALUE;
    if (!this.options.ordinal && !this.options.breaks || !positions || positions.length < 3 || typeof min2 === "undefined") {
      return time.getTimeTicks.apply(time, arguments);
    }
    const posLength = positions.length;
    for (end = 0; end < posLength; end++) {
      outsideMax = end && positions[end - 1] > max2;
      if (positions[end] < min2) {
        start2 = end;
      }
      if (end === posLength - 1 || positions[end + 1] - positions[end] > closestDistance * 5 || outsideMax) {
        if (positions[end] > lastGroupPosition) {
          segmentPositions = time.getTimeTicks(normalizedInterval, positions[start2], positions[end], startOfWeek2);
          while (segmentPositions.length && segmentPositions[0] <= lastGroupPosition) {
            segmentPositions.shift();
          }
          if (segmentPositions.length) {
            lastGroupPosition = segmentPositions[segmentPositions.length - 1];
          }
          segmentStarts.push(groupPositions.length);
          groupPositions = groupPositions.concat(segmentPositions);
        }
        start2 = end + 1;
      }
      if (outsideMax) {
        break;
      }
    }
    if (segmentPositions) {
      info = segmentPositions.info;
      if (findHigherRanks && info.unitRange <= timeUnits$1.hour) {
        end = groupPositions.length - 1;
        for (start2 = 1; start2 < end; start2++) {
          if (time.dateFormat("%d", groupPositions[start2]) !== time.dateFormat("%d", groupPositions[start2 - 1])) {
            higherRanks[groupPositions[start2]] = "day";
            hasCrossedHigherRank = true;
          }
        }
        if (hasCrossedHigherRank) {
          higherRanks[groupPositions[0]] = "day";
        }
        info.higherRanks = higherRanks;
      }
      info.segmentStarts = segmentStarts;
      groupPositions.info = info;
    } else {
      error$5(12, false, this.chart);
    }
    if (findHigherRanks && defined$Q(tickPixelIntervalOption)) {
      const length = groupPositions.length, translatedArr = [], distances = [];
      let itemToRemove, translated, lastTranslated, medianDistance, distance, i = length;
      while (i--) {
        translated = this.translate(groupPositions[i]);
        if (lastTranslated) {
          distances[i] = lastTranslated - translated;
        }
        translatedArr[i] = lastTranslated = translated;
      }
      distances.sort((a, b) => a - b);
      medianDistance = distances[Math.floor(distances.length / 2)];
      if (medianDistance < tickPixelIntervalOption * 0.6) {
        medianDistance = null;
      }
      i = groupPositions[length - 1] > max2 ? length - 1 : length;
      lastTranslated = void 0;
      while (i--) {
        translated = translatedArr[i];
        distance = Math.abs(lastTranslated - translated);
        if (lastTranslated && distance < tickPixelIntervalOption * 0.8 && (medianDistance === null || distance < medianDistance * 0.8)) {
          if (higherRanks[groupPositions[i]] && !higherRanks[groupPositions[i + 1]]) {
            itemToRemove = i + 1;
            lastTranslated = translated;
          } else {
            itemToRemove = i;
          }
          groupPositions.splice(itemToRemove, 1);
        } else {
          lastTranslated = translated;
        }
      }
    }
    return groupPositions;
  }
  function index2val(index) {
    const axis = this, ordinal = axis.ordinal, ordinalPositions = ordinal.positions;
    if (!ordinalPositions) {
      return index;
    }
    let i = ordinalPositions.length - 1, distance;
    if (index < 0) {
      index = ordinalPositions[0];
    } else if (index > i) {
      index = ordinalPositions[i];
    } else {
      i = Math.floor(index);
      distance = index - i;
    }
    if (typeof distance !== "undefined" && typeof ordinalPositions[i] !== "undefined") {
      return ordinalPositions[i] + (distance ? distance * (ordinalPositions[i + 1] - ordinalPositions[i]) : 0);
    }
    return index;
  }
  function lin2val(val) {
    const axis = this, ordinal = axis.ordinal, localMin = axis.old ? axis.old.min : axis.min, localA = axis.old ? axis.old.transA : axis.transA;
    const positions = ordinal.getExtendedPositions();
    if (positions?.length) {
      const pixelVal = correctFloat$7((val - localMin) * localA + axis.minPixelPadding), index = correctFloat$7(ordinal.getIndexOfPoint(pixelVal, positions)), mantissa = correctFloat$7(index % 1);
      if (index >= 0 && index <= positions.length - 1) {
        const leftNeighbour = positions[Math.floor(index)], rightNeighbour = positions[Math.ceil(index)], distance = rightNeighbour - leftNeighbour;
        return positions[Math.floor(index)] + mantissa * distance;
      }
    }
    return val;
  }
  function getIndexInArray(ordinalPositions, val) {
    const index = OrdinalAxis2.Additions.findIndexOf(ordinalPositions, val, true);
    if (ordinalPositions[index] === val) {
      return index;
    }
    const percent = (val - ordinalPositions[index]) / (ordinalPositions[index + 1] - ordinalPositions[index]);
    return index + percent;
  }
  function onAxisAfterInit() {
    const axis = this;
    if (!axis.ordinal) {
      axis.ordinal = new OrdinalAxis2.Additions(axis);
    }
  }
  function onAxisFoundExtremes2() {
    const axis = this, { eventArgs, options: options2 } = axis;
    if (axis.isXAxis && defined$Q(options2.overscroll) && options2.overscroll !== 0 && isNumber$N(axis.max) && isNumber$N(axis.min)) {
      if (axis.options.ordinal && !axis.ordinal.originalOrdinalRange) {
        axis.ordinal.getExtendedPositions(false);
      }
      if (axis.max === axis.dataMax && // Panning is an exception. We don't want to apply
      // overscroll when panning over the dataMax
      (eventArgs?.trigger !== "pan" || axis.isInternal) && // Scrollbar buttons are the other execption
      eventArgs?.trigger !== "navigator") {
        const overscroll = axis.ordinal.convertOverscroll(options2.overscroll);
        axis.max += overscroll;
        if (!axis.isInternal && defined$Q(axis.userMin) && eventArgs?.trigger !== "mousewheel") {
          axis.min += overscroll;
        }
      }
    }
  }
  function onAxisAfterSetScale() {
    const axis = this;
    if (axis.horiz && !axis.isDirty) {
      axis.isDirty = axis.isOrdinal && axis.chart.navigator && !axis.chart.navigator.adaptToUpdatedData;
    }
  }
  function onAxisInitialAxisTranslation() {
    const axis = this;
    if (axis.ordinal) {
      axis.ordinal.beforeSetTickPositions();
      axis.tickInterval = axis.ordinal.postProcessTickInterval(axis.tickInterval);
    }
  }
  function onChartPan(e) {
    const chart = this, xAxis2 = chart.xAxis[0], overscroll = xAxis2.ordinal.convertOverscroll(xAxis2.options.overscroll), chartX = e.originalEvent.chartX, panning = chart.options.chart.panning;
    let runBase = false;
    if (panning && panning.type !== "y" && xAxis2.options.ordinal && xAxis2.series.length && // On touch devices, let default function handle the pinching
    (!e.touches || e.touches.length <= 1)) {
      const mouseDownX = chart.mouseDownX, extremes = xAxis2.getExtremes(), dataMin = extremes.dataMin, dataMax = extremes.dataMax, min2 = extremes.min, max2 = extremes.max, hoverPoints = chart.hoverPoints, closestPointRange = xAxis2.closestPointRange || xAxis2.ordinal?.overscrollPointsRange, pointPixelWidth = xAxis2.translationSlope * (xAxis2.ordinal.slope || closestPointRange), movedUnits = Math.round((mouseDownX - chartX) / pointPixelWidth), extendedOrdinalPositions = xAxis2.ordinal.getExtendedPositions(), extendedAxis = {
        ordinal: {
          positions: extendedOrdinalPositions,
          extendedOrdinalPositions
        }
      }, index2val2 = xAxis2.index2val, val2lin2 = xAxis2.val2lin;
      let trimmedRange, ordinalPositions;
      if (min2 <= dataMin && movedUnits < 0 || max2 + overscroll >= dataMax && movedUnits > 0) {
        return;
      }
      if (!extendedAxis.ordinal.positions) {
        runBase = true;
      } else if (Math.abs(movedUnits) > 1) {
        if (hoverPoints) {
          hoverPoints.forEach(function(point) {
            point.setState();
          });
        }
        ordinalPositions = extendedAxis.ordinal.positions;
        if (dataMax > ordinalPositions[ordinalPositions.length - 1]) {
          ordinalPositions.push(dataMax);
        }
        chart.setFixedRange(max2 - min2);
        trimmedRange = xAxis2.navigatorAxis.toFixedRange(void 0, void 0, index2val2.apply(extendedAxis, [
          val2lin2.apply(extendedAxis, [min2, true]) + movedUnits
        ]), index2val2.apply(extendedAxis, [
          val2lin2.apply(extendedAxis, [max2, true]) + movedUnits
        ]));
        if (trimmedRange.min >= Math.min(ordinalPositions[0], min2) && trimmedRange.max <= Math.max(ordinalPositions[ordinalPositions.length - 1], max2) + overscroll) {
          xAxis2.setExtremes(trimmedRange.min, trimmedRange.max, true, false, { trigger: "pan" });
        }
        chart.mouseDownX = chartX;
        css$6(chart.container, { cursor: "move" });
      }
    } else {
      runBase = true;
    }
    if (runBase || panning && /y/.test(panning.type)) {
      if (overscroll) {
        xAxis2.max = xAxis2.dataMax + overscroll;
      }
    } else {
      e.preventDefault();
    }
  }
  function onSeriesUpdatedData() {
    const xAxis2 = this.xAxis;
    if (xAxis2?.options.ordinal) {
      delete xAxis2.ordinal.index;
      delete xAxis2.ordinal.originalOrdinalRange;
    }
  }
  function val2lin(val, toIndex) {
    const axis = this, ordinal = axis.ordinal, ordinalPositions = ordinal.positions;
    let slope = ordinal.slope, extendedOrdinalPositions;
    if (!ordinalPositions) {
      return val;
    }
    const ordinalLength = ordinalPositions.length;
    let ordinalIndex;
    if (ordinalPositions[0] <= val && ordinalPositions[ordinalLength - 1] >= val) {
      ordinalIndex = getIndexInArray(ordinalPositions, val);
    } else {
      extendedOrdinalPositions = ordinal.getExtendedPositions?.();
      if (!extendedOrdinalPositions?.length) {
        return val;
      }
      const length = extendedOrdinalPositions.length;
      if (!slope) {
        slope = (extendedOrdinalPositions[length - 1] - extendedOrdinalPositions[0]) / length;
      }
      const originalPositionsReference = getIndexInArray(extendedOrdinalPositions, ordinalPositions[0]);
      if (val >= extendedOrdinalPositions[0] && val <= extendedOrdinalPositions[length - 1]) {
        ordinalIndex = getIndexInArray(extendedOrdinalPositions, val) - originalPositionsReference;
      } else {
        if (!toIndex) {
          return val;
        }
        if (val < extendedOrdinalPositions[0]) {
          const diff = extendedOrdinalPositions[0] - val, approximateIndexOffset = diff / slope;
          ordinalIndex = -originalPositionsReference - approximateIndexOffset;
        } else {
          const diff = val - extendedOrdinalPositions[length - 1], approximateIndexOffset = diff / slope;
          ordinalIndex = approximateIndexOffset + length - originalPositionsReference;
        }
      }
    }
    return toIndex ? ordinalIndex : slope * (ordinalIndex || 0) + ordinal.offset;
  }
  class Additions {
    /* *
     *
     *  Constructors
     *
     * */
    /**
     * @private
     */
    constructor(axis) {
      this.index = {};
      this.axis = axis;
    }
    /* *
    *
    *  Functions
    *
    * */
    /**
     * Calculate the ordinal positions before tick positions are calculated.
     * @private
     */
    beforeSetTickPositions() {
      const axis = this.axis, ordinal = axis.ordinal, extremes = axis.getExtremes(), min2 = extremes.min, max2 = extremes.max, hasBreaks = axis.brokenAxis?.hasBreaks, isOrdinal = axis.options.ordinal;
      let len, uniqueOrdinalPositions, dist, minIndex, maxIndex, slope, i, ordinalPositions = [], overscrollPointsRange = Number.MAX_VALUE, useOrdinal = false, adjustOrdinalExtremesPoints = false, isBoosted = false;
      if (isOrdinal || hasBreaks) {
        let distanceBetweenPoint = 0;
        axis.series.forEach(function(series, i2) {
          const xData = series.getColumn("x", true);
          uniqueOrdinalPositions = [];
          if (i2 > 0 && series.options.id !== "highcharts-navigator-series" && xData.length > 1) {
            adjustOrdinalExtremesPoints = distanceBetweenPoint !== xData[1] - xData[0];
          }
          distanceBetweenPoint = xData[1] - xData[0];
          if (series.boosted) {
            isBoosted = series.boosted;
          }
          if (series.reserveSpace() && (series.takeOrdinalPosition !== false || hasBreaks)) {
            ordinalPositions = ordinalPositions.concat(xData);
            len = ordinalPositions.length;
            ordinalPositions.sort(function(a, b) {
              return a - b;
            });
            overscrollPointsRange = Math.min(overscrollPointsRange, pick$1g(
              // Check for a single-point series:
              series.closestPointRange,
              overscrollPointsRange
            ));
            if (len) {
              i2 = 0;
              while (i2 < len - 1) {
                if (ordinalPositions[i2] !== ordinalPositions[i2 + 1]) {
                  uniqueOrdinalPositions.push(ordinalPositions[i2 + 1]);
                }
                i2++;
              }
              if (uniqueOrdinalPositions[0] !== ordinalPositions[0]) {
                uniqueOrdinalPositions.unshift(ordinalPositions[0]);
              }
              ordinalPositions = uniqueOrdinalPositions;
            }
          }
        });
        if (!axis.ordinal.originalOrdinalRange) {
          axis.ordinal.originalOrdinalRange = (ordinalPositions.length - 1) * overscrollPointsRange;
        }
        if (adjustOrdinalExtremesPoints && isBoosted) {
          ordinalPositions.pop();
          ordinalPositions.shift();
        }
        len = ordinalPositions.length;
        if (len > 2) {
          dist = ordinalPositions[1] - ordinalPositions[0];
          i = len - 1;
          while (i-- && !useOrdinal) {
            if (ordinalPositions[i + 1] - ordinalPositions[i] !== dist) {
              useOrdinal = true;
            }
          }
          if (!axis.options.keepOrdinalPadding && (ordinalPositions[0] - min2 > dist || max2 - ordinalPositions[ordinalPositions.length - 1] > dist)) {
            useOrdinal = true;
          }
        } else if (axis.options.overscroll) {
          if (len === 2) {
            overscrollPointsRange = ordinalPositions[1] - ordinalPositions[0];
          } else if (len === 1) {
            overscrollPointsRange = axis.ordinal.convertOverscroll(axis.options.overscroll);
            ordinalPositions = [
              ordinalPositions[0],
              ordinalPositions[0] + overscrollPointsRange
            ];
          } else {
            overscrollPointsRange = ordinal.overscrollPointsRange;
          }
        }
        if (useOrdinal || axis.forceOrdinal) {
          if (axis.options.overscroll) {
            ordinal.overscrollPointsRange = overscrollPointsRange;
            ordinalPositions = ordinalPositions.concat(ordinal.getOverscrollPositions());
          }
          ordinal.positions = ordinalPositions;
          minIndex = axis.ordinal2lin(
            // #5979
            Math.max(min2, ordinalPositions[0]),
            true
          );
          maxIndex = Math.max(axis.ordinal2lin(Math.min(max2, ordinalPositions[ordinalPositions.length - 1]), true), 1);
          ordinal.slope = slope = (max2 - min2) / (maxIndex - minIndex);
          ordinal.offset = min2 - minIndex * slope;
        } else {
          ordinal.overscrollPointsRange = pick$1g(axis.closestPointRange, ordinal.overscrollPointsRange);
          ordinal.positions = axis.ordinal.slope = ordinal.offset = void 0;
        }
      }
      axis.isOrdinal = isOrdinal && useOrdinal;
      ordinal.groupIntervalFactor = null;
    }
    /**
     * Faster way of using the Array.indexOf method.
     * Works for sorted arrays only with unique values.
     *
     * @param {Array} sortedArray
     *        The sorted array inside which we are looking for.
     * @param {number} key
     *        The key to being found.
     * @param {boolean} indirectSearch
     *        In case of lack of the point in the array, should return
     *        value be equal to -1 or the closest smaller index.
     *  @private
     */
    static findIndexOf(sortedArray, key2, indirectSearch) {
      let start2 = 0, end = sortedArray.length - 1, middle;
      while (start2 < end) {
        middle = Math.ceil((start2 + end) / 2);
        if (sortedArray[middle] <= key2) {
          start2 = middle;
        } else {
          end = middle - 1;
        }
      }
      if (sortedArray[start2] === key2) {
        return start2;
      }
      return !indirectSearch ? -1 : start2;
    }
    /**
     * Get the ordinal positions for the entire data set. This is necessary
     * in chart panning because we need to find out what points or data
     * groups are available outside the visible range. When a panning
     * operation starts, if an index for the given grouping does not exists,
     * it is created and cached. This index is deleted on updated data, so
     * it will be regenerated the next time a panning operation starts.
     * @private
     */
    getExtendedPositions(withOverscroll = true) {
      const ordinal = this, axis = ordinal.axis, axisProto = axis.constructor.prototype, chart = axis.chart, key2 = axis.series.reduce((k, series) => {
        const grouping = series.currentDataGrouping;
        return k + (grouping ? grouping.count + grouping.unitName : "raw");
      }, ""), overscroll = withOverscroll ? axis.ordinal.convertOverscroll(axis.options.overscroll) : 0, extremes = axis.getExtremes();
      let fakeAxis, fakeSeries = void 0, ordinalIndex = ordinal.index;
      if (!ordinalIndex) {
        ordinalIndex = ordinal.index = {};
      }
      if (!ordinalIndex[key2]) {
        fakeAxis = {
          series: [],
          chart,
          forceOrdinal: false,
          getExtremes: function() {
            return {
              min: extremes.dataMin,
              max: extremes.dataMax + overscroll
            };
          },
          applyGrouping: axisProto.applyGrouping,
          getGroupPixelWidth: axisProto.getGroupPixelWidth,
          getTimeTicks: axisProto.getTimeTicks,
          options: {
            ordinal: true
          },
          ordinal: {
            getGroupIntervalFactor: this.getGroupIntervalFactor
          },
          ordinal2lin: axisProto.ordinal2lin,
          // #6276
          getIndexOfPoint: axisProto.getIndexOfPoint,
          val2lin: axisProto.val2lin
          // #2590
        };
        fakeAxis.ordinal.axis = fakeAxis;
        axis.series.forEach((series) => {
          fakeSeries = {
            xAxis: fakeAxis,
            chart,
            groupPixelWidth: series.groupPixelWidth,
            destroyGroupedData: Highcharts.noop,
            getColumn: series.getColumn,
            applyGrouping: series.applyGrouping,
            getProcessedData: series.getProcessedData,
            reserveSpace: series.reserveSpace,
            visible: series.visible
          };
          const xData = series.getColumn("x").concat(withOverscroll ? ordinal.getOverscrollPositions() : []);
          fakeSeries.dataTable = new DataTableCore({
            columns: {
              x: xData
            }
          });
          fakeSeries.options = {
            ...series.options,
            dataGrouping: series.currentDataGrouping ? {
              firstAnchor: series.options.dataGrouping?.firstAnchor,
              anchor: series.options.dataGrouping?.anchor,
              lastAnchor: series.options.dataGrouping?.firstAnchor,
              enabled: true,
              forced: true,
              approximation: "open",
              units: [[
                series.currentDataGrouping.unitName,
                [series.currentDataGrouping.count]
              ]]
            } : {
              enabled: false
            }
          };
          fakeAxis.series.push(fakeSeries);
          series.processData.apply(fakeSeries);
        });
        fakeAxis.applyGrouping({ hasExtremesChanged: true });
        if (fakeSeries?.closestPointRange !== fakeSeries?.basePointRange && fakeSeries.currentDataGrouping) {
          fakeAxis.forceOrdinal = true;
        }
        axis.ordinal.beforeSetTickPositions.apply({ axis: fakeAxis });
        if (!axis.ordinal.originalOrdinalRange && fakeAxis.ordinal.originalOrdinalRange) {
          axis.ordinal.originalOrdinalRange = fakeAxis.ordinal.originalOrdinalRange;
        }
        if (fakeAxis.ordinal.positions) {
          ordinalIndex[key2] = fakeAxis.ordinal.positions;
        }
      }
      return ordinalIndex[key2];
    }
    /**
     * Find the factor to estimate how wide the plot area would have been if
     * ordinal gaps were included. This value is used to compute an imagined
     * plot width in order to establish the data grouping interval.
     *
     * A real world case is the intraday-candlestick example. Without this
     * logic, it would show the correct data grouping when viewing a range
     * within each day, but once moving the range to include the gap between
     * two days, the interval would include the cut-away night hours and the
     * data grouping would be wrong. So the below method tries to compensate
     * by identifying the most common point interval, in this case days.
     *
     * An opposite case is presented in issue #718. We have a long array of
     * daily data, then one point is appended one hour after the last point.
     * We expect the data grouping not to change.
     *
     * In the future, if we find cases where this estimation doesn't work
     * optimally, we might need to add a second pass to the data grouping
     * logic, where we do another run with a greater interval if the number
     * of data groups is more than a certain fraction of the desired group
     * count.
     * @private
     */
    getGroupIntervalFactor(xMin, xMax, series) {
      const ordinal = this, processedXData = series.getColumn("x", true), len = processedXData.length, distances = [];
      let median, i, groupIntervalFactor = ordinal.groupIntervalFactor;
      if (!groupIntervalFactor) {
        for (i = 0; i < len - 1; i++) {
          distances[i] = processedXData[i + 1] - processedXData[i];
        }
        distances.sort(function(a, b) {
          return a - b;
        });
        median = distances[Math.floor(len / 2)];
        xMin = Math.max(xMin, processedXData[0]);
        xMax = Math.min(xMax, processedXData[len - 1]);
        ordinal.groupIntervalFactor = groupIntervalFactor = len * median / (xMax - xMin);
      }
      return groupIntervalFactor;
    }
    /**
     * Get index of point inside the ordinal positions array.
     *
     * @private
     * @param {number} pixelVal
     * The pixel value of a point.
     *
     * @param {Array<number>} [ordinalArray]
     * An array of all points available on the axis for the given data set.
     * Either ordinalPositions if the value is inside the plotArea or
     * extendedOrdinalPositions if not.
     */
    getIndexOfPoint(pixelVal, ordinalArray) {
      const ordinal = this, axis = ordinal.axis, min2 = axis.min, minX = axis.minPixelPadding, indexOfMin = getIndexInArray(ordinalArray, min2);
      const ordinalPointPixelInterval = axis.translationSlope * (ordinal.slope || axis.closestPointRange || ordinal.overscrollPointsRange);
      const shiftIndex = correctFloat$7((pixelVal - minX) / ordinalPointPixelInterval);
      return indexOfMin + shiftIndex;
    }
    /**
     * Get ticks for an ordinal axis within a range where points don't
     * exist. It is required when overscroll is enabled. We can't base on
     * points, because we may not have any, so we use approximated
     * pointRange and generate these ticks between Axis.dataMax,
     * Axis.dataMax + Axis.overscroll evenly spaced. Used in panning and
     * navigator scrolling.
     * @private
     */
    getOverscrollPositions() {
      const ordinal = this, axis = ordinal.axis, extraRange = ordinal.convertOverscroll(axis.options.overscroll), distance = ordinal.overscrollPointsRange, positions = [];
      let max2 = axis.dataMax;
      if (defined$Q(distance)) {
        while (max2 < axis.dataMax + extraRange) {
          max2 += distance;
          positions.push(max2);
        }
      }
      return positions;
    }
    /**
     * Make the tick intervals closer because the ordinal gaps make the
     * ticks spread out or cluster.
     * @private
     */
    postProcessTickInterval(tickInterval) {
      const ordinal = this, axis = ordinal.axis, ordinalSlope = ordinal.slope, closestPointRange = axis.closestPointRange;
      let ret;
      if (ordinalSlope && closestPointRange) {
        if (!axis.options.breaks) {
          ret = tickInterval / (ordinalSlope / closestPointRange);
        } else {
          ret = closestPointRange || tickInterval;
        }
      } else {
        ret = tickInterval;
      }
      return ret;
    }
    /**
     * If overscroll is pixel or percentage value, convert it to axis range.
     *
     * @private
     * @param {number | string} overscroll
     * Overscroll value in axis range, pixels or percentage value.
     * @return {number}
     * Overscroll value in axis range.
     */
    convertOverscroll(overscroll = 0) {
      const ordinal = this, axis = ordinal.axis, calculateOverscroll = function(overscrollPercentage) {
        return pick$1g(ordinal.originalOrdinalRange, defined$Q(axis.dataMax) && defined$Q(axis.dataMin) ? axis.dataMax - axis.dataMin : 0) * overscrollPercentage;
      };
      if (isString$7(overscroll)) {
        const overscrollValue = parseInt(overscroll, 10);
        let isFullRange;
        if (defined$Q(axis.min) && defined$Q(axis.max) && defined$Q(axis.dataMin) && defined$Q(axis.dataMax)) {
          isFullRange = axis.max - axis.min === axis.dataMax - axis.dataMin;
          if (!isFullRange) {
            this.originalOrdinalRange = axis.max - axis.min;
          }
        }
        if (/%$/.test(overscroll)) {
          return calculateOverscroll(overscrollValue / 100);
        }
        if (/px/.test(overscroll)) {
          const limitedOverscrollValue = Math.min(overscrollValue, axis.len * 0.9), pixelToPercent = limitedOverscrollValue / axis.len;
          return calculateOverscroll(pixelToPercent / (isFullRange ? 1 - pixelToPercent : 1));
        }
        return 0;
      }
      return overscroll;
    }
  }
  OrdinalAxis2.Additions = Additions;
})(OrdinalAxis || (OrdinalAxis = {}));
const OrdinalAxis$1 = OrdinalAxis;
const lang$4 = {
  /**
   * The text for the label for the range selector buttons.
   *
   * @product highstock gantt
   */
  rangeSelectorZoom: "Zoom",
  /**
   * The text for the label for the "from" input box in the range
   * selector. Since v9.0, this string is empty as the label is not
   * rendered by default.
   *
   * @product highstock gantt
   */
  rangeSelectorFrom: "",
  /**
   * The text for the label for the "to" input box in the range selector.
   *
   * @product highstock gantt
   */
  rangeSelectorTo: "→",
  /**
   * The default text for the rangeselector buttons.
   *
   * @since 12.2.0
   */
  rangeSelector: {
    allText: "All",
    allTitle: "View all",
    monthText: "{count}m",
    monthTitle: "View {count} {#eq count 1}month{else}months{/eq}",
    yearText: "{count}y",
    yearTitle: "View {count} {#eq count 1}year{else}years{/eq}",
    ytdText: "YTD",
    ytdTitle: "View year to date"
  }
};
const rangeSelector = {
  /**
   * Whether to enable all buttons from the start. By default buttons are
   * only enabled if the corresponding time range exists on the X axis,
   * but enabling all buttons allows for dynamically loading different
   * time ranges.
   *
   * @sample {highstock} stock/rangeselector/allbuttonsenabled-true/
   *         All buttons enabled
   *
   * @since     2.0.3
   */
  allButtonsEnabled: false,
  /**
   * An array of configuration objects for the buttons.
   *
   * Defaults to:
   * ```js
   * buttons: [{
   *     type: 'month',
   *     count: 1,
   *     text: '1m',
   *     title: 'View 1 month'
   * }, {
   *     type: 'month',
   *     count: 3,
   *     text: '3m',
   *     title: 'View 3 months'
   * }, {
   *     type: 'month',
   *     count: 6,
   *     text: '6m',
   *     title: 'View 6 months'
   * }, {
   *     type: 'ytd',
   *     text: 'YTD',
   *     title: 'View year to date'
   * }, {
   *     type: 'year',
   *     count: 1,
   *     text: '1y',
   *     title: 'View 1 year'
   * }, {
   *     type: 'all',
   *     text: 'All',
   *     title: 'View all'
   * }]
   * ```
   *
   * @sample {highstock} stock/demo/rangeselector-datagrouping/
   *         Data grouping by buttons
   *
   * @type      {Array<*>}
   */
  buttons: [{
    type: "month",
    count: 1
  }, {
    type: "month",
    count: 3
  }, {
    type: "month",
    count: 6
  }, {
    type: "ytd"
  }, {
    type: "year",
    count: 1
  }, {
    type: "all"
  }],
  /**
   * How many units of the defined type the button should span. If `type`
   * is "month" and `count` is 3, the button spans three months.
   *
   * @type      {number}
   * @default   1
   * @apioption rangeSelector.buttons.count
   */
  /**
   * Fires when clicking on the rangeSelector button. One parameter,
   * event, is passed to the function, containing common event
   * information.
   *
   * ```js
   * click: function(e) {
   *   console.log(this);
   * }
   * ```
   *
   * Return false to stop default button's click action.
   *
   * @sample {highstock} stock/rangeselector/button-click/
   *         Click event on the button
   *
   * @type      {Highcharts.RangeSelectorClickCallbackFunction}
   * @apioption rangeSelector.buttons.events.click
   */
  /**
   * Additional range (in milliseconds) added to the end of the calculated
   * time span.
   *
   * @sample {highstock} stock/rangeselector/min-max-offsets/
   *         Button offsets
   *
   * @type      {number}
   * @default   0
   * @since     6.0.0
   * @apioption rangeSelector.buttons.offsetMax
   */
  /**
   * Additional range (in milliseconds) added to the start of the
   * calculated time span.
   *
   * @sample {highstock} stock/rangeselector/min-max-offsets/
   *         Button offsets
   *
   * @type      {number}
   * @default   0
   * @since     6.0.0
   * @apioption rangeSelector.buttons.offsetMin
   */
  /**
   * When buttons apply dataGrouping on a series, by default zooming
   * in/out will deselect buttons and unset dataGrouping. Enable this
   * option to keep buttons selected when extremes change.
   *
   * @sample {highstock} stock/rangeselector/preserve-datagrouping/
   *         Different preserveDataGrouping settings
   *
   * @type      {boolean}
   * @default   false
   * @since     6.1.2
   * @apioption rangeSelector.buttons.preserveDataGrouping
   */
  /**
   * A custom data grouping object for each button.
   *
   * @see [series.dataGrouping](#plotOptions.series.dataGrouping)
   *
   * @sample {highstock} stock/demo/rangeselector-datagrouping/
   *         Data grouping by range selector buttons
   *
   * @type      {*}
   * @extends   plotOptions.series.dataGrouping
   * @apioption rangeSelector.buttons.dataGrouping
   */
  /**
   * The text for the button itself.
   *
   * @type      {string}
   * @apioption rangeSelector.buttons.text
   */
  /**
   * Explanation for the button, shown as a tooltip on hover, and used by
   * assistive technology.
   *
   * @type      {string}
   * @apioption rangeSelector.buttons.title
   */
  /**
   * Defined the time span for the button. Can be one of `millisecond`,
   * `second`, `minute`, `hour`, `day`, `week`, `month`, `year`, `ytd`,
   * and `all`.
   *
   * @type       {Highcharts.RangeSelectorButtonTypeValue}
   * @apioption  rangeSelector.buttons.type
   */
  /**
   * The space in pixels between the buttons in the range selector.
   */
  buttonSpacing: 5,
  /**
   * Whether to collapse the range selector buttons into a dropdown when
   * there is not enough room to show everything in a single row, instead
   * of dividing the range selector into multiple rows.
   * Can be one of the following:
   *  - `always`: Always collapse
   *  - `responsive`: Only collapse when there is not enough room
   *  - `never`: Never collapse
   *
   * @sample {highstock} stock/rangeselector/dropdown/
   *         Dropdown option
   *
   * @validvalue ["always", "responsive", "never"]
   * @since 9.0.0
   */
  dropdown: "responsive",
  /**
   * Enable or disable the range selector. Default to `true` for stock
   * charts, using the `stockChart` factory.
   *
   * @sample {highstock} stock/rangeselector/enabled/
   *         Disable the range selector
   *
   * @type {boolean|undefined}
   * @default {highstock} true
   */
  enabled: void 0,
  /**
   * The vertical alignment of the rangeselector box. Allowed properties
   * are `top`, `middle`, `bottom`.
   *
   * @sample {highstock} stock/rangeselector/vertical-align-middle/
   *         Middle
   * @sample {highstock} stock/rangeselector/vertical-align-bottom/
   *         Bottom
   *
   * @type  {Highcharts.VerticalAlignValue}
   * @since 6.0.0
   */
  verticalAlign: "top",
  /**
   * A collection of attributes for the buttons. The object takes SVG
   * attributes like `fill`, `stroke`, `stroke-width`, as well as `style`,
   * a collection of CSS properties for the text.
   *
   * The object can also be extended with states, so you can set
   * presentational options for `hover`, `select` or `disabled` button
   * states.
   *
   * CSS styles for the text label.
   *
   * In styled mode, the buttons are styled by the
   * `.highcharts-range-selector-buttons .highcharts-button` rule with its
   * different states.
   *
   * @sample {highstock} stock/rangeselector/styling/
   *         Styling the buttons and inputs
   *
   * @type {Highcharts.SVGAttributes}
   */
  buttonTheme: {
    /** @ignore */
    width: 28,
    /** @ignore */
    height: 18,
    /** @ignore */
    padding: 2,
    /** @ignore */
    zIndex: 7
    // #484, #852
  },
  /**
   * When the rangeselector is floating, the plot area does not reserve
   * space for it. This opens for positioning anywhere on the chart.
   *
   * @sample {highstock} stock/rangeselector/floating/
   *         Placing the range selector between the plot area and the
   *         navigator
   *
   * @since 6.0.0
   */
  floating: false,
  /**
   * The x offset of the range selector relative to its horizontal
   * alignment within `chart.spacingLeft` and `chart.spacingRight`.
   *
   * @since 6.0.0
   */
  x: 0,
  /**
   * The y offset of the range selector relative to its horizontal
   * alignment within `chart.spacingLeft` and `chart.spacingRight`.
   *
   * @since 6.0.0
   */
  y: 0,
  /**
   * Deprecated. The height of the range selector. Currently it is
   * calculated dynamically.
   *
   * @deprecated
   * @type  {number|undefined}
   * @since 2.1.9
   */
  height: void 0,
  // Reserved space for buttons and input
  /**
   * The border color of the date input boxes.
   *
   * @sample {highstock} stock/rangeselector/styling/
   *         Styling the buttons and inputs
   *
   * @type      {Highcharts.ColorString}
   * @since     1.3.7
   */
  inputBoxBorderColor: "none",
  /**
   * The pixel height of the date input boxes.
   *
   * @sample {highstock} stock/rangeselector/styling/
   *         Styling the buttons and inputs
   *
   * @since     1.3.7
   */
  inputBoxHeight: 17,
  /**
   * The pixel width of the date input boxes. When `undefined`, the width
   * is fitted to the rendered content.
   *
   * @sample {highstock} stock/rangeselector/styling/
   *         Styling the buttons and inputs
   *
   * @type   {number|undefined}
   * @since  1.3.7
   */
  inputBoxWidth: void 0,
  /**
   * The date format in the input boxes when not selected for editing.
   * Defaults to `%e %b %Y`.
   *
   * This is used to determine which type of input to show,
   * `datetime-local`, `date` or `time` and falling back to `text` when
   * the browser does not support the input type or the format contains
   * milliseconds.
   *
   * @sample {highstock} stock/rangeselector/input-type/
   *         Input types
   * @sample {highstock} stock/rangeselector/input-format/
   *         Milliseconds in the range selector
   *
   */
  inputDateFormat: "%[ebY]",
  /**
   * A custom callback function to parse values entered in the input boxes and
   * return a valid JavaScript time as milliseconds since 1970. The first
   * argument passed is the value to parse, second is a boolean indicating use
   * of UTC time. The third is a reference to the `time` object. Time zone can
   * be read from `time.timezone`.
   *
   * This will only get called for inputs of type `text`. Since v8.2.3, the
   * input type is dynamically determined based on the granularity of the
   * `inputDateFormat` and the browser support.
   *
   * @sample {highstock} stock/rangeselector/input-format/
   *         Milliseconds in the range selector
   *
   * @type      {Highcharts.RangeSelectorParseCallbackFunction}
   * @since     1.3.3
   */
  inputDateParser: void 0,
  /**
   * The date format in the input boxes when they are selected for
   * editing. This must be a format that is recognized by JavaScript
   * Date.parse.
   *
   * This will only be used for inputs of type `text`. Since v8.2.3,
   * the input type is dynamically determined based on the granularity
   * of the `inputDateFormat` and the browser support.
   *
   * @sample {highstock} stock/rangeselector/input-format/
   *         Milliseconds in the range selector
   *
   */
  inputEditDateFormat: "%Y-%m-%d",
  /**
   * Enable or disable the date input boxes.
   */
  inputEnabled: true,
  /**
   * Positioning for the input boxes. Allowed properties are `align`,
   *  `x` and `y`.
   *
   * @since 1.2.4
   */
  inputPosition: {
    /**
     * The alignment of the input box. Allowed properties are `left`,
     * `center`, `right`.
     *
     * @sample {highstock} stock/rangeselector/input-button-opposite-alignment/
     *         Opposite alignment
     *
     * @sample {highstock} stock/rangeselector/input-button-same-alignment/
     *         Same alignment for buttons and input
     *
     * @type  {Highcharts.AlignValue}
     * @since 6.0.0
     */
    align: "right",
    /**
     * X offset of the input row.
     */
    x: 0,
    /**
     * Y offset of the input row.
     */
    y: 0
  },
  /**
   * The space in pixels between the labels and the date input boxes in
   * the range selector.
   *
   * @since 9.0.0
   */
  inputSpacing: 5,
  /**
   * The index of the button to appear pre-selected. If the selected range
   * exceeds the total data range and the 'all' option is available,
   * the 'all' option, showing the full range, is automatically selected.
   *
   * @type      {number}
   */
  selected: void 0,
  /**
   * Positioning for the button row.
   *
   * @since 1.2.4
   */
  buttonPosition: {
    /**
     * The alignment of the input box. Allowed properties are `left`,
     * `center`, `right`.
     *
     * @sample {highstock} stock/rangeselector/input-button-opposite-alignment/
     *         Opposite alignment
     *
     * @sample {highstock} stock/rangeselector/input-button-same-alignment/
     *         Same alignment for buttons and input
     *
     * @type  {Highcharts.AlignValue}
     * @since 6.0.0
     */
    align: "left",
    /**
     * X offset of the button row.
     */
    x: 0,
    /**
     * Y offset of the button row.
     */
    y: 0
  },
  /**
   * CSS for the HTML inputs in the range selector.
   *
   * In styled mode, the inputs are styled by the
   * `.highcharts-range-input text` rule in SVG mode, and
   * `input.highcharts-range-selector` when active.
   *
   * @sample {highstock} stock/rangeselector/styling/
   *         Styling the buttons and inputs
   *
   * @type      {Highcharts.CSSObject}
   * @apioption rangeSelector.inputStyle
   */
  inputStyle: {
    /** @ignore */
    color: "#334eff",
    /** @ignore */
    cursor: "pointer",
    /** @ignore */
    fontSize: "0.8em"
  },
  /**
   * CSS styles for the labels - the Zoom, From and To texts.
   *
   * In styled mode, the labels are styled by the
   * `.highcharts-range-label` class.
   *
   * @sample {highstock} stock/rangeselector/styling/
   *         Styling the buttons and inputs
   *
   * @type {Highcharts.CSSObject}
   */
  labelStyle: {
    /** @ignore */
    color: "#666666",
    /** @ignore */
    fontSize: "0.8em"
  }
};
const RangeSelectorDefaults = {
  lang: lang$4,
  rangeSelector
};
const { defaultOptions: defaultOptions$c } = DefaultOptions;
const { composed: composed$p } = Highcharts;
const { addEvent: addEvent$16, defined: defined$P, extend: extend$$, isNumber: isNumber$M, merge: merge$1c, pick: pick$1f, pushUnique: pushUnique$p } = Utilities;
const chartDestroyEvents = [];
let RangeSelectorConstructor;
function axisMinFromRange() {
  const rangeOptions = this.range, type = rangeOptions.type, max2 = this.max, time = this.chart.time, getTrueRange = function(base2, count) {
    const original = time.toParts(base2), modified = original.slice();
    if (type === "year") {
      modified[0] += count;
    } else {
      modified[1] += count;
    }
    let d = time.makeTime.apply(time, modified);
    const numbers = time.toParts(d);
    if (type === "month" && original[1] === numbers[1] && Math.abs(count) === 1) {
      modified[0] = original[0];
      modified[1] = original[1];
      modified[2] = 0;
    }
    d = time.makeTime.apply(time, modified);
    return d - base2;
  };
  let min2, range2;
  if (isNumber$M(rangeOptions)) {
    min2 = max2 - rangeOptions;
    range2 = rangeOptions;
  } else if (rangeOptions) {
    min2 = max2 + getTrueRange(max2, -(rangeOptions.count || 1));
    if (this.chart) {
      this.chart.setFixedRange(max2 - min2);
    }
  }
  const dataMin = pick$1f(this.dataMin, Number.MIN_VALUE);
  if (!isNumber$M(min2)) {
    min2 = dataMin;
  }
  if (min2 <= dataMin) {
    min2 = dataMin;
    if (typeof range2 === "undefined") {
      range2 = getTrueRange(min2, rangeOptions.count);
    }
    this.newMax = Math.min(min2 + range2, pick$1f(this.dataMax, Number.MAX_VALUE));
  }
  if (!isNumber$M(max2)) {
    min2 = void 0;
  } else if (!isNumber$M(rangeOptions) && rangeOptions && rangeOptions._offsetMin) {
    min2 += rangeOptions._offsetMin;
  }
  return min2;
}
function updateRangeSelectorButtons() {
  this.rangeSelector?.redrawElements();
}
function compose$m(AxisClass, ChartClass, RangeSelectorClass) {
  RangeSelectorConstructor = RangeSelectorClass;
  if (pushUnique$p(composed$p, "RangeSelector")) {
    const chartProto = ChartClass.prototype;
    AxisClass.prototype.minFromRange = axisMinFromRange;
    addEvent$16(ChartClass, "afterGetContainer", createRangeSelector);
    addEvent$16(ChartClass, "beforeRender", onChartBeforeRender$1);
    addEvent$16(ChartClass, "destroy", onChartDestroy$2);
    addEvent$16(ChartClass, "getMargins", onChartGetMargins$1);
    addEvent$16(ChartClass, "redraw", redrawRangeSelector);
    addEvent$16(ChartClass, "update", onChartUpdate);
    addEvent$16(ChartClass, "beforeRedraw", updateRangeSelectorButtons);
    chartProto.callbacks.push(redrawRangeSelector);
    extend$$(defaultOptions$c, { rangeSelector: RangeSelectorDefaults.rangeSelector });
    extend$$(defaultOptions$c.lang, RangeSelectorDefaults.lang);
  }
}
function createRangeSelector() {
  if (this.options.rangeSelector && this.options.rangeSelector.enabled) {
    this.rangeSelector = new RangeSelectorConstructor(this);
  }
}
function onChartBeforeRender$1() {
  const chart = this, rangeSelector2 = chart.rangeSelector;
  if (rangeSelector2) {
    if (isNumber$M(rangeSelector2.deferredYTDClick)) {
      rangeSelector2.clickButton(rangeSelector2.deferredYTDClick);
      delete rangeSelector2.deferredYTDClick;
    }
    const verticalAlign = rangeSelector2.options.verticalAlign;
    if (!rangeSelector2.options.floating) {
      if (verticalAlign === "bottom") {
        this.extraBottomMargin = true;
      } else if (verticalAlign === "top") {
        this.extraTopMargin = true;
      }
    }
  }
}
function redrawRangeSelector() {
  const chart = this;
  const rangeSelector2 = this.rangeSelector;
  if (!rangeSelector2) {
    return;
  }
  let alignTo;
  const extremes = chart.xAxis[0].getExtremes();
  const legend = chart.legend;
  const verticalAlign = rangeSelector2 && rangeSelector2.options.verticalAlign;
  if (isNumber$M(extremes.min)) {
    rangeSelector2.render(extremes.min, extremes.max);
  }
  if (legend.display && verticalAlign === "top" && verticalAlign === legend.options.verticalAlign) {
    alignTo = merge$1c(chart.spacingBox);
    if (legend.options.layout === "vertical") {
      alignTo.y = chart.plotTop;
    } else {
      alignTo.y += rangeSelector2.getHeight();
    }
    legend.group.placed = false;
    legend.align(alignTo);
  }
}
function onChartDestroy$2() {
  for (let i = 0, iEnd = chartDestroyEvents.length; i < iEnd; ++i) {
    const events = chartDestroyEvents[i];
    if (events[0] === this) {
      events[1].forEach((unbind) => unbind());
      chartDestroyEvents.splice(i, 1);
      return;
    }
  }
}
function onChartGetMargins$1() {
  const rangeSelector2 = this.rangeSelector;
  if (rangeSelector2?.options?.enabled) {
    const rangeSelectorHeight = rangeSelector2.getHeight();
    const verticalAlign = rangeSelector2.options.verticalAlign;
    if (!rangeSelector2.options.floating) {
      if (verticalAlign === "bottom") {
        this.marginBottom += rangeSelectorHeight;
      } else if (verticalAlign !== "middle") {
        this.plotTop += rangeSelectorHeight;
      }
    }
  }
}
function onChartUpdate(e) {
  const chart = this, options2 = e.options, optionsRangeSelector = options2.rangeSelector, extraBottomMarginWas = this.extraBottomMargin, extraTopMarginWas = this.extraTopMargin;
  let rangeSelector2 = chart.rangeSelector;
  if (optionsRangeSelector && optionsRangeSelector.enabled && !defined$P(rangeSelector2) && this.options.rangeSelector) {
    this.options.rangeSelector.enabled = true;
    this.rangeSelector = rangeSelector2 = new RangeSelectorConstructor(this);
  }
  this.extraBottomMargin = false;
  this.extraTopMargin = false;
  if (rangeSelector2) {
    const verticalAlign = optionsRangeSelector && optionsRangeSelector.verticalAlign || rangeSelector2.options && rangeSelector2.options.verticalAlign;
    if (!rangeSelector2.options.floating) {
      if (verticalAlign === "bottom") {
        this.extraBottomMargin = true;
      } else if (verticalAlign !== "middle") {
        this.extraTopMargin = true;
      }
    }
    if (this.extraBottomMargin !== extraBottomMarginWas || this.extraTopMargin !== extraTopMarginWas) {
      this.isDirtyBox = true;
    }
  }
}
const RangeSelectorComposition = {
  compose: compose$m
};
const { defaultOptions: defaultOptions$b } = DefaultOptions;
const { format: format$a } = Templating;
const { addEvent: addEvent$15, createElement: createElement$6, css: css$5, defined: defined$O, destroyObjectProperties: destroyObjectProperties$1, diffObjects: diffObjects$1, discardElement: discardElement$2, extend: extend$_, fireEvent: fireEvent$q, isNumber: isNumber$L, isString: isString$6, merge: merge$1b, objectEach: objectEach$f, pick: pick$1e, splat: splat$e } = Utilities;
function preferredInputType(format2) {
  const hasTimeKey = (char) => new RegExp(`%[[a-zA-Z]*${char}`).test(format2);
  const ms = isString$6(format2) ? format2.indexOf("%L") !== -1 : (
    // Implemented but not typed as of 2024
    format2.fractionalSecondDigits
  );
  if (ms) {
    return "text";
  }
  const date = isString$6(format2) ? ["a", "A", "d", "e", "w", "b", "B", "m", "o", "y", "Y"].some(hasTimeKey) : format2.dateStyle || format2.day || format2.month || format2.year;
  const time = isString$6(format2) ? ["H", "k", "I", "l", "M", "S"].some(hasTimeKey) : format2.timeStyle || format2.hour || format2.minute || format2.second;
  if (date && time) {
    return "datetime-local";
  }
  if (date) {
    return "date";
  }
  if (time) {
    return "time";
  }
  return "text";
}
class RangeSelector {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static compose(AxisClass, ChartClass) {
    RangeSelectorComposition.compose(AxisClass, ChartClass, RangeSelector);
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.isDirty = false;
    this.buttonOptions = [];
    this.initialButtonGroupWidth = 0;
    this.maxButtonWidth = () => {
      let buttonWidth = 0;
      this.buttons.forEach((button) => {
        const bBox = button.getBBox();
        if (bBox.width > buttonWidth) {
          buttonWidth = bBox.width;
        }
      });
      return buttonWidth;
    };
    this.init(chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * The method to run when one of the buttons in the range selectors is
   * clicked
   *
   * @private
   * @function Highcharts.RangeSelector#clickButton
   * @param {number} i
   *        The index of the button
   * @param {boolean} [redraw]
   */
  clickButton(i, redraw) {
    const rangeSelector2 = this, chart = rangeSelector2.chart, rangeOptions = rangeSelector2.buttonOptions[i], baseAxis = chart.xAxis[0], unionExtremes = chart.scroller && chart.scroller.getUnionExtremes() || baseAxis || {}, type = rangeOptions.type, dataGrouping = rangeOptions.dataGrouping;
    let dataMin = unionExtremes.dataMin, dataMax = unionExtremes.dataMax, newMin, newMax = isNumber$L(baseAxis?.max) ? Math.round(Math.min(baseAxis.max, dataMax ?? baseAxis.max)) : void 0, baseXAxisOptions, range2 = rangeOptions._range, rangeMin, ctx, ytdExtremes, addOffsetMin = true;
    if (dataMin === null || dataMax === null) {
      return;
    }
    rangeSelector2.setSelected(i);
    if (dataGrouping) {
      this.forcedDataGrouping = true;
      Axis.prototype.setDataGrouping.call(baseAxis || { chart: this.chart }, dataGrouping, false);
      this.frozenStates = rangeOptions.preserveDataGrouping;
    }
    if (type === "month" || type === "year") {
      if (!baseAxis) {
        range2 = rangeOptions;
      } else {
        ctx = {
          range: rangeOptions,
          max: newMax,
          chart,
          dataMin,
          dataMax
        };
        newMin = baseAxis.minFromRange.call(ctx);
        if (isNumber$L(ctx.newMax)) {
          newMax = ctx.newMax;
        }
        addOffsetMin = false;
      }
    } else if (range2) {
      if (isNumber$L(newMax)) {
        newMin = Math.max(newMax - range2, dataMin);
        newMax = Math.min(newMin + range2, dataMax);
        addOffsetMin = false;
      }
    } else if (type === "ytd") {
      if (baseAxis) {
        if (baseAxis.hasData() && (!isNumber$L(dataMax) || !isNumber$L(dataMin))) {
          dataMin = Number.MAX_VALUE;
          dataMax = -Number.MAX_VALUE;
          chart.series.forEach((series) => {
            const xData = series.getColumn("x");
            if (xData.length) {
              dataMin = Math.min(xData[0], dataMin);
              dataMax = Math.max(xData[xData.length - 1], dataMax);
            }
          });
          redraw = false;
        }
        if (isNumber$L(dataMax) && isNumber$L(dataMin)) {
          ytdExtremes = rangeSelector2.getYTDExtremes(dataMax, dataMin);
          newMin = rangeMin = ytdExtremes.min;
          newMax = ytdExtremes.max;
        }
      } else {
        rangeSelector2.deferredYTDClick = i;
        return;
      }
    } else if (type === "all" && baseAxis) {
      if (chart.navigator && chart.navigator.baseSeries[0]) {
        chart.navigator.baseSeries[0].xAxis.options.range = void 0;
      }
      newMin = dataMin;
      newMax = dataMax;
    }
    if (addOffsetMin && rangeOptions._offsetMin && defined$O(newMin)) {
      newMin += rangeOptions._offsetMin;
    }
    if (rangeOptions._offsetMax && defined$O(newMax)) {
      newMax += rangeOptions._offsetMax;
    }
    if (this.dropdown) {
      this.dropdown.selectedIndex = i + 1;
    }
    if (!baseAxis) {
      baseXAxisOptions = splat$e(chart.options.xAxis || {})[0];
      const axisRangeUpdateEvent = addEvent$15(chart, "afterCreateAxes", function() {
        const xAxis2 = chart.xAxis[0];
        xAxis2.range = xAxis2.options.range = range2;
        xAxis2.min = xAxis2.options.min = rangeMin;
      });
      addEvent$15(chart, "load", function resetMinAndRange() {
        const xAxis2 = chart.xAxis[0];
        chart.setFixedRange(rangeOptions._range);
        xAxis2.options.range = baseXAxisOptions.range;
        xAxis2.options.min = baseXAxisOptions.min;
        axisRangeUpdateEvent();
      });
    } else if (isNumber$L(newMin) && isNumber$L(newMax)) {
      baseAxis.setExtremes(
        newMin,
        newMax,
        pick$1e(redraw, true),
        void 0,
        // Auto animation
        {
          trigger: "rangeSelectorButton",
          rangeSelectorButton: rangeOptions
        }
      );
      chart.setFixedRange(rangeOptions._range);
    }
    fireEvent$q(this, "afterBtnClick");
  }
  /**
   * Set the selected option. This method only sets the internal flag, it
   * doesn't update the buttons or the actual zoomed range.
   *
   * @private
   * @function Highcharts.RangeSelector#setSelected
   * @param {number} [selected]
   */
  setSelected(selected) {
    this.selected = this.options.selected = selected;
  }
  /**
   * Initialize the range selector
   *
   * @private
   * @function Highcharts.RangeSelector#init
   * @param {Highcharts.Chart} chart
   */
  init(chart) {
    const rangeSelector2 = this, options2 = chart.options.rangeSelector, langOptions2 = chart.options.lang, buttonOptions = options2.buttons, selectedOption = options2.selected, blurInputs = function() {
      const minInput = rangeSelector2.minInput, maxInput = rangeSelector2.maxInput;
      if (minInput && !!minInput.blur) {
        fireEvent$q(minInput, "blur");
      }
      if (maxInput && !!maxInput.blur) {
        fireEvent$q(maxInput, "blur");
      }
    };
    rangeSelector2.chart = chart;
    rangeSelector2.options = options2;
    rangeSelector2.buttons = [];
    rangeSelector2.buttonOptions = buttonOptions.map((opt) => {
      if (opt.type && langOptions2.rangeSelector) {
        opt.text ?? (opt.text = langOptions2.rangeSelector[`${opt.type}Text`]);
        opt.title ?? (opt.title = langOptions2.rangeSelector[`${opt.type}Title`]);
      }
      opt.text = format$a(opt.text, {
        count: opt.count || 1
      });
      opt.title = format$a(opt.title, {
        count: opt.count || 1
      });
      return opt;
    });
    this.eventsToUnbind = [];
    this.eventsToUnbind.push(addEvent$15(chart.container, "mousedown", blurInputs));
    this.eventsToUnbind.push(addEvent$15(chart, "resize", blurInputs));
    buttonOptions.forEach(rangeSelector2.computeButtonRange);
    if (typeof selectedOption !== "undefined" && buttonOptions[selectedOption]) {
      this.clickButton(selectedOption, false);
    }
    this.eventsToUnbind.push(addEvent$15(chart, "load", function() {
      if (chart.xAxis && chart.xAxis[0]) {
        addEvent$15(chart.xAxis[0], "setExtremes", function(e) {
          if (isNumber$L(this.max) && isNumber$L(this.min) && this.max - this.min !== chart.fixedRange && e.trigger !== "rangeSelectorButton" && e.trigger !== "updatedData" && rangeSelector2.forcedDataGrouping && !rangeSelector2.frozenStates) {
            this.setDataGrouping(false, false);
          }
        });
      }
    }));
    this.createElements();
  }
  /**
   * Dynamically update the range selector buttons after a new range has been
   * set
   *
   * @private
   * @function Highcharts.RangeSelector#updateButtonStates
   */
  updateButtonStates() {
    const rangeSelector2 = this, chart = this.chart, dropdown = this.dropdown, dropdownLabel = this.dropdownLabel, baseAxis = chart.xAxis[0], actualRange = Math.round(baseAxis.max - baseAxis.min), hasNoData = !baseAxis.hasVisibleSeries, day = 24 * 36e5, unionExtremes = chart.scroller && chart.scroller.getUnionExtremes() || baseAxis, dataMin = unionExtremes.dataMin, dataMax = unionExtremes.dataMax, ytdExtremes = rangeSelector2.getYTDExtremes(dataMax, dataMin), ytdMin = ytdExtremes.min, ytdMax = ytdExtremes.max, selected = rangeSelector2.selected, allButtonsEnabled = rangeSelector2.options.allButtonsEnabled, buttonStates = new Array(rangeSelector2.buttonOptions.length).fill(0), selectedExists = isNumber$L(selected), buttons = rangeSelector2.buttons;
    let isSelectedTooGreat = false, selectedIndex = null;
    rangeSelector2.buttonOptions.forEach((rangeOptions, i) => {
      const range2 = rangeOptions._range, type = rangeOptions.type, count = rangeOptions.count || 1, offsetRange = rangeOptions._offsetMax - rangeOptions._offsetMin, isSelected = i === selected, isTooGreatRange = range2 > dataMax - dataMin, isTooSmallRange = range2 < baseAxis.minRange;
      let isYTDButNotSelected = false, isSameRange = range2 === actualRange;
      if (isSelected && isTooGreatRange) {
        isSelectedTooGreat = true;
      }
      if (baseAxis.isOrdinal && baseAxis.ordinal?.positions && range2 && actualRange < range2) {
        const positions = baseAxis.ordinal.positions, prevOrdinalPosition = OrdinalAxis$1.Additions.findIndexOf(positions, baseAxis.min, true), nextOrdinalPosition = Math.min(OrdinalAxis$1.Additions.findIndexOf(positions, baseAxis.max, true) + 1, positions.length - 1);
        if (positions[nextOrdinalPosition] - positions[prevOrdinalPosition] > range2) {
          isSameRange = true;
        }
      } else if (
        // Months and years have variable range so we check the extremes
        (type === "month" || type === "year") && actualRange + 36e5 >= { month: 28, year: 365 }[type] * day * count - offsetRange && actualRange - 36e5 <= { month: 31, year: 366 }[type] * day * count + offsetRange
      ) {
        isSameRange = true;
      } else if (type === "ytd") {
        isSameRange = ytdMax - ytdMin + offsetRange === actualRange;
        isYTDButNotSelected = !isSelected;
      } else if (type === "all") {
        isSameRange = baseAxis.max - baseAxis.min >= dataMax - dataMin;
      }
      const disable2 = !allButtonsEnabled && !(isSelectedTooGreat && type === "all") && (isTooGreatRange || isTooSmallRange || hasNoData);
      const select = isSelectedTooGreat && type === "all" || (isYTDButNotSelected ? false : isSameRange) || isSelected && rangeSelector2.frozenStates;
      if (disable2) {
        buttonStates[i] = 3;
      } else if (select) {
        if (!selectedExists || i === selected) {
          selectedIndex = i;
        }
      }
    });
    if (selectedIndex !== null) {
      buttonStates[selectedIndex] = 2;
      rangeSelector2.setSelected(selectedIndex);
      if (this.dropdown) {
        this.dropdown.selectedIndex = selectedIndex + 1;
      }
    } else {
      rangeSelector2.setSelected();
      if (this.dropdown) {
        this.dropdown.selectedIndex = -1;
      }
      if (dropdownLabel) {
        dropdownLabel.setState(0);
        dropdownLabel.attr({
          text: (defaultOptions$b.lang.rangeSelectorZoom || "") + " ▾"
        });
      }
    }
    for (let i = 0; i < buttonStates.length; i++) {
      const state = buttonStates[i];
      const button = buttons[i];
      if (button.state !== state) {
        button.setState(state);
        if (dropdown) {
          dropdown.options[i + 1].disabled = state === 3;
          if (state === 2) {
            if (dropdownLabel) {
              dropdownLabel.setState(2);
              dropdownLabel.attr({
                text: rangeSelector2.buttonOptions[i].text + " ▾"
              });
            }
            dropdown.selectedIndex = i + 1;
          }
          const bbox = dropdownLabel.getBBox();
          css$5(dropdown, {
            width: `${bbox.width}px`,
            height: `${bbox.height}px`
          });
        }
      }
    }
  }
  /**
   * Compute and cache the range for an individual button
   *
   * @private
   * @function Highcharts.RangeSelector#computeButtonRange
   * @param {Highcharts.RangeSelectorButtonsOptions} rangeOptions
   */
  computeButtonRange(rangeOptions) {
    const type = rangeOptions.type, count = rangeOptions.count || 1, fixedTimes = {
      millisecond: 1,
      second: 1e3,
      minute: 60 * 1e3,
      hour: 3600 * 1e3,
      day: 24 * 3600 * 1e3,
      week: 7 * 24 * 3600 * 1e3
    };
    if (fixedTimes[type]) {
      rangeOptions._range = fixedTimes[type] * count;
    } else if (type === "month" || type === "year") {
      rangeOptions._range = {
        month: 30,
        year: 365
      }[type] * 24 * 36e5 * count;
    }
    rangeOptions._offsetMin = pick$1e(rangeOptions.offsetMin, 0);
    rangeOptions._offsetMax = pick$1e(rangeOptions.offsetMax, 0);
    rangeOptions._range += rangeOptions._offsetMax - rangeOptions._offsetMin;
  }
  /**
   * Get the unix timestamp of a HTML input for the dates
   *
   * @private
   * @function Highcharts.RangeSelector#getInputValue
   */
  getInputValue(name) {
    const input = name === "min" ? this.minInput : this.maxInput;
    const options2 = this.chart.options.rangeSelector;
    const time = this.chart.time;
    if (input) {
      return (input.type === "text" && options2.inputDateParser || this.defaultInputDateParser)(input.value, time.timezone === "UTC", time);
    }
    return 0;
  }
  /**
   * Set the internal and displayed value of a HTML input for the dates
   *
   * @private
   * @function Highcharts.RangeSelector#setInputValue
   */
  setInputValue(name, inputTime) {
    const options2 = this.options, time = this.chart.time, input = name === "min" ? this.minInput : this.maxInput, dateBox = name === "min" ? this.minDateBox : this.maxDateBox;
    if (input) {
      input.setAttribute("type", preferredInputType(options2.inputDateFormat || "%e %b %Y"));
      const hcTimeAttr = input.getAttribute("data-hc-time");
      let updatedTime = defined$O(hcTimeAttr) ? Number(hcTimeAttr) : void 0;
      if (defined$O(inputTime)) {
        const previousTime = updatedTime;
        if (defined$O(previousTime)) {
          input.setAttribute("data-hc-time-previous", previousTime);
        }
        input.setAttribute("data-hc-time", inputTime);
        updatedTime = inputTime;
      }
      input.value = time.dateFormat(this.inputTypeFormats[input.type] || options2.inputEditDateFormat, updatedTime);
      if (dateBox) {
        dateBox.attr({
          text: time.dateFormat(options2.inputDateFormat, updatedTime)
        });
      }
    }
  }
  /**
   * Set the min and max value of a HTML input for the dates
   *
   * @private
   * @function Highcharts.RangeSelector#setInputExtremes
   */
  setInputExtremes(name, min2, max2) {
    const input = name === "min" ? this.minInput : this.maxInput;
    if (input) {
      const format2 = this.inputTypeFormats[input.type];
      const time = this.chart.time;
      if (format2) {
        const newMin = time.dateFormat(format2, min2);
        if (input.min !== newMin) {
          input.min = newMin;
        }
        const newMax = time.dateFormat(format2, max2);
        if (input.max !== newMax) {
          input.max = newMax;
        }
      }
    }
  }
  /**
   * @private
   * @function Highcharts.RangeSelector#showInput
   * @param {string} name
   */
  showInput(name) {
    const dateBox = name === "min" ? this.minDateBox : this.maxDateBox, input = name === "min" ? this.minInput : this.maxInput;
    if (input && dateBox && this.inputGroup) {
      const isTextInput = input.type === "text", { translateX = 0, translateY = 0 } = this.inputGroup, { x = 0, width = 0, height = 0 } = dateBox, { inputBoxWidth } = this.options;
      css$5(input, {
        width: isTextInput ? width + (inputBoxWidth ? -2 : 20) + "px" : "auto",
        height: height - 2 + "px",
        border: "2px solid silver"
      });
      if (isTextInput && inputBoxWidth) {
        css$5(input, {
          left: translateX + x + "px",
          top: translateY + "px"
        });
      } else {
        css$5(input, {
          left: Math.min(Math.round(x + translateX - (input.offsetWidth - width) / 2), this.chart.chartWidth - input.offsetWidth) + "px",
          top: translateY - (input.offsetHeight - height) / 2 + "px"
        });
      }
    }
  }
  /**
   * @private
   * @function Highcharts.RangeSelector#hideInput
   * @param {string} name
   */
  hideInput(name) {
    const input = name === "min" ? this.minInput : this.maxInput;
    if (input) {
      css$5(input, {
        top: "-9999em",
        border: 0,
        width: "1px",
        height: "1px"
      });
    }
  }
  /**
   * @private
   * @function Highcharts.RangeSelector#defaultInputDateParser
   */
  defaultInputDateParser(inputDate, useUTC, time) {
    return time?.parse(inputDate) || 0;
  }
  /**
   * Draw either the 'from' or the 'to' HTML input box of the range selector
   *
   * @private
   * @function Highcharts.RangeSelector#drawInput
   */
  drawInput(name) {
    const { chart, div, inputGroup } = this;
    const rangeSelector2 = this, chartStyle = chart.renderer.style || {}, renderer = chart.renderer, options2 = chart.options.rangeSelector, lang2 = defaultOptions$b.lang, isMin = name === "min";
    function updateExtremes(name2) {
      const { maxInput, minInput } = rangeSelector2, chartAxis = chart.xAxis[0], unionExtremes = chart.scroller?.getUnionExtremes() || chartAxis, dataMin = unionExtremes.dataMin, dataMax = unionExtremes.dataMax, currentExtreme = chart.xAxis[0].getExtremes()[name2];
      let value = rangeSelector2.getInputValue(name2);
      if (isNumber$L(value) && value !== currentExtreme) {
        if (isMin && maxInput && isNumber$L(dataMin)) {
          if (value > Number(maxInput.getAttribute("data-hc-time"))) {
            value = void 0;
          } else if (value < dataMin) {
            value = dataMin;
          }
        } else if (minInput && isNumber$L(dataMax)) {
          if (value < Number(minInput.getAttribute("data-hc-time"))) {
            value = void 0;
          } else if (value > dataMax) {
            value = dataMax;
          }
        }
        if (typeof value !== "undefined") {
          chartAxis.setExtremes(isMin ? value : chartAxis.min, isMin ? chartAxis.max : value, void 0, void 0, { trigger: "rangeSelectorInput" });
        }
      }
    }
    const text = lang2[isMin ? "rangeSelectorFrom" : "rangeSelectorTo"] || "";
    const label = renderer.label(text, 0).addClass("highcharts-range-label").attr({
      padding: text ? 2 : 0,
      height: text ? options2.inputBoxHeight : 0
    }).add(inputGroup);
    const dateBox = renderer.label("", 0).addClass("highcharts-range-input").attr({
      padding: 2,
      width: options2.inputBoxWidth,
      height: options2.inputBoxHeight,
      "text-align": "center"
    }).on("click", function() {
      rangeSelector2.showInput(name);
      rangeSelector2[name + "Input"].focus();
    });
    if (!chart.styledMode) {
      dateBox.attr({
        stroke: options2.inputBoxBorderColor,
        "stroke-width": 1
      });
    }
    dateBox.add(inputGroup);
    const input = createElement$6("input", {
      name,
      className: "highcharts-range-selector"
    }, void 0, div);
    input.setAttribute("type", preferredInputType(options2.inputDateFormat || "%e %b %Y"));
    if (!chart.styledMode) {
      label.css(merge$1b(chartStyle, options2.labelStyle));
      dateBox.css(merge$1b({
        color: "#333333"
        /* Palette.neutralColor80 */
      }, chartStyle, options2.inputStyle));
      css$5(input, extend$_({
        position: "absolute",
        border: 0,
        boxShadow: "0 0 15px rgba(0,0,0,0.3)",
        width: "1px",
        // Chrome needs a pixel to see it
        height: "1px",
        padding: 0,
        textAlign: "center",
        fontSize: chartStyle.fontSize,
        fontFamily: chartStyle.fontFamily,
        top: "-9999em"
        // #4798
      }, options2.inputStyle));
    }
    input.onfocus = () => {
      rangeSelector2.showInput(name);
    };
    input.onblur = () => {
      if (input === Highcharts.doc.activeElement) {
        updateExtremes(name);
      }
      rangeSelector2.hideInput(name);
      rangeSelector2.setInputValue(name);
      input.blur();
    };
    let keyDown = false;
    input.onchange = () => {
      if (!keyDown) {
        updateExtremes(name);
        rangeSelector2.hideInput(name);
        input.blur();
      }
    };
    input.onkeypress = (event) => {
      if (event.keyCode === 13) {
        updateExtremes(name);
      }
    };
    input.onkeydown = (event) => {
      keyDown = true;
      if (event.key === "ArrowUp" || event.key === "ArrowDown" || event.key === "Tab") {
        updateExtremes(name);
      }
    };
    input.onkeyup = () => {
      keyDown = false;
    };
    return { dateBox, input, label };
  }
  /**
   * Get the position of the range selector buttons and inputs. This can be
   * overridden from outside for custom positioning.
   *
   * @private
   * @function Highcharts.RangeSelector#getPosition
   */
  getPosition() {
    const chart = this.chart, options2 = chart.options.rangeSelector, top = options2.verticalAlign === "top" ? chart.plotTop - chart.axisOffset[0] : 0;
    return {
      buttonTop: top + options2.buttonPosition.y,
      inputTop: top + options2.inputPosition.y - 10
    };
  }
  /**
   * Get the extremes of YTD. Will choose dataMax if its value is lower than
   * the current timestamp. Will choose dataMin if its value is higher than
   * the timestamp for the start of current year.
   *
   * @private
   * @function Highcharts.RangeSelector#getYTDExtremes
   * @return {*}
   * Returns min and max for the YTD
   */
  getYTDExtremes(dataMax, dataMin) {
    const time = this.chart.time, year = time.toParts(dataMax)[0], startOfYear2 = time.makeTime(year, 0);
    return {
      max: dataMax,
      min: Math.max(dataMin, startOfYear2)
    };
  }
  createElements() {
    const chart = this.chart, renderer = chart.renderer, container = chart.container, chartOptions = chart.options, options2 = chartOptions.rangeSelector, inputEnabled = options2.inputEnabled, inputsZIndex = pick$1e(chartOptions.chart.style?.zIndex, 0) + 1;
    if (options2.enabled === false) {
      return;
    }
    this.group = renderer.g("range-selector-group").attr({
      zIndex: 7
    }).add();
    this.div = createElement$6("div", void 0, {
      position: "relative",
      height: 0,
      zIndex: inputsZIndex
    });
    if (this.buttonOptions.length) {
      this.renderButtons();
    }
    if (container.parentNode) {
      container.parentNode.insertBefore(this.div, container);
    }
    if (inputEnabled) {
      this.createInputs();
    }
  }
  /**
   * Create the input elements and its group.
   *
   */
  createInputs() {
    this.inputGroup = this.chart.renderer.g("input-group").add(this.group);
    const minElems = this.drawInput("min");
    this.minDateBox = minElems.dateBox;
    this.minLabel = minElems.label;
    this.minInput = minElems.input;
    const maxElems = this.drawInput("max");
    this.maxDateBox = maxElems.dateBox;
    this.maxLabel = maxElems.label;
    this.maxInput = maxElems.input;
  }
  /**
   * Render the range selector including the buttons and the inputs. The first
   * time render is called, the elements are created and positioned. On
   * subsequent calls, they are moved and updated.
   *
   * @private
   * @function Highcharts.RangeSelector#render
   * @param {number} [min]
   *        X axis minimum
   * @param {number} [max]
   *        X axis maximum
   */
  render(min2, max2) {
    if (this.options.enabled === false) {
      return;
    }
    const chart = this.chart, chartOptions = chart.options, options2 = chartOptions.rangeSelector, inputEnabled = options2.inputEnabled;
    if (inputEnabled) {
      if (!this.inputGroup) {
        this.createInputs();
      }
      this.setInputValue("min", min2);
      this.setInputValue("max", max2);
      if (!this.chart.styledMode) {
        this.maxLabel?.css(options2.labelStyle);
        this.minLabel?.css(options2.labelStyle);
      }
      const unionExtremes = chart.scroller && chart.scroller.getUnionExtremes() || chart.xAxis[0] || {};
      if (defined$O(unionExtremes.dataMin) && defined$O(unionExtremes.dataMax)) {
        const minRange = chart.xAxis[0].minRange || 0;
        this.setInputExtremes("min", unionExtremes.dataMin, Math.min(unionExtremes.dataMax, this.getInputValue("max")) - minRange);
        this.setInputExtremes("max", Math.max(unionExtremes.dataMin, this.getInputValue("min")) + minRange, unionExtremes.dataMax);
      }
      if (this.inputGroup) {
        let x = 0;
        [
          this.minLabel,
          this.minDateBox,
          this.maxLabel,
          this.maxDateBox
        ].forEach((label) => {
          if (label) {
            const { width } = label.getBBox();
            if (width) {
              label.attr({ x });
              x += width + options2.inputSpacing;
            }
          }
        });
      }
    } else {
      if (this.inputGroup) {
        this.inputGroup.destroy();
        delete this.inputGroup;
      }
    }
    if (!this.chart.styledMode) {
      if (this.zoomText) {
        this.zoomText.css(options2.labelStyle);
      }
    }
    this.alignElements();
    this.updateButtonStates();
  }
  /**
   * Render the range buttons. This only runs the first time, later the
   * positioning is laid out in alignElements.
   *
   * @private
   * @function Highcharts.RangeSelector#renderButtons
   */
  renderButtons() {
    var _a;
    const { chart, options: options2 } = this;
    const lang2 = defaultOptions$b.lang;
    const renderer = chart.renderer;
    const buttonTheme = merge$1b(options2.buttonTheme);
    const states2 = buttonTheme && buttonTheme.states;
    delete buttonTheme.width;
    delete buttonTheme.states;
    this.buttonGroup = renderer.g("range-selector-buttons").add(this.group);
    const dropdown = this.dropdown = createElement$6("select", void 0, {
      position: "absolute",
      padding: 0,
      border: 0,
      cursor: "pointer",
      opacity: 1e-4
    }, this.div);
    const userButtonTheme = chart.userOptions.rangeSelector?.buttonTheme;
    this.dropdownLabel = renderer.button("", 0, 0, () => {
    }, merge$1b(buttonTheme, {
      "stroke-width": pick$1e(buttonTheme["stroke-width"], 0),
      width: "auto",
      paddingLeft: pick$1e(options2.buttonTheme.paddingLeft, userButtonTheme?.padding, 8),
      paddingRight: pick$1e(options2.buttonTheme.paddingRight, userButtonTheme?.padding, 8)
    }), states2 && states2.hover, states2 && states2.select, states2 && states2.disabled).hide().add(this.group);
    addEvent$15(dropdown, "touchstart", () => {
      dropdown.style.fontSize = "16px";
    });
    const mouseOver2 = Highcharts.isMS ? "mouseover" : "mouseenter", mouseOut2 = Highcharts.isMS ? "mouseout" : "mouseleave";
    addEvent$15(dropdown, mouseOver2, () => {
      fireEvent$q(this.dropdownLabel.element, mouseOver2);
    });
    addEvent$15(dropdown, mouseOut2, () => {
      fireEvent$q(this.dropdownLabel.element, mouseOut2);
    });
    addEvent$15(dropdown, "change", () => {
      const button = this.buttons[dropdown.selectedIndex - 1];
      fireEvent$q(button.element, "click");
    });
    this.zoomText = renderer.label(lang2.rangeSelectorZoom || "", 0).attr({
      padding: options2.buttonTheme.padding,
      height: options2.buttonTheme.height,
      paddingLeft: 0,
      paddingRight: 0
    }).add(this.buttonGroup);
    if (!this.chart.styledMode) {
      this.zoomText.css(options2.labelStyle);
      (_a = options2.buttonTheme)["stroke-width"] ?? (_a["stroke-width"] = 0);
    }
    createElement$6("option", {
      textContent: this.zoomText.textStr,
      disabled: true
    }, void 0, dropdown);
    this.createButtons();
  }
  createButtons() {
    const { options: options2 } = this;
    const buttonTheme = merge$1b(options2.buttonTheme);
    const states2 = buttonTheme && buttonTheme.states;
    const width = buttonTheme.width || 28;
    delete buttonTheme.width;
    delete buttonTheme.states;
    this.buttonOptions.forEach((rangeOptions, i) => {
      this.createButton(rangeOptions, i, width, states2);
    });
  }
  createButton(rangeOptions, i, width, states2) {
    const { dropdown, buttons, chart, options: options2 } = this;
    const renderer = chart.renderer;
    const buttonTheme = merge$1b(options2.buttonTheme);
    dropdown?.add(createElement$6("option", {
      textContent: rangeOptions.title || rangeOptions.text
    }), i + 2);
    buttons[i] = renderer.button(rangeOptions.text ?? "", 0, 0, (e) => {
      const buttonEvents = rangeOptions.events && rangeOptions.events.click;
      let callDefaultEvent;
      if (buttonEvents) {
        callDefaultEvent = buttonEvents.call(rangeOptions, e);
      }
      if (callDefaultEvent !== false) {
        this.clickButton(i);
      }
      this.isActive = true;
    }, buttonTheme, states2 && states2.hover, states2 && states2.select, states2 && states2.disabled).attr({
      "text-align": "center",
      width
    }).add(this.buttonGroup);
    if (rangeOptions.title) {
      buttons[i].attr("title", rangeOptions.title);
    }
  }
  /**
   * Align the elements horizontally and vertically.
   *
   * @private
   * @function Highcharts.RangeSelector#alignElements
   */
  alignElements() {
    const { buttonGroup, buttons, chart, group: group2, inputGroup, options: options2, zoomText } = this;
    const chartOptions = chart.options;
    const navButtonOptions = chartOptions.exporting && chartOptions.exporting.enabled !== false && chartOptions.navigation && chartOptions.navigation.buttonOptions;
    const { buttonPosition, inputPosition, verticalAlign } = options2;
    const getXOffsetForExportButton = (group3, position, rightAligned) => {
      if (navButtonOptions && this.titleCollision(chart) && verticalAlign === "top" && rightAligned && position.y - group3.getBBox().height - 12 < (navButtonOptions.y || 0) + (navButtonOptions.height || 0) + chart.spacing[0]) {
        return -40;
      }
      return 0;
    };
    let plotLeft = chart.plotLeft;
    if (group2 && buttonPosition && inputPosition) {
      let translateX = buttonPosition.x - chart.spacing[3];
      if (buttonGroup) {
        this.positionButtons();
        if (!this.initialButtonGroupWidth) {
          let width = 0;
          if (zoomText) {
            width += zoomText.getBBox().width + 5;
          }
          buttons.forEach((button, i) => {
            width += button.width || 0;
            if (i !== buttons.length - 1) {
              width += options2.buttonSpacing;
            }
          });
          this.initialButtonGroupWidth = width;
        }
        plotLeft -= chart.spacing[3];
        const xOffsetForExportButton2 = getXOffsetForExportButton(buttonGroup, buttonPosition, buttonPosition.align === "right" || inputPosition.align === "right");
        this.alignButtonGroup(xOffsetForExportButton2);
        if (this.buttonGroup?.translateY) {
          this.dropdownLabel.attr({ y: this.buttonGroup.translateY });
        }
        group2.placed = buttonGroup.placed = chart.hasLoaded;
      }
      let xOffsetForExportButton = 0;
      if (options2.inputEnabled && inputGroup) {
        xOffsetForExportButton = getXOffsetForExportButton(inputGroup, inputPosition, buttonPosition.align === "right" || inputPosition.align === "right");
        if (inputPosition.align === "left") {
          translateX = plotLeft;
        } else if (inputPosition.align === "right") {
          translateX = -Math.max(chart.axisOffset[1], -xOffsetForExportButton);
        }
        inputGroup.align({
          y: inputPosition.y,
          width: inputGroup.getBBox().width,
          align: inputPosition.align,
          // Fix wrong getBBox() value on right align
          x: inputPosition.x + translateX - 2
        }, true, chart.spacingBox);
        inputGroup.placed = chart.hasLoaded;
      }
      this.handleCollision(xOffsetForExportButton);
      group2.align({
        verticalAlign
      }, true, chart.spacingBox);
      const alignTranslateY = group2.alignAttr.translateY;
      let groupHeight = group2.getBBox().height + 20;
      let translateY = 0;
      if (verticalAlign === "bottom") {
        const legendOptions = chart.legend && chart.legend.options;
        const legendHeight = legendOptions && legendOptions.verticalAlign === "bottom" && legendOptions.enabled && !legendOptions.floating ? chart.legend.legendHeight + pick$1e(legendOptions.margin, 10) : 0;
        groupHeight = groupHeight + legendHeight - 20;
        translateY = alignTranslateY - groupHeight - (options2.floating ? 0 : options2.y) - (chart.titleOffset ? chart.titleOffset[2] : 0) - 10;
      }
      if (verticalAlign === "top") {
        if (options2.floating) {
          translateY = 0;
        }
        if (chart.titleOffset && chart.titleOffset[0]) {
          translateY = chart.titleOffset[0];
        }
        translateY += chart.margin[0] - chart.spacing[0] || 0;
      } else if (verticalAlign === "middle") {
        if (inputPosition.y === buttonPosition.y) {
          translateY = alignTranslateY;
        } else if (inputPosition.y || buttonPosition.y) {
          if (inputPosition.y < 0 || buttonPosition.y < 0) {
            translateY -= Math.min(inputPosition.y, buttonPosition.y);
          } else {
            translateY = alignTranslateY - groupHeight;
          }
        }
      }
      group2.translate(options2.x, options2.y + Math.floor(translateY));
      const { minInput, maxInput, dropdown } = this;
      if (options2.inputEnabled && minInput && maxInput) {
        minInput.style.marginTop = group2.translateY + "px";
        maxInput.style.marginTop = group2.translateY + "px";
      }
      if (dropdown) {
        dropdown.style.marginTop = group2.translateY + "px";
      }
    }
  }
  /**
   * @private
   */
  redrawElements() {
    const chart = this.chart, { inputBoxHeight, inputBoxBorderColor } = this.options;
    this.maxDateBox?.attr({
      height: inputBoxHeight
    });
    this.minDateBox?.attr({
      height: inputBoxHeight
    });
    if (!chart.styledMode) {
      this.maxDateBox?.attr({
        stroke: inputBoxBorderColor
      });
      this.minDateBox?.attr({
        stroke: inputBoxBorderColor
      });
    }
    if (this.isDirty) {
      this.isDirty = false;
      this.isCollapsed = void 0;
      const newButtonsOptions = this.options.buttons ?? [];
      const btnLength = Math.min(newButtonsOptions.length, this.buttonOptions.length);
      const { dropdown, options: options2 } = this;
      const buttonTheme = merge$1b(options2.buttonTheme);
      const states2 = buttonTheme && buttonTheme.states;
      const width = buttonTheme.width || 28;
      if (newButtonsOptions.length < this.buttonOptions.length) {
        for (let i = this.buttonOptions.length - 1; i >= newButtonsOptions.length; i--) {
          const btn = this.buttons.pop();
          btn?.destroy();
          this.dropdown?.options.remove(i + 1);
        }
      }
      for (let i = btnLength - 1; i >= 0; i--) {
        const diff = diffObjects$1(newButtonsOptions[i], this.buttonOptions[i]);
        if (Object.keys(diff).length !== 0) {
          const rangeOptions = newButtonsOptions[i];
          this.buttons[i].destroy();
          dropdown?.options.remove(i + 1);
          this.createButton(rangeOptions, i, width, states2);
          this.computeButtonRange(rangeOptions);
        }
      }
      if (newButtonsOptions.length > this.buttonOptions.length) {
        for (let i = this.buttonOptions.length; i < newButtonsOptions.length; i++) {
          this.createButton(newButtonsOptions[i], i, width, states2);
          this.computeButtonRange(newButtonsOptions[i]);
        }
      }
      this.buttonOptions = this.options.buttons ?? [];
      if (defined$O(this.options.selected) && this.buttons.length) {
        this.clickButton(this.options.selected, false);
      }
    }
  }
  /**
   * Align the button group horizontally and vertically.
   *
   * @private
   * @function Highcharts.RangeSelector#alignButtonGroup
   * @param {number} xOffsetForExportButton
   * @param {number} [width]
   */
  alignButtonGroup(xOffsetForExportButton, width) {
    const { chart, options: options2, buttonGroup, dropdown, dropdownLabel } = this;
    const { buttonPosition } = options2;
    const plotLeft = chart.plotLeft - chart.spacing[3];
    let translateX = buttonPosition.x - chart.spacing[3];
    let dropdownTranslateX = chart.plotLeft;
    if (buttonPosition.align === "right") {
      translateX += xOffsetForExportButton - plotLeft;
      if (this.hasVisibleDropdown) {
        dropdownTranslateX = chart.chartWidth + xOffsetForExportButton - this.maxButtonWidth() - 20;
      }
    } else if (buttonPosition.align === "center") {
      translateX -= plotLeft / 2;
      if (this.hasVisibleDropdown) {
        dropdownTranslateX = chart.chartWidth / 2 - this.maxButtonWidth();
      }
    }
    if (dropdown) {
      css$5(dropdown, {
        left: dropdownTranslateX + "px",
        top: buttonGroup?.translateY + "px"
      });
    }
    dropdownLabel?.attr({
      x: dropdownTranslateX
    });
    if (buttonGroup) {
      buttonGroup.align({
        y: buttonPosition.y,
        width: pick$1e(width, this.initialButtonGroupWidth),
        align: buttonPosition.align,
        x: translateX
      }, true, chart.spacingBox);
    }
  }
  /**
   * @private
   * @function Highcharts.RangeSelector#positionButtons
   */
  positionButtons() {
    const { buttons, chart, options: options2, zoomText } = this;
    const verb = chart.hasLoaded ? "animate" : "attr";
    const { buttonPosition } = options2;
    const plotLeft = chart.plotLeft;
    let buttonLeft = plotLeft;
    if (zoomText && zoomText.visibility !== "hidden") {
      zoomText[verb]({
        x: pick$1e(plotLeft + buttonPosition.x, plotLeft)
      });
      buttonLeft += buttonPosition.x + zoomText.getBBox().width + 5;
    }
    for (let i = 0, iEnd = this.buttonOptions.length; i < iEnd; ++i) {
      if (buttons[i].visibility !== "hidden") {
        buttons[i][verb]({ x: buttonLeft });
        buttonLeft += (buttons[i].width || 0) + options2.buttonSpacing;
      } else {
        buttons[i][verb]({ x: plotLeft });
      }
    }
  }
  /**
   * Handle collision between the button group and the input group
   *
   * @private
   * @function Highcharts.RangeSelector#handleCollision
   *
   * @param  {number} xOffsetForExportButton
   *                  The X offset of the group required to make room for the
   *                  exporting button
   */
  handleCollision(xOffsetForExportButton) {
    const { chart, buttonGroup, inputGroup, initialButtonGroupWidth } = this;
    const { buttonPosition, dropdown, inputPosition } = this.options;
    const moveInputsDown = () => {
      if (inputGroup && buttonGroup) {
        inputGroup.attr({
          translateX: inputGroup.alignAttr.translateX + (chart.axisOffset[1] >= -xOffsetForExportButton ? 0 : -xOffsetForExportButton),
          translateY: inputGroup.alignAttr.translateY + buttonGroup.getBBox().height + 10
        });
      }
    };
    if (inputGroup && buttonGroup) {
      if (inputPosition.align === buttonPosition.align) {
        moveInputsDown();
        if (initialButtonGroupWidth > chart.plotWidth + xOffsetForExportButton - 20) {
          this.collapseButtons();
        } else {
          this.expandButtons();
        }
      } else if (initialButtonGroupWidth - xOffsetForExportButton + inputGroup.getBBox().width > chart.plotWidth) {
        if (dropdown === "responsive") {
          this.collapseButtons();
        } else {
          moveInputsDown();
        }
      } else {
        this.expandButtons();
      }
    } else if (buttonGroup && dropdown === "responsive") {
      if (initialButtonGroupWidth > chart.plotWidth) {
        this.collapseButtons();
      } else {
        this.expandButtons();
      }
    }
    if (buttonGroup) {
      if (dropdown === "always") {
        this.collapseButtons();
      }
      if (dropdown === "never") {
        this.expandButtons();
      }
    }
    this.alignButtonGroup(xOffsetForExportButton);
  }
  /**
   * Collapse the buttons and show the select element.
   *
   * @private
   * @function Highcharts.RangeSelector#collapseButtons
   * @param {number} xOffsetForExportButton
   */
  collapseButtons() {
    const { buttons, zoomText } = this;
    if (this.isCollapsed === true) {
      return;
    }
    this.isCollapsed = true;
    zoomText.hide();
    buttons.forEach((button) => void button.hide());
    this.showDropdown();
  }
  /**
   * Show all the buttons and hide the select element.
   *
   * @private
   * @function Highcharts.RangeSelector#expandButtons
   */
  expandButtons() {
    const { buttons, zoomText } = this;
    if (this.isCollapsed === false) {
      return;
    }
    this.isCollapsed = false;
    this.hideDropdown();
    zoomText.show();
    buttons.forEach((button) => void button.show());
    this.positionButtons();
  }
  /**
   * Position the select element on top of the button.
   *
   * @private
   * @function Highcharts.RangeSelector#showDropdown
   */
  showDropdown() {
    const { buttonGroup, dropdownLabel, dropdown } = this;
    if (buttonGroup && dropdown) {
      dropdownLabel.show();
      css$5(dropdown, { visibility: "inherit" });
      this.hasVisibleDropdown = true;
    }
  }
  /**
   * @private
   * @function Highcharts.RangeSelector#hideDropdown
   */
  hideDropdown() {
    const { dropdown } = this;
    if (dropdown) {
      this.dropdownLabel.hide();
      css$5(dropdown, {
        visibility: "hidden",
        width: "1px",
        height: "1px"
      });
      this.hasVisibleDropdown = false;
    }
  }
  /**
   * Extracts height of range selector
   *
   * @private
   * @function Highcharts.RangeSelector#getHeight
   * @return {number}
   * Returns rangeSelector height
   */
  getHeight() {
    const rangeSelector2 = this, options2 = rangeSelector2.options, rangeSelectorGroup = rangeSelector2.group, inputPosition = options2.inputPosition, buttonPosition = options2.buttonPosition, yPosition = options2.y, buttonPositionY = buttonPosition.y, inputPositionY = inputPosition.y;
    let rangeSelectorHeight = 0;
    if (options2.height) {
      return options2.height;
    }
    this.alignElements();
    rangeSelectorHeight = rangeSelectorGroup ? (
      // 13px to keep back compatibility
      rangeSelectorGroup.getBBox(true).height + 13 + yPosition
    ) : 0;
    const minPosition = Math.min(inputPositionY, buttonPositionY);
    if (inputPositionY < 0 && buttonPositionY < 0 || inputPositionY > 0 && buttonPositionY > 0) {
      rangeSelectorHeight += Math.abs(minPosition);
    }
    return rangeSelectorHeight;
  }
  /**
   * Detect collision with title or subtitle
   *
   * @private
   * @function Highcharts.RangeSelector#titleCollision
   * @return {boolean}
   * Returns collision status
   */
  titleCollision(chart) {
    return !(chart.options.title.text || chart.options.subtitle.text);
  }
  /**
   * Update the range selector with new options
   *
   * @private
   * @function Highcharts.RangeSelector#update
   * @param {Highcharts.RangeSelectorOptions} options
   */
  update(options2, redraw = true) {
    const chart = this.chart;
    merge$1b(true, this.options, options2);
    if (this.options.selected && this.options.selected >= this.options.buttons.length) {
      this.options.selected = void 0;
      chart.options.rangeSelector.selected = void 0;
    }
    if (defined$O(options2.enabled)) {
      this.destroy();
      return this.init(chart);
    }
    this.isDirty = !!options2.buttons;
    if (redraw) {
      this.render();
    }
  }
  /**
   * Destroys allocated elements.
   *
   * @private
   * @function Highcharts.RangeSelector#destroy
   */
  destroy() {
    const rSelector = this, minInput = rSelector.minInput, maxInput = rSelector.maxInput;
    if (rSelector.eventsToUnbind) {
      rSelector.eventsToUnbind.forEach((unbind) => unbind());
      rSelector.eventsToUnbind = void 0;
    }
    destroyObjectProperties$1(rSelector.buttons);
    if (minInput) {
      minInput.onfocus = minInput.onblur = minInput.onchange = null;
    }
    if (maxInput) {
      maxInput.onfocus = maxInput.onblur = maxInput.onchange = null;
    }
    objectEach$f(rSelector, function(val, key2) {
      if (val && key2 !== "chart") {
        if (val instanceof SVGElement$1) {
          val.destroy();
        } else if (val instanceof window.HTMLElement) {
          discardElement$2(val);
        }
        delete rSelector[key2];
      }
      if (val !== RangeSelector.prototype[key2]) {
        rSelector[key2] = null;
      }
    }, this);
    this.buttons = [];
  }
}
extend$_(RangeSelector.prototype, {
  /**
   * The date formats to use when setting min, max and value on date inputs.
   * @private
   */
  inputTypeFormats: {
    "datetime-local": "%Y-%m-%dT%H:%M:%S",
    "date": "%Y-%m-%d",
    "time": "%H:%M:%S"
  }
});
const { format: format$9 } = Templating;
const { getOptions: getOptions$2 } = DefaultOptions;
const { setFixedRange } = StockUtilities;
const { addEvent: addEvent$14, clamp: clamp$e, crisp: crisp$9, defined: defined$N, extend: extend$Z, find: find$c, isNumber: isNumber$K, isString: isString$5, merge: merge$1a, pick: pick$1d, splat: splat$d } = Utilities;
function getDefaultAxisOptions(coll, options2, defaultOptions2) {
  if (coll === "xAxis") {
    return {
      minPadding: 0,
      maxPadding: 0,
      overscroll: 0,
      ordinal: true
    };
  }
  if (coll === "yAxis") {
    return {
      labels: {
        y: -2
      },
      opposite: defaultOptions2.opposite ?? options2.opposite ?? true,
      showLastLabel: !!// #6104, show last label by default for category axes
      (options2.categories || options2.type === "category"),
      title: {
        text: void 0
      }
    };
  }
  return {};
}
function getForcedAxisOptions(type, chartOptions) {
  if (type === "xAxis") {
    const navigatorEnabled = pick$1d(chartOptions.navigator?.enabled, NavigatorDefaults.enabled, true);
    const axisOptions = {
      type: "datetime",
      categories: void 0
    };
    if (navigatorEnabled) {
      axisOptions.startOnTick = false;
      axisOptions.endOnTick = false;
    }
    return axisOptions;
  }
  return {};
}
class StockChart extends Chart$1 {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initializes the chart. The constructor's arguments are passed on
   * directly.
   *
   * @function Highcharts.StockChart#init
   *
   * @param {Highcharts.Options} userOptions
   *        Custom options.
   *
   * @param {Function} [callback]
   *        Function to run when the chart has loaded and all external
   *        images are loaded.
   *
   *
   * @emits Highcharts.StockChart#event:init
   * @emits Highcharts.StockChart#event:afterInit
   */
  init(userOptions, callback) {
    const defaultOptions2 = getOptions$2(), xAxisOptions = userOptions.xAxis, yAxisOptions = userOptions.yAxis, navigatorEnabled = pick$1d(userOptions.navigator?.enabled, NavigatorDefaults.enabled, true);
    userOptions.xAxis = userOptions.yAxis = void 0;
    const options2 = merge$1a(
      {
        chart: {
          panning: {
            enabled: true,
            type: "x"
          },
          zooming: {
            pinchType: "x",
            mouseWheel: {
              type: "x"
            }
          }
        },
        navigator: {
          enabled: navigatorEnabled
        },
        scrollbar: {
          // #4988 - check if setOptions was called
          enabled: pick$1d(ScrollbarDefaults.enabled, true)
        },
        rangeSelector: {
          // #4988 - check if setOptions was called
          enabled: pick$1d(RangeSelectorDefaults.rangeSelector.enabled, true)
        },
        title: {
          text: null
        },
        tooltip: {
          split: pick$1d(defaultOptions2.tooltip?.split, true),
          crosshairs: true
        },
        legend: {
          enabled: false
        }
      },
      userOptions,
      // User's options
      {
        isStock: true
        // Internal flag
      }
    );
    userOptions.xAxis = xAxisOptions;
    userOptions.yAxis = yAxisOptions;
    options2.xAxis = splat$d(userOptions.xAxis || {}).map((xAxisOptions2) => merge$1a(
      getDefaultAxisOptions("xAxis", xAxisOptions2, defaultOptions2.xAxis),
      // #7690
      xAxisOptions2,
      // User options
      getForcedAxisOptions("xAxis", userOptions)
    ));
    options2.yAxis = splat$d(userOptions.yAxis || {}).map((yAxisOptions2) => merge$1a(
      getDefaultAxisOptions("yAxis", yAxisOptions2, defaultOptions2.yAxis),
      // #7690
      yAxisOptions2
      // User options
    ));
    super.init(options2, callback);
  }
  /**
   * Factory for creating different axis types.
   * Extended to add stock defaults.
   *
   * @private
   * @function Highcharts.StockChart#createAxis
   * @param {string} coll
   * An axis type.
   * @param {Chart.CreateAxisOptionsObject} options
   * The axis creation options.
   */
  createAxis(coll, options2) {
    options2.axis = merge$1a(getDefaultAxisOptions(coll, options2.axis, getOptions$2()[coll]), options2.axis, getForcedAxisOptions(coll, this.userOptions));
    return super.createAxis(coll, options2);
  }
}
addEvent$14(Chart$1, "update", function(e) {
  const chart = this, options2 = e.options;
  if ("scrollbar" in options2 && chart.navigator) {
    merge$1a(true, chart.options.scrollbar, options2.scrollbar);
    chart.navigator.update({ enabled: !!chart.navigator.navigatorEnabled });
    delete options2.scrollbar;
  }
});
(function(StockChart2) {
  function compose2(ChartClass, AxisClass, SeriesClass, SVGRendererClass) {
    const seriesProto2 = SeriesClass.prototype;
    if (!seriesProto2.forceCropping) {
      addEvent$14(AxisClass, "afterDrawCrosshair", onAxisAfterDrawCrosshair);
      addEvent$14(AxisClass, "afterHideCrosshair", onAxisAfterHideCrosshair);
      addEvent$14(AxisClass, "autoLabelAlign", onAxisAutoLabelAlign);
      addEvent$14(AxisClass, "destroy", onAxisDestroy2);
      addEvent$14(AxisClass, "getPlotLinePath", onAxisGetPlotLinePath);
      ChartClass.prototype.setFixedRange = setFixedRange;
      seriesProto2.forceCropping = seriesForceCropping;
      addEvent$14(SeriesClass, "setOptions", onSeriesSetOptions);
      SVGRendererClass.prototype.crispPolyLine = svgRendererCrispPolyLine;
    }
  }
  StockChart2.compose = compose2;
  function onAxisAfterDrawCrosshair(event) {
    const axis = this;
    if (!(axis.crosshair?.label?.enabled && axis.cross && isNumber$K(axis.min) && isNumber$K(axis.max))) {
      return;
    }
    const chart = axis.chart, log = axis.logarithmic, options2 = axis.crosshair.label, horiz = axis.horiz, opposite = axis.opposite, left = axis.left, top = axis.top, width = axis.width, tickInside = axis.options.tickPosition === "inside", snap2 = axis.crosshair.snap !== false, e = event.e || axis.cross?.e, point = event.point;
    let crossLabel = axis.crossLabel, posx, posy, formatOption = options2.format, formatFormat = "", limit, offset2 = 0, min2 = axis.min, max2 = axis.max;
    if (log) {
      min2 = log.lin2log(axis.min);
      max2 = log.lin2log(axis.max);
    }
    const align = horiz ? "center" : opposite ? axis.labelAlign === "right" ? "right" : "left" : axis.labelAlign === "left" ? "left" : "center";
    if (!crossLabel) {
      crossLabel = axis.crossLabel = chart.renderer.label("", 0, void 0, options2.shape || "callout").addClass("highcharts-crosshair-label highcharts-color-" + (point?.series ? point.series.colorIndex : axis.series[0] && this.series[0].colorIndex)).attr({
        align: options2.align || align,
        padding: pick$1d(options2.padding, 8),
        r: pick$1d(options2.borderRadius, 3),
        zIndex: 2
      }).add(axis.labelGroup);
      if (!chart.styledMode) {
        crossLabel.attr({
          fill: options2.backgroundColor || point?.series?.color || // #14888
          "#666666",
          stroke: options2.borderColor || "",
          "stroke-width": options2.borderWidth || 0
        }).css(extend$Z({
          color: "#ffffff",
          fontWeight: "normal",
          fontSize: "0.7em",
          textAlign: "center"
        }, options2.style || {}));
      }
    }
    if (horiz) {
      posx = snap2 ? (point.plotX || 0) + left : e.chartX;
      posy = top + (opposite ? 0 : axis.height);
    } else {
      posx = left + axis.offset + (opposite ? width : 0);
      posy = snap2 ? (point.plotY || 0) + top : e.chartY;
    }
    if (!formatOption && !options2.formatter) {
      if (axis.dateTime) {
        formatFormat = "%b %d, %Y";
      }
      formatOption = "{value" + (formatFormat ? ":" + formatFormat : "") + "}";
    }
    const value = snap2 ? axis.isXAxis ? point.x : point.y : axis.toValue(horiz ? e.chartX : e.chartY);
    const isInside = point?.series ? point.series.isPointInside(point) : isNumber$K(value) && value > min2 && value < max2;
    let text = "";
    if (formatOption) {
      text = format$9(formatOption, { value }, chart);
    } else if (options2.formatter && isNumber$K(value)) {
      text = options2.formatter.call(axis, value);
    }
    crossLabel.attr({
      text,
      x: posx,
      y: posy,
      visibility: isInside ? "inherit" : "hidden"
    });
    const crossBox = crossLabel.getBBox();
    if (isNumber$K(crossLabel.x) && !horiz && !opposite) {
      posx = crossLabel.x - crossBox.width / 2;
    }
    if (isNumber$K(crossLabel.y)) {
      if (horiz) {
        if (tickInside && !opposite || !tickInside && opposite) {
          posy = crossLabel.y - crossBox.height;
        }
      } else {
        posy = crossLabel.y - crossBox.height / 2;
      }
    }
    if (horiz) {
      limit = {
        left,
        right: left + axis.width
      };
    } else {
      limit = {
        left: axis.labelAlign === "left" ? left : 0,
        right: axis.labelAlign === "right" ? left + axis.width : chart.chartWidth
      };
    }
    const translateX = crossLabel.translateX || 0;
    if (translateX < limit.left) {
      offset2 = limit.left - translateX;
    }
    if (translateX + crossBox.width >= limit.right) {
      offset2 = -(translateX + crossBox.width - limit.right);
    }
    crossLabel.attr({
      x: Math.max(0, posx + offset2),
      y: Math.max(0, posy),
      // First set x and y, then anchorX and anchorY, when box is actually
      // calculated, #5702
      anchorX: horiz ? posx : axis.opposite ? 0 : chart.chartWidth,
      anchorY: horiz ? axis.opposite ? chart.chartHeight : 0 : posy + crossBox.height / 2
    });
  }
  function onAxisAfterHideCrosshair() {
    const axis = this;
    if (axis.crossLabel) {
      axis.crossLabel = axis.crossLabel.hide();
    }
  }
  function onAxisAutoLabelAlign(e) {
    const axis = this, chart = axis.chart, options2 = axis.options, panes = chart._labelPanes = chart._labelPanes || {}, labelOptions = options2.labels;
    if (chart.options.isStock && axis.coll === "yAxis") {
      const key2 = options2.top + "," + options2.height;
      if (!panes[key2] && labelOptions.enabled) {
        if (labelOptions.distance === 15 && // Default
        axis.side === 1) {
          labelOptions.distance = 0;
        }
        if (typeof labelOptions.align === "undefined") {
          labelOptions.align = "right";
        }
        panes[key2] = axis;
        e.align = "right";
        e.preventDefault();
      }
    }
  }
  function onAxisDestroy2() {
    const axis = this, chart = axis.chart, key2 = axis.options && axis.options.top + "," + axis.options.height;
    if (key2 && chart._labelPanes && chart._labelPanes[key2] === axis) {
      delete chart._labelPanes[key2];
    }
  }
  function onAxisGetPlotLinePath(e) {
    const axis = this, series = axis.isLinked && !axis.series && axis.linkedParent ? axis.linkedParent.series : axis.series, chart = axis.chart, renderer = chart.renderer, axisLeft = axis.left, axisTop = axis.top, result = [], translatedValue = e.translatedValue, value = e.value, force = e.force, getAxis = (coll) => {
      const otherColl = coll === "xAxis" ? "yAxis" : "xAxis", opt = axis.options[otherColl];
      if (isNumber$K(opt)) {
        return [chart[otherColl][opt]];
      }
      if (isString$5(opt)) {
        return [chart.get(opt)];
      }
      return series.map((s) => s[otherColl]);
    };
    let x1, y1, x2, y2, axes = [], axes2, uniqueAxes, transVal;
    if (
      // For stock chart, by default render paths across the panes
      // except the case when `acrossPanes` is disabled by user (#6644)
      chart.options.isStock && e.acrossPanes !== false && // Ignore in case of colorAxis or zAxis. #3360, #3524, #6720
      axis.coll === "xAxis" || axis.coll === "yAxis"
    ) {
      e.preventDefault();
      axes = getAxis(axis.coll);
      axes2 = axis.isXAxis ? chart.yAxis : chart.xAxis;
      for (const A5 of axes2) {
        if (!A5.options.isInternal) {
          const a = A5.isXAxis ? "yAxis" : "xAxis", relatedAxis = defined$N(A5.options[a]) ? chart[a][A5.options[a]] : chart[a][0];
          if (axis === relatedAxis) {
            axes.push(A5);
          }
        }
      }
      uniqueAxes = axes.length ? [] : [axis.isXAxis ? chart.yAxis[0] : chart.xAxis[0]];
      for (const axis2 of axes) {
        if (uniqueAxes.indexOf(axis2) === -1 && // Do not draw on axis which overlap completely. #5424
        !find$c(uniqueAxes, (unique) => unique.pos === axis2.pos && unique.len === axis2.len)) {
          uniqueAxes.push(axis2);
        }
      }
      transVal = pick$1d(translatedValue, axis.translate(value || 0, void 0, void 0, e.old));
      if (isNumber$K(transVal)) {
        if (axis.horiz) {
          for (const axis2 of uniqueAxes) {
            let skip;
            y1 = axis2.pos;
            y2 = y1 + axis2.len;
            x1 = x2 = Math.round(transVal + axis.transB);
            if (force !== "pass" && (x1 < axisLeft || x1 > axisLeft + axis.width)) {
              if (force) {
                x1 = x2 = clamp$e(x1, axisLeft, axisLeft + axis.width);
              } else {
                skip = true;
              }
            }
            if (!skip) {
              result.push(["M", x1, y1], ["L", x2, y2]);
            }
          }
        } else {
          for (const axis2 of uniqueAxes) {
            let skip;
            x1 = axis2.pos;
            x2 = x1 + axis2.len;
            y1 = y2 = Math.round(axisTop + axis.height - transVal);
            if (force !== "pass" && (y1 < axisTop || y1 > axisTop + axis.height)) {
              if (force) {
                y1 = y2 = clamp$e(y1, axisTop, axisTop + axis.height);
              } else {
                skip = true;
              }
            }
            if (!skip) {
              result.push(["M", x1, y1], ["L", x2, y2]);
            }
          }
        }
      }
      e.path = result.length > 0 ? renderer.crispPolyLine(result, e.lineWidth || 1) : (
        // #3557 getPlotLinePath in regular Highcharts also returns null
        void 0
      );
    }
  }
  function onSeriesSetOptions(e) {
    const series = this;
    if (series.chart.options.isStock) {
      let overrides;
      if (series.is("column") || series.is("columnrange")) {
        overrides = {
          borderWidth: 0,
          shadow: false
        };
      } else if (!series.is("scatter") && !series.is("sma")) {
        overrides = {
          marker: {
            enabled: false,
            radius: 2
          }
        };
      }
      if (overrides) {
        e.plotOptions[series.type] = merge$1a(e.plotOptions[series.type], overrides);
      }
    }
  }
  function seriesForceCropping() {
    const series = this, chart = series.chart, options2 = series.options, dataGroupingOptions = options2.dataGrouping, groupingEnabled = series.allowDG !== false && dataGroupingOptions && pick$1d(dataGroupingOptions.enabled, chart.options.isStock);
    return groupingEnabled;
  }
  function stockChart(a, b, c) {
    return new StockChart2(a, b, c);
  }
  StockChart2.stockChart = stockChart;
  function svgRendererCrispPolyLine(points, width) {
    for (let i = 0; i < points.length; i = i + 2) {
      const start2 = points[i], end = points[i + 1];
      if (defined$N(start2[1]) && start2[1] === end[1]) {
        start2[1] = end[1] = crisp$9(start2[1], width);
      }
      if (defined$N(start2[2]) && start2[2] === end[2]) {
        start2[2] = end[2] = crisp$9(start2[2], width);
      }
    }
    return points;
  }
})(StockChart || (StockChart = {}));
const StockChart$1 = StockChart;
const { column: { prototype: { pointClass: ColumnPoint$2 } } } = SeriesRegistry$1.seriesTypes;
class HLCPoint extends ColumnPoint$2 {
}
const HLCSeriesDefaults = {
  /**
   * The approximate pixel width of each group. If for example a series
   * with 30 points is displayed over a 600 pixel wide plot area, no
   * grouping is performed. If however the series contains so many points
   * that the spacing is less than the groupPixelWidth, Highcharts will
   * try to group it into appropriate groups so that each is more or less
   * two pixels wide. Defaults to `5`.
   *
   * @type      {number}
   * @default   5
   * @product   highstock
   * @apioption plotOptions.hlc.dataGrouping.groupPixelWidth
   */
  /**
   * @type      {Highcharts.DataGroupingApproximationValue|Function}
   * @default   hlc
   * @product   highstock
   * @apioption plotOptions.hlc.dataGrouping.approximation
   */
  /**
   * @default   close
   * @apioption plotOptions.hlc.colorKey
   */
  /**
   * The pixel width of the line/border. Defaults to `1`.
   *
   * @sample {highstock} stock/plotoptions/hlc-linewidth/
   *         A greater line width
   *
   * @type    {number}
   * @default 1
   * @product highstock
   *
   * @public
   */
  lineWidth: 1,
  tooltip: {
    pointFormat: '<span style="color:{point.color}">●</span> <b> {series.name}</b><br/>{series.chart.options.lang.stockHigh}: {point.high}<br/>{series.chart.options.lang.stockLow}: {point.low}<br/>{series.chart.options.lang.stockClose}: {point.close}<br/>'
  },
  /**
   * @type {number|null}
   */
  threshold: null,
  states: {
    /**
     * @extends plotOptions.column.states.hover
     * @product highstock
     */
    hover: {
      /**
       * The pixel width of the line representing the HLC point.
       *
       * @type    {number}
       * @default 3
       * @product highstock
       */
      lineWidth: 3
    }
  },
  /**
   * Determines which one of  `high`, `low`, `close` values should
   * be represented as `point.y`, which is later used to set dataLabel
   * position and [compare](#plotOptions.series.compare).
   *
   * @sample {highstock} stock/plotoptions/hlc-pointvalkey/
   *         Possible values
   *
   * @declare    Highcharts.OptionsHLCPointValKeyValue
   * @type       {string}
   * @default    close
   * @validvalue ["high", "low", "close"]
   * @product    highstock
   * @apioption  plotOptions.hlc.pointValKey
   */
  /**
   * @default   close
   * @apioption plotOptions.hlc.colorKey
   */
  stickyTracking: true
};
const { column: ColumnSeries$d } = SeriesRegistry$1.seriesTypes;
const { crisp: crisp$8, extend: extend$Y, merge: merge$19 } = Utilities;
const { defaultOptions: defaultOptions$a } = DefaultOptions;
let HLCSeries$2 = class HLCSeries2 extends ColumnSeries$d {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Extend the path if close is not between high and low.
   *
   * @param {SVGPath} path the path array of the point
   * @param {number} halfStrokeWidth
   * @param {number} value value of the point to which the stem should be extended
   */
  extendStem(path, halfStrokeWidth, value) {
    const start2 = path[0];
    const end = path[1];
    if (typeof start2[2] === "number") {
      start2[2] = Math.max(value + halfStrokeWidth, start2[2]);
    }
    if (typeof end[2] === "number") {
      end[2] = Math.min(value - halfStrokeWidth, end[2]);
    }
  }
  /**
   * Function to create SVGPath of the point based on the
   * plot positions of this point.
   * @private
   */
  getPointPath(point, graphic) {
    const strokeWidth = graphic.strokeWidth(), series = point.series, crispX = crisp$8(point.plotX || 0, strokeWidth), halfWidth = Math.round(point.shapeArgs.width / 2);
    const path = [
      ["M", crispX, Math.round(point.yBottom)],
      ["L", crispX, Math.round(point.plotHigh)]
    ];
    if (point.close !== null) {
      const plotClose = crisp$8(point.plotClose, strokeWidth);
      path.push(["M", crispX, plotClose], ["L", crispX + halfWidth, plotClose]);
      series.extendStem(path, strokeWidth / 2, plotClose);
    }
    return path;
  }
  /**
   * Draw single point
   * @private
   */
  drawSinglePoint(point) {
    const series = point.series, chart = series.chart;
    let path, graphic = point.graphic;
    if (typeof point.plotY !== "undefined") {
      if (!graphic) {
        point.graphic = graphic = chart.renderer.path().add(series.group);
      }
      if (!chart.styledMode) {
        graphic.attr(series.pointAttribs(point, point.selected && "select"));
      }
      path = series.getPointPath(point, graphic);
      graphic[!graphic ? "attr" : "animate"]({ d: path }).addClass(point.getClassName(), true);
    }
  }
  /**
   * Draw the data points
   * @private
   */
  drawPoints() {
    this.points.forEach(this.drawSinglePoint);
  }
  /**
   * @private
   * @function Highcharts.seriesTypes.hlc#init
   */
  init() {
    super.init.apply(this, arguments);
    this.options.stacking = void 0;
  }
  /**
   * Postprocess mapping between options and SVG attributes
   * @private
   */
  pointAttribs(point, state) {
    const attribs = super.pointAttribs.call(this, point, state);
    delete attribs.fill;
    return attribs;
  }
  toYData(point) {
    return [point.high, point.low, point.close];
  }
  /**
   * Translate data points from raw values x and y to plotX and plotY
   *
   * @private
   * @function Highcharts.seriesTypes.hlc#translate
   */
  translate() {
    const series = this, yAxis2 = series.yAxis, names2 = this.pointArrayMap && this.pointArrayMap.slice() || [], translated = names2.map((name) => `plot${name.charAt(0).toUpperCase() + name.slice(1)}`);
    translated.push("yBottom");
    names2.push("low");
    super.translate.apply(series);
    series.points.forEach(function(point) {
      names2.forEach(function(name, i) {
        let value = point[name];
        if (value !== null) {
          if (series.dataModify) {
            value = series.dataModify.modifyValue(value);
          }
          point[translated[i]] = yAxis2.toPixels(value, true);
        }
      });
      point.tooltipPos[1] = point.plotHigh + yAxis2.pos - series.chart.plotTop;
    });
  }
};
HLCSeries$2.defaultOptions = merge$19(ColumnSeries$d.defaultOptions, HLCSeriesDefaults);
extend$Y(HLCSeries$2.prototype, {
  pointClass: HLCPoint,
  animate: null,
  // Disable animation
  directTouch: false,
  keysAffectYAxis: ["low", "high"],
  pointArrayMap: ["high", "low", "close"],
  pointAttrToOptions: {
    stroke: "color",
    "stroke-width": "lineWidth"
  },
  pointValKey: "close"
});
const HLCDefaultLangOptions = {
  stockOpen: "Open",
  stockHigh: "High",
  stockLow: "Low",
  stockClose: "Close"
};
extend$Y(defaultOptions$a.lang, HLCDefaultLangOptions);
SeriesRegistry$1.registerSeriesType("hlc", HLCSeries$2);
const { seriesTypes: { hlc: HLCSeries$1 } } = SeriesRegistry$1;
class OHLCPoint extends HLCSeries$1.prototype.pointClass {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Extend the parent method by adding up or down to the class name.
   * @private
   * @function Highcharts.seriesTypes.ohlc#getClassName
   */
  getClassName() {
    return super.getClassName.call(this) + (this.open < this.close ? " highcharts-point-up" : " highcharts-point-down");
  }
  /**
   * Save upColor as point color (#14826).
   * @private
   * @function Highcharts.seriesTypes.ohlc#resolveUpColor
   */
  resolveUpColor() {
    if (this.open < this.close && !this.options.color && this.series.options.upColor) {
      this.color = this.series.options.upColor;
    }
  }
  /**
   * Extend the parent method by saving upColor.
   * @private
   * @function Highcharts.seriesTypes.ohlc#resolveColor
   */
  resolveColor() {
    super.resolveColor();
    if (!this.series.is("heikinashi")) {
      this.resolveUpColor();
    }
  }
  /**
   * Extend the parent method by saving upColor.
   * @private
   * @function Highcharts.seriesTypes.ohlc#getZone
   *
   * @return {Highcharts.SeriesZonesOptionsObject}
   *         The zone item.
   */
  getZone() {
    const zone = super.getZone();
    this.resolveUpColor();
    return zone;
  }
  /**
   * Extend the parent method by resolving up/down colors (#15849)
   * @private
   **/
  applyOptions() {
    super.applyOptions.apply(this, arguments);
    if (this.resolveColor) {
      this.resolveColor();
    }
    return this;
  }
}
const OHLCSeriesDefaults = {
  /**
   * @type      {Highcharts.DataGroupingApproximationValue|Function}
   * @default   ohlc
   * @product   highstock
   * @apioption plotOptions.ohlc.dataGrouping.approximation
   */
  /**
   * Determines which one of  `open`, `high`, `low`, `close` values should
   * be represented as `point.y`, which is later used to set dataLabel
   * position and [compare](#plotOptions.series.compare).
   *
   * @declare    Highcharts.OptionsPointValKeyValue
   * @default    close
   * @validvalue ["open", "high", "low", "close"]
   * @product    highstock
   * @apioption  plotOptions.ohlc.pointValKey
   */
  /**
   * Line color for up points.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highstock
   * @apioption plotOptions.ohlc.upColor
   */
  tooltip: {
    pointFormat: '<span style="color:{point.color}">●</span> <b> {series.name}</b><br/>{series.chart.options.lang.stockOpen}: {point.open}<br/>{series.chart.options.lang.stockHigh}: {point.high}<br/>{series.chart.options.lang.stockLow}: {point.low}<br/>{series.chart.options.lang.stockClose}: {point.close}<br/>'
  }
};
const { composed: composed$o } = Highcharts;
const { hlc: HLCSeries } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$13, crisp: crisp$7, extend: extend$X, merge: merge$18, pushUnique: pushUnique$o } = Utilities;
function onSeriesAfterSetOptions(e) {
  const options2 = e.options, dataGrouping = options2.dataGrouping;
  if (dataGrouping && options2.useOhlcData && options2.id !== "highcharts-navigator-series") {
    dataGrouping.approximation = "ohlc";
  }
}
function onSeriesInit(eventOptions) {
  const series = this, options2 = eventOptions.options;
  if (options2.useOhlcData && options2.id !== "highcharts-navigator-series") {
    extend$X(series, {
      pointValKey: OHLCSeries$1.prototype.pointValKey,
      // Keys: ohlcProto.keys, // @todo potentially nonsense
      pointArrayMap: OHLCSeries$1.prototype.pointArrayMap,
      toYData: OHLCSeries$1.prototype.toYData
    });
  }
}
let OHLCSeries$1 = class OHLCSeries2 extends HLCSeries {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(SeriesClass, ..._args) {
    if (pushUnique$o(composed$o, "OHLCSeries")) {
      addEvent$13(SeriesClass, "afterSetOptions", onSeriesAfterSetOptions);
      addEvent$13(SeriesClass, "init", onSeriesInit);
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  getPointPath(point, graphic) {
    const path = super.getPointPath(point, graphic), strokeWidth = graphic.strokeWidth(), crispX = crisp$7(point.plotX || 0, strokeWidth), halfWidth = Math.round(point.shapeArgs.width / 2);
    if (point.open !== null) {
      const plotOpen = crisp$7(point.plotOpen, strokeWidth);
      path.push(["M", crispX, plotOpen], ["L", crispX - halfWidth, plotOpen]);
      super.extendStem(path, strokeWidth / 2, plotOpen);
    }
    return path;
  }
  /**
   * Postprocess mapping between options and SVG attributes
   * @private
   */
  pointAttribs(point, state) {
    const attribs = super.pointAttribs.call(this, point, state), options2 = this.options;
    delete attribs.fill;
    if (!point.options.color && options2.upColor && point.open < point.close) {
      attribs.stroke = options2.upColor;
    }
    return attribs;
  }
  toYData(point) {
    return [point.open, point.high, point.low, point.close];
  }
};
OHLCSeries$1.defaultOptions = merge$18(HLCSeries.defaultOptions, OHLCSeriesDefaults);
extend$X(OHLCSeries$1.prototype, {
  pointClass: OHLCPoint,
  pointArrayMap: ["open", "high", "low", "close"]
});
SeriesRegistry$1.registerSeriesType("ohlc", OHLCSeries$1);
const CandlestickSeriesDefaults = {
  /**
   * The specific line color for up candle sticks. The default is to
   * inherit the general `lineColor` setting.
   *
   * @sample {highstock} stock/plotoptions/candlestick-linecolor/
   *         Candlestick line colors
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     1.3.6
   * @product   highstock
   * @apioption plotOptions.candlestick.upLineColor
   */
  states: {
    /**
     * @extends plotOptions.column.states.hover
     * @product highstock
     */
    hover: {
      /**
       * The pixel width of the line/border around the
       * candlestick.
       *
       * @product highstock
       */
      lineWidth: 2
    }
  },
  /**
   * @type    {number|null}
   * @product highstock
   */
  threshold: null,
  /**
   * The color of the line/border of the candlestick.
   *
   * In styled mode, the line stroke can be set with the
   * `.highcharts-candlestick-series .highcahrts-point` rule.
   *
   * @see [upLineColor](#plotOptions.candlestick.upLineColor)
   *
   * @sample {highstock} stock/plotoptions/candlestick-linecolor/
   *         Candlestick line colors
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default #000000
   * @product highstock
   */
  lineColor: "#000000",
  /**
   * The pixel width of the candlestick line/border. Defaults to `1`.
   *
   *
   * In styled mode, the line stroke width can be set with the
   * `.highcharts-candlestick-series .highcahrts-point` rule.
   *
   * @product highstock
   */
  lineWidth: 1,
  /**
   * The fill color of the candlestick when values are rising.
   *
   * In styled mode, the up color can be set with the
   * `.highcharts-candlestick-series .highcharts-point-up` rule.
   *
   * @sample {highstock} stock/plotoptions/candlestick-color/
   *         Custom colors
   * @sample {highstock} highcharts/css/candlestick/
   *         Colors in styled mode
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default #ffffff
   * @product highstock
  */
  upColor: "#ffffff",
  /**
   * @product highstock
   */
  stickyTracking: true
};
const { column: ColumnSeries$c, ohlc: OHLCSeries } = SeriesRegistry$1.seriesTypes;
const { crisp: crisp$6, merge: merge$17 } = Utilities;
class CandlestickSeries extends OHLCSeries {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Postprocess mapping between options and SVG attributes
   *
   * @private
   * @function Highcharts.seriesTypes.candlestick#pointAttribs
   */
  pointAttribs(point, state) {
    const attribs = ColumnSeries$c.prototype.pointAttribs.call(this, point, state), options2 = this.options, isUp = point.open < point.close, stroke = options2.lineColor || this.color, color2 = point.color || this.color;
    attribs["stroke-width"] = options2.lineWidth;
    attribs.fill = point.options.color || (isUp ? options2.upColor || color2 : color2);
    attribs.stroke = point.options.lineColor || (isUp ? options2.upLineColor || stroke : stroke);
    if (state) {
      const stateOptions = options2.states[state];
      attribs.fill = stateOptions.color || attribs.fill;
      attribs.stroke = stateOptions.lineColor || attribs.stroke;
      attribs["stroke-width"] = stateOptions.lineWidth || attribs["stroke-width"];
    }
    return attribs;
  }
  /**
   * Draw the data points.
   *
   * @private
   * @function Highcharts.seriesTypes.candlestick#drawPoints
   */
  drawPoints() {
    const series = this, points = series.points, chart = series.chart, reversedYAxis = series.yAxis.reversed;
    for (const point of points) {
      let graphic = point.graphic, plotOpen, plotClose, topBox, bottomBox, hasTopWhisker, hasBottomWhisker, crispX, path, halfWidth;
      const isNew = !graphic;
      if (typeof point.plotY !== "undefined") {
        if (!graphic) {
          point.graphic = graphic = chart.renderer.path().add(series.group);
        }
        if (!series.chart.styledMode) {
          graphic.attr(series.pointAttribs(point, point.selected && "select")).shadow(series.options.shadow);
        }
        const strokeWidth = graphic.strokeWidth();
        crispX = crisp$6(point.plotX || 0, strokeWidth);
        plotOpen = point.plotOpen;
        plotClose = point.plotClose;
        topBox = Math.min(plotOpen, plotClose);
        bottomBox = Math.max(plotOpen, plotClose);
        halfWidth = Math.round(point.shapeArgs.width / 2);
        hasTopWhisker = reversedYAxis ? bottomBox !== point.yBottom : Math.round(topBox) !== Math.round(point.plotHigh || 0);
        hasBottomWhisker = reversedYAxis ? Math.round(topBox) !== Math.round(point.plotHigh || 0) : bottomBox !== point.yBottom;
        topBox = crisp$6(topBox, strokeWidth);
        bottomBox = crisp$6(bottomBox, strokeWidth);
        path = [];
        path.push(
          ["M", crispX - halfWidth, bottomBox],
          ["L", crispX - halfWidth, topBox],
          ["L", crispX + halfWidth, topBox],
          ["L", crispX + halfWidth, bottomBox],
          ["Z"],
          // Ensure a nice rectangle #2602
          ["M", crispX, topBox],
          [
            "L",
            // #460, #2094
            crispX,
            hasTopWhisker ? Math.round(reversedYAxis ? point.yBottom : point.plotHigh) : topBox
          ],
          ["M", crispX, bottomBox],
          [
            "L",
            // #460, #2094
            crispX,
            hasBottomWhisker ? Math.round(reversedYAxis ? point.plotHigh : point.yBottom) : bottomBox
          ]
        );
        graphic[isNew ? "attr" : "animate"]({ d: path }).addClass(point.getClassName(), true);
      }
    }
  }
}
CandlestickSeries.defaultOptions = merge$17(OHLCSeries.defaultOptions, { tooltip: OHLCSeries.defaultOptions.tooltip }, CandlestickSeriesDefaults);
SeriesRegistry$1.registerSeriesType("candlestick", CandlestickSeries);
const { column: { prototype: { pointClass: ColumnPoint$1 } } } = SeriesRegistry$1.seriesTypes;
const { isNumber: isNumber$J } = Utilities;
class FlagsPoint extends ColumnPoint$1 {
  constructor() {
    super(...arguments);
    this.ttBelow = false;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  isValid() {
    return isNumber$J(this.y) || typeof this.y === "undefined";
  }
  /**
   * @private
   */
  hasNewShapeType() {
    const shape = this.options.shape || this.series.options.shape;
    return this.graphic && shape && shape !== this.graphic.symbolKey;
  }
}
const FlagsSeriesDefaults = {
  /**
   * The corner radius of the border surrounding each flag. For `squarepin`
   * shaped flags only. A number signifies pixels. A percentage string, like
   * for example 50%, signifies a relative size.
   */
  borderRadius: 0,
  /**
   * In case the flag is placed on a series, on what point key to place
   * it. Line and columns have one key, `y`. In range or OHLC-type series,
   * however, the flag can optionally be placed on the `open`, `high`,
   * `low` or `close` key.
   *
   * @sample {highstock} stock/plotoptions/flags-onkey/
   *         Range series, flag on high
   *
   * @type       {string}
   * @default    y
   * @since      4.2.2
   * @product    highstock
   * @validvalue ["y", "open", "high", "low", "close"]
   * @apioption  plotOptions.flags.onKey
   */
  /**
   * The id of the series that the flags should be drawn on. If no id
   * is given, the flags are drawn on the x axis.
   *
   * @sample {highstock} stock/plotoptions/flags/
   *         Flags on series and on x axis
   *
   * @type      {string}
   * @product   highstock
   * @apioption plotOptions.flags.onSeries
   */
  pointRange: 0,
  // #673
  /**
   * Whether the flags are allowed to overlap sideways. If `false`, the
   * flags are moved sideways using an algorithm that seeks to place every
   * flag as close as possible to its original position.
   *
   * @sample {highstock} stock/plotoptions/flags-allowoverlapx
   *         Allow sideways overlap
   *
   * @since 6.0.4
   */
  allowOverlapX: false,
  /**
   * The shape of the marker. Can be one of "flag", "circlepin",
   * "squarepin", or an image of the format `url(/path-to-image.jpg)`.
   * Individual shapes can also be set for each point.
   *
   * @sample {highstock} stock/plotoptions/flags/
   *         Different shapes
   *
   * @type    {Highcharts.FlagsShapeValue}
   * @product highstock
   */
  shape: "flag",
  /**
   * When multiple flags in the same series fall on the same value, this
   * number determines the vertical offset between them.
   *
   * @sample {highstock} stock/plotoptions/flags-stackdistance/
   *         A greater stack distance
   *
   * @product highstock
   */
  stackDistance: 12,
  /**
   * Text alignment for the text inside the flag.
   *
   * @since      5.0.0
   * @product    highstock
   * @validvalue ["left", "center", "right"]
   */
  textAlign: "center",
  /**
   * Specific tooltip options for flag series. Flag series tooltips are
   * different from most other types in that a flag doesn't have a data
   * value, so the tooltip rather displays the `text` option for each
   * point.
   *
   * @extends   plotOptions.series.tooltip
   * @excluding changeDecimals, valueDecimals, valuePrefix, valueSuffix
   * @product   highstock
   */
  tooltip: {
    pointFormat: "{point.text}"
  },
  /**
   * @type {number|null}
   */
  threshold: null,
  /**
   * The text to display on each flag. This can be defined on series
   * level, or individually for each point. Defaults to `"A"`.
   *
   * @type      {string}
   * @default   A
   * @product   highstock
   * @apioption plotOptions.flags.title
   */
  /**
   * The y position of the top left corner of the flag relative to either
   * the series (if onSeries is defined), or the x axis. Defaults to
   * `-30`.
   *
   * @product highstock
   */
  y: -30,
  /**
   * Whether to use HTML to render the flag texts. Using HTML allows for
   * advanced formatting, images and reliable bi-directional text
   * rendering. Note that exported images won't respect the HTML, and that
   * HTML won't respect Z-index settings.
   *
   * @type      {boolean}
   * @default   false
   * @since     1.3
   * @product   highstock
   * @apioption plotOptions.flags.useHTML
   */
  /**
   * Fixed width of the flag's shape. By default, width is autocalculated
   * according to the flag's title.
   *
   * @sample {highstock} stock/demo/flags-shapes/
   *         Flags with fixed width
   *
   * @type      {number}
   * @product   highstock
   * @apioption plotOptions.flags.width
   */
  /**
   * Fixed height of the flag's shape. By default, height is
   * autocalculated according to the flag's title.
   *
   * @type      {number}
   * @product   highstock
   * @apioption plotOptions.flags.height
   */
  /**
   * The fill color for the flags.
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product highstock
   */
  fillColor: "#ffffff",
  /**
   * The color of the line/border of the flag.
   *
   * In styled mode, the stroke is set in the
   * `.highcharts-flag-series.highcharts-point` rule.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default   #000000
   * @product   highstock
   * @apioption plotOptions.flags.lineColor
   */
  /**
   * The pixel width of the flag's line/border.
   *
   * @product highstock
   */
  lineWidth: 1,
  states: {
    /**
     * @extends plotOptions.column.states.hover
     * @product highstock
     */
    hover: {
      /**
       * The color of the line/border of the flag.
       *
       * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @product highstock
       */
      lineColor: "#000000",
      /**
       * The fill or background color of the flag.
       *
       * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @product highstock
       */
      fillColor: "#ccd3ff"
      /* Palette.highlightColor20 */
    }
  },
  /**
   * The text styles of the flag.
   *
   * In styled mode, the styles are set in the
   * `.highcharts-flag-series .highcharts-point` rule.
   *
   * @type    {Highcharts.CSSObject}
   * @default {"fontSize": "11px", "fontWeight": "bold"}
   * @product highstock
   */
  style: {
    /** @ignore-option */
    fontSize: "0.7em",
    /** @ignore-option */
    fontWeight: "bold"
  }
};
var FlagsSymbols;
(function(FlagsSymbols2) {
  const modifiedMembers = [];
  function compose2(SVGRendererClass) {
    if (modifiedMembers.indexOf(SVGRendererClass) === -1) {
      modifiedMembers.push(SVGRendererClass);
      const symbols2 = SVGRendererClass.prototype.symbols;
      symbols2.flag = flag;
      createPinSymbol(symbols2, "circle");
      createPinSymbol(symbols2, "square");
    }
    const RendererClass = RendererRegistry$1.getRendererType();
    if (modifiedMembers.indexOf(RendererClass)) {
      modifiedMembers.push(RendererClass);
    }
  }
  FlagsSymbols2.compose = compose2;
  function flag(x, y, w, h, options2) {
    const anchorX = options2 && options2.anchorX || x, anchorY = options2 && options2.anchorY || y;
    const path = this.circle(anchorX - 1, anchorY - 1, 2, 2);
    path.push(["M", anchorX, anchorY], ["L", x, y + h], ["L", x, y], ["L", x + w, y], ["L", x + w, y + h], ["L", x, y + h], ["Z"]);
    return path;
  }
  function createPinSymbol(symbols2, shape) {
    symbols2[shape + "pin"] = function(x, y, w, h, options2) {
      const anchorX = options2 && options2.anchorX, anchorY = options2 && options2.anchorY;
      let path;
      if (shape === "circle" && h > w) {
        x -= Math.round((h - w) / 2);
        w = h;
      }
      path = symbols2[shape](x, y, w, h, options2);
      if (anchorX && anchorY) {
        let labelX = anchorX;
        if (shape === "circle") {
          labelX = x + w / 2;
        } else {
          const startSeg = path[0];
          const endSeg = path[1];
          if (startSeg[0] === "M" && endSeg[0] === "L") {
            labelX = (startSeg[1] + endSeg[1]) / 2;
          }
        }
        const labelY = y > anchorY ? y : y + h;
        path.push([
          "M",
          labelX,
          labelY
        ], [
          "L",
          anchorX,
          anchorY
        ]);
        path = path.concat(symbols2.circle(anchorX - 1, anchorY - 1, 2, 2));
      }
      return path;
    };
  }
})(FlagsSymbols || (FlagsSymbols = {}));
const FlagsSymbols$1 = FlagsSymbols;
const { composed: composed$n } = Highcharts;
const { prototype: columnProto$5 } = ColumnSeries$f;
const { prototype: seriesProto$4 } = Series$9;
const { defined: defined$M, pushUnique: pushUnique$n, stableSort: stableSort$5 } = Utilities;
var OnSeriesComposition;
(function(OnSeriesComposition2) {
  function compose2(SeriesClass) {
    if (pushUnique$n(composed$n, "OnSeries")) {
      const seriesProto2 = SeriesClass.prototype;
      seriesProto2.getPlotBox = getPlotBox;
      seriesProto2.translate = translate2;
    }
    return SeriesClass;
  }
  OnSeriesComposition2.compose = compose2;
  function getPlotBox(name) {
    return seriesProto$4.getPlotBox.call(this.options.onSeries && this.chart.get(this.options.onSeries) || this, name);
  }
  OnSeriesComposition2.getPlotBox = getPlotBox;
  function translate2() {
    columnProto$5.translate.apply(this);
    const series = this, options2 = series.options, chart = series.chart, points = series.points, optionsOnSeries = options2.onSeries, onSeries = optionsOnSeries && chart.get(optionsOnSeries), step = onSeries && onSeries.options.step, onData = onSeries && onSeries.points, inverted = chart.inverted, xAxis2 = series.xAxis, yAxis2 = series.yAxis;
    let cursor = points.length - 1, point, lastPoint, onKey = options2.onKey || "y", i = onData && onData.length, xOffset = 0, leftPoint, lastX, rightPoint, currentDataGrouping, distanceRatio;
    if (onSeries && onSeries.visible && i) {
      xOffset = (onSeries.pointXOffset || 0) + (onSeries.barW || 0) / 2;
      currentDataGrouping = onSeries.currentDataGrouping;
      lastX = onData[i - 1].x + (currentDataGrouping ? currentDataGrouping.totalRange : 0);
      stableSort$5(points, (a, b) => a.x - b.x);
      onKey = "plot" + onKey[0].toUpperCase() + onKey.substr(1);
      while (i-- && points[cursor]) {
        leftPoint = onData[i];
        point = points[cursor];
        point.y = leftPoint.y;
        if (leftPoint.x <= point.x && typeof leftPoint[onKey] !== "undefined") {
          if (point.x <= lastX) {
            point.plotY = leftPoint[onKey];
            if (leftPoint.x < point.x && !step) {
              rightPoint = onData[i + 1];
              if (rightPoint && typeof rightPoint[onKey] !== "undefined") {
                if (defined$M(point.plotX) && onSeries.is("spline")) {
                  leftPoint = leftPoint;
                  rightPoint = rightPoint;
                  const p0 = [
                    leftPoint.plotX || 0,
                    leftPoint.plotY || 0
                  ], p32 = [
                    rightPoint.plotX || 0,
                    rightPoint.plotY || 0
                  ], p12 = leftPoint.controlPoints?.high || p0, p22 = rightPoint.controlPoints?.low || p32, pixelThreshold = 0.25, maxIterations = 100, calculateCoord = (t2, key2) => (
                    // The parametric formula for the
                    // cubic Bezier curve.
                    Math.pow(1 - t2, 3) * p0[key2] + 3 * (1 - t2) * (1 - t2) * t2 * p12[key2] + 3 * (1 - t2) * t2 * t2 * p22[key2] + t2 * t2 * t2 * p32[key2]
                  );
                  let tMin = 0, tMax = 1, t;
                  for (let i2 = 0; i2 < maxIterations; i2++) {
                    const tMid = (tMin + tMax) / 2;
                    const xMid = calculateCoord(tMid, 0);
                    if (xMid === null) {
                      break;
                    }
                    if (Math.abs(xMid - point.plotX) < pixelThreshold) {
                      t = tMid;
                      break;
                    }
                    if (xMid < point.plotX) {
                      tMin = tMid;
                    } else {
                      tMax = tMid;
                    }
                  }
                  if (defined$M(t)) {
                    point.plotY = calculateCoord(t, 1);
                    point.y = yAxis2.toValue(point.plotY, true);
                  }
                } else {
                  distanceRatio = (point.x - leftPoint.x) / (rightPoint.x - leftPoint.x);
                  point.plotY += distanceRatio * // The plotY distance
                  (rightPoint[onKey] - leftPoint[onKey]);
                  point.y += distanceRatio * (rightPoint.y - leftPoint.y);
                }
              }
            }
          }
          cursor--;
          i++;
          if (cursor < 0) {
            break;
          }
        }
      }
    }
    points.forEach((point2, i2) => {
      let stackIndex;
      point2.plotX += xOffset;
      if (typeof point2.plotY === "undefined" || inverted) {
        if (point2.plotX >= 0 && point2.plotX <= xAxis2.len) {
          if (inverted) {
            point2.plotY = xAxis2.translate(point2.x, 0, 1, 0, 1);
            point2.plotX = defined$M(point2.y) ? yAxis2.translate(point2.y, 0, 0, 0, 1) : 0;
          } else {
            point2.plotY = (xAxis2.opposite ? 0 : series.yAxis.len) + xAxis2.offset;
          }
        } else {
          point2.shapeArgs = {};
        }
      }
      lastPoint = points[i2 - 1];
      if (lastPoint && lastPoint.plotX === point2.plotX) {
        if (typeof lastPoint.stackIndex === "undefined") {
          lastPoint.stackIndex = 0;
        }
        stackIndex = lastPoint.stackIndex + 1;
      }
      point2.stackIndex = stackIndex;
    });
    this.onSeries = onSeries;
  }
  OnSeriesComposition2.translate = translate2;
})(OnSeriesComposition || (OnSeriesComposition = {}));
const OnSeriesComposition$1 = OnSeriesComposition;
const { noop: noop$e } = Highcharts;
const { distribute } = R$1;
const { series: Series$5, seriesTypes: { column: ColumnSeries$b } } = SeriesRegistry$1;
const { addEvent: addEvent$12, defined: defined$L, extend: extend$W, isNumber: isNumber$I, merge: merge$16, objectEach: objectEach$e, wrap: wrap$f } = Utilities;
class FlagsSeries extends ColumnSeries$b {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Disable animation, but keep clipping (#8546).
   * @private
   */
  animate(init2) {
    if (init2) {
      this.setClip();
    }
  }
  /**
   * Draw the markers.
   * @private
   */
  drawPoints() {
    const series = this, points = series.points, chart = series.chart, renderer = chart.renderer, inverted = chart.inverted, options2 = series.options, optionsY = options2.y, yAxis2 = series.yAxis, boxesMap = {}, boxes = [], borderRadius = isNumber$I(options2.borderRadius) ? options2.borderRadius : 0;
    let plotX, plotY, shape, i, point, graphic, stackIndex, anchorY, attribs, outsideRight, centered;
    i = points.length;
    while (i--) {
      point = points[i];
      outsideRight = (inverted ? point.plotY : point.plotX) > series.xAxis.len;
      plotX = point.plotX;
      stackIndex = point.stackIndex;
      shape = point.options.shape || options2.shape;
      plotY = point.plotY;
      if (typeof plotY !== "undefined") {
        plotY = point.plotY + optionsY - (typeof stackIndex !== "undefined" && stackIndex * options2.stackDistance);
      }
      point.anchorX = stackIndex ? void 0 : point.plotX;
      anchorY = stackIndex ? void 0 : point.plotY;
      centered = shape !== "flag";
      graphic = point.graphic;
      if (typeof plotY !== "undefined" && plotX >= 0 && !outsideRight) {
        if (graphic && point.hasNewShapeType()) {
          graphic = graphic.destroy();
        }
        if (!graphic) {
          graphic = point.graphic = renderer.label("", 0, void 0, shape, void 0, void 0, options2.useHTML).addClass("highcharts-point").add(series.markerGroup);
          if (point.graphic.div) {
            point.graphic.div.point = point;
          }
          graphic.isNew = true;
        }
        graphic.attr({
          align: centered ? "center" : "left",
          width: options2.width,
          height: options2.height,
          "text-align": options2.textAlign,
          r: borderRadius
        });
        if (!chart.styledMode) {
          graphic.attr(series.pointAttribs(point)).css(merge$16(options2.style, point.style)).shadow(options2.shadow);
        }
        if (plotX > 0) {
          plotX -= graphic.strokeWidth() % 2;
        }
        attribs = {
          y: plotY,
          anchorY
        };
        if (options2.allowOverlapX) {
          attribs.x = plotX;
          attribs.anchorX = point.anchorX;
        }
        graphic.attr({
          // Allow empty string as a flag title (#20549)
          text: point.options.title ?? options2.title ?? "A"
        })[graphic.isNew ? "attr" : "animate"](attribs);
        if (!options2.allowOverlapX) {
          if (!boxesMap[point.plotX]) {
            boxesMap[point.plotX] = {
              align: centered ? 0.5 : 0,
              size: graphic.width || 0,
              target: plotX,
              anchorX: plotX
            };
          } else {
            boxesMap[point.plotX].size = Math.max(boxesMap[point.plotX].size, graphic.width || 0);
          }
        }
        point.tooltipPos = [
          plotX,
          plotY + yAxis2.pos - chart.plotTop
        ];
      } else if (graphic) {
        point.graphic = graphic.destroy();
      }
    }
    if (!options2.allowOverlapX) {
      let maxDistance = 100;
      objectEach$e(boxesMap, function(box) {
        box.plotX = box.anchorX;
        boxes.push(box);
        maxDistance = Math.max(box.size, maxDistance);
      });
      distribute(boxes, inverted ? yAxis2.len : this.xAxis.len, maxDistance);
      for (const point2 of points) {
        const plotX2 = point2.plotX, graphic2 = point2.graphic, box = graphic2 && boxesMap[plotX2];
        if (box && graphic2) {
          if (!defined$L(box.pos)) {
            graphic2.hide().isNew = true;
          } else {
            graphic2[graphic2.isNew ? "attr" : "animate"]({
              x: box.pos + (box.align || 0) * box.size,
              anchorX: point2.anchorX
            }).show().isNew = false;
          }
        }
      }
    }
    if (options2.useHTML && series.markerGroup) {
      wrap$f(series.markerGroup, "on", function(proceed) {
        return SVGElement$1.prototype.on.apply(
          // For HTML
          // eslint-disable-next-line no-invalid-this
          proceed.apply(this, [].slice.call(arguments, 1)),
          // And for SVG
          [].slice.call(arguments, 1)
        );
      });
    }
  }
  /**
   * Extend the column trackers with listeners to expand and contract
   * stacks.
   * @private
   */
  drawTracker() {
    const series = this, points = series.points;
    super.drawTracker();
    for (const point of points) {
      const graphic = point.graphic;
      if (graphic) {
        if (point.unbindMouseOver) {
          point.unbindMouseOver();
        }
        point.unbindMouseOver = addEvent$12(graphic.element, "mouseover", function() {
          if (point.stackIndex > 0 && !point.raised) {
            point._y = graphic.y;
            graphic.attr({
              y: point._y - 8
            });
            point.raised = true;
          }
          for (const otherPoint of points) {
            if (otherPoint !== point && otherPoint.raised && otherPoint.graphic) {
              otherPoint.graphic.attr({
                y: otherPoint._y
              });
              otherPoint.raised = false;
            }
          }
        });
      }
    }
  }
  /**
   * Get presentational attributes
   * @private
   */
  pointAttribs(point, state) {
    const options2 = this.options, color2 = point && point.color || this.color;
    let lineColor = options2.lineColor, lineWidth = point && point.lineWidth, fill = point && point.fillColor || options2.fillColor;
    if (state) {
      fill = options2.states[state].fillColor;
      lineColor = options2.states[state].lineColor;
      lineWidth = options2.states[state].lineWidth;
    }
    return {
      fill: fill || color2,
      stroke: lineColor || color2,
      "stroke-width": lineWidth || options2.lineWidth || 0
    };
  }
  /**
   * @private
   */
  setClip() {
    Series$5.prototype.setClip.apply(this, arguments);
    if (this.options.clip !== false && this.sharedClipKey && this.markerGroup) {
      this.markerGroup.clip(this.chart.sharedClips[this.sharedClipKey]);
    }
  }
}
FlagsSeries.compose = FlagsSymbols$1.compose;
FlagsSeries.defaultOptions = merge$16(ColumnSeries$b.defaultOptions, FlagsSeriesDefaults);
OnSeriesComposition$1.compose(FlagsSeries);
extend$W(FlagsSeries.prototype, {
  allowDG: false,
  forceCrop: true,
  invertible: false,
  // Flags series group should not be invertible (#14063).
  noSharedTooltip: true,
  pointClass: FlagsPoint,
  sorted: false,
  takeOrdinalPosition: false,
  // #1074
  trackerGroups: ["markerGroup"],
  buildKDTree: noop$e,
  /**
   * Inherit the initialization from base Series.
   * @private
   */
  init: Series$5.prototype.init
});
SeriesRegistry$1.registerSeriesType("flags", FlagsSeries);
const { addEvent: addEvent$11, find: find$b, fireEvent: fireEvent$p, isArray: isArray$e, isNumber: isNumber$H, pick: pick$1c } = Utilities;
var BrokenAxis;
(function(BrokenAxis2) {
  function compose2(AxisClass, SeriesClass) {
    if (!AxisClass.keepProps.includes("brokenAxis")) {
      AxisClass.keepProps.push("brokenAxis");
      addEvent$11(AxisClass, "init", onAxisInit2);
      addEvent$11(AxisClass, "afterInit", onAxisAfterInit);
      addEvent$11(AxisClass, "afterSetTickPositions", onAxisAfterSetTickPositions);
      addEvent$11(AxisClass, "afterSetOptions", onAxisAfterSetOptions2);
      const seriesProto2 = SeriesClass.prototype;
      seriesProto2.drawBreaks = seriesDrawBreaks;
      seriesProto2.gappedPath = seriesGappedPath;
      addEvent$11(SeriesClass, "afterGeneratePoints", onSeriesAfterGeneratePoints);
      addEvent$11(SeriesClass, "afterRender", onSeriesAfterRender);
    }
    return AxisClass;
  }
  BrokenAxis2.compose = compose2;
  function onAxisAfterInit() {
    if (typeof this.brokenAxis !== "undefined") {
      this.brokenAxis.setBreaks(this.options.breaks, false);
    }
  }
  function onAxisAfterSetOptions2() {
    const axis = this;
    if (axis.brokenAxis?.hasBreaks) {
      axis.options.ordinal = false;
    }
  }
  function onAxisAfterSetTickPositions() {
    const axis = this, brokenAxis = axis.brokenAxis;
    if (brokenAxis?.hasBreaks) {
      const tickPositions = axis.tickPositions, info = axis.tickPositions.info, newPositions = [];
      for (let i = 0; i < tickPositions.length; i++) {
        if (!brokenAxis.isInAnyBreak(tickPositions[i])) {
          newPositions.push(tickPositions[i]);
        }
      }
      axis.tickPositions = newPositions;
      axis.tickPositions.info = info;
    }
  }
  function onAxisInit2() {
    const axis = this;
    if (!axis.brokenAxis) {
      axis.brokenAxis = new Additions(axis);
    }
  }
  function onSeriesAfterGeneratePoints() {
    const { isDirty, options: { connectNulls }, points, xAxis: xAxis2, yAxis: yAxis2 } = this;
    if (isDirty) {
      let i = points.length;
      while (i--) {
        const point = points[i];
        const nullGap = point.y === null && connectNulls === false;
        const isPointInBreak = !nullGap && (xAxis2?.brokenAxis?.isInAnyBreak(point.x, true) || yAxis2?.brokenAxis?.isInAnyBreak(point.y, true));
        point.visible = isPointInBreak ? false : point.options.visible !== false;
      }
    }
  }
  function onSeriesAfterRender() {
    this.drawBreaks(this.xAxis, ["x"]);
    this.drawBreaks(this.yAxis, pick$1c(this.pointArrayMap, ["y"]));
  }
  function seriesDrawBreaks(axis, keys) {
    const series = this, points = series.points;
    let breaks, threshold, y;
    if (axis?.brokenAxis?.hasBreaks) {
      const brokenAxis = axis.brokenAxis;
      keys.forEach(function(key2) {
        breaks = brokenAxis?.breakArray || [];
        threshold = axis.isXAxis ? axis.min : pick$1c(series.options.threshold, axis.min);
        const breaksOutOfRange = axis?.options?.breaks?.filter(function(brk) {
          let isOut = true;
          for (let i = 0; i < breaks.length; i++) {
            const otherBreak = breaks[i];
            if (otherBreak.from === brk.from && otherBreak.to === brk.to) {
              isOut = false;
              break;
            }
          }
          return isOut;
        });
        points.forEach(function(point) {
          y = pick$1c(point["stack" + key2.toUpperCase()], point[key2]);
          breaks.forEach(function(brk) {
            if (isNumber$H(threshold) && isNumber$H(y)) {
              let eventName = "";
              if (threshold < brk.from && y > brk.to || threshold > brk.from && y < brk.from) {
                eventName = "pointBreak";
              } else if (threshold < brk.from && y > brk.from && y < brk.to || threshold > brk.from && y > brk.to && y < brk.from) {
                eventName = "pointInBreak";
              }
              if (eventName) {
                fireEvent$p(axis, eventName, { point, brk });
              }
            }
          });
          breaksOutOfRange?.forEach(function(brk) {
            fireEvent$p(axis, "pointOutsideOfBreak", { point, brk });
          });
        });
      });
    }
  }
  function seriesGappedPath() {
    const currentDataGrouping = this.currentDataGrouping, groupingSize = currentDataGrouping?.gapSize, points = this.points.slice(), yAxis2 = this.yAxis;
    let gapSize = this.options.gapSize, i = points.length - 1, stack;
    if (gapSize && i > 0) {
      if (this.options.gapUnit !== "value") {
        gapSize *= this.basePointRange;
      }
      if (groupingSize && groupingSize > gapSize && // Except when DG is forced (e.g. from other series)
      // and has lower granularity than actual points (#11351)
      groupingSize >= this.basePointRange) {
        gapSize = groupingSize;
      }
      let current, next;
      while (i--) {
        if (!(next && next.visible !== false)) {
          next = points[i + 1];
        }
        current = points[i];
        if (next.visible === false || current.visible === false) {
          continue;
        }
        if (next.x - current.x > gapSize) {
          const xRange = (current.x + next.x) / 2;
          points.splice(
            // Insert after this one
            i + 1,
            0,
            {
              isNull: true,
              x: xRange
            }
          );
          if (yAxis2.stacking && this.options.stacking) {
            stack = yAxis2.stacking.stacks[this.stackKey][xRange] = new StackItem(yAxis2, yAxis2.options.stackLabels, false, xRange, this.stack);
            stack.total = 0;
          }
        }
        next = current;
      }
    }
    return this.getGraphPath(points);
  }
  class Additions {
    /* *
     *
     *  Static Functions
     *
     * */
    /**
     * @private
     */
    static isInBreak(brk, val) {
      const repeat = brk.repeat || Infinity, from = brk.from, length = brk.to - brk.from, test = val >= from ? (val - from) % repeat : repeat - (from - val) % repeat;
      let ret;
      if (!brk.inclusive) {
        ret = test < length && test !== 0;
      } else {
        ret = test <= length;
      }
      return ret;
    }
    /**
     * @private
     */
    static lin2Val(val) {
      const axis = this;
      const brokenAxis = axis.brokenAxis;
      const breakArray = brokenAxis?.breakArray;
      if (!breakArray || !isNumber$H(val)) {
        return val;
      }
      let nval = val, brk, i;
      for (i = 0; i < breakArray.length; i++) {
        brk = breakArray[i];
        if (brk.from >= nval) {
          break;
        } else if (brk.to < nval) {
          nval += brk.len;
        } else if (Additions.isInBreak(brk, nval)) {
          nval += brk.len;
        }
      }
      return nval;
    }
    /**
     * @private
     */
    static val2Lin(val) {
      const axis = this;
      const brokenAxis = axis.brokenAxis;
      const breakArray = brokenAxis?.breakArray;
      if (!breakArray || !isNumber$H(val)) {
        return val;
      }
      let nval = val, brk, i;
      for (i = 0; i < breakArray.length; i++) {
        brk = breakArray[i];
        if (brk.to <= val) {
          nval -= brk.len;
        } else if (brk.from >= val) {
          break;
        } else if (Additions.isInBreak(brk, val)) {
          nval -= val - brk.from;
          break;
        }
      }
      return nval;
    }
    /* *
     *
     *  Constructors
     *
     * */
    constructor(axis) {
      this.hasBreaks = false;
      this.axis = axis;
    }
    /* *
     *
     *  Functions
     *
     * */
    /**
     * Returns the first break found where the x is larger then break.from
     * and smaller then break.to.
     *
     * @param {number} x
     * The number which should be within a break.
     *
     * @param {Array<Highcharts.XAxisBreaksOptions>} breaks
     * The array of breaks to search within.
     *
     * @return {Highcharts.XAxisBreaksOptions|undefined}
     * Returns the first break found that matches, returns false if no break
     * is found.
     */
    findBreakAt(x, breaks) {
      return find$b(breaks, function(b) {
        return b.from < x && x < b.to;
      });
    }
    /**
     * @private
     */
    isInAnyBreak(val, testKeep) {
      const brokenAxis = this, axis = brokenAxis.axis, breaks = axis.options.breaks || [];
      let i = breaks.length, inbrk, keep, ret;
      if (i && isNumber$H(val)) {
        while (i--) {
          if (Additions.isInBreak(breaks[i], val)) {
            inbrk = true;
            if (!keep) {
              keep = pick$1c(breaks[i].showPoints, !axis.isXAxis);
            }
          }
        }
        if (inbrk && testKeep) {
          ret = inbrk && !keep;
        } else {
          ret = inbrk;
        }
      }
      return ret;
    }
    /**
     * Dynamically set or unset breaks in an axis. This function in lighter
     * than using Axis.update, and it also preserves animation.
     *
     * @private
     * @function Highcharts.Axis#setBreaks
     *
     * @param {Array<Highcharts.XAxisBreaksOptions>} [breaks]
     * The breaks to add. When `undefined` it removes existing breaks.
     *
     * @param {boolean} [redraw=true]
     * Whether to redraw the chart immediately.
     */
    setBreaks(breaks, redraw) {
      const brokenAxis = this, axis = brokenAxis.axis, time = axis.chart.time, hasBreaks = isArray$e(breaks) && !!breaks.length && !!Object.keys(breaks[0]).length;
      axis.isDirty = brokenAxis.hasBreaks !== hasBreaks;
      brokenAxis.hasBreaks = hasBreaks;
      breaks?.forEach((brk) => {
        brk.from = time.parse(brk.from) || 0;
        brk.to = time.parse(brk.to) || 0;
      });
      if (breaks !== axis.options.breaks) {
        axis.options.breaks = axis.userOptions.breaks = breaks;
      }
      axis.forceRedraw = true;
      axis.series.forEach(function(series) {
        series.isDirty = true;
      });
      if (!hasBreaks && axis.val2lin === Additions.val2Lin) {
        delete axis.val2lin;
        delete axis.lin2val;
      }
      if (hasBreaks) {
        axis.userOptions.ordinal = false;
        axis.lin2val = Additions.lin2Val;
        axis.val2lin = Additions.val2Lin;
        axis.setExtremes = function(newMin, newMax, redraw2, animation, eventArguments) {
          if (brokenAxis.hasBreaks) {
            const breaks2 = this.options.breaks || [];
            let axisBreak;
            while (axisBreak = brokenAxis.findBreakAt(newMin, breaks2)) {
              newMin = axisBreak.to;
            }
            while (axisBreak = brokenAxis.findBreakAt(newMax, breaks2)) {
              newMax = axisBreak.from;
            }
            if (newMax < newMin) {
              newMax = newMin;
            }
          }
          axis.constructor.prototype.setExtremes.call(this, newMin, newMax, redraw2, animation, eventArguments);
        };
        axis.setAxisTranslation = function() {
          axis.constructor.prototype.setAxisTranslation.call(this);
          brokenAxis.unitLength = void 0;
          if (brokenAxis.hasBreaks) {
            const breaks2 = axis.options.breaks || [], breakArrayT = [], breakArray = [], pointRangePadding = pick$1c(axis.pointRangePadding, 0);
            let length = 0, inBrk, repeat, min2 = axis.userMin || axis.min, max2 = axis.userMax || axis.max, start2, i;
            breaks2.forEach(function(brk) {
              repeat = brk.repeat || Infinity;
              if (isNumber$H(min2) && isNumber$H(max2)) {
                if (Additions.isInBreak(brk, min2)) {
                  min2 += brk.to % repeat - min2 % repeat;
                }
                if (Additions.isInBreak(brk, max2)) {
                  max2 -= max2 % repeat - brk.from % repeat;
                }
              }
            });
            breaks2.forEach(function(brk) {
              start2 = brk.from;
              repeat = brk.repeat || Infinity;
              if (isNumber$H(min2) && isNumber$H(max2)) {
                while (start2 - repeat > min2) {
                  start2 -= repeat;
                }
                while (start2 < min2) {
                  start2 += repeat;
                }
                for (i = start2; i < max2; i += repeat) {
                  breakArrayT.push({
                    value: i,
                    move: "in"
                  });
                  breakArrayT.push({
                    value: i + brk.to - brk.from,
                    move: "out",
                    size: brk.breakSize
                  });
                }
              }
            });
            breakArrayT.sort(function(a, b) {
              return a.value === b.value ? (a.move === "in" ? 0 : 1) - (b.move === "in" ? 0 : 1) : a.value - b.value;
            });
            inBrk = 0;
            start2 = min2;
            breakArrayT.forEach(function(brk) {
              inBrk += brk.move === "in" ? 1 : -1;
              if (inBrk === 1 && brk.move === "in") {
                start2 = brk.value;
              }
              if (inBrk === 0 && isNumber$H(start2)) {
                breakArray.push({
                  from: start2,
                  to: brk.value,
                  len: brk.value - start2 - (brk.size || 0)
                });
                length += brk.value - start2 - (brk.size || 0);
              }
            });
            brokenAxis.breakArray = breakArray;
            if (isNumber$H(min2) && isNumber$H(max2) && isNumber$H(axis.min)) {
              brokenAxis.unitLength = max2 - min2 - length + pointRangePadding;
              fireEvent$p(axis, "afterBreaks");
              if (axis.staticScale) {
                axis.transA = axis.staticScale;
              } else if (brokenAxis.unitLength) {
                axis.transA *= (max2 - axis.min + pointRangePadding) / brokenAxis.unitLength;
              }
              if (pointRangePadding) {
                axis.minPixelPadding = axis.transA * (axis.minPointOffset || 0);
              }
              axis.min = min2;
              axis.max = max2;
            }
          }
        };
      }
      if (pick$1c(redraw, true)) {
        axis.chart.redraw();
      }
    }
  }
  BrokenAxis2.Additions = Additions;
})(BrokenAxis || (BrokenAxis = {}));
const BrokenAxis$1 = BrokenAxis;
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/broken-axis
 * @requires highcharts
 *
 * (c) 2009-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$j = Highcharts;
G$j.BrokenAxis = G$j.BrokenAxis || BrokenAxis$1;
G$j.BrokenAxis.compose(G$j.Axis, G$j.Series);
const ApproximationRegistry = {
  // Approximations added programmatically
};
const { arrayMax: arrayMax$5, arrayMin: arrayMin$4, correctFloat: correctFloat$6, extend: extend$V, isNumber: isNumber$G } = Utilities;
function average(arr) {
  const len = arr.length;
  let ret = sum(arr);
  if (isNumber$G(ret) && len) {
    ret = correctFloat$6(ret / len);
  }
  return ret;
}
function averages() {
  const ret = [];
  [].forEach.call(arguments, function(arr) {
    ret.push(average(arr));
  });
  return typeof ret[0] === "undefined" ? void 0 : ret;
}
function close(arr) {
  return arr.length ? arr[arr.length - 1] : arr.hasNulls ? null : void 0;
}
function high(arr) {
  return arr.length ? arrayMax$5(arr) : arr.hasNulls ? null : void 0;
}
function hlc(high2, low2, close2) {
  high2 = ApproximationRegistry.high(high2);
  low2 = ApproximationRegistry.low(low2);
  close2 = ApproximationRegistry.close(close2);
  if (isNumber$G(high2) || isNumber$G(low2) || isNumber$G(close2)) {
    return [high2, low2, close2];
  }
}
function low(arr) {
  return arr.length ? arrayMin$4(arr) : arr.hasNulls ? null : void 0;
}
function ohlc$1(open2, high2, low2, close2) {
  open2 = ApproximationRegistry.open(open2);
  high2 = ApproximationRegistry.high(high2);
  low2 = ApproximationRegistry.low(low2);
  close2 = ApproximationRegistry.close(close2);
  if (isNumber$G(open2) || isNumber$G(high2) || isNumber$G(low2) || isNumber$G(close2)) {
    return [open2, high2, low2, close2];
  }
}
function open(arr) {
  return arr.length ? arr[0] : arr.hasNulls ? null : void 0;
}
function range(low2, high2) {
  low2 = ApproximationRegistry.low(low2);
  high2 = ApproximationRegistry.high(high2);
  if (isNumber$G(low2) || isNumber$G(high2)) {
    return [low2, high2];
  }
  if (low2 === null && high2 === null) {
    return null;
  }
}
function sum(arr) {
  let len = arr.length, ret;
  if (!len && arr.hasNulls) {
    ret = null;
  } else if (len) {
    ret = 0;
    while (len--) {
      ret += arr[len];
    }
  }
  return ret;
}
const ApproximationDefaults = {
  average,
  averages,
  close,
  high,
  hlc,
  low,
  ohlc: ohlc$1,
  open,
  range,
  sum
};
extend$V(ApproximationRegistry, ApproximationDefaults);
const common$1 = {
  /// enabled: null, // (true for stock charts, false for basic),
  // forced: undefined,
  groupPixelWidth: 2,
  // The first one is the point or start value, the second is the start
  // value if we're dealing with range, the third one is the end value if
  // dealing with a range
  dateTimeLabelFormats: {
    millisecond: [
      "%[AebHMSL]",
      "%[AebHMSL]",
      "-%[HMSL]"
    ],
    second: [
      "%[AebHMS]",
      "%[AebHMS]",
      "-%[HMS]"
    ],
    minute: [
      "%[AebHM]",
      "%[AebHM]",
      "-%[HM]"
    ],
    hour: [
      "%[AebHM]",
      "%[AebHM]",
      "-%[HM]"
    ],
    day: [
      "%[AebY]",
      "%[Aeb]",
      "-%[AebY]"
    ],
    week: [
      "%v %[AebY]",
      "%[Aeb]",
      "-%[AebY]"
    ],
    month: [
      "%[BY]",
      "%[B]",
      "-%[BY]"
    ],
    year: [
      "%Y",
      "%Y",
      "-%Y"
    ]
  }
  /// smoothed = false, // enable this for navigator series only
};
const seriesSpecific = {
  line: {},
  spline: {},
  area: {},
  areaspline: {},
  arearange: {},
  column: {
    groupPixelWidth: 10
  },
  columnrange: {
    groupPixelWidth: 10
  },
  candlestick: {
    groupPixelWidth: 10
  },
  ohlc: {
    groupPixelWidth: 5
  },
  hlc: {
    groupPixelWidth: 5
    // Move to HeikinAshiSeries.ts after refactoring data grouping.
  },
  heikinashi: {
    groupPixelWidth: 10
  }
};
const units$1 = [
  [
    "millisecond",
    // Unit name
    [1, 2, 5, 10, 20, 25, 50, 100, 200, 500]
    // Allowed multiples
  ],
  [
    "second",
    [1, 2, 5, 10, 15, 30]
  ],
  [
    "minute",
    [1, 2, 5, 10, 15, 30]
  ],
  [
    "hour",
    [1, 2, 3, 4, 6, 8, 12]
  ],
  [
    "day",
    [1]
  ],
  [
    "week",
    [1]
  ],
  [
    "month",
    [1, 3, 6]
  ],
  [
    "year",
    null
  ]
];
const DataGroupingDefaults = {
  common: common$1,
  seriesSpecific,
  units: units$1
};
const { addEvent: addEvent$10, extend: extend$U, merge: merge$15, pick: pick$1b } = Utilities;
let AxisConstructor;
function applyGrouping$1(e) {
  const axis = this, series = axis.series;
  series.forEach(function(series2) {
    series2.groupPixelWidth = void 0;
  });
  series.forEach(function(series2) {
    series2.groupPixelWidth = axis.getGroupPixelWidth && axis.getGroupPixelWidth();
    if (series2.groupPixelWidth) {
      series2.hasProcessed = true;
    }
    series2.applyGrouping(!!e.hasExtremesChanged);
  });
}
function compose$l(AxisClass) {
  AxisConstructor = AxisClass;
  const axisProto = AxisClass.prototype;
  if (!axisProto.applyGrouping) {
    addEvent$10(AxisClass, "afterSetScale", onAfterSetScale$1);
    addEvent$10(AxisClass, "postProcessData", applyGrouping$1);
    extend$U(axisProto, {
      applyGrouping: applyGrouping$1,
      getGroupPixelWidth,
      setDataGrouping
    });
  }
}
function getGroupPixelWidth() {
  const series = this.series;
  let i = series.length, groupPixelWidth = 0, doGrouping = false, dataLength, dgOptions;
  while (i--) {
    dgOptions = series[i].options.dataGrouping;
    if (dgOptions) {
      groupPixelWidth = Math.max(
        groupPixelWidth,
        // Fallback to commonOptions (#9693)
        pick$1b(dgOptions.groupPixelWidth, DataGroupingDefaults.common.groupPixelWidth)
      );
      dataLength = (series[i].dataTable.modified || series[i].dataTable).rowCount;
      if (series[i].groupPixelWidth || dataLength > this.chart.plotSizeX / groupPixelWidth || dataLength && dgOptions.forced) {
        doGrouping = true;
      }
    }
  }
  return doGrouping ? groupPixelWidth : 0;
}
function onAfterSetScale$1() {
  this.series.forEach(function(series) {
    series.hasProcessed = false;
  });
}
function setDataGrouping(dataGrouping, redraw) {
  const axis = this;
  let i;
  redraw = pick$1b(redraw, true);
  if (!dataGrouping) {
    dataGrouping = {
      forced: false,
      units: null
    };
  }
  if (this instanceof AxisConstructor) {
    i = this.series.length;
    while (i--) {
      this.series[i].update({
        dataGrouping
      }, false);
    }
  } else {
    this.chart.options.series.forEach(function(seriesOptions) {
      seriesOptions.dataGrouping = typeof dataGrouping === "boolean" ? dataGrouping : merge$15(dataGrouping, seriesOptions.dataGrouping);
    });
  }
  if (axis.ordinal) {
    axis.ordinal.slope = void 0;
  }
  if (redraw) {
    this.chart.redraw();
  }
}
const DataGroupingAxisComposition = {
  compose: compose$l
};
const { series: { prototype: seriesProto$3 } } = SeriesRegistry$1;
const { addEvent: addEvent$$, defined: defined$K, error: error$4, extend: extend$T, isNumber: isNumber$F, merge: merge$14, pick: pick$1a, splat: splat$c } = Utilities;
const baseGeneratePoints = seriesProto$3.generatePoints;
function adjustExtremes(xAxis2, groupedXData) {
  if (defined$K(groupedXData[0]) && isNumber$F(xAxis2.min) && isNumber$F(xAxis2.dataMin) && groupedXData[0] < xAxis2.min) {
    if (!defined$K(xAxis2.options.min) && xAxis2.min <= xAxis2.dataMin || xAxis2.min === xAxis2.dataMin) {
      xAxis2.min = Math.min(groupedXData[0], xAxis2.min);
    }
    xAxis2.dataMin = Math.min(groupedXData[0], xAxis2.dataMin);
  }
  if (defined$K(groupedXData[groupedXData.length - 1]) && isNumber$F(xAxis2.max) && isNumber$F(xAxis2.dataMax) && groupedXData[groupedXData.length - 1] > xAxis2.max) {
    if (!defined$K(xAxis2.options.max) && isNumber$F(xAxis2.dataMax) && xAxis2.max >= xAxis2.dataMax || xAxis2.max === xAxis2.dataMax) {
      xAxis2.max = Math.max(groupedXData[groupedXData.length - 1], xAxis2.max);
    }
    xAxis2.dataMax = Math.max(groupedXData[groupedXData.length - 1], xAxis2.dataMax);
  }
}
function anchorPoints(series, groupedXData, xMax) {
  const options2 = series.options, dataGroupingOptions = options2.dataGrouping, totalRange = series.currentDataGrouping && series.currentDataGrouping.gapSize, xData = series.getColumn("x");
  if (!(dataGroupingOptions && xData.length && totalRange && series.groupMap)) {
    return;
  }
  const groupedDataLastIndex = groupedXData.length - 1, anchor = dataGroupingOptions.anchor, firstAnchor = dataGroupingOptions.firstAnchor, lastAnchor = dataGroupingOptions.lastAnchor;
  let anchorIndexIterator = groupedXData.length - 1, anchorFirstIndex = 0;
  if (firstAnchor && xData[0] >= groupedXData[0]) {
    anchorFirstIndex++;
    const groupStart = series.groupMap[0].start, groupLength = series.groupMap[0].length;
    let firstGroupEnd;
    if (isNumber$F(groupStart) && isNumber$F(groupLength)) {
      firstGroupEnd = groupStart + (groupLength - 1);
    }
    groupedXData[0] = {
      start: groupedXData[0],
      middle: groupedXData[0] + 0.5 * totalRange,
      end: groupedXData[0] + totalRange,
      firstPoint: xData[0],
      lastPoint: firstGroupEnd && xData[firstGroupEnd]
    }[firstAnchor];
  }
  if (groupedDataLastIndex > 0 && lastAnchor && totalRange && groupedXData[groupedDataLastIndex] >= xMax - totalRange) {
    anchorIndexIterator--;
    const lastGroupStart = series.groupMap[series.groupMap.length - 1].start;
    groupedXData[groupedDataLastIndex] = {
      start: groupedXData[groupedDataLastIndex],
      middle: groupedXData[groupedDataLastIndex] + 0.5 * totalRange,
      end: groupedXData[groupedDataLastIndex] + totalRange,
      firstPoint: lastGroupStart && xData[lastGroupStart],
      lastPoint: xData[xData.length - 1]
    }[lastAnchor];
  }
  if (anchor && anchor !== "start") {
    const shiftInterval = totalRange * { middle: 0.5, end: 1 }[anchor];
    while (anchorIndexIterator >= anchorFirstIndex) {
      groupedXData[anchorIndexIterator] += shiftInterval;
      anchorIndexIterator--;
    }
  }
}
function applyGrouping(hasExtremesChanged) {
  const series = this, chart = series.chart, options2 = series.options, dataGroupingOptions = options2.dataGrouping, groupingEnabled = series.allowDG !== false && dataGroupingOptions && pick$1a(dataGroupingOptions.enabled, chart.options.isStock), reserveSpace = series.reserveSpace(), lastDataGrouping = this.currentDataGrouping;
  let currentDataGrouping, croppedData, revertRequireSorting = false;
  if (groupingEnabled && !series.requireSorting) {
    series.requireSorting = revertRequireSorting = true;
  }
  const skip = skipDataGrouping(series, hasExtremesChanged) === false || !groupingEnabled;
  if (revertRequireSorting) {
    series.requireSorting = false;
  }
  if (skip) {
    return;
  }
  series.destroyGroupedData();
  const table = dataGroupingOptions.groupAll ? series.dataTable : series.dataTable.modified || series.dataTable, processedXData = series.getColumn("x", !dataGroupingOptions.groupAll), xData = processedXData, plotSizeX = chart.plotSizeX, xAxis2 = series.xAxis, extremes = xAxis2.getExtremes(), ordinal = xAxis2.options.ordinal, groupPixelWidth = series.groupPixelWidth;
  let i, hasGroupedData;
  if (groupPixelWidth && xData && table.rowCount && plotSizeX && isNumber$F(extremes.min)) {
    hasGroupedData = true;
    series.isDirty = true;
    series.points = null;
    const xMin = extremes.min, xMax = extremes.max, groupIntervalFactor = ordinal && xAxis2.ordinal && xAxis2.ordinal.getGroupIntervalFactor(xMin, xMax, series) || 1, interval = groupPixelWidth * (xMax - xMin) / plotSizeX * groupIntervalFactor, groupPositions = xAxis2.getTimeTicks(
      DateTimeAxis$1.Additions.prototype.normalizeTimeTickInterval(interval, dataGroupingOptions.units || DataGroupingDefaults.units),
      // Processed data may extend beyond axis (#4907)
      Math.min(xMin, xData[0]),
      Math.max(xMax, xData[xData.length - 1]),
      xAxis2.options.startOfWeek,
      processedXData,
      series.closestPointRange
    ), groupedData = seriesProto$3.groupData.apply(series, [
      table,
      groupPositions,
      dataGroupingOptions.approximation
    ]);
    let modified = groupedData.modified, groupedXData = modified.getColumn("x", true), gapSize = 0;
    if (dataGroupingOptions?.smoothed && modified.rowCount) {
      dataGroupingOptions.firstAnchor = "firstPoint";
      dataGroupingOptions.anchor = "middle";
      dataGroupingOptions.lastAnchor = "lastPoint";
      error$4(32, false, chart, {
        "dataGrouping.smoothed": "use dataGrouping.anchor"
      });
    }
    for (i = 1; i < groupPositions.length; i++) {
      if (!groupPositions.info.segmentStarts || groupPositions.info.segmentStarts.indexOf(i) === -1) {
        gapSize = Math.max(groupPositions[i] - groupPositions[i - 1], gapSize);
      }
    }
    currentDataGrouping = groupPositions.info;
    currentDataGrouping.gapSize = gapSize;
    series.closestPointRange = groupPositions.info.totalRange;
    series.groupMap = groupedData.groupMap;
    series.currentDataGrouping = currentDataGrouping;
    anchorPoints(series, groupedXData || [], xMax);
    if (reserveSpace && groupedXData) {
      adjustExtremes(xAxis2, groupedXData);
    }
    if (dataGroupingOptions.groupAll) {
      series.allGroupedTable = modified;
      croppedData = series.cropData(modified, xAxis2.min || 0, xAxis2.max || 0);
      modified = croppedData.modified;
      groupedXData = modified.getColumn("x");
      series.cropStart = croppedData.start;
    }
    series.dataTable.modified = modified;
  } else {
    series.groupMap = void 0;
    series.currentDataGrouping = void 0;
  }
  series.hasGroupedData = hasGroupedData;
  series.preventGraphAnimation = (lastDataGrouping && lastDataGrouping.totalRange) !== (currentDataGrouping && currentDataGrouping.totalRange);
}
function compose$k(SeriesClass) {
  const seriesProto2 = SeriesClass.prototype;
  if (!seriesProto2.applyGrouping) {
    const PointClass = SeriesClass.prototype.pointClass;
    addEvent$$(PointClass, "update", function() {
      if (this.dataGroup) {
        error$4(24, false, this.series.chart);
        return false;
      }
    });
    addEvent$$(SeriesClass, "afterSetOptions", onAfterSetOptions$1);
    addEvent$$(SeriesClass, "destroy", destroyGroupedData);
    extend$T(seriesProto2, {
      applyGrouping,
      destroyGroupedData,
      generatePoints,
      getDGApproximation,
      groupData
    });
  }
}
function destroyGroupedData() {
  if (this.groupedData) {
    this.groupedData.forEach(function(point, i) {
      if (point) {
        this.groupedData[i] = point.destroy ? point.destroy() : null;
      }
    }, this);
    this.groupedData.length = 0;
    delete this.allGroupedTable;
  }
}
function generatePoints() {
  baseGeneratePoints.apply(this);
  this.destroyGroupedData();
  this.groupedData = this.hasGroupedData ? this.points : null;
}
function getDGApproximation() {
  if (this.is("arearange")) {
    return "range";
  }
  if (this.is("ohlc")) {
    return "ohlc";
  }
  if (this.is("hlc")) {
    return "hlc";
  }
  if (
    // #18974, default approximation for cumulative
    // should be `sum` when `dataGrouping` is enabled
    this.is("column") || this.options.cumulative
  ) {
    return "sum";
  }
  return "average";
}
function groupData(table, groupPositions, approximation) {
  const xData = table.getColumn("x", true) || [], yData = table.getColumn("y", true), series = this, data = series.data, dataOptions = series.options && series.options.data, groupedXData = [], modified = new DataTableCore(), groupMap = [], dataLength = table.rowCount, handleYData = !!yData, values = [], pointArrayMap = series.pointArrayMap, pointArrayMapLength = pointArrayMap && pointArrayMap.length, extendedPointArrayMap = ["x"].concat(pointArrayMap || ["y"]), valueColumns = (pointArrayMap || ["y"]).map(() => []), groupAll = this.options.dataGrouping && this.options.dataGrouping.groupAll;
  let pointX, pointY, groupedY, pos = 0, start2 = 0;
  const approximationFn = typeof approximation === "function" ? approximation : approximation && ApproximationRegistry[approximation] ? ApproximationRegistry[approximation] : ApproximationRegistry[series.getDGApproximation && series.getDGApproximation() || "average"];
  if (pointArrayMapLength) {
    let len = pointArrayMap.length;
    while (len--) {
      values.push([]);
    }
  } else {
    values.push([]);
  }
  const valuesLen = pointArrayMapLength || 1;
  for (let i = 0; i <= dataLength; i++) {
    if (xData[i] < groupPositions[0]) {
      continue;
    }
    while (typeof groupPositions[pos + 1] !== "undefined" && xData[i] >= groupPositions[pos + 1] || i === dataLength) {
      pointX = groupPositions[pos];
      series.dataGroupInfo = {
        start: groupAll ? start2 : series.cropStart + start2,
        length: values[0].length,
        groupStart: pointX
      };
      groupedY = approximationFn.apply(series, values);
      if (series.pointClass && !defined$K(series.dataGroupInfo.options)) {
        series.dataGroupInfo.options = merge$14(series.pointClass.prototype.optionsToObject.call({ series }, series.options.data[series.cropStart + start2]));
        extendedPointArrayMap.forEach(function(key2) {
          delete series.dataGroupInfo.options[key2];
        });
      }
      if (typeof groupedY !== "undefined") {
        groupedXData.push(pointX);
        const groupedValuesArr = splat$c(groupedY);
        for (let j = 0; j < groupedValuesArr.length; j++) {
          valueColumns[j].push(groupedValuesArr[j]);
        }
        groupMap.push(series.dataGroupInfo);
      }
      start2 = i;
      for (let j = 0; j < valuesLen; j++) {
        values[j].length = 0;
        values[j].hasNulls = false;
      }
      pos += 1;
      if (i === dataLength) {
        break;
      }
    }
    if (i === dataLength) {
      break;
    }
    if (pointArrayMap) {
      const index = groupAll ? i : series.cropStart + i, point = data && data[index] || series.pointClass.prototype.applyOptions.apply({
        series
      }, [dataOptions[index]]);
      let val;
      for (let j = 0; j < pointArrayMapLength; j++) {
        val = point[pointArrayMap[j]];
        if (isNumber$F(val)) {
          values[j].push(val);
        } else if (val === null) {
          values[j].hasNulls = true;
        }
      }
    } else {
      pointY = handleYData ? yData[i] : null;
      if (isNumber$F(pointY)) {
        values[0].push(pointY);
      } else if (pointY === null) {
        values[0].hasNulls = true;
      }
    }
  }
  const columns = {
    x: groupedXData
  };
  (pointArrayMap || ["y"]).forEach((key2, i) => {
    columns[key2] = valueColumns[i];
  });
  modified.setColumns(columns);
  return {
    groupMap,
    modified
  };
}
function onAfterSetOptions$1(e) {
  const options2 = e.options, type = this.type, plotOptions = this.chart.options.plotOptions, baseOptions = this.useCommonDataGrouping && DataGroupingDefaults.common, seriesSpecific2 = DataGroupingDefaults.seriesSpecific;
  let defaultOptions2 = DefaultOptions.defaultOptions.plotOptions[type].dataGrouping;
  if (plotOptions && (seriesSpecific2[type] || baseOptions)) {
    const rangeSelector2 = this.chart.rangeSelector;
    if (!defaultOptions2) {
      defaultOptions2 = merge$14(DataGroupingDefaults.common, seriesSpecific2[type]);
    }
    options2.dataGrouping = merge$14(
      baseOptions,
      defaultOptions2,
      plotOptions.series && plotOptions.series.dataGrouping,
      // #1228
      // Set by the StockChart constructor:
      plotOptions[type].dataGrouping,
      this.userOptions.dataGrouping,
      !options2.isInternal && rangeSelector2 && isNumber$F(rangeSelector2.selected) && rangeSelector2.buttonOptions[rangeSelector2.selected].dataGrouping
    );
  }
}
function skipDataGrouping(series, force) {
  return !(series.isCartesian && !series.isDirty && !series.xAxis.isDirty && !series.yAxis.isDirty && !force);
}
const DataGroupingSeriesComposition = {
  compose: compose$k,
  groupData
};
const { format: format$8 } = Templating;
const { composed: composed$m } = Highcharts;
const { addEvent: addEvent$_, extend: extend$S, isNumber: isNumber$E, pick: pick$19, pushUnique: pushUnique$m } = Utilities;
function compose$j(AxisClass, SeriesClass, TooltipClass) {
  DataGroupingAxisComposition.compose(AxisClass);
  DataGroupingSeriesComposition.compose(SeriesClass);
  if (TooltipClass && pushUnique$m(composed$m, "DataGrouping")) {
    addEvent$_(TooltipClass, "headerFormatter", onTooltipHeaderFormatter);
  }
}
function onTooltipHeaderFormatter(e) {
  const chart = this.chart, time = chart.time, point = e.point, series = point.series, options2 = series.options, tooltipOptions = series.tooltipOptions, dataGroupingOptions = options2.dataGrouping, xAxis2 = series.xAxis;
  let xDateFormat = tooltipOptions.xDateFormat || "", xDateFormatEnd, currentDataGrouping, dateTimeLabelFormats, labelFormats, formattedKey, formatString = tooltipOptions[e.isFooter ? "footerFormat" : "headerFormat"];
  if (xAxis2 && xAxis2.options.type === "datetime" && dataGroupingOptions && isNumber$E(point.key)) {
    currentDataGrouping = series.currentDataGrouping;
    dateTimeLabelFormats = dataGroupingOptions.dateTimeLabelFormats || // Fallback to commonOptions (#9693)
    DataGroupingDefaults.common.dateTimeLabelFormats;
    if (currentDataGrouping) {
      labelFormats = dateTimeLabelFormats[currentDataGrouping.unitName];
      if (currentDataGrouping.count === 1) {
        xDateFormat = labelFormats[0];
      } else {
        xDateFormat = labelFormats[1];
        xDateFormatEnd = labelFormats[2];
      }
    } else if (!xDateFormat && dateTimeLabelFormats && xAxis2.dateTime) {
      xDateFormat = xAxis2.dateTime.getXDateFormat(point.x, tooltipOptions.dateTimeLabelFormats);
    }
    const groupStart = pick$19(series.groupMap?.[point.index].groupStart, point.key), groupEnd = groupStart + (currentDataGrouping?.totalRange || 0) - 1;
    formattedKey = time.dateFormat(xDateFormat, groupStart);
    if (xDateFormatEnd) {
      formattedKey += time.dateFormat(xDateFormatEnd, groupEnd);
    }
    if (series.chart.styledMode) {
      formatString = this.styledModeFormat(formatString);
    }
    e.text = format$8(formatString, {
      point: extend$S(point, { key: formattedKey }),
      series
    }, chart);
    e.preventDefault();
  }
}
const DataGroupingComposition = {
  compose: compose$j,
  groupData: DataGroupingSeriesComposition.groupData
};
/**
 * @license Highstock JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/datagrouping
 * @requires highcharts
 *
 * Data grouping module
 *
 * (c) 2010-2025 Torstein Hønsi
 *
 * License: www.highcharts.com/license
 */
const G$i = Highcharts;
G$i.dataGrouping = G$i.dataGrouping || {};
G$i.dataGrouping.approximationDefaults = G$i.dataGrouping.approximationDefaults || ApproximationDefaults;
G$i.dataGrouping.approximations = G$i.dataGrouping.approximations || ApproximationRegistry;
DataGroupingComposition.compose(G$i.Axis, G$i.Series, G$i.Tooltip);
const { defined: defined$J, isNumber: isNumber$D, pick: pick$18 } = Utilities;
const annotationsFieldsTypes = {
  backgroundColor: "string",
  borderColor: "string",
  borderRadius: "string",
  color: "string",
  fill: "string",
  fontSize: "string",
  labels: "string",
  name: "string",
  stroke: "string",
  title: "string"
};
function getAssignedAxis$3(coords) {
  return coords.filter((coord) => {
    const extremes = coord.axis.getExtremes(), axisMin = extremes.min, axisMax2 = extremes.max, minPointOffset = pick$18(coord.axis.minPointOffset, 0);
    return isNumber$D(axisMin) && isNumber$D(axisMax2) && coord.value >= axisMin - minPointOffset && coord.value <= axisMax2 + minPointOffset && // Don't count navigator axis
    !coord.axis.options.isInternal;
  })[0];
}
function getFieldType$1(key2, value) {
  const predefinedType = annotationsFieldsTypes[key2];
  let fieldType = typeof value;
  if (defined$J(predefinedType)) {
    fieldType = predefinedType;
  }
  return {
    "string": "text",
    "number": "number",
    "boolean": "checkbox"
  }[fieldType];
}
const NavigationBindingUtilities = {
  getAssignedAxis: getAssignedAxis$3,
  getFieldType: getFieldType$1
};
const { addEvent: addEvent$Z, isObject: isObject$d, pick: pick$17, defined: defined$I, merge: merge$13 } = Utilities;
const { getAssignedAxis: getAssignedAxis$2 } = NavigationBindingUtilities;
const composedClasses = [], defaultOptions$9 = {
  enabled: true,
  sensitivity: 1.1
};
let wheelTimer;
const optionsToObject = (options2) => {
  if (!isObject$d(options2)) {
    options2 = {
      enabled: options2 ?? true
    };
  }
  return merge$13(defaultOptions$9, options2);
};
const zoomBy = function(chart, howMuch, xAxis2, yAxis2, mouseX, mouseY, options2) {
  const type = pick$17(options2.type, chart.zooming.type, "");
  let axes = [];
  if (type === "x") {
    axes = xAxis2;
  } else if (type === "y") {
    axes = yAxis2;
  } else if (type === "xy") {
    axes = chart.axes;
  }
  const hasZoomed = chart.transform({
    axes,
    // Create imaginary reference and target rectangles around the mouse
    // point that scales up or down with `howMuch`;
    to: {
      x: mouseX - 5,
      y: mouseY - 5,
      // Must use 10 to get passed the limit for too small reference.
      // Below this, the transform will default to a pan.
      width: 10,
      height: 10
    },
    from: {
      x: mouseX - 5 * howMuch,
      y: mouseY - 5 * howMuch,
      width: 10 * howMuch,
      height: 10 * howMuch
    },
    trigger: "mousewheel"
  });
  if (hasZoomed) {
    if (defined$I(wheelTimer)) {
      clearTimeout(wheelTimer);
    }
    wheelTimer = setTimeout(() => {
      chart.pointer?.drop();
    }, 400);
  }
  return hasZoomed;
};
function onAfterGetContainer() {
  const wheelZoomOptions = optionsToObject(this.zooming.mouseWheel);
  if (wheelZoomOptions.enabled) {
    addEvent$Z(this.container, "wheel", (e) => {
      e = this.pointer?.normalize(e) || e;
      const { pointer } = this, allowZoom = pointer && !pointer.inClass(e.target, "highcharts-no-mousewheel");
      if (this.isInsidePlot(e.chartX - this.plotLeft, e.chartY - this.plotTop) && allowZoom) {
        const wheelSensitivity = wheelZoomOptions.sensitivity || 1.1, delta = e.detail || (e.deltaY || 0) / 120, xAxisCoords = getAssignedAxis$2(pointer.getCoordinates(e).xAxis), yAxisCoords = getAssignedAxis$2(pointer.getCoordinates(e).yAxis);
        const hasZoomed = zoomBy(this, Math.pow(wheelSensitivity, delta), xAxisCoords ? [xAxisCoords.axis] : this.xAxis, yAxisCoords ? [yAxisCoords.axis] : this.yAxis, e.chartX, e.chartY, wheelZoomOptions);
        if (hasZoomed) {
          e.preventDefault?.();
        }
      }
    });
  }
}
function compose$i(ChartClass) {
  if (composedClasses.indexOf(ChartClass) === -1) {
    composedClasses.push(ChartClass);
    addEvent$Z(ChartClass, "afterGetContainer", onAfterGetContainer);
  }
}
const MouseWheelZoomComposition = {
  compose: compose$i
};
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/mouse-wheel-zoom
 * @requires highcharts
 *
 * Mousewheel zoom module
 *
 * (c) 2023 Askel Eirik Johansson
 *
 * License: www.highcharts.com/license
 */
const G$h = Highcharts;
G$h.MouseWheelZoom = G$h.MouseWheelZoom || MouseWheelZoomComposition;
G$h.MouseWheelZoom.compose(G$h.Chart);
/**
 * @license Highstock JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/stock
 * @requires highcharts
 *
 * Highcharts Stock as a plugin for Highcharts
 *
 * (c) 2010-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$g = Highcharts;
G$g.Navigator = G$g.Navigator || Navigator;
G$g.OrdinalAxis = G$g.OrdinalAxis || OrdinalAxis$1;
G$g.RangeSelector = G$g.RangeSelector || RangeSelector;
G$g.Scrollbar = G$g.Scrollbar || Scrollbar;
G$g.stockChart = G$g.stockChart || StockChart$1.stockChart;
G$g.StockChart = G$g.StockChart || G$g.stockChart;
G$g.extend(G$g.StockChart, StockChart$1);
DataModifyComposition$1.compose(G$g.Series, G$g.Axis, G$g.Point);
FlagsSeries.compose(G$g.Renderer);
OHLCSeries$1.compose(G$g.Series);
G$g.Navigator.compose(G$g.Chart, G$g.Axis, G$g.Series);
G$g.OrdinalAxis.compose(G$g.Axis, G$g.Series, G$g.Chart);
G$g.RangeSelector.compose(G$g.Axis, G$g.Chart);
G$g.Scrollbar.compose(G$g.Axis);
G$g.StockChart.compose(G$g.Chart, G$g.Axis, G$g.Series, G$g.SVGRenderer);
/**
 * @license Highstock JS v12.2.0 (2025-04-07)
 * @module highcharts/highstock
 *
 * (c) 2009-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
G$k.product = "Highstock";
const { doc: doc$m, win: win$7 } = Highcharts;
const { css: css$4 } = Utilities;
const simulatedEventTarget$2 = win$7.EventTarget && new win$7.EventTarget() || "none";
function addClass$3(el, className) {
  if (el.classList) {
    el.classList.add(className);
  } else if (el.className.indexOf(className) < 0) {
    el.className += " " + className;
  }
}
function removeClass$1(el, className) {
  if (el.classList) {
    el.classList.remove(className);
  } else {
    el.className = el.className.replace(new RegExp(className, "g"), "");
  }
}
function cloneMouseEvent$1(e) {
  if (typeof win$7.MouseEvent === "function") {
    return new win$7.MouseEvent(e.type, e);
  }
  if (doc$m?.createEvent) {
    const evt = doc$m.createEvent("MouseEvent");
    if (evt.initMouseEvent) {
      evt.initMouseEvent(
        e.type,
        e.bubbles,
        // #10561, #12161
        e.cancelable,
        e.view || win$7,
        e.detail,
        e.screenX,
        e.screenY,
        e.clientX,
        e.clientY,
        e.ctrlKey,
        e.altKey,
        e.shiftKey,
        e.metaKey,
        e.button,
        e.relatedTarget
      );
      return evt;
    }
  }
  return getFakeMouseEvent$5(e.type);
}
function cloneTouchEvent$1(e) {
  const touchListToTouchArray = (l) => {
    const touchArray = [];
    for (let i = 0; i < l.length; ++i) {
      const item = l.item(i);
      if (item) {
        touchArray.push(item);
      }
    }
    return touchArray;
  };
  if (typeof win$7.TouchEvent === "function") {
    const newEvent = new win$7.TouchEvent(e.type, {
      touches: touchListToTouchArray(e.touches),
      targetTouches: touchListToTouchArray(e.targetTouches),
      changedTouches: touchListToTouchArray(e.changedTouches),
      ctrlKey: e.ctrlKey,
      shiftKey: e.shiftKey,
      altKey: e.altKey,
      metaKey: e.metaKey,
      bubbles: e.bubbles,
      cancelable: e.cancelable,
      composed: e.composed,
      detail: e.detail,
      view: e.view
    });
    if (e.defaultPrevented) {
      newEvent.preventDefault();
    }
    return newEvent;
  }
  const fakeEvt = cloneMouseEvent$1(e);
  fakeEvt.touches = e.touches;
  fakeEvt.changedTouches = e.changedTouches;
  fakeEvt.targetTouches = e.targetTouches;
  return fakeEvt;
}
function escapeStringForHTML$1(str) {
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;").replace(/\//g, "&#x2F;");
}
function getElement$2(id) {
  return doc$m.getElementById(id);
}
function getFakeMouseEvent$5(type, position, relatedTarget) {
  const pos = position || {
    x: 0,
    y: 0
  };
  if (typeof win$7.MouseEvent === "function") {
    return new win$7.MouseEvent(type, {
      bubbles: true,
      cancelable: true,
      composed: true,
      button: 0,
      buttons: 1,
      relatedTarget: relatedTarget || simulatedEventTarget$2,
      view: win$7,
      detail: type === "click" ? 1 : 0,
      screenX: pos.x,
      screenY: pos.y,
      clientX: pos.x,
      clientY: pos.y
    });
  }
  if (doc$m?.createEvent) {
    const evt = doc$m.createEvent("MouseEvent");
    if (evt.initMouseEvent) {
      evt.initMouseEvent(
        type,
        true,
        // Bubble
        true,
        // Cancel
        win$7,
        // View
        type === "click" ? 1 : 0,
        // Detail
        // Coords
        pos.x,
        pos.y,
        pos.x,
        pos.y,
        // Pressed keys
        false,
        false,
        false,
        false,
        0,
        // Button
        null
        // Related target
      );
      return evt;
    }
  }
  return { type };
}
function getHeadingTagNameForElement$1(element) {
  const getIncreasedHeadingLevel = (tagName) => {
    const headingLevel = parseInt(tagName.slice(1), 10), newLevel = Math.min(6, headingLevel + 1);
    return "h" + newLevel;
  };
  const isHeading = (tagName) => /^H[1-6]$/i.test(tagName);
  const getPreviousSiblingsHeading = (el) => {
    let sibling = el;
    while (sibling = sibling.previousSibling) {
      const tagName = sibling.tagName || "";
      if (isHeading(tagName)) {
        return tagName;
      }
    }
    return "";
  };
  const getHeadingRecursive = (el) => {
    const prevSiblingsHeading = getPreviousSiblingsHeading(el);
    if (prevSiblingsHeading) {
      return getIncreasedHeadingLevel(prevSiblingsHeading);
    }
    const parent = el.parentElement;
    if (!parent) {
      return "h6";
    }
    const parentTagName = parent.tagName;
    if (isHeading(parentTagName)) {
      return getIncreasedHeadingLevel(parentTagName);
    }
    return getHeadingRecursive(parent);
  };
  return getHeadingRecursive(element);
}
function removeElement$3(element) {
  if (element && element.parentNode) {
    element.parentNode.removeChild(element);
  }
}
function removeChildNodes$1(element) {
  while (element.lastChild) {
    element.removeChild(element.lastChild);
  }
}
function reverseChildNodes$1(node) {
  let i = node.childNodes.length;
  while (i--) {
    node.appendChild(node.childNodes[i]);
  }
}
function stripHTMLTagsFromString$2(str, isForExport = false) {
  return typeof str === "string" ? isForExport ? str.replace(/<\/?[^>]+(>|$)/g, "") : str.replace(/<\/?(?!\s)[^>]+(>|$)/g, "") : str;
}
function visuallyHideElement$2(element) {
  css$4(element, {
    position: "absolute",
    width: "1px",
    height: "1px",
    overflow: "hidden",
    whiteSpace: "nowrap",
    clip: "rect(1px, 1px, 1px, 1px)",
    marginTop: "-3px",
    "-ms-filter": "progid:DXImageTransform.Microsoft.Alpha(Opacity=1)",
    filter: "alpha(opacity=1)",
    opacity: 0.01
  });
}
const HTMLUtilities = {
  addClass: addClass$3,
  cloneMouseEvent: cloneMouseEvent$1,
  cloneTouchEvent: cloneTouchEvent$1,
  escapeStringForHTML: escapeStringForHTML$1,
  getElement: getElement$2,
  getFakeMouseEvent: getFakeMouseEvent$5,
  getHeadingTagNameForElement: getHeadingTagNameForElement$1,
  removeChildNodes: removeChildNodes$1,
  removeClass: removeClass$1,
  removeElement: removeElement$3,
  reverseChildNodes: reverseChildNodes$1,
  simulatedEventTarget: simulatedEventTarget$2,
  stripHTMLTagsFromString: stripHTMLTagsFromString$2,
  visuallyHideElement: visuallyHideElement$2
};
const { format: format$7 } = Templating;
const { getNestedProperty, pick: pick$16 } = Utilities;
var A11yI18nComposition;
(function(A11yI18nComposition2) {
  function compose2(ChartClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.langFormat) {
      chartProto.langFormat = langFormat;
    }
  }
  A11yI18nComposition2.compose = compose2;
  function formatExtendedStatement(statement, ctx) {
    const eachStart = statement.indexOf("#each("), pluralStart = statement.indexOf("#plural("), indexStart = statement.indexOf("["), indexEnd = statement.indexOf("]");
    let arr, result;
    if (eachStart > -1) {
      const eachEnd = statement.slice(eachStart).indexOf(")") + eachStart, preEach = statement.substring(0, eachStart), postEach = statement.substring(eachEnd + 1), eachStatement = statement.substring(eachStart + 6, eachEnd), eachArguments = eachStatement.split(",");
      let lenArg = Number(eachArguments[1]), len;
      result = "";
      arr = getNestedProperty(eachArguments[0], ctx);
      if (arr) {
        lenArg = isNaN(lenArg) ? arr.length : lenArg;
        len = lenArg < 0 ? arr.length + lenArg : Math.min(lenArg, arr.length);
        for (let i = 0; i < len; ++i) {
          result += preEach + arr[i] + postEach;
        }
      }
      return result.length ? result : "";
    }
    if (pluralStart > -1) {
      const pluralEnd = statement.slice(pluralStart).indexOf(")") + pluralStart, pluralStatement = statement.substring(pluralStart + 8, pluralEnd), pluralArguments = pluralStatement.split(","), num = Number(getNestedProperty(pluralArguments[0], ctx));
      switch (num) {
        case 0:
          result = pick$16(pluralArguments[4], pluralArguments[1]);
          break;
        case 1:
          result = pick$16(pluralArguments[2], pluralArguments[1]);
          break;
        case 2:
          result = pick$16(pluralArguments[3], pluralArguments[1]);
          break;
        default:
          result = pluralArguments[1];
      }
      return result ? stringTrim(result) : "";
    }
    if (indexStart > -1) {
      const arrayName = statement.substring(0, indexStart), ix = Number(statement.substring(indexStart + 1, indexEnd));
      let val;
      arr = getNestedProperty(arrayName, ctx);
      if (!isNaN(ix) && arr) {
        if (ix < 0) {
          val = arr[arr.length + ix];
          if (typeof val === "undefined") {
            val = arr[0];
          }
        } else {
          val = arr[ix];
          if (typeof val === "undefined") {
            val = arr[arr.length - 1];
          }
        }
      }
      return typeof val !== "undefined" ? val : "";
    }
    return "{" + statement + "}";
  }
  function i18nFormat(formatString, context, chart) {
    const getFirstBracketStatement = (sourceStr, offset2) => {
      const str = sourceStr.slice(offset2 || 0), startBracket = str.indexOf("{"), endBracket = str.indexOf("}");
      if (startBracket > -1 && endBracket > startBracket) {
        return {
          statement: str.substring(startBracket + 1, endBracket),
          begin: offset2 + startBracket + 1,
          end: offset2 + endBracket
        };
      }
    }, tokens = [];
    let bracketRes, constRes, cursor = 0;
    do {
      bracketRes = getFirstBracketStatement(formatString, cursor);
      constRes = formatString.substring(cursor, bracketRes && bracketRes.begin - 1);
      if (constRes.length) {
        tokens.push({
          value: constRes,
          type: "constant"
        });
      }
      if (bracketRes) {
        tokens.push({
          value: bracketRes.statement,
          type: "statement"
        });
      }
      cursor = bracketRes ? bracketRes.end + 1 : cursor + 1;
    } while (bracketRes);
    tokens.forEach((token) => {
      if (token.type === "statement") {
        token.value = formatExtendedStatement(token.value, context);
      }
    });
    return format$7(tokens.reduce((acc, cur) => acc + cur.value, ""), context, chart);
  }
  A11yI18nComposition2.i18nFormat = i18nFormat;
  function langFormat(langKey, context) {
    const keys = langKey.split(".");
    let formatString = this.options.lang, i = 0;
    for (; i < keys.length; ++i) {
      formatString = formatString && formatString[keys[i]];
    }
    return typeof formatString === "string" ? i18nFormat(formatString, context, this) : "";
  }
  function stringTrim(str) {
    return str.trim && str.trim() || str.replace(/^\s+|\s+$/g, "");
  }
})(A11yI18nComposition || (A11yI18nComposition = {}));
const A11yI18n = A11yI18nComposition;
const { doc: doc$l } = Highcharts;
const { stripHTMLTagsFromString: stripHTMLTags$3 } = HTMLUtilities;
const { defined: defined$H, find: find$a, fireEvent: fireEvent$o } = Utilities;
function fireEventOnWrappedOrUnwrappedElement$3(el, eventObject) {
  const type = eventObject.type;
  const hcEvents = el.hcEvents;
  if (!!doc$l?.createEvent && (el.dispatchEvent || el.fireEvent)) {
    if (el.dispatchEvent) {
      el.dispatchEvent(eventObject);
    } else {
      el.fireEvent(type, eventObject);
    }
  } else if (hcEvents && hcEvents[type]) {
    fireEvent$o(el, type, eventObject);
  } else if (el.element) {
    fireEventOnWrappedOrUnwrappedElement$3(el.element, eventObject);
  }
}
function getChartTitle$5(chart) {
  return stripHTMLTags$3(chart.options.title.text || chart.langFormat("accessibility.defaultChartTitle", { chart }), chart.renderer.forExport);
}
function getAxisDescription$2(axis) {
  return axis && (axis.options.accessibility?.description || axis.axisTitle?.textStr || axis.options.id || axis.categories && "categories" || axis.dateTime && "Time" || "values");
}
function getAxisRangeDescription$3(axis) {
  const axisOptions = axis.options || {};
  if (axisOptions.accessibility && typeof axisOptions.accessibility.rangeDescription !== "undefined") {
    return axisOptions.accessibility.rangeDescription;
  }
  if (axis.categories) {
    return getCategoryAxisRangeDesc(axis);
  }
  if (axis.dateTime && (axis.min === 0 || axis.dataMin === 0)) {
    return getAxisTimeLengthDesc(axis);
  }
  return getAxisFromToDescription(axis);
}
function getCategoryAxisRangeDesc(axis) {
  const chart = axis.chart;
  if (axis.dataMax && axis.dataMin) {
    return chart.langFormat("accessibility.axis.rangeCategories", {
      chart,
      axis,
      numCategories: axis.dataMax - axis.dataMin + 1
    });
  }
  return "";
}
function getAxisTimeLengthDesc(axis) {
  const chart = axis.chart, range2 = {}, min2 = axis.dataMin || axis.min || 0, max2 = axis.dataMax || axis.max || 0;
  let rangeUnit = "Seconds";
  range2.Seconds = (max2 - min2) / 1e3;
  range2.Minutes = range2.Seconds / 60;
  range2.Hours = range2.Minutes / 60;
  range2.Days = range2.Hours / 24;
  ["Minutes", "Hours", "Days"].forEach(function(unit) {
    if (range2[unit] > 2) {
      rangeUnit = unit;
    }
  });
  const rangeValue = range2[rangeUnit].toFixed(
    rangeUnit !== "Seconds" && rangeUnit !== "Minutes" ? 1 : 0
    // Use decimals for days/hours
  );
  return chart.langFormat("accessibility.axis.timeRange" + rangeUnit, {
    chart,
    axis,
    range: rangeValue.replace(".0", "")
  });
}
function getAxisFromToDescription(axis) {
  const chart = axis.chart, options2 = chart.options, dateRangeFormat = options2 && options2.accessibility && options2.accessibility.screenReaderSection.axisRangeDateFormat || "", extremes = {
    min: axis.dataMin || axis.min || 0,
    max: axis.dataMax || axis.max || 0
  }, format2 = function(key2) {
    return axis.dateTime ? chart.time.dateFormat(dateRangeFormat, extremes[key2]) : extremes[key2].toString();
  };
  return chart.langFormat("accessibility.axis.rangeFromTo", {
    chart,
    axis,
    rangeFrom: format2("min"),
    rangeTo: format2("max")
  });
}
function getSeriesFirstPointElement$1(series) {
  if (series.points && series.points.length) {
    const firstPointWithGraphic = find$a(series.points, (p) => !!p.graphic);
    return firstPointWithGraphic && firstPointWithGraphic.graphic && firstPointWithGraphic.graphic.element;
  }
}
function getSeriesA11yElement$1(series) {
  const firstPointEl = getSeriesFirstPointElement$1(series);
  return firstPointEl && firstPointEl.parentNode || series.graph && series.graph.element || series.group && series.group.element;
}
function unhideChartElementFromAT$7(chart, element) {
  element.setAttribute("aria-hidden", false);
  if (element === chart.renderTo || !element.parentNode || element.parentNode === doc$l.body) {
    return;
  }
  Array.prototype.forEach.call(element.parentNode.childNodes, function(node) {
    if (!node.hasAttribute("aria-hidden")) {
      node.setAttribute("aria-hidden", true);
    }
  });
  unhideChartElementFromAT$7(chart, element.parentNode);
}
function hideSeriesFromAT$1(series) {
  const seriesEl = getSeriesA11yElement$1(series);
  if (seriesEl) {
    seriesEl.setAttribute("aria-hidden", true);
  }
}
function getSeriesFromName$1(chart, name) {
  if (!name) {
    return chart.series;
  }
  return (chart.series || []).filter(function(s) {
    return s.name === name;
  });
}
function getPointFromXY$1(series, x, y) {
  let i = series.length, res;
  while (i--) {
    res = find$a(series[i].points || [], function(p) {
      return p.x === x && p.y === y;
    });
    if (res) {
      return res;
    }
  }
}
function getRelativePointAxisPosition(axis, point) {
  if (!defined$H(axis.dataMin) || !defined$H(axis.dataMax)) {
    return 0;
  }
  const axisStart = axis.toPixels(axis.dataMin), axisEnd = axis.toPixels(axis.dataMax), positionProp = axis.coll === "xAxis" ? "x" : "y", pointPos = axis.toPixels(point[positionProp] || 0);
  return (pointPos - axisStart) / (axisEnd - axisStart);
}
function scrollAxisToPoint$1(point) {
  const xAxis2 = point.series.xAxis, yAxis2 = point.series.yAxis, axis = xAxis2 && xAxis2.scrollbar ? xAxis2 : yAxis2, scrollbar = axis && axis.scrollbar;
  if (scrollbar && defined$H(scrollbar.to) && defined$H(scrollbar.from)) {
    const range2 = scrollbar.to - scrollbar.from;
    const pos = getRelativePointAxisPosition(axis, point);
    scrollbar.updatePosition(pos - range2 / 2, pos + range2 / 2);
    fireEvent$o(scrollbar, "changed", {
      from: scrollbar.from,
      to: scrollbar.to,
      trigger: "scrollbar",
      DOMEvent: null
    });
  }
}
const ChartUtilities = {
  fireEventOnWrappedOrUnwrappedElement: fireEventOnWrappedOrUnwrappedElement$3,
  getChartTitle: getChartTitle$5,
  getAxisDescription: getAxisDescription$2,
  getAxisRangeDescription: getAxisRangeDescription$3,
  getPointFromXY: getPointFromXY$1,
  getSeriesFirstPointElement: getSeriesFirstPointElement$1,
  getSeriesFromName: getSeriesFromName$1,
  getSeriesA11yElement: getSeriesA11yElement$1,
  unhideChartElementFromAT: unhideChartElementFromAT$7,
  hideSeriesFromAT: hideSeriesFromAT$1,
  scrollAxisToPoint: scrollAxisToPoint$1
};
const { doc: doc$k } = Highcharts;
const { removeElement: removeElement$2 } = HTMLUtilities;
class DOMElementProvider {
  /* *
   *
   *  Constructor
   *
   * */
  constructor() {
    this.elements = [];
  }
  /**
   * Create an element and keep track of it for later removal.
   * Same args as document.createElement
   * @private
   */
  createElement() {
    const el = doc$k.createElement.apply(doc$k, arguments);
    this.elements.push(el);
    return el;
  }
  /**
   * Destroy created element, removing it from the DOM.
   * @private
   */
  removeElement(element) {
    removeElement$2(element);
    this.elements.splice(this.elements.indexOf(element), 1);
  }
  /**
   * Destroy all created elements, removing them from the DOM.
   * @private
   */
  destroyCreatedElements() {
    this.elements.forEach(function(element) {
      removeElement$2(element);
    });
    this.elements = [];
  }
}
const { addEvent: addEvent$Y } = Utilities;
class EventProvider {
  /* *
   *
   *  Constructor
   *
   * */
  constructor() {
    this.eventRemovers = [];
  }
  /**
   * Add an event to an element and keep track of it for later removal.
   * Same args as Highcharts.addEvent.
   * @private
   */
  addEvent() {
    const remover = addEvent$Y.apply(Highcharts, arguments);
    this.eventRemovers.push({
      element: arguments[0],
      // HTML element
      remover
    });
    return remover;
  }
  /**
   * Remove added event.
   * @private
   */
  removeEvent(event) {
    const pos = this.eventRemovers.map((e) => e.remover).indexOf(event);
    this.eventRemovers[pos].remover();
    this.eventRemovers.splice(pos, 1);
  }
  /**
   * Remove all added events.
   * @private
   */
  removeAddedEvents() {
    this.eventRemovers.map((e) => e.remover).forEach((remover) => remover());
    this.eventRemovers = [];
  }
}
const { fireEventOnWrappedOrUnwrappedElement: fireEventOnWrappedOrUnwrappedElement$2 } = ChartUtilities;
const { getFakeMouseEvent: getFakeMouseEvent$4 } = HTMLUtilities;
class AccessibilityComponent {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Called when accessibility is disabled or chart is destroyed.
   *
   * @function Highcharts.AccessibilityComponent#destroy
   */
  destroy() {
  }
  /**
   * Get keyboard navigation handler for this component.
   *
   * @function Highcharts.AccessibilityComponent#getKeyboardNavigation
   * @return   {Highcharts.KeyboardNavigationHandler|Array<Highcharts.KeyboardNavigationHandler>}
   *           The keyboard navigation handler(s) for this component.
   */
  getKeyboardNavigation() {
    return [];
  }
  /**
   * Called on component initialization.
   *
   * @function Highcharts.AccessibilityComponent#init
   */
  init() {
  }
  /**
   * Called on every chart render.
   *
   * @function Highcharts.AccessibilityComponent#onChartRender
   */
  onChartRender() {
  }
  /**
   * Called on updates to the chart, including options changes.
   * Note that this is also called on first render of chart.
   *
   * @function Highcharts.AccessibilityComponent#onChartUpdate
   */
  onChartUpdate() {
  }
  /**
   * Initialize the class
   * @private
   * @param {Highcharts.Chart} chart The chart object
   * @param {Highcharts.ProxyProvider} proxyProvider The proxy provider of the accessibility module
   */
  initBase(chart, proxyProvider) {
    this.chart = chart;
    this.eventProvider = new EventProvider();
    this.domElementProvider = new DOMElementProvider();
    this.proxyProvider = proxyProvider;
    this.keyCodes = {
      left: 37,
      right: 39,
      up: 38,
      down: 40,
      enter: 13,
      space: 32,
      esc: 27,
      tab: 9,
      pageUp: 33,
      pageDown: 34,
      end: 35,
      home: 36
    };
  }
  /**
   * Add an event to an element and keep track of it for later removal.
   * See EventProvider for details.
   * @private
   */
  addEvent(el, type, fn, options2) {
    return this.eventProvider.addEvent(el, type, fn, options2);
  }
  /**
   * Create an element and keep track of it for later removal.
   * See DOMElementProvider for details.
   * @private
   */
  createElement(tagName, options2) {
    return this.domElementProvider.createElement(tagName, options2);
  }
  /**
   * Fire a fake click event on an element. It is useful to have this on
   * AccessibilityComponent for users of custom components.
   * @private
   */
  fakeClickEvent(el) {
    const fakeEvent = getFakeMouseEvent$4("click");
    fireEventOnWrappedOrUnwrappedElement$2(el, fakeEvent);
  }
  /**
   * Remove traces of the component.
   * @private
   */
  destroyBase() {
    this.domElementProvider.destroyCreatedElements();
    this.eventProvider.removeAddedEvents();
  }
}
const { find: find$9 } = Utilities;
class KeyboardNavigationHandler {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, options2) {
    this.chart = chart;
    this.keyCodeMap = options2.keyCodeMap || [];
    this.validate = options2.validate;
    this.init = options2.init;
    this.terminate = options2.terminate;
    this.response = {
      success: 1,
      // Keycode was handled
      prev: 2,
      // Move to prev module
      next: 3,
      // Move to next module
      noHandler: 4,
      // There is no handler for this keycode
      fail: 5
      // Handler failed
    };
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Find handler function(s) for key code in the keyCodeMap and run it.
   *
   * @function KeyboardNavigationHandler#run
   * @param {global.KeyboardEvent} e
   * @return {number} Returns a response code indicating whether the run was
   *      a success/fail/unhandled, or if we should move to next/prev module.
   */
  run(e) {
    const keyCode = e.which || e.keyCode;
    let response = this.response.noHandler;
    const handlerCodeSet = find$9(this.keyCodeMap, function(codeSet) {
      return codeSet[0].indexOf(keyCode) > -1;
    });
    if (handlerCodeSet) {
      response = handlerCodeSet[1].call(this, keyCode, e);
    } else if (keyCode === 9) {
      response = this.response[e.shiftKey ? "prev" : "next"];
    }
    return response;
  }
}
const { unhideChartElementFromAT: unhideChartElementFromAT$6, getChartTitle: getChartTitle$4 } = ChartUtilities;
const { doc: doc$j } = Highcharts;
const { stripHTMLTagsFromString: stripHTMLTags$2 } = HTMLUtilities;
class ContainerComponent extends AccessibilityComponent {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Called on first render/updates to the chart, including options changes.
   */
  onChartUpdate() {
    this.handleSVGTitleElement();
    this.setSVGContainerLabel();
    this.setGraphicContainerAttrs();
    this.setRenderToAttrs();
    this.makeCreditsAccessible();
  }
  /**
   * @private
   */
  handleSVGTitleElement() {
    const chart = this.chart, titleId = "highcharts-title-" + chart.index, titleContents = stripHTMLTags$2(chart.langFormat("accessibility.svgContainerTitle", {
      chartTitle: getChartTitle$4(chart)
    }));
    if (titleContents.length) {
      const titleElement = this.svgTitleElement = this.svgTitleElement || doc$j.createElementNS("http://www.w3.org/2000/svg", "title");
      titleElement.textContent = titleContents;
      titleElement.id = titleId;
      chart.renderTo.insertBefore(titleElement, chart.renderTo.firstChild);
    }
  }
  /**
   * @private
   */
  setSVGContainerLabel() {
    const chart = this.chart, svgContainerLabel = chart.langFormat("accessibility.svgContainerLabel", {
      chartTitle: getChartTitle$4(chart)
    });
    if (chart.renderer.box && svgContainerLabel.length) {
      chart.renderer.box.setAttribute("aria-label", svgContainerLabel);
    }
  }
  /**
   * @private
   */
  setGraphicContainerAttrs() {
    const chart = this.chart, label = chart.langFormat("accessibility.graphicContainerLabel", {
      chartTitle: getChartTitle$4(chart)
    });
    if (label.length) {
      chart.container.setAttribute("aria-label", label);
    }
  }
  /**
   * Set attributes on the chart container element.
   * @private
   */
  setRenderToAttrs() {
    const chart = this.chart, shouldHaveLandmark = chart.options.accessibility.landmarkVerbosity !== "disabled", containerLabel = chart.langFormat("accessibility.chartContainerLabel", {
      title: getChartTitle$4(chart),
      chart
    });
    if (containerLabel) {
      chart.renderTo.setAttribute("role", shouldHaveLandmark ? "region" : "group");
      chart.renderTo.setAttribute("aria-label", containerLabel);
    }
  }
  /**
   * @private
   */
  makeCreditsAccessible() {
    const chart = this.chart, credits = chart.credits;
    if (credits) {
      if (credits.textStr) {
        credits.element.setAttribute("aria-label", chart.langFormat("accessibility.credits", {
          creditsStr: stripHTMLTags$2(credits.textStr, chart.renderer.forExport)
        }));
      }
      unhideChartElementFromAT$6(chart, credits.element);
    }
  }
  /**
   * Empty handler to just set focus on chart
   * @private
   */
  getKeyboardNavigation() {
    const chart = this.chart;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [],
      validate: function() {
        return true;
      },
      init: function() {
        const a11y = chart.accessibility;
        if (a11y) {
          a11y.keyboardNavigation.tabindexContainer.focus();
        }
      }
    });
  }
  /**
   * Accessibility disabled/chart destroyed.
   */
  destroy() {
    this.chart.renderTo.setAttribute("aria-hidden", true);
  }
}
const { addEvent: addEvent$X, pick: pick$15 } = Utilities;
var FocusBorderComposition;
(function(FocusBorderComposition2) {
  const svgElementBorderUpdateTriggers = [
    "x",
    "y",
    "transform",
    "width",
    "height",
    "r",
    "d",
    "stroke-width"
  ];
  function compose2(ChartClass, SVGElementClass) {
    const chartProto = ChartClass.prototype, svgElementProto = SVGElementClass.prototype;
    if (!chartProto.renderFocusBorder) {
      chartProto.renderFocusBorder = chartRenderFocusBorder;
      chartProto.setFocusToElement = chartSetFocusToElement;
    }
    if (!svgElementProto.addFocusBorder) {
      svgElementProto.addFocusBorder = svgElementAddFocusBorder;
      svgElementProto.removeFocusBorder = svgElementRemoveFocusBorder;
    }
  }
  FocusBorderComposition2.compose = compose2;
  function chartRenderFocusBorder() {
    const focusElement = this.focusElement, focusBorderOptions = this.options.accessibility.keyboardNavigation.focusBorder;
    if (focusElement) {
      focusElement.removeFocusBorder();
      if (focusBorderOptions.enabled) {
        focusElement.addFocusBorder(focusBorderOptions.margin, {
          stroke: focusBorderOptions.style.color,
          strokeWidth: focusBorderOptions.style.lineWidth,
          r: focusBorderOptions.style.borderRadius
        });
      }
    }
  }
  function chartSetFocusToElement(svgElement, focusElement) {
    const focusBorderOptions = this.options.accessibility.keyboardNavigation.focusBorder, browserFocusElement = focusElement || svgElement.element;
    if (browserFocusElement && browserFocusElement.focus) {
      if (!(browserFocusElement.hcEvents && browserFocusElement.hcEvents.focusin)) {
        addEvent$X(browserFocusElement, "focusin", function() {
        });
      }
      browserFocusElement.focus();
      if (focusBorderOptions.hideBrowserFocusOutline) {
        browserFocusElement.style.outline = "none";
      }
    }
    if (this.focusElement) {
      this.focusElement.removeFocusBorder();
    }
    this.focusElement = svgElement;
    this.renderFocusBorder();
  }
  function svgElementAddDestroyFocusBorderHook(el) {
    if (el.focusBorderDestroyHook) {
      return;
    }
    const origDestroy = el.destroy;
    el.destroy = function() {
      if (el.focusBorder && el.focusBorder.destroy) {
        el.focusBorder.destroy();
      }
      return origDestroy.apply(el, arguments);
    };
    el.focusBorderDestroyHook = origDestroy;
  }
  function svgElementAddFocusBorder(margin, attribs) {
    if (this.focusBorder) {
      this.removeFocusBorder();
    }
    const bb = this.getBBox(), pad2 = pick$15(margin, 3), parent = this.parentGroup, scaleX = this.scaleX || parent && parent.scaleX, scaleY = this.scaleY || parent && parent.scaleY, oneDefined = scaleX ? !scaleY : scaleY, scaleBoth = oneDefined ? Math.abs(scaleX || scaleY || 1) : (Math.abs(scaleX || 1) + Math.abs(scaleY || 1)) / 2, lineHeight = this.renderer.fontMetrics(this).h;
    bb.x += this.translateX ? this.translateX : 0;
    bb.y += this.translateY ? this.translateY : 0;
    let borderPosX = bb.x - pad2, borderPosY = bb.y - pad2, borderWidth = bb.width + 2 * pad2, borderHeight = bb.height + 2 * pad2;
    function getTextAnchorCorrection(text) {
      let posXCorrection = 0, posYCorrection = 0;
      if (text.attr("text-anchor") === "middle") {
        posXCorrection = posYCorrection = 0.5;
      } else if (!text.rotation) {
        posYCorrection = 0.75;
      } else {
        posXCorrection = 0.25;
      }
      return {
        x: posXCorrection,
        y: posYCorrection
      };
    }
    const isLabel = !!this.text;
    if (this.element.nodeName === "text" || isLabel) {
      const isRotated = !!this.rotation;
      const correction = !isLabel ? getTextAnchorCorrection(this) : {
        x: isRotated ? 1 : 0,
        y: 0
      };
      const attrX = +this.attr("x");
      const attrY = +this.attr("y");
      if (!isNaN(attrX)) {
        borderPosX = attrX - bb.width * correction.x - pad2;
      }
      if (!isNaN(attrY)) {
        const dim = this.attr("text-anchor") === "start" ? lineHeight : bb.height;
        borderPosY = attrY - dim * correction.y - pad2;
      }
      if (isLabel && isRotated) {
        const temp = borderWidth;
        borderWidth = borderHeight;
        borderHeight = temp;
        if (!isNaN(attrX)) {
          borderPosX = attrX - bb.height * correction.x - pad2;
        }
        if (!isNaN(attrY)) {
          borderPosY = attrY - bb.width * correction.y - pad2;
        }
      }
    }
    this.focusBorder = this.renderer.rect(borderPosX, borderPosY, borderWidth, borderHeight, parseInt((attribs && attribs.r || 0).toString(), 10) / scaleBoth).addClass("highcharts-focus-border").attr({
      zIndex: 99
    }).add(parent);
    if (!this.renderer.styledMode) {
      this.focusBorder.attr({
        stroke: attribs && attribs.stroke,
        "stroke-width": (attribs && attribs.strokeWidth || 0) / scaleBoth
      });
    }
    avgElementAddUpdateFocusBorderHooks(this, margin, attribs);
    svgElementAddDestroyFocusBorderHook(this);
  }
  function avgElementAddUpdateFocusBorderHooks(el, ...updateParams) {
    if (el.focusBorderUpdateHooks) {
      return;
    }
    el.focusBorderUpdateHooks = {};
    svgElementBorderUpdateTriggers.forEach((trigger) => {
      const setterKey = trigger + "Setter";
      const origSetter = el[setterKey] || el._defaultSetter;
      el.focusBorderUpdateHooks[setterKey] = origSetter;
      el[setterKey] = function() {
        const ret = origSetter.apply(el, arguments);
        el.addFocusBorder.apply(el, updateParams);
        return ret;
      };
    });
  }
  function svgElementRemoveDestroyFocusBorderHook(el) {
    if (!el.focusBorderDestroyHook) {
      return;
    }
    el.destroy = el.focusBorderDestroyHook;
    delete el.focusBorderDestroyHook;
  }
  function svgElementRemoveFocusBorder() {
    svgElementRemoveUpdateFocusBorderHooks(this);
    svgElementRemoveDestroyFocusBorderHook(this);
    if (this.focusBorder) {
      this.focusBorder.destroy();
      delete this.focusBorder;
    }
  }
  function svgElementRemoveUpdateFocusBorderHooks(el) {
    if (!el.focusBorderUpdateHooks) {
      return;
    }
    Object.keys(el.focusBorderUpdateHooks).forEach((setterKey) => {
      const origSetter = el.focusBorderUpdateHooks[setterKey];
      if (origSetter === el._defaultSetter) {
        delete el[setterKey];
      } else {
        el[setterKey] = origSetter;
      }
    });
    delete el.focusBorderUpdateHooks;
  }
})(FocusBorderComposition || (FocusBorderComposition = {}));
const FocusBorderComposition$1 = FocusBorderComposition;
const { doc: doc$i } = Highcharts;
const { addClass: addClass$2, visuallyHideElement: visuallyHideElement$1 } = HTMLUtilities;
const { attr: attr$7 } = Utilities;
class Announcer {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, type) {
    this.chart = chart;
    this.domElementProvider = new DOMElementProvider();
    this.announceRegion = this.addAnnounceRegion(type);
  }
  /* *
   *
   *  Functions
   *
   * */
  destroy() {
    this.domElementProvider.destroyCreatedElements();
  }
  announce(message2) {
    AST.setElementHTML(this.announceRegion, message2);
    if (this.clearAnnouncementRegionTimer) {
      clearTimeout(this.clearAnnouncementRegionTimer);
    }
    this.clearAnnouncementRegionTimer = setTimeout(() => {
      this.announceRegion.innerHTML = AST.emptyHTML;
      delete this.clearAnnouncementRegionTimer;
    }, 3e3);
  }
  addAnnounceRegion(type) {
    const chartContainer = this.chart.announcerContainer || this.createAnnouncerContainer(), div = this.domElementProvider.createElement("div");
    attr$7(div, {
      "aria-hidden": false,
      "aria-live": type,
      "aria-atomic": true
    });
    if (this.chart.styledMode) {
      addClass$2(div, "highcharts-visually-hidden");
    } else {
      visuallyHideElement$1(div);
    }
    chartContainer.appendChild(div);
    return div;
  }
  createAnnouncerContainer() {
    const chart = this.chart, container = doc$i.createElement("div");
    attr$7(container, {
      "aria-hidden": false,
      "class": "highcharts-announcer-container"
    });
    container.style.position = "relative";
    chart.renderTo.insertBefore(container, chart.renderTo.firstChild);
    chart.announcerContainer = container;
    return container;
  }
}
const { escapeStringForHTML, stripHTMLTagsFromString: stripHTMLTagsFromString$1 } = HTMLUtilities;
function getChartAnnotationLabels(chart) {
  const annotations = chart.annotations || [];
  return annotations.reduce((acc, cur) => {
    if (cur.options && cur.options.visible !== false) {
      acc = acc.concat(cur.labels);
    }
    return acc;
  }, []);
}
function getLabelText(label) {
  return label.options && label.options.accessibility && label.options.accessibility.description || label.graphic && label.graphic.text && label.graphic.text.textStr || "";
}
function getAnnotationLabelDescription(label) {
  const a11yDesc = label.options && label.options.accessibility && label.options.accessibility.description;
  if (a11yDesc) {
    return a11yDesc;
  }
  const chart = label.chart;
  const labelText = getLabelText(label);
  const points = label.points;
  const getAriaLabel = (point) => point.graphic && point.graphic.element && point.graphic.element.getAttribute("aria-label") || "";
  const getValueDesc = (point) => {
    const valDesc = point.accessibility && point.accessibility.valueDescription || getAriaLabel(point);
    const seriesName = point && point.series.name || "";
    return (seriesName ? seriesName + ", " : "") + "data point " + valDesc;
  };
  const pointValueDescriptions = points.filter((p) => !!p.graphic).map(getValueDesc).filter((desc) => !!desc);
  const numPoints = pointValueDescriptions.length;
  const pointsSelector = numPoints > 1 ? "MultiplePoints" : numPoints ? "SinglePoint" : "NoPoints";
  const langFormatStr = "accessibility.screenReaderSection.annotations.description" + pointsSelector;
  const context = {
    annotationText: labelText,
    annotation: label,
    numPoints,
    annotationPoint: pointValueDescriptions[0],
    additionalAnnotationPoints: pointValueDescriptions.slice(1)
  };
  return chart.langFormat(langFormatStr, context);
}
function getAnnotationListItems(chart) {
  const labels = getChartAnnotationLabels(chart);
  return labels.map((label) => {
    const desc = escapeStringForHTML(stripHTMLTagsFromString$1(getAnnotationLabelDescription(label), chart.renderer.forExport));
    return desc ? `<li>${desc}</li>` : "";
  });
}
function getAnnotationsInfoHTML$1(chart) {
  const annotations = chart.annotations;
  if (!(annotations && annotations.length)) {
    return "";
  }
  const annotationItems = getAnnotationListItems(chart);
  return `<ul style="list-style-type: none">${annotationItems.join(" ")}</ul>`;
}
function getPointAnnotationTexts$1(point) {
  const labels = getChartAnnotationLabels(point.series.chart);
  const pointLabels = labels.filter((label) => label.points.indexOf(point) > -1);
  if (!pointLabels.length) {
    return [];
  }
  return pointLabels.map((label) => `${getLabelText(label)}`);
}
const AnnotationsA11y = {
  getAnnotationsInfoHTML: getAnnotationsInfoHTML$1,
  getPointAnnotationTexts: getPointAnnotationTexts$1
};
const { getAnnotationsInfoHTML } = AnnotationsA11y;
const { getAxisDescription: getAxisDescription$1, getAxisRangeDescription: getAxisRangeDescription$2, getChartTitle: getChartTitle$3, unhideChartElementFromAT: unhideChartElementFromAT$5 } = ChartUtilities;
const { format: format$6 } = Templating;
const { doc: doc$h } = Highcharts;
const { addClass: addClass$1, getElement: getElement$1, getHeadingTagNameForElement, stripHTMLTagsFromString, visuallyHideElement } = HTMLUtilities;
const { attr: attr$6, pick: pick$14, replaceNested } = Utilities;
function getTableSummary(chart) {
  return chart.langFormat("accessibility.table.tableSummary", { chart });
}
function getTypeDescForMapChart(chart, formatContext) {
  return formatContext.mapTitle ? chart.langFormat("accessibility.chartTypes.mapTypeDescription", formatContext) : chart.langFormat("accessibility.chartTypes.unknownMap", formatContext);
}
function getTypeDescForCombinationChart(chart, formatContext) {
  return chart.langFormat("accessibility.chartTypes.combinationChart", formatContext);
}
function getTypeDescForEmptyChart(chart, formatContext) {
  return chart.langFormat("accessibility.chartTypes.emptyChart", formatContext);
}
function buildTypeDescriptionFromSeries(chart, types, context) {
  const firstType = types[0], typeExplanation = chart.langFormat("accessibility.seriesTypeDescriptions." + firstType, context), multi = chart.series && chart.series.length < 2 ? "Single" : "Multiple";
  return (chart.langFormat("accessibility.chartTypes." + firstType + multi, context) || chart.langFormat("accessibility.chartTypes.default" + multi, context)) + (typeExplanation ? " " + typeExplanation : "");
}
function getTypeDescription(chart, types) {
  const firstType = types[0], firstSeries = chart.series && chart.series[0] || {}, mapTitle = chart.mapView && chart.mapView.geoMap && chart.mapView.geoMap.title, formatContext = {
    numSeries: chart.series.length,
    numPoints: firstSeries.points && firstSeries.points.length,
    chart,
    mapTitle
  };
  if (!firstType) {
    return getTypeDescForEmptyChart(chart, formatContext);
  }
  if (firstType === "map" || firstType === "tiledwebmap") {
    return getTypeDescForMapChart(chart, formatContext);
  }
  if (chart.types.length > 1) {
    return getTypeDescForCombinationChart(chart, formatContext);
  }
  return buildTypeDescriptionFromSeries(chart, types, formatContext);
}
function stripEmptyHTMLTags(str) {
  return replaceNested(str, [/<([\w\-.:!]+)\b[^<>]*>\s*<\/\1>/g, ""]);
}
class InfoRegionsComponent extends AccessibilityComponent {
  constructor() {
    super(...arguments);
    this.screenReaderSections = {};
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Init the component
   * @private
   */
  init() {
    const chart = this.chart;
    const component = this;
    this.initRegionsDefinitions();
    this.addEvent(chart, "aftergetTableAST", function(e) {
      component.onDataTableCreated(e);
    });
    this.addEvent(chart, "afterViewData", function(e) {
      if (e.wasHidden) {
        component.dataTableDiv = e.element;
        setTimeout(function() {
          component.focusDataTable();
        }, 300);
      }
    });
    this.addEvent(chart, "afterHideData", function() {
      if (component.viewDataTableButton) {
        component.viewDataTableButton.setAttribute("aria-expanded", "false");
      }
    });
    if (chart.exporting) {
      this.addEvent(chart, "afterPrint", function() {
        component.updateAllScreenReaderSections();
      });
    }
    this.announcer = new Announcer(chart, "assertive");
  }
  /**
   * @private
   */
  initRegionsDefinitions() {
    const component = this, accessibilityOptions = this.chart.options.accessibility;
    this.screenReaderSections = {
      before: {
        element: null,
        buildContent: function(chart) {
          const formatter = accessibilityOptions.screenReaderSection.beforeChartFormatter;
          return formatter ? formatter(chart) : component.defaultBeforeChartFormatter(chart);
        },
        insertIntoDOM: function(el, chart) {
          chart.renderTo.insertBefore(el, chart.renderTo.firstChild);
        },
        afterInserted: function() {
          if (typeof component.sonifyButtonId !== "undefined") {
            component.initSonifyButton(component.sonifyButtonId);
          }
          if (typeof component.dataTableButtonId !== "undefined") {
            component.initDataTableButton(component.dataTableButtonId);
          }
        }
      },
      after: {
        element: null,
        buildContent: function(chart) {
          const formatter = accessibilityOptions.screenReaderSection.afterChartFormatter;
          return formatter ? formatter(chart) : component.defaultAfterChartFormatter();
        },
        insertIntoDOM: function(el, chart) {
          chart.renderTo.insertBefore(el, chart.container.nextSibling);
        },
        afterInserted: function() {
          if (component.chart.accessibility && accessibilityOptions.keyboardNavigation.enabled) {
            component.chart.accessibility.keyboardNavigation.updateExitAnchor();
          }
        }
      }
    };
  }
  /**
   * Called on chart render. Have to update the sections on render, in order
   * to get a11y info from series.
   */
  onChartRender() {
    this.linkedDescriptionElement = this.getLinkedDescriptionElement();
    this.setLinkedDescriptionAttrs();
    this.updateAllScreenReaderSections();
  }
  updateAllScreenReaderSections() {
    const component = this;
    Object.keys(this.screenReaderSections).forEach(function(regionKey) {
      component.updateScreenReaderSection(regionKey);
    });
  }
  /**
   * @private
   */
  getLinkedDescriptionElement() {
    const chartOptions = this.chart.options, linkedDescOption = chartOptions.accessibility.linkedDescription;
    if (!linkedDescOption) {
      return;
    }
    if (typeof linkedDescOption !== "string") {
      return linkedDescOption;
    }
    const query = format$6(linkedDescOption, this.chart), queryMatch = doc$h.querySelectorAll(query);
    if (queryMatch.length === 1) {
      return queryMatch[0];
    }
  }
  /**
   * @private
   */
  setLinkedDescriptionAttrs() {
    const el = this.linkedDescriptionElement;
    if (el) {
      el.setAttribute("aria-hidden", "true");
      addClass$1(el, "highcharts-linked-description");
    }
  }
  /**
   * @private
   * @param {string} regionKey
   * The name/key of the region to update
   */
  updateScreenReaderSection(regionKey) {
    const chart = this.chart;
    const region = this.screenReaderSections[regionKey];
    const content2 = region.buildContent(chart);
    const sectionDiv = region.element = region.element || this.createElement("div");
    const hiddenDiv = sectionDiv.firstChild || this.createElement("div");
    if (content2) {
      this.setScreenReaderSectionAttribs(sectionDiv, regionKey);
      AST.setElementHTML(hiddenDiv, content2);
      sectionDiv.appendChild(hiddenDiv);
      region.insertIntoDOM(sectionDiv, chart);
      if (chart.styledMode) {
        addClass$1(hiddenDiv, "highcharts-visually-hidden");
      } else {
        visuallyHideElement(hiddenDiv);
      }
      unhideChartElementFromAT$5(chart, hiddenDiv);
      if (region.afterInserted) {
        region.afterInserted();
      }
    } else {
      if (sectionDiv.parentNode) {
        sectionDiv.parentNode.removeChild(sectionDiv);
      }
      region.element = null;
    }
  }
  /**
   * Apply a11y attributes to a screen reader info section
   * @private
   * @param {Highcharts.HTMLDOMElement} sectionDiv The section element
   * @param {string} regionKey Name/key of the region we are setting attrs for
   */
  setScreenReaderSectionAttribs(sectionDiv, regionKey) {
    const chart = this.chart, labelText = chart.langFormat("accessibility.screenReaderSection." + regionKey + "RegionLabel", { chart, chartTitle: getChartTitle$3(chart) }), sectionId = `highcharts-screen-reader-region-${regionKey}-${chart.index}`;
    attr$6(sectionDiv, {
      id: sectionId,
      "aria-label": labelText || void 0
    });
    sectionDiv.style.position = "relative";
    if (labelText) {
      sectionDiv.setAttribute("role", chart.options.accessibility.landmarkVerbosity === "all" ? "region" : "group");
    }
  }
  /**
   * @private
   */
  defaultBeforeChartFormatter() {
    const chart = this.chart, format2 = chart.options.accessibility.screenReaderSection.beforeChartFormat;
    if (!format2) {
      return "";
    }
    const axesDesc = this.getAxesDescription(), shouldHaveSonifyBtn = chart.sonify && chart.options.sonification && chart.options.sonification.enabled, sonifyButtonId = "highcharts-a11y-sonify-data-btn-" + chart.index, dataTableButtonId = "hc-linkto-highcharts-data-table-" + chart.index, annotationsList = getAnnotationsInfoHTML(chart), annotationsTitleStr = chart.langFormat("accessibility.screenReaderSection.annotations.heading", { chart }), context = {
      headingTagName: getHeadingTagNameForElement(chart.renderTo),
      chartTitle: getChartTitle$3(chart),
      typeDescription: this.getTypeDescriptionText(),
      chartSubtitle: this.getSubtitleText(),
      chartLongdesc: this.getLongdescText(),
      xAxisDescription: axesDesc.xAxis,
      yAxisDescription: axesDesc.yAxis,
      playAsSoundButton: shouldHaveSonifyBtn ? this.getSonifyButtonText(sonifyButtonId) : "",
      viewTableButton: chart.getCSV ? this.getDataTableButtonText(dataTableButtonId) : "",
      annotationsTitle: annotationsList ? annotationsTitleStr : "",
      annotationsList
    }, formattedString = A11yI18n.i18nFormat(format2, context, chart);
    this.dataTableButtonId = dataTableButtonId;
    this.sonifyButtonId = sonifyButtonId;
    return stripEmptyHTMLTags(formattedString);
  }
  /**
   * @private
   */
  defaultAfterChartFormatter() {
    const chart = this.chart;
    const format2 = chart.options.accessibility.screenReaderSection.afterChartFormat;
    if (!format2) {
      return "";
    }
    const context = { endOfChartMarker: this.getEndOfChartMarkerText() };
    const formattedString = A11yI18n.i18nFormat(format2, context, chart);
    return stripEmptyHTMLTags(formattedString);
  }
  /**
   * @private
   */
  getLinkedDescription() {
    const el = this.linkedDescriptionElement, content2 = el && el.innerHTML || "";
    return stripHTMLTagsFromString(content2, this.chart.renderer.forExport);
  }
  /**
   * @private
   */
  getLongdescText() {
    const chartOptions = this.chart.options, captionOptions = chartOptions.caption, captionText = captionOptions && captionOptions.text, linkedDescription = this.getLinkedDescription();
    return chartOptions.accessibility.description || linkedDescription || captionText || "";
  }
  /**
   * @private
   */
  getTypeDescriptionText() {
    const chart = this.chart;
    return chart.types ? chart.options.accessibility.typeDescription || getTypeDescription(chart, chart.types) : "";
  }
  /**
   * @private
   */
  getDataTableButtonText(buttonId) {
    const chart = this.chart, buttonText = chart.langFormat("accessibility.table.viewAsDataTableButtonText", { chart, chartTitle: getChartTitle$3(chart) });
    return '<button id="' + buttonId + '">' + buttonText + "</button>";
  }
  /**
   * @private
   */
  getSonifyButtonText(buttonId) {
    const chart = this.chart;
    if (chart.options.sonification && chart.options.sonification.enabled === false) {
      return "";
    }
    const buttonText = chart.langFormat("accessibility.sonification.playAsSoundButtonText", { chart, chartTitle: getChartTitle$3(chart) });
    return '<button id="' + buttonId + '">' + buttonText + "</button>";
  }
  /**
   * @private
   */
  getSubtitleText() {
    const subtitle = this.chart.options.subtitle;
    return stripHTMLTagsFromString(subtitle && subtitle.text || "", this.chart.renderer.forExport);
  }
  /**
   * @private
   */
  getEndOfChartMarkerText() {
    const endMarkerId = `highcharts-end-of-chart-marker-${this.chart.index}`, endMarker = getElement$1(endMarkerId);
    if (endMarker) {
      return endMarker.outerHTML;
    }
    const chart = this.chart, markerText = chart.langFormat("accessibility.screenReaderSection.endOfChartMarker", { chart }), id = "highcharts-end-of-chart-marker-" + chart.index;
    return '<div id="' + id + '">' + markerText + "</div>";
  }
  /**
   * @private
   * @param {Highcharts.Dictionary<string>} e
   */
  onDataTableCreated(e) {
    const chart = this.chart;
    if (chart.options.accessibility.enabled) {
      if (this.viewDataTableButton) {
        this.viewDataTableButton.setAttribute("aria-expanded", "true");
      }
      const attributes = e.tree.attributes || {};
      attributes.tabindex = -1;
      attributes.summary = getTableSummary(chart);
      e.tree.attributes = attributes;
    }
  }
  /**
   * @private
   */
  focusDataTable() {
    const tableDiv = this.dataTableDiv, table = tableDiv && tableDiv.getElementsByTagName("table")[0];
    if (table && table.focus) {
      table.focus();
    }
  }
  /**
   * @private
   * @param {string} sonifyButtonId
   */
  initSonifyButton(sonifyButtonId) {
    const el = this.sonifyButton = getElement$1(sonifyButtonId);
    const chart = this.chart;
    const defaultHandler = (e) => {
      if (el) {
        el.setAttribute("aria-hidden", "true");
        el.setAttribute("aria-label", "");
      }
      e.preventDefault();
      e.stopPropagation();
      const announceMsg = chart.langFormat("accessibility.sonification.playAsSoundClickAnnouncement", { chart });
      this.announcer.announce(announceMsg);
      setTimeout(() => {
        if (el) {
          el.removeAttribute("aria-hidden");
          el.removeAttribute("aria-label");
        }
        if (chart.sonify) {
          chart.sonify();
        }
      }, 1e3);
    };
    if (el && chart) {
      el.setAttribute("tabindex", -1);
      el.onclick = function(e) {
        const onPlayAsSoundClick = chart.options.accessibility && chart.options.accessibility.screenReaderSection.onPlayAsSoundClick;
        (onPlayAsSoundClick || defaultHandler).call(this, e, chart);
      };
    }
  }
  /**
   * Set attribs and handlers for default viewAsDataTable button if exists.
   * @private
   * @param {string} tableButtonId
   */
  initDataTableButton(tableButtonId) {
    const el = this.viewDataTableButton = getElement$1(tableButtonId), chart = this.chart, tableId = tableButtonId.replace("hc-linkto-", "");
    if (el) {
      attr$6(el, {
        tabindex: -1,
        "aria-expanded": !!getElement$1(tableId)
      });
      el.onclick = chart.options.accessibility.screenReaderSection.onViewDataTableClick || function() {
        chart.viewData();
      };
    }
  }
  /**
   * Return object with text description of each of the chart's axes.
   * @private
   */
  getAxesDescription() {
    const chart = this.chart, shouldDescribeColl = function(collectionKey, defaultCondition) {
      const axes = chart[collectionKey];
      return axes.length > 1 || axes[0] && pick$14(axes[0].options.accessibility && axes[0].options.accessibility.enabled, defaultCondition);
    }, hasNoMap = !!chart.types && chart.types.indexOf("map") < 0 && chart.types.indexOf("treemap") < 0 && chart.types.indexOf("tilemap") < 0, hasCartesian = !!chart.hasCartesianSeries, showXAxes = shouldDescribeColl("xAxis", !chart.angular && hasCartesian && hasNoMap), showYAxes = shouldDescribeColl("yAxis", hasCartesian && hasNoMap), desc = {};
    if (showXAxes) {
      desc.xAxis = this.getAxisDescriptionText("xAxis");
    }
    if (showYAxes) {
      desc.yAxis = this.getAxisDescriptionText("yAxis");
    }
    return desc;
  }
  /**
   * @private
   */
  getAxisDescriptionText(collectionKey) {
    const chart = this.chart;
    const axes = chart[collectionKey];
    return chart.langFormat("accessibility.axis." + collectionKey + "Description" + (axes.length > 1 ? "Plural" : "Singular"), {
      chart,
      names: axes.map(function(axis) {
        return getAxisDescription$1(axis);
      }),
      ranges: axes.map(function(axis) {
        return getAxisRangeDescription$2(axis);
      }),
      numAxes: axes.length
    });
  }
  /**
   * Remove component traces
   */
  destroy() {
    if (this.announcer) {
      this.announcer.destroy();
    }
  }
}
const { attr: attr$5 } = Utilities;
const { getChartTitle: getChartTitle$2, unhideChartElementFromAT: unhideChartElementFromAT$4 } = ChartUtilities;
const { getFakeMouseEvent: getFakeMouseEvent$3 } = HTMLUtilities;
function getExportMenuButtonElement(chart) {
  return chart.exportSVGElements && chart.exportSVGElements[0];
}
function exportingShouldHaveA11y(chart) {
  const exportingOpts = chart.options.exporting, exportButton = getExportMenuButtonElement(chart);
  return !!(exportingOpts && exportingOpts.enabled !== false && exportingOpts.accessibility && exportingOpts.accessibility.enabled && exportButton && exportButton.element);
}
class MenuComponent extends AccessibilityComponent {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Init the component
   */
  init() {
    const chart = this.chart, component = this;
    this.addEvent(chart, "exportMenuShown", function() {
      component.onMenuShown();
    });
    this.addEvent(chart, "exportMenuHidden", function() {
      component.onMenuHidden();
    });
    this.createProxyGroup();
  }
  /**
   * @private
   */
  onMenuHidden() {
    const menu = this.chart.exportContextMenu;
    if (menu) {
      menu.setAttribute("aria-hidden", "true");
    }
    this.setExportButtonExpandedState("false");
  }
  /**
   * @private
   */
  onMenuShown() {
    const chart = this.chart, menu = chart.exportContextMenu;
    if (menu) {
      this.addAccessibleContextMenuAttribs();
      unhideChartElementFromAT$4(chart, menu);
    }
    this.setExportButtonExpandedState("true");
  }
  /**
   * @private
   * @param {string} stateStr
   */
  setExportButtonExpandedState(stateStr) {
    if (this.exportButtonProxy) {
      this.exportButtonProxy.innerElement.setAttribute("aria-expanded", stateStr);
    }
  }
  /**
   * Called on each render of the chart. We need to update positioning of the
   * proxy overlay.
   */
  onChartRender() {
    const chart = this.chart, focusEl = chart.focusElement, a11y = chart.accessibility;
    this.proxyProvider.clearGroup("chartMenu");
    this.proxyMenuButton();
    if (this.exportButtonProxy && focusEl && focusEl === chart.exportingGroup) {
      if (focusEl.focusBorder) {
        chart.setFocusToElement(focusEl, this.exportButtonProxy.innerElement);
      } else if (a11y) {
        a11y.keyboardNavigation.tabindexContainer.focus();
      }
    }
  }
  /**
   * @private
   */
  proxyMenuButton() {
    const chart = this.chart;
    const proxyProvider = this.proxyProvider;
    const buttonEl = getExportMenuButtonElement(chart);
    if (exportingShouldHaveA11y(chart) && buttonEl) {
      this.exportButtonProxy = proxyProvider.addProxyElement("chartMenu", { click: buttonEl }, "button", {
        "aria-label": chart.langFormat("accessibility.exporting.menuButtonLabel", {
          chart,
          chartTitle: getChartTitle$2(chart)
        }),
        "aria-expanded": false,
        title: chart.options.lang.contextButtonTitle || null
      });
    }
  }
  /**
   * @private
   */
  createProxyGroup() {
    const chart = this.chart;
    if (chart && this.proxyProvider) {
      this.proxyProvider.addGroup("chartMenu");
    }
  }
  /**
   * @private
   */
  addAccessibleContextMenuAttribs() {
    const chart = this.chart, exportList = chart.exportDivElements;
    if (exportList && exportList.length) {
      exportList.forEach((item) => {
        if (item) {
          if (item.tagName === "LI" && !(item.children && item.children.length)) {
            item.setAttribute("tabindex", -1);
          } else {
            item.setAttribute("aria-hidden", "true");
          }
        }
      });
      const parentDiv = exportList[0] && exportList[0].parentNode;
      if (parentDiv) {
        attr$5(parentDiv, {
          "aria-hidden": void 0,
          "aria-label": chart.langFormat("accessibility.exporting.chartMenuLabel", { chart }),
          role: "list"
          // Needed for webkit/VO
        });
      }
    }
  }
  /**
   * Get keyboard navigation handler for this component.
   * @private
   */
  getKeyboardNavigation() {
    const keys = this.keyCodes, chart = this.chart, component = this;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [
        // Arrow prev handler
        [
          [keys.left, keys.up],
          function() {
            return component.onKbdPrevious(this);
          }
        ],
        // Arrow next handler
        [
          [keys.right, keys.down],
          function() {
            return component.onKbdNext(this);
          }
        ],
        // Click handler
        [
          [keys.enter, keys.space],
          function() {
            return component.onKbdClick(this);
          }
        ]
      ],
      // Only run exporting navigation if exporting support exists and is
      // enabled on chart
      validate: function() {
        return !!chart.exporting && chart.options.exporting?.buttons?.contextButton.enabled !== false && chart.options.exporting.enabled !== false && chart.options.exporting.accessibility.enabled !== false;
      },
      // Focus export menu button
      init: function() {
        const proxy = component.exportButtonProxy;
        const svgEl = component.chart.exportingGroup;
        if (proxy && svgEl) {
          chart.setFocusToElement(svgEl, proxy.innerElement);
        }
      },
      // Hide the menu
      terminate: function() {
        chart.hideExportMenu();
      }
    });
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
   * @return {number} Response code
   */
  onKbdPrevious(keyboardNavigationHandler) {
    const chart = this.chart;
    const a11yOptions = chart.options.accessibility;
    const response = keyboardNavigationHandler.response;
    let i = chart.highlightedExportItemIx || 0;
    while (i--) {
      if (chart.highlightExportItem(i)) {
        return response.success;
      }
    }
    if (a11yOptions.keyboardNavigation.wrapAround) {
      chart.highlightLastExportItem();
      return response.success;
    }
    return response.prev;
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
   * @return {number} Response code
   */
  onKbdNext(keyboardNavigationHandler) {
    const chart = this.chart;
    const a11yOptions = chart.options.accessibility;
    const response = keyboardNavigationHandler.response;
    for (let i = (chart.highlightedExportItemIx || 0) + 1; i < chart.exportDivElements.length; ++i) {
      if (chart.highlightExportItem(i)) {
        return response.success;
      }
    }
    if (a11yOptions.keyboardNavigation.wrapAround) {
      chart.highlightExportItem(0);
      return response.success;
    }
    return response.next;
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
   * @return {number} Response code
   */
  onKbdClick(keyboardNavigationHandler) {
    const chart = this.chart;
    const curHighlightedItem = chart.exportDivElements[chart.highlightedExportItemIx];
    const exportButtonElement = getExportMenuButtonElement(chart).element;
    if (chart.openMenu) {
      this.fakeClickEvent(curHighlightedItem);
    } else {
      this.fakeClickEvent(exportButtonElement);
      chart.highlightExportItem(0);
    }
    return keyboardNavigationHandler.response.success;
  }
}
(function(MenuComponent2) {
  function compose2(ChartClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.hideExportMenu) {
      chartProto.hideExportMenu = chartHideExportMenu;
      chartProto.highlightExportItem = chartHighlightExportItem;
      chartProto.highlightLastExportItem = chartHighlightLastExportItem;
      chartProto.showExportMenu = chartShowExportMenu;
    }
  }
  MenuComponent2.compose = compose2;
  function chartShowExportMenu() {
    const exportButton = getExportMenuButtonElement(this);
    if (exportButton) {
      const el = exportButton.element;
      if (el.onclick) {
        el.onclick(getFakeMouseEvent$3("click"));
      }
    }
  }
  function chartHideExportMenu() {
    const chart = this, exportList = chart.exportDivElements;
    if (exportList && chart.exportContextMenu && chart.openMenu) {
      exportList.forEach((el) => {
        if (el && el.className === "highcharts-menu-item" && el.onmouseout) {
          el.onmouseout(getFakeMouseEvent$3("mouseout"));
        }
      });
      chart.highlightedExportItemIx = 0;
      chart.exportContextMenu.hideMenu();
      chart.container.focus();
    }
  }
  function chartHighlightExportItem(ix) {
    const listItem = this.exportDivElements && this.exportDivElements[ix];
    const curHighlighted = this.exportDivElements && this.exportDivElements[this.highlightedExportItemIx];
    if (listItem && listItem.tagName === "LI" && !(listItem.children && listItem.children.length)) {
      const hasSVGFocusSupport = !!(this.renderTo.getElementsByTagName("g")[0] || {}).focus;
      if (listItem.focus && hasSVGFocusSupport) {
        listItem.focus();
      }
      if (curHighlighted && curHighlighted.onmouseout) {
        curHighlighted.onmouseout(getFakeMouseEvent$3("mouseout"));
      }
      if (listItem.onmouseover) {
        listItem.onmouseover(getFakeMouseEvent$3("mouseover"));
      }
      this.highlightedExportItemIx = ix;
      return true;
    }
    return false;
  }
  function chartHighlightLastExportItem() {
    const chart = this;
    if (chart.exportDivElements) {
      let i = chart.exportDivElements.length;
      while (i--) {
        if (chart.highlightExportItem(i)) {
          return true;
        }
      }
    }
    return false;
  }
})(MenuComponent || (MenuComponent = {}));
const MenuComponent$1 = MenuComponent;
const { doc: doc$g, win: win$6 } = Highcharts;
const { addEvent: addEvent$W, defined: defined$G, fireEvent: fireEvent$n } = Utilities;
const { getElement, simulatedEventTarget: simulatedEventTarget$1 } = HTMLUtilities;
class KeyboardNavigation {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, components) {
    this.currentModuleIx = NaN;
    this.modules = [];
    this.init(chart, components);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the class
   * @private
   * @param {Highcharts.Chart} chart
   *        Chart object
   * @param {Object} components
   *        Map of component names to AccessibilityComponent objects.
   */
  init(chart, components) {
    const ep = this.eventProvider = new EventProvider();
    this.chart = chart;
    this.components = components;
    this.modules = [];
    this.currentModuleIx = 0;
    this.update();
    ep.addEvent(this.tabindexContainer, "keydown", (e) => this.onKeydown(e));
    ep.addEvent(this.tabindexContainer, "focus", (e) => this.onFocus(e));
    ["mouseup", "touchend"].forEach((eventName) => ep.addEvent(doc$g, eventName, (e) => this.onMouseUp(e)));
    ["mousedown", "touchstart"].forEach((eventName) => ep.addEvent(chart.renderTo, eventName, () => {
      this.isClickingChart = true;
    }));
  }
  /**
   * Update the modules for the keyboard navigation.
   * @param {Array<string>} [order]
   *        Array specifying the tab order of the components.
   */
  update(order) {
    const a11yOptions = this.chart.options.accessibility, keyboardOptions = a11yOptions && a11yOptions.keyboardNavigation, components = this.components;
    this.updateContainerTabindex();
    if (keyboardOptions && keyboardOptions.enabled && order && order.length) {
      this.modules = order.reduce(function(modules, componentName) {
        const navModules = components[componentName].getKeyboardNavigation();
        return modules.concat(navModules);
      }, []);
      this.updateExitAnchor();
    } else {
      this.modules = [];
      this.currentModuleIx = 0;
      this.removeExitAnchor();
    }
  }
  /**
   * We use an exit anchor to move focus out of chart whenever we want, by
   * setting focus to this div and not preventing the default tab action. We
   * also use this when users come back into the chart by tabbing back, in
   * order to navigate from the end of the chart.
   * @private
   */
  updateExitAnchor() {
    const endMarkerId = `highcharts-end-of-chart-marker-${this.chart.index}`, endMarker = getElement(endMarkerId);
    this.removeExitAnchor();
    if (endMarker) {
      this.makeElementAnExitAnchor(endMarker);
      this.exitAnchor = endMarker;
    } else {
      this.createExitAnchor();
    }
  }
  /**
   * Move to prev/next module.
   * @private
   * @param {number} direction
   * Direction to move. +1 for next, -1 for prev.
   * @return {boolean}
   * True if there was a valid module in direction.
   */
  move(direction) {
    const curModule = this.modules && this.modules[this.currentModuleIx];
    if (curModule && curModule.terminate) {
      curModule.terminate(direction);
    }
    if (this.chart.focusElement) {
      this.chart.focusElement.removeFocusBorder();
    }
    this.currentModuleIx += direction;
    const newModule = this.modules && this.modules[this.currentModuleIx];
    if (newModule) {
      if (newModule.validate && !newModule.validate()) {
        return this.move(direction);
      }
      if (newModule.init) {
        newModule.init(direction);
        return true;
      }
    }
    this.currentModuleIx = 0;
    this.exiting = true;
    if (direction > 0) {
      this.exitAnchor && this.exitAnchor.focus();
    } else {
      this.tabindexContainer.focus();
    }
    return false;
  }
  /**
   * Function to run on container focus
   * @private
   * @param {global.FocusEvent} e Browser focus event.
   */
  onFocus(e) {
    const chart = this.chart, focusComesFromChart = e.relatedTarget && chart.container.contains(e.relatedTarget), a11yOptions = chart.options.accessibility, keyboardOptions = a11yOptions && a11yOptions.keyboardNavigation, enabled = keyboardOptions && keyboardOptions.enabled;
    if (enabled && !this.exiting && !this.tabbingInBackwards && !this.isClickingChart && !focusComesFromChart) {
      const ix = this.getFirstValidModuleIx();
      if (ix !== null) {
        this.currentModuleIx = ix;
        this.modules[ix].init(1);
      }
    }
    this.keyboardReset = false;
    this.exiting = false;
  }
  /**
   * Reset chart navigation state if we mouse click and it's not already
   * reset. Reset fully if outside the chart, otherwise just hide focus
   * indicator.
   * @private
   */
  onMouseUp(e) {
    delete this.isClickingChart;
    if (!this.keyboardReset && e.relatedTarget !== simulatedEventTarget$1) {
      const chart = this.chart;
      if (!e.target || !chart.container.contains(e.target)) {
        const curMod = this.modules && this.modules[this.currentModuleIx || 0];
        if (curMod && curMod.terminate) {
          curMod.terminate();
        }
        this.currentModuleIx = 0;
      }
      if (chart.focusElement) {
        chart.focusElement.removeFocusBorder();
        delete chart.focusElement;
      }
      this.keyboardReset = true;
    }
  }
  /**
   * Function to run on keydown
   * @private
   * @param {global.KeyboardEvent} ev Browser keydown event.
   */
  onKeydown(ev) {
    const e = ev || win$6.event, curNavModule = this.modules && this.modules.length && this.modules[this.currentModuleIx];
    let preventDefault;
    const target = e.target;
    if (target && target.nodeName === "INPUT" && !target.classList.contains("highcharts-a11y-proxy-element")) {
      return;
    }
    this.keyboardReset = false;
    this.exiting = false;
    if (curNavModule) {
      const response = curNavModule.run(e);
      if (response === curNavModule.response.success) {
        preventDefault = true;
      } else if (response === curNavModule.response.prev) {
        preventDefault = this.move(-1);
      } else if (response === curNavModule.response.next) {
        preventDefault = this.move(1);
      }
      if (preventDefault) {
        e.preventDefault();
        e.stopPropagation();
      }
    }
  }
  /**
   * Chart container should have tabindex if navigation is enabled.
   * @private
   */
  updateContainerTabindex() {
    const a11yOptions = this.chart.options.accessibility, keyboardOptions = a11yOptions && a11yOptions.keyboardNavigation, shouldHaveTabindex = !(keyboardOptions && keyboardOptions.enabled === false), chart = this.chart, container = chart.container;
    let tabindexContainer;
    if (chart.renderTo.hasAttribute("tabindex")) {
      container.removeAttribute("tabindex");
      tabindexContainer = chart.renderTo;
    } else {
      tabindexContainer = container;
    }
    this.tabindexContainer = tabindexContainer;
    const curTabindex = tabindexContainer.getAttribute("tabindex");
    if (shouldHaveTabindex && !curTabindex) {
      tabindexContainer.setAttribute("tabindex", "0");
    } else if (!shouldHaveTabindex) {
      chart.container.removeAttribute("tabindex");
    }
  }
  /**
   * Add new exit anchor to the chart.
   * @private
   */
  createExitAnchor() {
    const chart = this.chart, exitAnchor = this.exitAnchor = doc$g.createElement("div");
    chart.renderTo.appendChild(exitAnchor);
    this.makeElementAnExitAnchor(exitAnchor);
  }
  /**
   * Add attributes and events to an element to make it function as an
   * exit anchor.
   * @private
   */
  makeElementAnExitAnchor(el) {
    const chartTabindex = this.tabindexContainer.getAttribute("tabindex") || 0;
    el.setAttribute("class", "highcharts-exit-anchor");
    el.setAttribute("tabindex", chartTabindex);
    el.setAttribute("aria-hidden", false);
    this.addExitAnchorEventsToEl(el);
  }
  /**
   * Destroy the exit anchor and remove from DOM.
   * @private
   */
  removeExitAnchor() {
    if (this.exitAnchor) {
      const el = this.eventProvider.eventRemovers.find((el2) => el2.element === this.exitAnchor);
      if (el && defined$G(el.remover)) {
        this.eventProvider.removeEvent(el.remover);
      }
      if (this.exitAnchor.parentNode) {
        this.exitAnchor.parentNode.removeChild(this.exitAnchor);
      }
      delete this.exitAnchor;
    }
  }
  /**
   * Add focus handler to exit anchor element.
   * @private
   */
  addExitAnchorEventsToEl(element) {
    const chart = this.chart, keyboardNavigation = this;
    this.eventProvider.addEvent(element, "focus", function(ev) {
      const e = ev || win$6.event, focusComesFromChart = e.relatedTarget && chart.container.contains(e.relatedTarget), comingInBackwards = !(focusComesFromChart || keyboardNavigation.exiting);
      if (chart.focusElement) {
        delete chart.focusElement;
      }
      if (comingInBackwards) {
        keyboardNavigation.tabbingInBackwards = true;
        keyboardNavigation.tabindexContainer.focus();
        delete keyboardNavigation.tabbingInBackwards;
        e.preventDefault();
        if (keyboardNavigation.modules && keyboardNavigation.modules.length) {
          keyboardNavigation.currentModuleIx = keyboardNavigation.modules.length - 1;
          const curModule = keyboardNavigation.modules[keyboardNavigation.currentModuleIx];
          if (curModule && curModule.validate && !curModule.validate()) {
            keyboardNavigation.move(-1);
          } else if (curModule) {
            curModule.init(-1);
          }
        }
      } else {
        keyboardNavigation.exiting = false;
      }
    });
  }
  /**
   * Get the ix of the first module that either does not require validation or
   * validates positively.
   * @private
   */
  getFirstValidModuleIx() {
    const len = this.modules.length;
    for (let i = 0; i < len; ++i) {
      const mod = this.modules[i];
      if (!mod.validate || mod.validate()) {
        return i;
      }
    }
    return null;
  }
  /**
   * Remove all traces of keyboard navigation.
   * @private
   */
  destroy() {
    this.removeExitAnchor();
    this.eventProvider.removeAddedEvents();
    this.chart.container.removeAttribute("tabindex");
  }
}
(function(KeyboardNavigation2) {
  function compose2(ChartClass) {
    MenuComponent$1.compose(ChartClass);
    const chartProto = ChartClass.prototype;
    if (!chartProto.dismissPopupContent) {
      chartProto.dismissPopupContent = chartDismissPopupContent;
      if (doc$g) {
        addEvent$W(doc$g, "keydown", documentOnKeydown);
      }
    }
    return ChartClass;
  }
  KeyboardNavigation2.compose = compose2;
  function chartDismissPopupContent() {
    const chart = this;
    fireEvent$n(this, "dismissPopupContent", {}, function() {
      if (chart.tooltip) {
        chart.tooltip.hide(0);
      }
      chart.hideExportMenu();
    });
  }
  function documentOnKeydown(e) {
    const keycode = e.which || e.keyCode;
    const esc = 27;
    if (keycode === esc && Highcharts.charts) {
      Highcharts.charts.forEach((chart) => {
        if (chart && chart.dismissPopupContent) {
          chart.dismissPopupContent();
        }
      });
    }
  }
})(KeyboardNavigation || (KeyboardNavigation = {}));
const KeyboardNavigation$1 = KeyboardNavigation;
const { animObject: animObject$7 } = animationExports;
const { doc: doc$f } = Highcharts;
const { addEvent: addEvent$V, fireEvent: fireEvent$m, isNumber: isNumber$C, pick: pick$13, syncTimeout: syncTimeout$4 } = Utilities;
const { getChartTitle: getChartTitle$1 } = ChartUtilities;
const { stripHTMLTagsFromString: stripHTMLTags$1, addClass, removeClass } = HTMLUtilities;
function scrollLegendToItem(legend, itemIx) {
  const itemPage = (legend.allItems[itemIx].legendItem || {}).pageIx, curPage = legend.currentPage;
  if (typeof itemPage !== "undefined" && itemPage + 1 !== curPage) {
    legend.scroll(1 + itemPage - curPage);
  }
}
function shouldDoLegendA11y(chart) {
  const items = chart.legend && chart.legend.allItems, legendA11yOptions = chart.options.legend.accessibility || {}, unsupportedColorAxis = chart.colorAxis && chart.colorAxis.some((c) => !c.dataClasses || !c.dataClasses.length);
  return !!(items && items.length && !unsupportedColorAxis && legendA11yOptions.enabled !== false);
}
function setLegendItemHoverState(hoverActive, item) {
  const legendItem = item.legendItem || {};
  item.setState(hoverActive ? "hover" : "", true);
  for (const key2 of ["group", "label", "symbol"]) {
    const svgElement = legendItem[key2];
    const element = svgElement && svgElement.element || svgElement;
    if (element) {
      fireEvent$m(element, hoverActive ? "mouseover" : "mouseout");
    }
  }
}
class LegendComponent extends AccessibilityComponent {
  constructor() {
    super(...arguments);
    this.highlightedLegendItemIx = NaN;
    this.proxyGroup = null;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Init the component
   * @private
   */
  init() {
    const component = this;
    this.recreateProxies();
    this.addEvent(Legend$1, "afterScroll", function() {
      if (this.chart === component.chart) {
        component.proxyProvider.updateGroupProxyElementPositions("legend");
        component.updateLegendItemProxyVisibility();
        if (component.highlightedLegendItemIx > -1) {
          this.chart.highlightLegendItem(component.highlightedLegendItemIx);
        }
      }
    });
    this.addEvent(Legend$1, "afterPositionItem", function(e) {
      if (this.chart === component.chart && this.chart.renderer) {
        component.updateProxyPositionForItem(e.item);
      }
    });
    this.addEvent(Legend$1, "afterRender", function() {
      if (this.chart === component.chart && this.chart.renderer && component.recreateProxies()) {
        syncTimeout$4(() => component.proxyProvider.updateGroupProxyElementPositions("legend"), animObject$7(pick$13(this.chart.renderer.globalAnimation, true)).duration);
      }
    });
  }
  /**
   * Update visibility of legend items when using paged legend
   * @private
   */
  updateLegendItemProxyVisibility() {
    const chart = this.chart;
    const legend = chart.legend;
    const items = legend.allItems || [];
    const curPage = legend.currentPage || 1;
    const clipHeight = legend.clipHeight || 0;
    let legendItem;
    items.forEach((item) => {
      if (item.a11yProxyElement) {
        const hasPages = legend.pages && legend.pages.length;
        const proxyEl = item.a11yProxyElement.element;
        let hide = false;
        legendItem = item.legendItem || {};
        if (hasPages) {
          const itemPage = legendItem.pageIx || 0;
          const y = legendItem.y || 0;
          const h = legendItem.label ? Math.round(legendItem.label.getBBox().height) : 0;
          hide = y + h - legend.pages[itemPage] > clipHeight || itemPage !== curPage - 1;
        }
        if (hide) {
          if (chart.styledMode) {
            addClass(proxyEl, "highcharts-a11y-invisible");
          } else {
            proxyEl.style.visibility = "hidden";
          }
        } else {
          removeClass(proxyEl, "highcharts-a11y-invisible");
          proxyEl.style.visibility = "";
        }
      }
    });
  }
  /**
   * @private
   */
  onChartRender() {
    if (!shouldDoLegendA11y(this.chart)) {
      this.removeProxies();
    }
  }
  /**
   * @private
   */
  highlightAdjacentLegendPage(direction) {
    const chart = this.chart;
    const legend = chart.legend;
    const curPageIx = legend.currentPage || 1;
    const newPageIx = curPageIx + direction;
    const pages = legend.pages || [];
    if (newPageIx > 0 && newPageIx <= pages.length) {
      let i = 0, res;
      for (const item of legend.allItems) {
        if (((item.legendItem || {}).pageIx || 0) + 1 === newPageIx) {
          res = chart.highlightLegendItem(i);
          if (res) {
            this.highlightedLegendItemIx = i;
          }
        }
        ++i;
      }
    }
  }
  /**
   * @private
   */
  updateProxyPositionForItem(item) {
    if (item.a11yProxyElement) {
      item.a11yProxyElement.refreshPosition();
    }
  }
  /**
   * Returns false if legend a11y is disabled and proxies were not created,
   * true otherwise.
   * @private
   */
  recreateProxies() {
    const focusedElement = doc$f.activeElement;
    const proxyGroup = this.proxyGroup;
    const shouldRestoreFocus = focusedElement && proxyGroup && proxyGroup.contains(focusedElement);
    this.removeProxies();
    if (shouldDoLegendA11y(this.chart)) {
      this.addLegendProxyGroup();
      this.proxyLegendItems();
      this.updateLegendItemProxyVisibility();
      this.updateLegendTitle();
      if (shouldRestoreFocus) {
        this.chart.highlightLegendItem(this.highlightedLegendItemIx);
      }
      return true;
    }
    return false;
  }
  /**
   * @private
   */
  removeProxies() {
    this.proxyProvider.removeGroup("legend");
  }
  /**
   * @private
   */
  updateLegendTitle() {
    const chart = this.chart;
    const legendTitle = stripHTMLTags$1((chart.legend && chart.legend.options.title && chart.legend.options.title.text || "").replace(/<br ?\/?>/g, " "), chart.renderer.forExport);
    const legendLabel = chart.langFormat("accessibility.legend.legendLabel" + (legendTitle ? "" : "NoTitle"), {
      chart,
      legendTitle,
      chartTitle: getChartTitle$1(chart)
    });
    this.proxyProvider.updateGroupAttrs("legend", {
      "aria-label": legendLabel
    });
  }
  /**
   * @private
   */
  addLegendProxyGroup() {
    const a11yOptions = this.chart.options.accessibility;
    const groupRole = a11yOptions.landmarkVerbosity === "all" ? "region" : null;
    this.proxyGroup = this.proxyProvider.addGroup("legend", "ul", {
      // Filled by updateLegendTitle, to keep up to date without
      // recreating group
      "aria-label": "_placeholder_",
      role: groupRole
    });
  }
  /**
   * @private
   */
  proxyLegendItems() {
    const component = this, items = (this.chart.legend || {}).allItems || [];
    let legendItem;
    items.forEach((item) => {
      legendItem = item.legendItem || {};
      if (legendItem.label && legendItem.label.element) {
        component.proxyLegendItem(item);
      }
    });
  }
  /**
   * @private
   * @param {Highcharts.BubbleLegendItem|Point|Highcharts.Series} item
   */
  proxyLegendItem(item) {
    const legendItem = item.legendItem || {};
    if (!legendItem.label || !legendItem.group) {
      return;
    }
    const itemLabel = this.chart.langFormat("accessibility.legend.legendItem", {
      chart: this.chart,
      itemName: stripHTMLTags$1(item.name, this.chart.renderer.forExport),
      item
    });
    const attribs = {
      tabindex: -1,
      "aria-pressed": item.visible,
      "aria-label": itemLabel
    };
    const proxyPositioningElement = legendItem.group.div ? legendItem.label : legendItem.group;
    item.a11yProxyElement = this.proxyProvider.addProxyElement("legend", {
      click: legendItem.label,
      visual: proxyPositioningElement.element
    }, "button", attribs);
  }
  /**
   * Get keyboard navigation handler for this component.
   * @private
   */
  getKeyboardNavigation() {
    const keys = this.keyCodes, component = this, chart = this.chart;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [
        [
          [keys.left, keys.right, keys.up, keys.down],
          function(keyCode) {
            return component.onKbdArrowKey(this, keyCode);
          }
        ],
        [
          [keys.enter, keys.space],
          function() {
            return component.onKbdClick(this);
          }
        ],
        [
          [keys.pageDown, keys.pageUp],
          function(keyCode) {
            const direction = keyCode === keys.pageDown ? 1 : -1;
            component.highlightAdjacentLegendPage(direction);
            return this.response.success;
          }
        ]
      ],
      validate: function() {
        return component.shouldHaveLegendNavigation();
      },
      init: function() {
        chart.highlightLegendItem(0);
        component.highlightedLegendItemIx = 0;
      },
      terminate: function() {
        component.highlightedLegendItemIx = -1;
        chart.legend.allItems.forEach((item) => setLegendItemHoverState(false, item));
      }
    });
  }
  /**
   * Arrow key navigation
   * @private
   */
  onKbdArrowKey(keyboardNavigationHandler, key2) {
    const { keyCodes: { left, up }, highlightedLegendItemIx, chart } = this, numItems = chart.legend.allItems.length, wrapAround = chart.options.accessibility.keyboardNavigation.wrapAround, direction = key2 === left || key2 === up ? -1 : 1, res = chart.highlightLegendItem(highlightedLegendItemIx + direction);
    if (res) {
      this.highlightedLegendItemIx += direction;
    } else if (wrapAround && numItems > 1) {
      this.highlightedLegendItemIx = direction > 0 ? 0 : numItems - 1;
      chart.highlightLegendItem(this.highlightedLegendItemIx);
    }
    return keyboardNavigationHandler.response.success;
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
   * @return {number} Response code
   */
  onKbdClick(keyboardNavigationHandler) {
    const legendItem = this.chart.legend.allItems[this.highlightedLegendItemIx];
    if (legendItem && legendItem.a11yProxyElement) {
      legendItem.a11yProxyElement.click();
    }
    return keyboardNavigationHandler.response.success;
  }
  /**
   * @private
   */
  shouldHaveLegendNavigation() {
    if (!shouldDoLegendA11y(this.chart)) {
      return false;
    }
    const chart = this.chart, legendOptions = chart.options.legend || {}, legendA11yOptions = legendOptions.accessibility || {};
    return !!(chart.legend.display && legendA11yOptions.keyboardNavigation && legendA11yOptions.keyboardNavigation.enabled);
  }
  /**
   * Clean up
   * @private
   */
  destroy() {
    this.removeProxies();
  }
}
(function(LegendComponent2) {
  function chartHighlightLegendItem(ix) {
    const items = this.legend.allItems;
    const oldIx = this.accessibility && this.accessibility.components.legend.highlightedLegendItemIx;
    const itemToHighlight = items[ix], legendItem = itemToHighlight?.legendItem || {};
    if (itemToHighlight) {
      if (isNumber$C(oldIx) && items[oldIx]) {
        setLegendItemHoverState(false, items[oldIx]);
      }
      scrollLegendToItem(this.legend, ix);
      const legendItemProp = legendItem.label;
      const proxyBtn = itemToHighlight.a11yProxyElement && itemToHighlight.a11yProxyElement.innerElement;
      if (legendItemProp && legendItemProp.element && proxyBtn) {
        this.setFocusToElement(legendItemProp, proxyBtn);
      }
      setLegendItemHoverState(true, itemToHighlight);
      return true;
    }
    return false;
  }
  function compose2(ChartClass, LegendClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.highlightLegendItem) {
      chartProto.highlightLegendItem = chartHighlightLegendItem;
      addEvent$V(LegendClass, "afterColorizeItem", legendOnAfterColorizeItem);
    }
  }
  LegendComponent2.compose = compose2;
  function legendOnAfterColorizeItem(e) {
    const chart = this.chart, a11yOptions = chart.options.accessibility, legendItem = e.item;
    if (a11yOptions.enabled && legendItem && legendItem.a11yProxyElement) {
      legendItem.a11yProxyElement.innerElement.setAttribute("aria-pressed", e.visible ? "true" : "false");
    }
  }
})(LegendComponent || (LegendComponent = {}));
const LegendComponent$1 = LegendComponent;
const { animObject: animObject$6 } = animationExports;
const { format: format$5 } = Templating;
const { clamp: clamp$d, pick: pick$12, syncTimeout: syncTimeout$3 } = Utilities;
const { getFakeMouseEvent: getFakeMouseEvent$2 } = HTMLUtilities;
const { getAxisRangeDescription: getAxisRangeDescription$1, fireEventOnWrappedOrUnwrappedElement: fireEventOnWrappedOrUnwrappedElement$1 } = ChartUtilities;
class NavigatorComponent extends AccessibilityComponent {
  /**
   * Init the component
   * @private
   */
  init() {
    const chart = this.chart, component = this;
    this.announcer = new Announcer(chart, "polite");
    this.addEvent(Navigator, "afterRender", function() {
      if (this.chart === component.chart && this.chart.renderer) {
        syncTimeout$3(() => {
          component.proxyProvider.updateGroupProxyElementPositions("navigator");
          component.updateHandleValues();
        }, animObject$6(pick$12(this.chart.renderer.globalAnimation, true)).duration);
      }
    });
  }
  /**
   * Called on updates
   * @private
   */
  onChartUpdate() {
    const chart = this.chart, options2 = chart.options, navigator2 = options2.navigator;
    if (navigator2.enabled && navigator2.accessibility?.enabled) {
      const verbosity = options2.accessibility.landmarkVerbosity, groupFormatStr = options2.lang.accessibility?.navigator.groupLabel;
      this.proxyProvider.removeGroup("navigator");
      this.proxyProvider.addGroup("navigator", "div", {
        role: verbosity === "all" ? "region" : "group",
        "aria-label": format$5(groupFormatStr, { chart }, chart)
      });
      const handleFormatStr = options2.lang.accessibility?.navigator.handleLabel;
      [0, 1].forEach((n) => {
        const handle = this.getHandleByIx(n);
        if (handle) {
          const proxyEl = this.proxyProvider.addProxyElement("navigator", {
            click: handle
          }, "input", {
            type: "range",
            "aria-label": format$5(handleFormatStr, { handleIx: n, chart }, chart)
          });
          this[n ? "maxHandleProxy" : "minHandleProxy"] = proxyEl.innerElement;
          proxyEl.innerElement.style.pointerEvents = "none";
          proxyEl.innerElement.oninput = () => this.updateNavigator();
        }
      });
      this.updateHandleValues();
    } else {
      this.proxyProvider.removeGroup("navigator");
    }
  }
  /**
   * Get navigation for a navigator handle.
   * @private
   * @return {Highcharts.KeyboardNavigationHandler} The module object.
   */
  getNavigatorHandleNavigation(handleIx) {
    const component = this, chart = this.chart, proxyEl = handleIx ? this.maxHandleProxy : this.minHandleProxy, keys = this.keyCodes;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [[
        [keys.left, keys.right, keys.up, keys.down],
        function(keyCode) {
          if (proxyEl) {
            const delta = keyCode === keys.left || keyCode === keys.up ? -1 : 1;
            proxyEl.value = "" + clamp$d(parseFloat(proxyEl.value) + delta, 0, 100);
            component.updateNavigator(() => {
              const handle = component.getHandleByIx(handleIx);
              if (handle) {
                chart.setFocusToElement(handle, proxyEl);
              }
            });
          }
          return this.response.success;
        }
      ]],
      init: () => {
        chart.setFocusToElement(this.getHandleByIx(handleIx), proxyEl);
      },
      validate: () => !!(this.getHandleByIx(handleIx) && proxyEl && chart.options.navigator.accessibility?.enabled)
    });
  }
  /**
   * Get keyboard navigation handlers for this component.
   * @return {Array<Highcharts.KeyboardNavigationHandler>}
   *         List of module objects.
   */
  getKeyboardNavigation() {
    return [
      this.getNavigatorHandleNavigation(0),
      this.getNavigatorHandleNavigation(1)
    ];
  }
  /**
   * Remove component traces
   */
  destroy() {
    if (this.updateNavigatorThrottleTimer) {
      clearTimeout(this.updateNavigatorThrottleTimer);
    }
    this.proxyProvider.removeGroup("navigator");
    if (this.announcer) {
      this.announcer.destroy();
    }
  }
  /**
   * Update the value of the handles to match current navigator pos.
   * @private
   */
  updateHandleValues() {
    const navigator2 = this.chart.navigator;
    if (navigator2 && this.minHandleProxy && this.maxHandleProxy) {
      const length = navigator2.size;
      this.minHandleProxy.value = "" + Math.round(navigator2.zoomedMin / length * 100);
      this.maxHandleProxy.value = "" + Math.round(navigator2.zoomedMax / length * 100);
    }
  }
  /**
   * Get a navigator handle by its index
   * @private
   */
  getHandleByIx(ix) {
    const navigator2 = this.chart.navigator;
    return navigator2 && navigator2.handles && navigator2.handles[ix];
  }
  /**
   * Update navigator to match changed proxy values.
   * @private
   */
  updateNavigator(beforeAnnounce) {
    const performUpdate = (beforeAnnounce2) => {
      const chart = this.chart, { navigator: navigator2, pointer } = chart;
      if (navigator2 && pointer && this.minHandleProxy && this.maxHandleProxy) {
        const chartPos = pointer.getChartPosition(), minNewX = parseFloat(this.minHandleProxy.value) / 100 * navigator2.size, maxNewX = parseFloat(this.maxHandleProxy.value) / 100 * navigator2.size;
        [
          [0, "mousedown", navigator2.zoomedMin],
          [0, "mousemove", minNewX],
          [0, "mouseup", minNewX],
          [1, "mousedown", navigator2.zoomedMax],
          [1, "mousemove", maxNewX],
          [1, "mouseup", maxNewX]
        ].forEach(([handleIx, type, x]) => {
          const handle = this.getHandleByIx(handleIx)?.element;
          if (handle) {
            fireEventOnWrappedOrUnwrappedElement$1(handle, getFakeMouseEvent$2(type, {
              x: chartPos.left + navigator2.left + x,
              y: chartPos.top + navigator2.top
            }, handle));
          }
        });
        if (beforeAnnounce2) {
          beforeAnnounce2();
        }
        const announceFormatStr = chart.options.lang.accessibility?.navigator.changeAnnouncement, axisRangeDescription = getAxisRangeDescription$1(chart.xAxis[0]);
        this.announcer.announce(format$5(announceFormatStr, { axisRangeDescription, chart }, chart));
      }
    };
    if (this.updateNavigatorThrottleTimer) {
      clearTimeout(this.updateNavigatorThrottleTimer);
    }
    this.updateNavigatorThrottleTimer = setTimeout(performUpdate.bind(this, beforeAnnounce), 20);
  }
}
const { getPointAnnotationTexts } = AnnotationsA11y;
const { getAxisDescription, getSeriesFirstPointElement, getSeriesA11yElement, unhideChartElementFromAT: unhideChartElementFromAT$3 } = ChartUtilities;
const { format: format$4, numberFormat } = Templating;
const { reverseChildNodes, stripHTMLTagsFromString: stripHTMLTags } = HTMLUtilities;
const { find: find$8, isNumber: isNumber$B, isString: isString$4, pick: pick$11, defined: defined$F } = Utilities;
function findFirstPointWithGraphic(point) {
  const sourcePointIndex = point.index;
  if (!point.series || !point.series.data || !defined$F(sourcePointIndex)) {
    return null;
  }
  const nullInteraction = point.series.options?.nullInteraction;
  return find$8(point.series.data, function(p) {
    return !!(p && typeof p.index !== "undefined" && (nullInteraction || p.index > sourcePointIndex) && p.graphic && p.graphic.element);
  }) || null;
}
function shouldAddMockPoint(point) {
  const series = point.series, chart = series && series.chart, isSunburst = series && series.is("sunburst"), isNull = point.isNull, shouldDescribeNull = chart && chart.options.accessibility.point.describeNull;
  return isNull && !isSunburst && shouldDescribeNull;
}
function makeMockElement(point, pos) {
  const renderer = point.series.chart.renderer, mock = renderer.rect(pos.x, pos.y, 1, 1);
  mock.attr({
    "class": "highcharts-a11y-mock-point",
    fill: "none",
    opacity: 0,
    "fill-opacity": 0,
    "stroke-opacity": 0
  });
  return mock;
}
function addMockPointElement(point) {
  const series = point.series, firstPointWithGraphic = findFirstPointWithGraphic(point), firstGraphic = firstPointWithGraphic && firstPointWithGraphic.graphic, parentGroup = firstGraphic ? firstGraphic.parentGroup : series.graph || series.group, mockPos = firstPointWithGraphic ? {
    x: pick$11(point.plotX, firstPointWithGraphic.plotX, 0),
    y: pick$11(point.plotY, firstPointWithGraphic.plotY, 0)
  } : {
    x: pick$11(point.plotX, 0),
    y: pick$11(point.plotY, 0)
  }, mockElement = makeMockElement(point, mockPos);
  if (parentGroup && parentGroup.element) {
    point.graphic = mockElement;
    point.hasMockGraphic = true;
    mockElement.add(parentGroup);
    parentGroup.element.insertBefore(mockElement.element, firstGraphic ? firstGraphic.element : null);
    return mockElement.element;
  }
}
function hasMorePointsThanDescriptionThreshold(series) {
  const chartA11yOptions = series.chart.options.accessibility, threshold = chartA11yOptions.series.pointDescriptionEnabledThreshold;
  return !!(threshold !== false && series.points && series.points.length >= +threshold);
}
function shouldSetScreenReaderPropsOnPoints(series) {
  const seriesA11yOptions = series.options.accessibility || {};
  return !hasMorePointsThanDescriptionThreshold(series) && !seriesA11yOptions.exposeAsGroupOnly;
}
function shouldSetKeyboardNavPropsOnPoints(series) {
  const chartA11yOptions = series.chart.options.accessibility, seriesNavOptions = chartA11yOptions.keyboardNavigation.seriesNavigation;
  return !!(series.points && (series.points.length < +seriesNavOptions.pointNavigationEnabledThreshold || seriesNavOptions.pointNavigationEnabledThreshold === false));
}
function shouldDescribeSeriesElement(series) {
  const chart = series.chart, chartOptions = chart.options.chart, chartHas3d = chartOptions.options3d && chartOptions.options3d.enabled, hasMultipleSeries = chart.series.length > 1, describeSingleSeriesOption = chart.options.accessibility.series.describeSingleSeries, exposeAsGroupOnlyOption = (series.options.accessibility || {}).exposeAsGroupOnly, noDescribe3D = chartHas3d && hasMultipleSeries;
  return !noDescribe3D && (hasMultipleSeries || describeSingleSeriesOption || exposeAsGroupOnlyOption || hasMorePointsThanDescriptionThreshold(series));
}
function pointNumberToString(point, value) {
  const series = point.series, chart = series.chart, a11yPointOptions = chart.options.accessibility.point || {}, seriesA11yPointOptions = series.options.accessibility && series.options.accessibility.point || {}, tooltipOptions = series.tooltipOptions || {}, lang2 = chart.options.lang;
  if (isNumber$B(value)) {
    return numberFormat(value, seriesA11yPointOptions.valueDecimals || a11yPointOptions.valueDecimals || tooltipOptions.valueDecimals || -1, lang2.decimalPoint, lang2.accessibility.thousandsSep || lang2.thousandsSep);
  }
  return value;
}
function getSeriesDescriptionText(series) {
  const seriesA11yOptions = series.options.accessibility || {}, descOpt = seriesA11yOptions.description;
  return descOpt && series.chart.langFormat("accessibility.series.description", {
    description: descOpt,
    series
  }) || "";
}
function getSeriesAxisDescriptionText(series, axisCollection) {
  const axis = series[axisCollection];
  return series.chart.langFormat("accessibility.series." + axisCollection + "Description", {
    name: getAxisDescription(axis),
    series
  });
}
function getPointA11yTimeDescription(point) {
  const series = point.series, chart = series.chart, seriesA11yOptions = series.options.accessibility && series.options.accessibility.point || {}, a11yOptions = chart.options.accessibility.point || {}, dateXAxis = series.xAxis && series.xAxis.dateTime;
  if (dateXAxis) {
    const tooltipDateFormat = dateXAxis.getXDateFormat(point.x || 0, chart.options.tooltip.dateTimeLabelFormats), dateFormat2 = seriesA11yOptions.dateFormatter && seriesA11yOptions.dateFormatter(point) || a11yOptions.dateFormatter && a11yOptions.dateFormatter(point) || seriesA11yOptions.dateFormat || a11yOptions.dateFormat || tooltipDateFormat;
    return chart.time.dateFormat(dateFormat2, point.x || 0, void 0);
  }
}
function getPointXDescription(point) {
  const timeDesc = getPointA11yTimeDescription(point), xAxis2 = point.series.xAxis || {}, pointCategory = xAxis2.categories && defined$F(point.category) && ("" + point.category).replace("<br/>", " "), canUseId = defined$F(point.id) && ("" + point.id).indexOf("highcharts-") < 0, fallback = "x, " + point.x;
  return point.name || timeDesc || pointCategory || (canUseId ? point.id : fallback);
}
function getPointArrayMapValueDescription(point, prefix, suffix) {
  const pre = prefix || "", suf = suffix || "", keyToValStr = function(key2) {
    const num = pointNumberToString(point, pick$11(point[key2], point.options[key2]));
    return num !== void 0 ? key2 + ": " + pre + num + suf : num;
  }, pointArrayMap = point.series.pointArrayMap;
  return pointArrayMap.reduce(function(desc, key2) {
    const propDesc = keyToValStr(key2);
    return propDesc ? desc + (desc.length ? ", " : "") + propDesc : desc;
  }, "");
}
function getPointValue(point) {
  const series = point.series, a11yPointOpts = series.chart.options.accessibility.point || {}, seriesA11yPointOpts = series.chart.options.accessibility && series.chart.options.accessibility.point || {}, tooltipOptions = series.tooltipOptions || {}, valuePrefix = seriesA11yPointOpts.valuePrefix || a11yPointOpts.valuePrefix || tooltipOptions.valuePrefix || "", valueSuffix = seriesA11yPointOpts.valueSuffix || a11yPointOpts.valueSuffix || tooltipOptions.valueSuffix || "", fallbackKey = typeof point.value !== "undefined" ? "value" : "y", fallbackDesc = pointNumberToString(point, point[fallbackKey]);
  if (point.isNull) {
    return series.chart.langFormat("accessibility.series.nullPointValue", {
      point
    });
  }
  if (series.pointArrayMap) {
    return getPointArrayMapValueDescription(point, valuePrefix, valueSuffix);
  }
  return valuePrefix + fallbackDesc + valueSuffix;
}
function getPointAnnotationDescription(point) {
  const chart = point.series.chart;
  const langKey = "accessibility.series.pointAnnotationsDescription";
  const annotations = getPointAnnotationTexts(point);
  const context = { point, annotations };
  return annotations.length ? chart.langFormat(langKey, context) : "";
}
function getPointValueDescription(point) {
  const series = point.series, chart = series.chart, seriesA11yOptions = series.options.accessibility, seriesValueDescFormat = seriesA11yOptions && seriesA11yOptions.point && seriesA11yOptions.point.valueDescriptionFormat, pointValueDescriptionFormat = seriesValueDescFormat || chart.options.accessibility.point.valueDescriptionFormat, showXDescription = pick$11(series.xAxis && series.xAxis.options.accessibility && series.xAxis.options.accessibility.enabled, !chart.angular && series.type !== "flowmap"), xDesc = showXDescription ? getPointXDescription(point) : "", context = {
    point,
    index: defined$F(point.index) ? point.index + 1 : "",
    xDescription: xDesc,
    value: getPointValue(point),
    separator: showXDescription ? ", " : ""
  };
  return format$4(pointValueDescriptionFormat, context, chart);
}
function defaultPointDescriptionFormatter$1(point) {
  const series = point.series, shouldExposeSeriesName = series.chart.series.length > 1 || series.options.name, valText = getPointValueDescription(point), description = point.options && point.options.accessibility && point.options.accessibility.description, userDescText = description ? " " + description : "", seriesNameText = shouldExposeSeriesName ? " " + series.name + "." : "", annotationsDesc = getPointAnnotationDescription(point), pointAnnotationsText = annotationsDesc ? " " + annotationsDesc : "";
  point.accessibility = point.accessibility || {};
  point.accessibility.valueDescription = valText;
  return valText + userDescText + seriesNameText + pointAnnotationsText;
}
function setPointScreenReaderAttribs(point, pointElement) {
  const series = point.series, seriesPointA11yOptions = series.options.accessibility?.point || {}, a11yPointOptions = series.chart.options.accessibility.point || {}, label = stripHTMLTags(isString$4(seriesPointA11yOptions.descriptionFormat) && format$4(seriesPointA11yOptions.descriptionFormat, point, series.chart) || seriesPointA11yOptions.descriptionFormatter?.(point) || isString$4(a11yPointOptions.descriptionFormat) && format$4(a11yPointOptions.descriptionFormat, point, series.chart) || a11yPointOptions.descriptionFormatter?.(point) || defaultPointDescriptionFormatter$1(point), series.chart.renderer.forExport);
  pointElement.setAttribute("role", "img");
  pointElement.setAttribute("aria-label", label);
}
function describePointsInSeries(series) {
  const setScreenReaderProps = shouldSetScreenReaderPropsOnPoints(series), setKeyboardProps = shouldSetKeyboardNavPropsOnPoints(series), shouldDescribeNullPoints = series.chart.options.accessibility.point.describeNull;
  if (setScreenReaderProps || setKeyboardProps) {
    series.points.forEach((point) => {
      const pointEl = point.graphic && point.graphic.element || shouldAddMockPoint(point) && addMockPointElement(point), pointA11yDisabled = point.options && point.options.accessibility && point.options.accessibility.enabled === false;
      if (pointEl) {
        if (point.isNull && !shouldDescribeNullPoints) {
          pointEl.setAttribute("aria-hidden", true);
          return;
        }
        pointEl.setAttribute("tabindex", "-1");
        if (!series.chart.styledMode) {
          pointEl.style.outline = "none";
        }
        if (setScreenReaderProps && !pointA11yDisabled) {
          setPointScreenReaderAttribs(point, pointEl);
        } else {
          pointEl.setAttribute("aria-hidden", true);
        }
      }
    });
  }
}
function defaultSeriesDescriptionFormatter$1(series) {
  const chart = series.chart, chartTypes = chart.types || [], description = getSeriesDescriptionText(series), shouldDescribeAxis = function(coll) {
    return chart[coll] && chart[coll].length > 1 && series[coll];
  }, seriesNumber = series.index + 1, xAxisInfo = getSeriesAxisDescriptionText(series, "xAxis"), yAxisInfo = getSeriesAxisDescriptionText(series, "yAxis"), summaryContext = {
    seriesNumber,
    series,
    chart
  }, combinationSuffix = chartTypes.length > 1 ? "Combination" : "", summary = chart.langFormat("accessibility.series.summary." + series.type + combinationSuffix, summaryContext) || chart.langFormat("accessibility.series.summary.default" + combinationSuffix, summaryContext), axisDescription = (shouldDescribeAxis("yAxis") ? " " + yAxisInfo + "." : "") + (shouldDescribeAxis("xAxis") ? " " + xAxisInfo + "." : ""), formatStr = pick$11(series.options.accessibility && series.options.accessibility.descriptionFormat, chart.options.accessibility.series.descriptionFormat, "");
  return format$4(formatStr, {
    seriesDescription: summary,
    authorDescription: description ? " " + description : "",
    axisDescription,
    series,
    chart,
    seriesNumber
  }, void 0);
}
function describeSeriesElement(series, seriesElement) {
  const seriesA11yOptions = series.options.accessibility || {}, a11yOptions = series.chart.options.accessibility, landmarkVerbosity = a11yOptions.landmarkVerbosity;
  if (seriesA11yOptions.exposeAsGroupOnly) {
    seriesElement.setAttribute("role", "img");
  } else if (landmarkVerbosity === "all") {
    seriesElement.setAttribute("role", "region");
  } else {
    seriesElement.setAttribute("role", "group");
  }
  seriesElement.setAttribute("tabindex", "-1");
  if (!series.chart.styledMode) {
    seriesElement.style.outline = "none";
  }
  seriesElement.setAttribute("aria-label", stripHTMLTags(a11yOptions.series.descriptionFormatter && a11yOptions.series.descriptionFormatter(series) || defaultSeriesDescriptionFormatter$1(series), series.chart.renderer.forExport));
}
function describeSeries$1(series) {
  const chart = series.chart, firstPointEl = getSeriesFirstPointElement(series), seriesEl = getSeriesA11yElement(series), is3d = chart.is3d && chart.is3d();
  if (seriesEl) {
    if (seriesEl.lastChild === firstPointEl && !is3d) {
      reverseChildNodes(seriesEl);
    }
    describePointsInSeries(series);
    unhideChartElementFromAT$3(chart, seriesEl);
    if (shouldDescribeSeriesElement(series)) {
      describeSeriesElement(series, seriesEl);
    } else {
      seriesEl.removeAttribute("aria-label");
    }
  }
}
const SeriesDescriber = {
  defaultPointDescriptionFormatter: defaultPointDescriptionFormatter$1,
  defaultSeriesDescriptionFormatter: defaultSeriesDescriptionFormatter$1,
  describeSeries: describeSeries$1
};
const { composed: composed$l } = Highcharts;
const { addEvent: addEvent$U, defined: defined$E, pushUnique: pushUnique$l } = Utilities;
const { getChartTitle } = ChartUtilities;
const { defaultPointDescriptionFormatter, defaultSeriesDescriptionFormatter } = SeriesDescriber;
function chartHasAnnounceEnabled(chart) {
  return !!chart.options.accessibility.announceNewData.enabled;
}
function findPointInDataArray(point) {
  const candidates = point.series.data.filter((candidate) => point.x === candidate.x && point.y === candidate.y);
  return candidates.length === 1 ? candidates[0] : point;
}
function getUniqueSeries(arrayA, arrayB) {
  const uniqueSeries = (arrayA || []).concat(arrayB || []).reduce((acc, cur) => {
    acc[cur.name + cur.index] = cur;
    return acc;
  }, {});
  return Object.keys(uniqueSeries).map((ix) => uniqueSeries[ix]);
}
class NewDataAnnouncer {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.dirty = {
      allSeries: {}
    };
    this.lastAnnouncementTime = 0;
    this.chart = chart;
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Initialize the new data announcer.
   * @private
   */
  init() {
    const chart = this.chart;
    const announceOptions = chart.options.accessibility.announceNewData;
    const announceType = announceOptions.interruptUser ? "assertive" : "polite";
    this.lastAnnouncementTime = 0;
    this.dirty = {
      allSeries: {}
    };
    this.eventProvider = new EventProvider();
    this.announcer = new Announcer(chart, announceType);
    this.addEventListeners();
  }
  /**
   * Remove traces of announcer.
   * @private
   */
  destroy() {
    this.eventProvider.removeAddedEvents();
    this.announcer.destroy();
  }
  /**
   * Add event listeners for the announcer
   * @private
   */
  addEventListeners() {
    const announcer = this, chart = this.chart, e = this.eventProvider;
    e.addEvent(chart, "afterApplyDrilldown", function() {
      announcer.lastAnnouncementTime = 0;
    });
    e.addEvent(chart, "afterAddSeries", function(e2) {
      announcer.onSeriesAdded(e2.series);
    });
    e.addEvent(chart, "redraw", function() {
      announcer.announceDirtyData();
    });
  }
  /**
   * On new data series added, update dirty list.
   * @private
   * @param {Highcharts.Series} series
   */
  onSeriesAdded(series) {
    if (chartHasAnnounceEnabled(this.chart)) {
      this.dirty.hasDirty = true;
      this.dirty.allSeries[series.name + series.index] = series;
      this.dirty.newSeries = defined$E(this.dirty.newSeries) ? void 0 : series;
    }
  }
  /**
   * Gather what we know and announce the data to user.
   * @private
   */
  announceDirtyData() {
    const chart = this.chart, announcer = this;
    if (chart.options.accessibility.announceNewData && this.dirty.hasDirty) {
      let newPoint = this.dirty.newPoint;
      if (newPoint) {
        newPoint = findPointInDataArray(newPoint);
      }
      this.queueAnnouncement(Object.keys(this.dirty.allSeries).map((ix) => announcer.dirty.allSeries[ix]), this.dirty.newSeries, newPoint);
      this.dirty = {
        allSeries: {}
      };
    }
  }
  /**
   * Announce to user that there is new data.
   * @private
   * @param {Array<Highcharts.Series>} dirtySeries
   *          Array of series with new data.
   * @param {Highcharts.Series} [newSeries]
   *          If a single new series was added, a reference to this series.
   * @param {Highcharts.Point} [newPoint]
   *          If a single point was added, a reference to this point.
   */
  queueAnnouncement(dirtySeries, newSeries, newPoint) {
    const chart = this.chart;
    const annOptions = chart.options.accessibility.announceNewData;
    if (annOptions.enabled) {
      const now = +/* @__PURE__ */ new Date();
      const dTime = now - this.lastAnnouncementTime;
      const time = Math.max(0, annOptions.minAnnounceInterval - dTime);
      const allSeries = getUniqueSeries(this.queuedAnnouncement && this.queuedAnnouncement.series, dirtySeries);
      const message2 = this.buildAnnouncementMessage(allSeries, newSeries, newPoint);
      if (message2) {
        if (this.queuedAnnouncement) {
          clearTimeout(this.queuedAnnouncementTimer);
        }
        this.queuedAnnouncement = {
          time: now,
          message: message2,
          series: allSeries
        };
        this.queuedAnnouncementTimer = setTimeout(() => {
          if (this && this.announcer) {
            this.lastAnnouncementTime = +/* @__PURE__ */ new Date();
            this.announcer.announce(this.queuedAnnouncement.message);
            delete this.queuedAnnouncement;
            delete this.queuedAnnouncementTimer;
          }
        }, time);
      }
    }
  }
  /**
   * Get announcement message for new data.
   * @private
   * @param {Array<Highcharts.Series>} dirtySeries
   *          Array of series with new data.
   * @param {Highcharts.Series} [newSeries]
   *          If a single new series was added, a reference to this series.
   * @param {Highcharts.Point} [newPoint]
   *          If a single point was added, a reference to this point.
   *
   * @return {string|null}
   * The announcement message to give to user.
   */
  buildAnnouncementMessage(dirtySeries, newSeries, newPoint) {
    const chart = this.chart, annOptions = chart.options.accessibility.announceNewData;
    if (annOptions.announcementFormatter) {
      const formatterRes = annOptions.announcementFormatter(dirtySeries, newSeries, newPoint);
      if (formatterRes !== false) {
        return formatterRes.length ? formatterRes : null;
      }
    }
    const multiple = Highcharts.charts && Highcharts.charts.length > 1 ? "Multiple" : "Single", langKey = newSeries ? "newSeriesAnnounce" + multiple : newPoint ? "newPointAnnounce" + multiple : "newDataAnnounce", chartTitle = getChartTitle(chart);
    return chart.langFormat("accessibility.announceNewData." + langKey, {
      chartTitle,
      seriesDesc: newSeries ? defaultSeriesDescriptionFormatter(newSeries) : null,
      pointDesc: newPoint ? defaultPointDescriptionFormatter(newPoint) : null,
      point: newPoint,
      series: newSeries
    });
  }
}
(function(NewDataAnnouncer2) {
  function compose2(SeriesClass) {
    if (pushUnique$l(composed$l, "A11y.NDA")) {
      addEvent$U(SeriesClass, "addPoint", seriesOnAddPoint);
      addEvent$U(SeriesClass, "updatedData", seriesOnUpdatedData);
    }
  }
  NewDataAnnouncer2.compose = compose2;
  function seriesOnAddPoint(e) {
    const chart = this.chart, newDataAnnouncer = chart.accessibility?.components.series.newDataAnnouncer;
    if (newDataAnnouncer && newDataAnnouncer.chart === chart && chartHasAnnounceEnabled(chart)) {
      newDataAnnouncer.dirty.newPoint = defined$E(newDataAnnouncer.dirty.newPoint) ? void 0 : e.point;
    }
  }
  function seriesOnUpdatedData() {
    const chart = this.chart, newDataAnnouncer = chart.accessibility?.components.series.newDataAnnouncer;
    if (newDataAnnouncer && newDataAnnouncer.chart === chart && chartHasAnnounceEnabled(chart)) {
      newDataAnnouncer.dirty.hasDirty = true;
      newDataAnnouncer.dirty.allSeries[this.name + this.index] = this;
    }
  }
})(NewDataAnnouncer || (NewDataAnnouncer = {}));
const NewDataAnnouncer$1 = NewDataAnnouncer;
const { doc: doc$e, win: win$5 } = Highcharts;
const { attr: attr$4, css: css$3, merge: merge$12 } = Utilities;
const { fireEventOnWrappedOrUnwrappedElement } = ChartUtilities;
const { cloneMouseEvent, cloneTouchEvent, getFakeMouseEvent: getFakeMouseEvent$1, removeElement: removeElement$1 } = HTMLUtilities;
class ProxyElement {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, target, proxyElementType = "button", wrapperElementType, attributes) {
    this.chart = chart;
    this.target = target;
    this.eventProvider = new EventProvider();
    const innerEl = this.innerElement = doc$e.createElement(proxyElementType), wrapperEl = this.element = wrapperElementType ? doc$e.createElement(wrapperElementType) : innerEl;
    if (!chart.styledMode) {
      this.hideElementVisually(innerEl);
    }
    if (wrapperElementType) {
      if (wrapperElementType === "li" && !chart.styledMode) {
        wrapperEl.style.listStyle = "none";
      }
      wrapperEl.appendChild(innerEl);
      this.element = wrapperEl;
    }
    this.updateTarget(target, attributes);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Fake a click event on the target.
   */
  click() {
    const pos = this.getTargetPosition();
    pos.x += pos.width / 2;
    pos.y += pos.height / 2;
    const fakeEventObject = getFakeMouseEvent$1("click", pos);
    fireEventOnWrappedOrUnwrappedElement(this.target.click, fakeEventObject);
  }
  /**
   * Update the target to be proxied. The position and events are updated to
   * match the new target.
   * @param target The new target definition
   * @param attributes New HTML attributes to apply to the proxy. Set an
   * attribute to null to remove.
   */
  updateTarget(target, attributes) {
    this.target = target;
    this.updateCSSClassName();
    const attrs = attributes || {};
    Object.keys(attrs).forEach((a) => {
      if (attrs[a] === null) {
        delete attrs[a];
      }
    });
    const targetAriaLabel = this.getTargetAttr(target.click, "aria-label");
    attr$4(this.innerElement, merge$12(targetAriaLabel ? {
      "aria-label": targetAriaLabel
    } : {}, attrs));
    this.eventProvider.removeAddedEvents();
    this.addProxyEventsToElement(this.innerElement, target.click);
    this.refreshPosition();
  }
  /**
   * Refresh the position of the proxy element to match the current target
   */
  refreshPosition() {
    const bBox = this.getTargetPosition();
    css$3(this.innerElement, {
      width: (bBox.width || 1) + "px",
      height: (bBox.height || 1) + "px",
      left: (Math.round(bBox.x) || 0) + "px",
      top: (Math.round(bBox.y) || 0) + "px"
    });
  }
  /**
   * Remove button from DOM, and clear events.
   */
  remove() {
    this.eventProvider.removeAddedEvents();
    removeElement$1(this.element);
  }
  // -------------------------- private ------------------------------------
  /**
   * Update the CSS class name to match target
   */
  updateCSSClassName() {
    const stringHasNoTooltip = (s) => s.indexOf("highcharts-no-tooltip") > -1;
    const legend = this.chart.legend;
    const groupDiv = legend.group && legend.group.div;
    const noTooltipOnGroup = stringHasNoTooltip(groupDiv && groupDiv.className || "");
    const targetClassName = this.getTargetAttr(this.target.click, "class") || "";
    const noTooltipOnTarget = stringHasNoTooltip(targetClassName);
    this.innerElement.className = noTooltipOnGroup || noTooltipOnTarget ? "highcharts-a11y-proxy-element highcharts-no-tooltip" : "highcharts-a11y-proxy-element";
  }
  /**
   * Mirror events for a proxy element to a target
   */
  addProxyEventsToElement(element, target) {
    [
      "click",
      "touchstart",
      "touchend",
      "touchcancel",
      "touchmove",
      "mouseover",
      "mouseenter",
      "mouseleave",
      "mouseout"
    ].forEach((evtType) => {
      const isTouchEvent = evtType.indexOf("touch") === 0;
      this.eventProvider.addEvent(element, evtType, (e) => {
        const clonedEvent = isTouchEvent ? cloneTouchEvent(e) : cloneMouseEvent(e);
        if (target) {
          fireEventOnWrappedOrUnwrappedElement(target, clonedEvent);
        }
        e.stopPropagation();
        if (!isTouchEvent) {
          e.preventDefault();
        }
      }, { passive: false });
    });
  }
  /**
   * Set visually hidden style on a proxy element
   */
  hideElementVisually(el) {
    css$3(el, {
      borderWidth: 0,
      backgroundColor: "transparent",
      cursor: "pointer",
      outline: "none",
      opacity: 1e-3,
      filter: "alpha(opacity=1)",
      zIndex: 999,
      overflow: "hidden",
      padding: 0,
      margin: 0,
      display: "block",
      position: "absolute",
      "-ms-filter": "progid:DXImageTransform.Microsoft.Alpha(Opacity=1)"
    });
  }
  /**
   * Get the position relative to chart container for the target
   */
  getTargetPosition() {
    const clickTarget = this.target.click;
    const clickTargetElement = clickTarget.element ? clickTarget.element : clickTarget;
    const posElement = this.target.visual || clickTargetElement;
    const chartDiv = this.chart.renderTo, pointer = this.chart.pointer;
    if (chartDiv && posElement?.getBoundingClientRect && pointer) {
      const scrollTop = win$5.scrollY || doc$e.documentElement.scrollTop, rectEl = posElement.getBoundingClientRect(), chartPos = pointer.getChartPosition();
      return {
        x: (rectEl.left - chartPos.left) / chartPos.scaleX,
        // #21994, Add scroll position as "getBoundingClientRect"
        // returns the position from the viewport, not the document top.
        y: (rectEl.top + scrollTop - chartPos.top) / chartPos.scaleY,
        width: rectEl.right / chartPos.scaleX - rectEl.left / chartPos.scaleX,
        height: rectEl.bottom / chartPos.scaleY - rectEl.top / chartPos.scaleY
      };
    }
    return { x: 0, y: 0, width: 1, height: 1 };
  }
  /**
   * Get an attribute value of a target
   */
  getTargetAttr(target, key2) {
    if (target.element) {
      return target.element.getAttribute(key2);
    }
    return target.getAttribute(key2);
  }
}
const { doc: doc$d } = Highcharts;
const { attr: attr$3, css: css$2 } = Utilities;
const { unhideChartElementFromAT: unhideChartElementFromAT$2 } = ChartUtilities;
const { removeChildNodes } = HTMLUtilities;
class ProxyProvider {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.chart = chart;
    this.domElementProvider = new DOMElementProvider();
    this.groups = {};
    this.groupOrder = [];
    this.beforeChartProxyPosContainer = this.createProxyPosContainer("before");
    this.afterChartProxyPosContainer = this.createProxyPosContainer("after");
    this.update();
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable */
  /**
   * Add a new proxy element to a group, proxying a target control.
   */
  addProxyElement(groupKey, target, proxyElementType = "button", attributes) {
    const group2 = this.groups[groupKey];
    if (!group2) {
      throw new Error("ProxyProvider.addProxyElement: Invalid group key " + groupKey);
    }
    const wrapperElementType = group2.type === "ul" || group2.type === "ol" ? "li" : void 0, proxy = new ProxyElement(this.chart, target, proxyElementType, wrapperElementType, attributes);
    group2.proxyContainerElement.appendChild(proxy.element);
    group2.proxyElements.push(proxy);
    return proxy;
  }
  /**
   * Create a group that will contain proxy elements. The group order is
   * automatically updated according to the last group order keys.
   *
   * Returns the added group.
   */
  addGroup(groupKey, groupElementType = "div", attributes) {
    const existingGroup = this.groups[groupKey];
    if (existingGroup) {
      return existingGroup.groupElement;
    }
    const proxyContainer = this.domElementProvider.createElement(groupElementType);
    let groupElement;
    if (attributes && attributes.role && groupElementType !== "div") {
      groupElement = this.domElementProvider.createElement("div");
      groupElement.appendChild(proxyContainer);
    } else {
      groupElement = proxyContainer;
    }
    groupElement.className = "highcharts-a11y-proxy-group highcharts-a11y-proxy-group-" + groupKey.replace(/\W/g, "-");
    this.groups[groupKey] = {
      proxyContainerElement: proxyContainer,
      groupElement,
      type: groupElementType,
      proxyElements: []
    };
    attr$3(groupElement, attributes || {});
    if (groupElementType === "ul") {
      proxyContainer.setAttribute("role", "list");
    }
    this.afterChartProxyPosContainer.appendChild(groupElement);
    this.updateGroupOrder(this.groupOrder);
    return groupElement;
  }
  /**
   * Update HTML attributes of a group.
   */
  updateGroupAttrs(groupKey, attributes) {
    const group2 = this.groups[groupKey];
    if (!group2) {
      throw new Error("ProxyProvider.updateGroupAttrs: Invalid group key " + groupKey);
    }
    attr$3(group2.groupElement, attributes);
  }
  /**
   * Reorder the proxy groups.
   *
   * The group key "series" refers to the chart's data points / <svg> element.
   * This is so that the keyboardNavigation.order option can be used to
   * determine the proxy group order.
   */
  updateGroupOrder(groupKeys) {
    this.groupOrder = groupKeys.slice();
    if (this.isDOMOrderGroupOrder()) {
      return;
    }
    const seriesIx = groupKeys.indexOf("series");
    const beforeKeys = seriesIx > -1 ? groupKeys.slice(0, seriesIx) : groupKeys;
    const afterKeys = seriesIx > -1 ? groupKeys.slice(seriesIx + 1) : [];
    const activeElement = doc$d.activeElement;
    ["before", "after"].forEach((pos) => {
      const posContainer = this[pos === "before" ? "beforeChartProxyPosContainer" : "afterChartProxyPosContainer"];
      const keys = pos === "before" ? beforeKeys : afterKeys;
      removeChildNodes(posContainer);
      keys.forEach((groupKey) => {
        const group2 = this.groups[groupKey];
        if (group2) {
          posContainer.appendChild(group2.groupElement);
        }
      });
    });
    if ((this.beforeChartProxyPosContainer.contains(activeElement) || this.afterChartProxyPosContainer.contains(activeElement)) && activeElement && activeElement.focus) {
      activeElement.focus();
    }
  }
  /**
   * Remove all proxy elements in a group
   */
  clearGroup(groupKey) {
    const group2 = this.groups[groupKey];
    if (!group2) {
      throw new Error("ProxyProvider.clearGroup: Invalid group key " + groupKey);
    }
    removeChildNodes(group2.proxyContainerElement);
  }
  /**
   * Remove a group from the DOM and from the proxy provider's group list.
   * All child elements are removed.
   * If the group does not exist, nothing happens.
   */
  removeGroup(groupKey) {
    const group2 = this.groups[groupKey];
    if (group2) {
      this.domElementProvider.removeElement(group2.groupElement);
      if (group2.groupElement !== group2.proxyContainerElement) {
        this.domElementProvider.removeElement(group2.proxyContainerElement);
      }
      delete this.groups[groupKey];
    }
  }
  /**
   * Update the position and order of all proxy groups and elements
   */
  update() {
    this.updatePosContainerPositions();
    this.updateGroupOrder(this.groupOrder);
    this.updateProxyElementPositions();
  }
  /**
   * Update all proxy element positions
   */
  updateProxyElementPositions() {
    Object.keys(this.groups).forEach(this.updateGroupProxyElementPositions.bind(this));
  }
  /**
   * Update a group's proxy elements' positions.
   * If the group does not exist, nothing happens.
   */
  updateGroupProxyElementPositions(groupKey) {
    const group2 = this.groups[groupKey];
    if (group2) {
      group2.proxyElements.forEach((el) => el.refreshPosition());
    }
  }
  /**
   * Remove all added elements
   */
  destroy() {
    this.domElementProvider.destroyCreatedElements();
  }
  // -------------------------- private ------------------------------------
  /**
   * Create and return a pos container element (the overall containers for
   * the proxy groups).
   */
  createProxyPosContainer(classNamePostfix) {
    const el = this.domElementProvider.createElement("div");
    el.setAttribute("aria-hidden", "false");
    el.className = "highcharts-a11y-proxy-container" + (classNamePostfix ? "-" + classNamePostfix : "");
    css$2(el, {
      top: "0",
      left: "0"
    });
    if (!this.chart.styledMode) {
      el.style.whiteSpace = "nowrap";
      el.style.position = "absolute";
    }
    return el;
  }
  /**
   * Get an array of group keys that corresponds to the current group order
   * in the DOM.
   */
  getCurrentGroupOrderInDOM() {
    const getGroupKeyFromElement = (el) => {
      const allGroups = Object.keys(this.groups);
      let i = allGroups.length;
      while (i--) {
        const groupKey = allGroups[i];
        const group2 = this.groups[groupKey];
        if (group2 && el === group2.groupElement) {
          return groupKey;
        }
      }
    };
    const getChildrenGroupOrder = (el) => {
      const childrenOrder = [];
      const children = el.children;
      for (let i = 0; i < children.length; ++i) {
        const groupKey = getGroupKeyFromElement(children[i]);
        if (groupKey) {
          childrenOrder.push(groupKey);
        }
      }
      return childrenOrder;
    };
    const before = getChildrenGroupOrder(this.beforeChartProxyPosContainer);
    const after = getChildrenGroupOrder(this.afterChartProxyPosContainer);
    before.push("series");
    return before.concat(after);
  }
  /**
   * Check if the current DOM order matches the current group order, so that
   * a reordering/update is unnecessary.
   */
  isDOMOrderGroupOrder() {
    const domOrder = this.getCurrentGroupOrderInDOM();
    const groupOrderWithGroups = this.groupOrder.filter((x) => x === "series" || !!this.groups[x]);
    let i = domOrder.length;
    if (i !== groupOrderWithGroups.length) {
      return false;
    }
    while (i--) {
      if (domOrder[i] !== groupOrderWithGroups[i]) {
        return false;
      }
    }
    return true;
  }
  /**
   * Update the DOM positions of the before/after proxy
   * positioning containers for the groups.
   */
  updatePosContainerPositions() {
    const chart = this.chart;
    if (chart.renderer.forExport) {
      return;
    }
    const rendererSVGEl = chart.renderer.box;
    chart.container.insertBefore(this.afterChartProxyPosContainer, rendererSVGEl.nextSibling);
    chart.container.insertBefore(this.beforeChartProxyPosContainer, rendererSVGEl);
    unhideChartElementFromAT$2(this.chart, this.afterChartProxyPosContainer);
    unhideChartElementFromAT$2(this.chart, this.beforeChartProxyPosContainer);
  }
}
const { unhideChartElementFromAT: unhideChartElementFromAT$1, getAxisRangeDescription } = ChartUtilities;
const { addEvent: addEvent$T, attr: attr$2 } = Utilities;
function shouldRunInputNavigation(chart) {
  return Boolean(chart.rangeSelector && chart.rangeSelector.inputGroup && chart.rangeSelector.inputGroup.element.style.visibility !== "hidden" && chart.options.rangeSelector.inputEnabled !== false && chart.rangeSelector.minInput && chart.rangeSelector.maxInput);
}
class RangeSelectorComponent extends AccessibilityComponent {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Init the component
   * @private
   */
  init() {
    const chart = this.chart;
    this.announcer = new Announcer(chart, "polite");
  }
  /**
   * Called on first render/updates to the chart, including options changes.
   */
  onChartUpdate() {
    const chart = this.chart, component = this, rangeSelector2 = chart.rangeSelector;
    if (!rangeSelector2) {
      return;
    }
    this.updateSelectorVisibility();
    this.setDropdownAttrs();
    if (rangeSelector2.buttons && rangeSelector2.buttons.length) {
      rangeSelector2.buttons.forEach((button) => {
        component.setRangeButtonAttrs(button);
      });
    }
    if (rangeSelector2.maxInput && rangeSelector2.minInput) {
      ["minInput", "maxInput"].forEach(function(key2, i) {
        const input = rangeSelector2[key2];
        if (input) {
          unhideChartElementFromAT$1(chart, input);
          component.setRangeInputAttrs(input, "accessibility.rangeSelector." + (i ? "max" : "min") + "InputLabel");
        }
      });
    }
  }
  /**
   * Hide buttons from AT when showing dropdown, and vice versa.
   * @private
   */
  updateSelectorVisibility() {
    const chart = this.chart;
    const rangeSelector2 = chart.rangeSelector;
    const dropdown = rangeSelector2 && rangeSelector2.dropdown;
    const buttons = rangeSelector2 && rangeSelector2.buttons || [];
    const hideFromAT = (el) => el.setAttribute("aria-hidden", true);
    if (rangeSelector2 && rangeSelector2.hasVisibleDropdown && dropdown) {
      unhideChartElementFromAT$1(chart, dropdown);
      buttons.forEach((btn) => hideFromAT(btn.element));
    } else {
      if (dropdown) {
        hideFromAT(dropdown);
      }
      buttons.forEach((btn) => unhideChartElementFromAT$1(chart, btn.element));
    }
  }
  /**
   * Set accessibility related attributes on dropdown element.
   * @private
   */
  setDropdownAttrs() {
    const chart = this.chart;
    const dropdown = chart.rangeSelector && chart.rangeSelector.dropdown;
    if (dropdown) {
      const label = chart.langFormat("accessibility.rangeSelector.dropdownLabel", { rangeTitle: chart.options.lang.rangeSelectorZoom });
      dropdown.setAttribute("aria-label", label);
      dropdown.setAttribute("tabindex", -1);
    }
  }
  /**
   * Set attrs for a range button
   * @private
   */
  setRangeButtonAttrs(button) {
    attr$2(button.element, {
      tabindex: -1,
      role: "button"
    });
  }
  /**
   * Set attrs for a date input
   * @private
   */
  setRangeInputAttrs(input, langKey) {
    const chart = this.chart;
    attr$2(input, {
      tabindex: -1,
      "aria-label": chart.langFormat(langKey, { chart })
    });
  }
  /**
   * Handle arrow key nav
   * @private
   */
  onButtonNavKbdArrowKey(keyboardNavigationHandler, keyCode) {
    const response = keyboardNavigationHandler.response, keys = this.keyCodes, chart = this.chart, wrapAround = chart.options.accessibility.keyboardNavigation.wrapAround, direction = keyCode === keys.left || keyCode === keys.up ? -1 : 1, didHighlight = chart.highlightRangeSelectorButton(chart.highlightedRangeSelectorItemIx + direction);
    if (!didHighlight) {
      if (wrapAround) {
        keyboardNavigationHandler.init(direction);
        return response.success;
      }
      return response[direction > 0 ? "next" : "prev"];
    }
    return response.success;
  }
  /**
   * Handle keyboard click
   * @private
   */
  onButtonNavKbdClick(keyboardNavigationHandler) {
    const response = keyboardNavigationHandler.response, chart = this.chart, wasDisabled = chart.oldRangeSelectorItemState === 3;
    if (!wasDisabled) {
      this.fakeClickEvent(chart.rangeSelector.buttons[chart.highlightedRangeSelectorItemIx].element);
    }
    return response.success;
  }
  /**
   * Called whenever a range selector button has been clicked, either by
   * mouse, touch, or kbd/voice/other.
   * @private
   */
  onAfterBtnClick() {
    const chart = this.chart;
    const axisRangeDescription = getAxisRangeDescription(chart.xAxis[0]);
    const announcement = chart.langFormat("accessibility.rangeSelector.clickButtonAnnouncement", { chart, axisRangeDescription });
    if (announcement) {
      this.announcer.announce(announcement);
    }
  }
  /**
   * Handle move between input elements with Tab key
   * @private
   */
  onInputKbdMove(direction) {
    const chart = this.chart;
    const rangeSel = chart.rangeSelector;
    const newIx = chart.highlightedInputRangeIx = (chart.highlightedInputRangeIx || 0) + direction;
    const newIxOutOfRange = newIx > 1 || newIx < 0;
    if (newIxOutOfRange) {
      if (chart.accessibility) {
        chart.accessibility.keyboardNavigation.exiting = true;
        chart.accessibility.keyboardNavigation.tabindexContainer.focus();
        return chart.accessibility.keyboardNavigation.move(direction);
      }
    } else if (rangeSel) {
      const svgEl = rangeSel[newIx ? "maxDateBox" : "minDateBox"];
      const inputEl = rangeSel[newIx ? "maxInput" : "minInput"];
      if (svgEl && inputEl) {
        chart.setFocusToElement(svgEl, inputEl);
      }
    }
    return true;
  }
  /**
   * Init date input navigation
   * @private
   */
  onInputNavInit(direction) {
    const component = this;
    const chart = this.chart;
    const buttonIxToHighlight = direction > 0 ? 0 : 1;
    const rangeSel = chart.rangeSelector;
    const svgEl = rangeSel && rangeSel[buttonIxToHighlight ? "maxDateBox" : "minDateBox"];
    const minInput = rangeSel && rangeSel.minInput;
    const maxInput = rangeSel && rangeSel.maxInput;
    const inputEl = buttonIxToHighlight ? maxInput : minInput;
    chart.highlightedInputRangeIx = buttonIxToHighlight;
    if (svgEl && minInput && maxInput) {
      chart.setFocusToElement(svgEl, inputEl);
      if (this.removeInputKeydownHandler) {
        this.removeInputKeydownHandler();
      }
      const keydownHandler = (e) => {
        const isTab = (e.which || e.keyCode) === this.keyCodes.tab;
        if (isTab && component.onInputKbdMove(e.shiftKey ? -1 : 1)) {
          e.preventDefault();
          e.stopPropagation();
        }
      };
      const minRemover = addEvent$T(minInput, "keydown", keydownHandler);
      const maxRemover = addEvent$T(maxInput, "keydown", keydownHandler);
      this.removeInputKeydownHandler = () => {
        minRemover();
        maxRemover();
      };
    }
  }
  /**
   * Terminate date input nav
   * @private
   */
  onInputNavTerminate() {
    const rangeSel = this.chart.rangeSelector || {};
    if (rangeSel.maxInput) {
      rangeSel.hideInput("max");
    }
    if (rangeSel.minInput) {
      rangeSel.hideInput("min");
    }
    if (this.removeInputKeydownHandler) {
      this.removeInputKeydownHandler();
      delete this.removeInputKeydownHandler;
    }
  }
  /**
   * Init range selector dropdown nav
   * @private
   */
  initDropdownNav() {
    const chart = this.chart;
    const rangeSelector2 = chart.rangeSelector;
    const dropdown = rangeSelector2 && rangeSelector2.dropdown;
    if (rangeSelector2 && dropdown) {
      chart.setFocusToElement(rangeSelector2.buttonGroup, dropdown);
      if (this.removeDropdownKeydownHandler) {
        this.removeDropdownKeydownHandler();
      }
      this.removeDropdownKeydownHandler = addEvent$T(dropdown, "keydown", (e) => {
        const isTab = (e.which || e.keyCode) === this.keyCodes.tab, a11y = chart.accessibility;
        if (isTab) {
          e.preventDefault();
          e.stopPropagation();
          if (a11y) {
            a11y.keyboardNavigation.move(e.shiftKey ? -1 : 1);
          }
        }
      });
    }
  }
  /**
   * Get navigation for the range selector buttons.
   * @private
   * @return {Highcharts.KeyboardNavigationHandler} The module object.
   */
  getRangeSelectorButtonNavigation() {
    const chart = this.chart;
    const keys = this.keyCodes;
    const component = this;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [
        [
          [keys.left, keys.right, keys.up, keys.down],
          function(keyCode) {
            return component.onButtonNavKbdArrowKey(this, keyCode);
          }
        ],
        [
          [keys.enter, keys.space],
          function() {
            return component.onButtonNavKbdClick(this);
          }
        ]
      ],
      validate: function() {
        return !!(chart.rangeSelector && chart.rangeSelector.buttons && chart.rangeSelector.buttons.length);
      },
      init: function(direction) {
        const rangeSelector2 = chart.rangeSelector;
        if (rangeSelector2 && rangeSelector2.hasVisibleDropdown) {
          component.initDropdownNav();
        } else if (rangeSelector2) {
          const lastButtonIx = rangeSelector2.buttons.length - 1;
          chart.highlightRangeSelectorButton(direction > 0 ? 0 : lastButtonIx);
        }
      },
      terminate: function() {
        if (component.removeDropdownKeydownHandler) {
          component.removeDropdownKeydownHandler();
          delete component.removeDropdownKeydownHandler;
        }
      }
    });
  }
  /**
   * Get navigation for the range selector input boxes.
   * @private
   * @return {Highcharts.KeyboardNavigationHandler}
   *         The module object.
   */
  getRangeSelectorInputNavigation() {
    const chart = this.chart;
    const component = this;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [],
      validate: function() {
        return shouldRunInputNavigation(chart);
      },
      init: function(direction) {
        component.onInputNavInit(direction);
      },
      terminate: function() {
        component.onInputNavTerminate();
      }
    });
  }
  /**
   * Get keyboard navigation handlers for this component.
   * @return {Array<Highcharts.KeyboardNavigationHandler>}
   *         List of module objects.
   */
  getKeyboardNavigation() {
    return [
      this.getRangeSelectorButtonNavigation(),
      this.getRangeSelectorInputNavigation()
    ];
  }
  /**
   * Remove component traces
   */
  destroy() {
    if (this.removeDropdownKeydownHandler) {
      this.removeDropdownKeydownHandler();
    }
    if (this.removeInputKeydownHandler) {
      this.removeInputKeydownHandler();
    }
    if (this.announcer) {
      this.announcer.destroy();
    }
  }
}
(function(RangeSelectorComponent2) {
  function chartHighlightRangeSelectorButton(ix) {
    const buttons = this.rangeSelector && this.rangeSelector.buttons || [];
    const curHighlightedIx = this.highlightedRangeSelectorItemIx;
    const curSelectedIx = this.rangeSelector && this.rangeSelector.selected;
    if (typeof curHighlightedIx !== "undefined" && buttons[curHighlightedIx] && curHighlightedIx !== curSelectedIx) {
      buttons[curHighlightedIx].setState(this.oldRangeSelectorItemState || 0);
    }
    this.highlightedRangeSelectorItemIx = ix;
    if (buttons[ix]) {
      this.setFocusToElement(buttons[ix].box, buttons[ix].element);
      if (ix !== curSelectedIx) {
        this.oldRangeSelectorItemState = buttons[ix].state;
        buttons[ix].setState(1);
      }
      return true;
    }
    return false;
  }
  function compose2(ChartClass, RangeSelectorClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.highlightRangeSelectorButton) {
      chartProto.highlightRangeSelectorButton = chartHighlightRangeSelectorButton;
      addEvent$T(RangeSelectorClass, "afterBtnClick", rangeSelectorAfterBtnClick);
    }
  }
  RangeSelectorComponent2.compose = compose2;
  function rangeSelectorAfterBtnClick() {
    const a11y = this.chart.accessibility;
    if (a11y && a11y.components.rangeSelector) {
      return a11y.components.rangeSelector.onAfterBtnClick();
    }
  }
})(RangeSelectorComponent || (RangeSelectorComponent = {}));
const RangeSelectorComponent$1 = RangeSelectorComponent;
const { composed: composed$k } = Highcharts;
const { addEvent: addEvent$S, merge: merge$11, pushUnique: pushUnique$k } = Utilities;
var ForcedMarkersComposition;
(function(ForcedMarkersComposition2) {
  function compose2(SeriesClass) {
    if (pushUnique$k(composed$k, "A11y.FM")) {
      addEvent$S(SeriesClass, "afterSetOptions", seriesOnAfterSetOptions);
      addEvent$S(SeriesClass, "render", seriesOnRender);
      addEvent$S(SeriesClass, "afterRender", seriesOnAfterRender);
      addEvent$S(SeriesClass, "renderCanvas", seriesOnRenderCanvas);
    }
  }
  ForcedMarkersComposition2.compose = compose2;
  function forceZeroOpacityMarkerOptions(options2) {
    merge$11(true, options2, {
      marker: {
        enabled: true,
        states: {
          normal: {
            opacity: 0
          }
        }
      }
    });
  }
  function getPointMarkerOpacity(pointOptions) {
    return pointOptions.marker.states && pointOptions.marker.states.normal && pointOptions.marker.states.normal.opacity;
  }
  function handleForcePointMarkers(series) {
    let i = series.points.length;
    while (i--) {
      const point = series.points[i];
      const pointOptions = point.options;
      const hadForcedMarker = point.hasForcedA11yMarker;
      delete point.hasForcedA11yMarker;
      if (pointOptions.marker) {
        const isStillForcedMarker = hadForcedMarker && getPointMarkerOpacity(pointOptions) === 0;
        if (pointOptions.marker.enabled && !isStillForcedMarker) {
          unforcePointMarkerOptions(pointOptions);
          point.hasForcedA11yMarker = false;
        } else if (pointOptions.marker.enabled === false) {
          forceZeroOpacityMarkerOptions(pointOptions);
          point.hasForcedA11yMarker = true;
        }
      }
    }
  }
  function hasIndividualPointMarkerOptions(series) {
    return !!(series._hasPointMarkers && series.points && series.points.length);
  }
  function isWithinDescriptionThreshold(series) {
    const a11yOptions = series.chart.options.accessibility;
    return series.points.length < a11yOptions.series.pointDescriptionEnabledThreshold || a11yOptions.series.pointDescriptionEnabledThreshold === false;
  }
  function seriesOnAfterRender() {
    const series = this;
    if (series.chart.styledMode) {
      if (series.markerGroup) {
        series.markerGroup[series.a11yMarkersForced ? "addClass" : "removeClass"]("highcharts-a11y-markers-hidden");
      }
      if (hasIndividualPointMarkerOptions(series)) {
        series.points.forEach((point) => {
          if (point.graphic) {
            point.graphic[point.hasForcedA11yMarker ? "addClass" : "removeClass"]("highcharts-a11y-marker-hidden");
            point.graphic[point.hasForcedA11yMarker === false ? "addClass" : "removeClass"]("highcharts-a11y-marker-visible");
          }
        });
      }
    }
  }
  function seriesOnAfterSetOptions(e) {
    this.resetA11yMarkerOptions = merge$11(e.options.marker || {}, this.userOptions.marker || {});
  }
  function seriesOnRender() {
    const series = this, options2 = series.options;
    if (shouldForceMarkers(series)) {
      if (options2.marker && options2.marker.enabled === false) {
        series.a11yMarkersForced = true;
        forceZeroOpacityMarkerOptions(series.options);
      }
      if (hasIndividualPointMarkerOptions(series)) {
        handleForcePointMarkers(series);
      }
    } else if (series.a11yMarkersForced) {
      delete series.a11yMarkersForced;
      unforceSeriesMarkerOptions(series);
      delete series.resetA11yMarkerOptions;
    }
  }
  function shouldForceMarkers(series) {
    const chart = series.chart, chartA11yEnabled = chart.options.accessibility.enabled, seriesA11yEnabled = (series.options.accessibility && series.options.accessibility.enabled) !== false;
    return chartA11yEnabled && seriesA11yEnabled && isWithinDescriptionThreshold(series);
  }
  function unforcePointMarkerOptions(pointOptions) {
    merge$11(true, pointOptions.marker, {
      states: {
        normal: {
          opacity: getPointMarkerOpacity(pointOptions) || 1
        }
      }
    });
  }
  function unforceSeriesMarkerOptions(series) {
    const resetMarkerOptions = series.resetA11yMarkerOptions;
    if (resetMarkerOptions) {
      const originalOpacity = resetMarkerOptions.states && resetMarkerOptions.states.normal && resetMarkerOptions.states.normal.opacity;
      if (series.userOptions && series.userOptions.marker) {
        series.userOptions.marker.enabled = true;
      }
      series.update({
        marker: {
          enabled: resetMarkerOptions.enabled,
          states: {
            normal: { opacity: originalOpacity }
          }
        }
      });
    }
  }
  function seriesOnRenderCanvas() {
    if (this.boosted && this.a11yMarkersForced) {
      merge$11(true, this.options, {
        marker: {
          enabled: false
        }
      });
      delete this.a11yMarkersForced;
    }
  }
})(ForcedMarkersComposition || (ForcedMarkersComposition = {}));
const ForcedMarkers = ForcedMarkersComposition;
const { seriesTypes: seriesTypes$2 } = SeriesRegistry$1;
const { doc: doc$c } = Highcharts;
const { defined: defined$D, fireEvent: fireEvent$l } = Utilities;
const { getPointFromXY, getSeriesFromName, scrollAxisToPoint } = ChartUtilities;
function getPointIndex(point) {
  const index = point.index, points = point.series.points;
  let i = points.length;
  if (points[index] !== point) {
    while (i--) {
      if (points[i] === point) {
        return i;
      }
    }
  } else {
    return index;
  }
}
function isSkipSeries(series) {
  const a11yOptions = series.chart.options.accessibility, seriesNavOptions = a11yOptions.keyboardNavigation.seriesNavigation, seriesA11yOptions = series.options.accessibility || {}, seriesKbdNavOptions = seriesA11yOptions.keyboardNavigation;
  return seriesKbdNavOptions && seriesKbdNavOptions.enabled === false || seriesA11yOptions.enabled === false || series.options.enableMouseTracking === false || // #8440
  !series.visible || // Skip all points in a series where pointNavigationEnabledThreshold is
  // reached
  seriesNavOptions.pointNavigationEnabledThreshold && +seriesNavOptions.pointNavigationEnabledThreshold <= series.points.length;
}
function isSkipPoint(point) {
  const series = point.series, nullInteraction = series.options.nullInteraction, pointOptions = point.options, pointA11yOptions = pointOptions.accessibility, a11yOptions = series.chart.options.accessibility, pointA11yDisabled = pointA11yOptions?.enabled === false;
  return a11yOptions.keyboardNavigation.seriesNavigation.skipNullPoints ?? (!(!point.isNull || nullInteraction) && point.visible === false || point.isInside === false || pointA11yDisabled || isSkipSeries(series));
}
function getFirstValidPointInSeries(series) {
  const points = series.points || [], len = points.length;
  for (let i = 0; i < len; ++i) {
    if (!isSkipPoint(points[i])) {
      return points[i];
    }
  }
  return null;
}
function getFirstValidPointInChart(chart) {
  const series = chart.series || [], len = series.length;
  for (let i = 0; i < len; ++i) {
    if (!isSkipSeries(series[i])) {
      const point = getFirstValidPointInSeries(series[i]);
      if (point) {
        return point;
      }
    }
  }
  return null;
}
function highlightLastValidPointInChart(chart) {
  const numSeries = chart.series.length;
  let i = numSeries, res = false;
  while (i--) {
    chart.highlightedPoint = chart.series[i].points[chart.series[i].points.length - 1];
    res = chart.series[i].highlightNextValidPoint();
    if (res) {
      break;
    }
  }
  return res;
}
function updateChartFocusAfterDrilling(chart) {
  const point = getFirstValidPointInChart(chart);
  if (point) {
    point.highlight(false);
  }
}
function highlightFirstValidPointInChart(chart) {
  delete chart.highlightedPoint;
  const point = getFirstValidPointInChart(chart);
  return point ? point.highlight() : false;
}
class SeriesKeyboardNavigation {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, keyCodes) {
    this.keyCodes = keyCodes;
    this.chart = chart;
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Init the keyboard navigation
   */
  init() {
    const keyboardNavigation = this, chart = this.chart, e = this.eventProvider = new EventProvider();
    e.addEvent(Series$9, "destroy", function() {
      return keyboardNavigation.onSeriesDestroy(this);
    });
    e.addEvent(chart, "afterApplyDrilldown", function() {
      updateChartFocusAfterDrilling(this);
    });
    e.addEvent(chart, "drilldown", function(e2) {
      const point = e2.point, series = point.series;
      keyboardNavigation.lastDrilledDownPoint = {
        x: point.x,
        y: point.y,
        seriesName: series ? series.name : ""
      };
    });
    e.addEvent(chart, "drillupall", function() {
      setTimeout(function() {
        keyboardNavigation.onDrillupAll();
      }, 10);
    });
    e.addEvent(Point$3, "afterSetState", function() {
      const point = this;
      const pointEl = point.graphic && point.graphic.element;
      const focusedElement = doc$c.activeElement;
      const focusedElClassName = focusedElement && focusedElement.getAttribute("class");
      const isProxyFocused = focusedElClassName && focusedElClassName.indexOf("highcharts-a11y-proxy-element") > -1;
      if (chart.highlightedPoint === point && focusedElement !== pointEl && !isProxyFocused && pointEl && pointEl.focus) {
        pointEl.focus();
      }
    });
  }
  /**
   * After drillup we want to find the point that was drilled down to and
   * highlight it.
   * @private
   */
  onDrillupAll() {
    const last = this.lastDrilledDownPoint, chart = this.chart, series = last && getSeriesFromName(chart, last.seriesName);
    let point;
    if (last && series && defined$D(last.x) && defined$D(last.y)) {
      point = getPointFromXY(series, last.x, last.y);
    }
    point = point || getFirstValidPointInChart(chart);
    if (chart.container) {
      chart.container.focus();
    }
    if (point && point.highlight) {
      point.highlight(false);
    }
  }
  /**
   * @private
   */
  getKeyboardNavigationHandler() {
    const keyboardNavigation = this, keys = this.keyCodes, chart = this.chart, inverted = chart.inverted;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [
        [
          inverted ? [keys.up, keys.down] : [keys.left, keys.right],
          function(keyCode) {
            return keyboardNavigation.onKbdSideways(this, keyCode);
          }
        ],
        [
          inverted ? [keys.left, keys.right] : [keys.up, keys.down],
          function(keyCode) {
            return keyboardNavigation.onKbdVertical(this, keyCode);
          }
        ],
        [
          [keys.enter, keys.space],
          function(keyCode, event) {
            const point = chart.highlightedPoint;
            if (point) {
              const { plotLeft, plotTop } = this.chart, { plotX = 0, plotY = 0 } = point;
              event = {
                ...event,
                chartX: plotLeft + plotX,
                chartY: plotTop + plotY,
                point,
                target: point.graphic?.element || event.target
              };
              fireEvent$l(point.series, "click", event);
              point.firePointEvent("click", event);
            }
            return this.response.success;
          }
        ],
        [
          [keys.home],
          function() {
            highlightFirstValidPointInChart(chart);
            return this.response.success;
          }
        ],
        [
          [keys.end],
          function() {
            highlightLastValidPointInChart(chart);
            return this.response.success;
          }
        ],
        [
          [keys.pageDown, keys.pageUp],
          function(keyCode) {
            chart.highlightAdjacentSeries(keyCode === keys.pageDown);
            return this.response.success;
          }
        ]
      ],
      init: function() {
        return keyboardNavigation.onHandlerInit(this);
      },
      validate: function() {
        return !!getFirstValidPointInChart(chart);
      },
      terminate: function() {
        return keyboardNavigation.onHandlerTerminate();
      }
    });
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} handler
   * @param {number} keyCode
   * @return {number}
   * response
   */
  onKbdSideways(handler, keyCode) {
    const keys = this.keyCodes, isNext = keyCode === keys.right || keyCode === keys.down;
    return this.attemptHighlightAdjacentPoint(handler, isNext);
  }
  /**
   * When keyboard navigation inits.
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} handler The handler object
   * @return {number}
   * response
   */
  onHandlerInit(handler) {
    const chart = this.chart, kbdNavOptions = chart.options.accessibility.keyboardNavigation;
    if (kbdNavOptions.seriesNavigation.rememberPointFocus && chart.highlightedPoint) {
      chart.highlightedPoint.highlight();
    } else {
      highlightFirstValidPointInChart(chart);
    }
    return handler.response.success;
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} handler
   * @param {number} keyCode
   * @return {number}
   * response
   */
  onKbdVertical(handler, keyCode) {
    const chart = this.chart, keys = this.keyCodes, isNext = keyCode === keys.down || keyCode === keys.right, navOptions = chart.options.accessibility.keyboardNavigation.seriesNavigation;
    if (navOptions.mode && navOptions.mode === "serialize") {
      return this.attemptHighlightAdjacentPoint(handler, isNext);
    }
    const highlightMethod = chart.highlightedPoint && chart.highlightedPoint.series.keyboardMoveVertical ? "highlightAdjacentPointVertical" : "highlightAdjacentSeries";
    chart[highlightMethod](isNext);
    return handler.response.success;
  }
  /**
   * @private
   */
  onHandlerTerminate() {
    const chart = this.chart, kbdNavOptions = chart.options.accessibility.keyboardNavigation;
    if (chart.tooltip) {
      chart.tooltip.hide(0);
    }
    const hoverSeries = chart.highlightedPoint && chart.highlightedPoint.series;
    if (hoverSeries && hoverSeries.onMouseOut) {
      hoverSeries.onMouseOut();
    }
    if (chart.highlightedPoint && chart.highlightedPoint.onMouseOut) {
      chart.highlightedPoint.onMouseOut();
    }
    if (!kbdNavOptions.seriesNavigation.rememberPointFocus) {
      delete chart.highlightedPoint;
    }
  }
  /**
   * Function that attempts to highlight next/prev point. Handles wrap around.
   * @private
   */
  attemptHighlightAdjacentPoint(handler, directionIsNext) {
    const chart = this.chart, wrapAround = chart.options.accessibility.keyboardNavigation.wrapAround, highlightSuccessful = chart.highlightAdjacentPoint(directionIsNext);
    if (!highlightSuccessful) {
      if (wrapAround && (directionIsNext ? highlightFirstValidPointInChart(chart) : highlightLastValidPointInChart(chart))) {
        return handler.response.success;
      }
      return handler.response[directionIsNext ? "next" : "prev"];
    }
    return handler.response.success;
  }
  /**
   * @private
   */
  onSeriesDestroy(series) {
    const chart = this.chart, currentHighlightedPointDestroyed = chart.highlightedPoint && chart.highlightedPoint.series === series;
    if (currentHighlightedPointDestroyed) {
      delete chart.highlightedPoint;
      if (chart.focusElement) {
        chart.focusElement.removeFocusBorder();
      }
    }
  }
  /**
   * @private
   */
  destroy() {
    this.eventProvider.removeAddedEvents();
  }
}
(function(SeriesKeyboardNavigation2) {
  function chartHighlightAdjacentPoint(next) {
    const chart = this, series = chart.series, curPoint = chart.highlightedPoint, curPointIndex = curPoint && getPointIndex(curPoint) || 0, curPoints = curPoint && curPoint.series.points || [], lastSeries = chart.series && chart.series[chart.series.length - 1], lastPoint = lastSeries && lastSeries.points && lastSeries.points[lastSeries.points.length - 1];
    let newSeries, newPoint;
    if (!series[0] || !series[0].points) {
      return false;
    }
    if (!curPoint) {
      newPoint = next ? series[0].points[0] : lastPoint;
    } else {
      newSeries = series[curPoint.series.index + (next ? 1 : -1)];
      newPoint = curPoints[curPointIndex + (next ? 1 : -1)];
      if (!newPoint && newSeries) {
        newPoint = newSeries.points[next ? 0 : newSeries.points.length - 1];
      }
      if (!newPoint) {
        return false;
      }
    }
    if (isSkipPoint(newPoint)) {
      newSeries = newPoint.series;
      if (isSkipSeries(newSeries)) {
        chart.highlightedPoint = next ? newSeries.points[newSeries.points.length - 1] : newSeries.points[0];
      } else {
        chart.highlightedPoint = newPoint;
      }
      return chart.highlightAdjacentPoint(next);
    }
    return newPoint.highlight();
  }
  function chartHighlightAdjacentPointVertical(down) {
    const curPoint = this.highlightedPoint;
    let minDistance = Infinity, bestPoint;
    if (!defined$D(curPoint.plotX) || !defined$D(curPoint.plotY)) {
      return false;
    }
    this.series.forEach((series) => {
      if (isSkipSeries(series)) {
        return;
      }
      series.points.forEach((point) => {
        if (!defined$D(point.plotY) || !defined$D(point.plotX) || point === curPoint) {
          return;
        }
        let yDistance = point.plotY - curPoint.plotY;
        const width = Math.abs(point.plotX - curPoint.plotX), distance = Math.abs(yDistance) * Math.abs(yDistance) + width * width * 4;
        if (series.yAxis && series.yAxis.reversed) {
          yDistance *= -1;
        }
        if (yDistance <= 0 && down || yDistance >= 0 && !down || distance < 5 || // Points in same spot => infinite loop
        isSkipPoint(point)) {
          return;
        }
        if (distance < minDistance) {
          minDistance = distance;
          bestPoint = point;
        }
      });
    });
    return bestPoint ? bestPoint.highlight() : false;
  }
  function chartHighlightAdjacentSeries(down) {
    const chart = this, curPoint = chart.highlightedPoint, lastSeries = chart.series && chart.series[chart.series.length - 1], lastPoint = lastSeries && lastSeries.points && lastSeries.points[lastSeries.points.length - 1];
    let newSeries, newPoint, adjacentNewPoint;
    if (!chart.highlightedPoint) {
      newSeries = down ? chart.series && chart.series[0] : lastSeries;
      newPoint = down ? newSeries && newSeries.points && newSeries.points[0] : lastPoint;
      return newPoint ? newPoint.highlight() : false;
    }
    newSeries = chart.series[curPoint.series.index + (down ? -1 : 1)];
    if (!newSeries) {
      return false;
    }
    newPoint = getClosestPoint(curPoint, newSeries, 4);
    if (!newPoint) {
      return false;
    }
    if (isSkipSeries(newSeries)) {
      newPoint.highlight();
      adjacentNewPoint = chart.highlightAdjacentSeries(down);
      if (!adjacentNewPoint) {
        curPoint.highlight();
        return false;
      }
      return adjacentNewPoint;
    }
    newPoint.highlight();
    return newPoint.series.highlightNextValidPoint();
  }
  function compose2(ChartClass, PointClass, SeriesClass) {
    const chartProto = ChartClass.prototype, pointProto2 = PointClass.prototype, seriesProto2 = SeriesClass.prototype;
    if (!chartProto.highlightAdjacentPoint) {
      chartProto.highlightAdjacentPoint = chartHighlightAdjacentPoint;
      chartProto.highlightAdjacentPointVertical = chartHighlightAdjacentPointVertical;
      chartProto.highlightAdjacentSeries = chartHighlightAdjacentSeries;
      pointProto2.highlight = pointHighlight;
      seriesProto2.keyboardMoveVertical = true;
      [
        "column",
        "gantt",
        "pie"
      ].forEach((type) => {
        if (seriesTypes$2[type]) {
          seriesTypes$2[type].prototype.keyboardMoveVertical = false;
        }
      });
      seriesProto2.highlightNextValidPoint = seriesHighlightNextValidPoint;
    }
  }
  SeriesKeyboardNavigation2.compose = compose2;
  function getClosestPoint(point, series, xWeight, yWeight) {
    let minDistance = Infinity, dPoint, minIx, distance, i = series.points.length;
    const hasUndefinedPosition = (point2) => !(defined$D(point2.plotX) && defined$D(point2.plotY));
    if (hasUndefinedPosition(point)) {
      return;
    }
    while (i--) {
      dPoint = series.points[i];
      if (hasUndefinedPosition(dPoint)) {
        continue;
      }
      distance = (point.plotX - dPoint.plotX) * (point.plotX - dPoint.plotX) * xWeight + (point.plotY - dPoint.plotY) * (point.plotY - dPoint.plotY) * 1;
      if (distance < minDistance) {
        minDistance = distance;
        minIx = i;
      }
    }
    return defined$D(minIx) ? series.points[minIx] : void 0;
  }
  function pointHighlight(highlightVisually = true) {
    const chart = this.series.chart, tooltipElement = chart.tooltip?.label?.element;
    if ((!this.isNull || this.series.options?.nullInteraction) && highlightVisually) {
      this.onMouseOver();
    } else {
      if (chart.tooltip) {
        chart.tooltip.hide(0);
      }
    }
    scrollAxisToPoint(this);
    if (this.graphic) {
      chart.setFocusToElement(this.graphic);
      if (!highlightVisually && chart.focusElement) {
        chart.focusElement.removeFocusBorder();
      }
    }
    chart.highlightedPoint = this;
    const tooltipTop = tooltipElement?.getBoundingClientRect().top;
    if (tooltipElement && tooltipTop && tooltipTop < 0) {
      const scrollTop = window.scrollY, newScrollTop = scrollTop + tooltipTop;
      window.scrollTo({
        behavior: "smooth",
        top: newScrollTop
      });
    }
    return this;
  }
  function seriesHighlightNextValidPoint() {
    const curPoint = this.chart.highlightedPoint, start2 = (curPoint && curPoint.series) === this ? getPointIndex(curPoint) : 0, points = this.points, len = points.length;
    if (points && len) {
      for (let i = start2; i < len; ++i) {
        if (!isSkipPoint(points[i])) {
          return points[i].highlight();
        }
      }
      for (let j = start2; j >= 0; --j) {
        if (!isSkipPoint(points[j])) {
          return points[j].highlight();
        }
      }
    }
    return false;
  }
})(SeriesKeyboardNavigation || (SeriesKeyboardNavigation = {}));
const SeriesKeyboardNavigation$1 = SeriesKeyboardNavigation;
const { hideSeriesFromAT } = ChartUtilities;
const { describeSeries } = SeriesDescriber;
class SeriesComponent extends AccessibilityComponent {
  /* *
   *
   *  Static Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * @private
   */
  static compose(ChartClass, PointClass, SeriesClass) {
    NewDataAnnouncer$1.compose(SeriesClass);
    ForcedMarkers.compose(SeriesClass);
    SeriesKeyboardNavigation$1.compose(ChartClass, PointClass, SeriesClass);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Init the component.
   */
  init() {
    this.newDataAnnouncer = new NewDataAnnouncer$1(this.chart);
    this.newDataAnnouncer.init();
    this.keyboardNavigation = new SeriesKeyboardNavigation$1(this.chart, this.keyCodes);
    this.keyboardNavigation.init();
    this.hideTooltipFromATWhenShown();
    this.hideSeriesLabelsFromATWhenShown();
  }
  /**
   * @private
   */
  hideTooltipFromATWhenShown() {
    const component = this;
    if (this.chart.tooltip) {
      this.addEvent(this.chart.tooltip.constructor, "refresh", function() {
        if (this.chart === component.chart && this.label && this.label.element) {
          this.label.element.setAttribute("aria-hidden", true);
        }
      });
    }
  }
  /**
   * @private
   */
  hideSeriesLabelsFromATWhenShown() {
    this.addEvent(this.chart, "afterDrawSeriesLabels", function() {
      this.series.forEach(function(series) {
        if (series.labelBySeries) {
          series.labelBySeries.attr("aria-hidden", true);
        }
      });
    });
  }
  /**
   * Called on chart render. It is necessary to do this for render in case
   * markers change on zoom/pixel density.
   */
  onChartRender() {
    const chart = this.chart;
    chart.series.forEach(function(series) {
      const shouldDescribeSeries = (series.options.accessibility && series.options.accessibility.enabled) !== false && series.visible && series.getPointsCollection().length !== 0;
      if (shouldDescribeSeries) {
        describeSeries(series);
      } else {
        hideSeriesFromAT(series);
      }
    });
  }
  /**
   * Get keyboard navigation handler for this component.
   * @private
   */
  getKeyboardNavigation() {
    return this.keyboardNavigation.getKeyboardNavigationHandler();
  }
  /**
   * Remove traces
   * @private
   */
  destroy() {
    this.newDataAnnouncer.destroy();
    this.keyboardNavigation.destroy();
  }
}
const { unhideChartElementFromAT } = ChartUtilities;
const { getFakeMouseEvent } = HTMLUtilities;
const { attr: attr$1, pick: pick$10 } = Utilities;
function chartHasMapZoom(chart) {
  return !!(chart.mapView && chart.mapNavigation && chart.mapNavigation.navButtons.length);
}
class ZoomComponent extends AccessibilityComponent {
  constructor() {
    super(...arguments);
    this.focusedMapNavButtonIx = -1;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the component
   */
  init() {
    const component = this, chart = this.chart;
    this.proxyProvider.addGroup("zoom", "div");
    [
      "afterShowResetZoom",
      "afterApplyDrilldown",
      "drillupall"
    ].forEach((eventType) => {
      component.addEvent(chart, eventType, function() {
        component.updateProxyOverlays();
      });
    });
  }
  /**
   * Called when chart is updated
   */
  onChartUpdate() {
    const chart = this.chart, component = this;
    if (chart.mapNavigation) {
      chart.mapNavigation.navButtons.forEach((button, i) => {
        unhideChartElementFromAT(chart, button.element);
        component.setMapNavButtonAttrs(button.element, "accessibility.zoom.mapZoom" + (i ? "Out" : "In"));
      });
    }
  }
  /**
   * @private
   * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} button
   * @param {string} labelFormatKey
   */
  setMapNavButtonAttrs(button, labelFormatKey) {
    const chart = this.chart, label = chart.langFormat(labelFormatKey, { chart });
    attr$1(button, {
      tabindex: -1,
      role: "button",
      "aria-label": label
    });
  }
  /**
   * Update the proxy overlays on every new render to ensure positions are
   * correct.
   */
  onChartRender() {
    this.updateProxyOverlays();
  }
  /**
   * Update proxy overlays, recreating the buttons.
   */
  updateProxyOverlays() {
    const chart = this.chart;
    this.proxyProvider.clearGroup("zoom");
    if (chart.resetZoomButton) {
      this.createZoomProxyButton(chart.resetZoomButton, "resetZoomProxyButton", chart.langFormat("accessibility.zoom.resetZoomButton", { chart }));
    }
    if (chart.drillUpButton && chart.breadcrumbs && chart.breadcrumbs.list) {
      const lastBreadcrumb = chart.breadcrumbs.list[chart.breadcrumbs.list.length - 1];
      this.createZoomProxyButton(chart.drillUpButton, "drillUpProxyButton", chart.langFormat("accessibility.drillUpButton", {
        chart,
        buttonText: chart.breadcrumbs.getButtonText(lastBreadcrumb)
      }));
    }
  }
  /**
   * @private
   * @param {Highcharts.SVGElement} buttonEl
   * @param {string} buttonProp
   * @param {string} label
   */
  createZoomProxyButton(buttonEl, buttonProp, label) {
    this[buttonProp] = this.proxyProvider.addProxyElement("zoom", {
      click: buttonEl
    }, "button", {
      "aria-label": label,
      tabindex: -1
    });
  }
  /**
   * Get keyboard navigation handler for map zoom.
   * @private
   * @return {Highcharts.KeyboardNavigationHandler} The module object
   */
  getMapZoomNavigation() {
    const keys = this.keyCodes, chart = this.chart, component = this;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [
        [
          [keys.up, keys.down, keys.left, keys.right],
          function(keyCode) {
            return component.onMapKbdArrow(this, keyCode);
          }
        ],
        [
          [keys.tab],
          function(_keyCode, e) {
            return component.onMapKbdTab(this, e);
          }
        ],
        [
          [keys.space, keys.enter],
          function() {
            return component.onMapKbdClick(this);
          }
        ]
      ],
      validate: function() {
        return chartHasMapZoom(chart);
      },
      init: function(direction) {
        return component.onMapNavInit(direction);
      }
    });
  }
  /**
   * Arrow key panning for maps.
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler The handler context.
   * @param {number} keyCode Key pressed.
   * @return {number} Response code
   */
  onMapKbdArrow(keyboardNavigationHandler, keyCode) {
    const chart = this.chart, keys = this.keyCodes, target = chart.container, isY = keyCode === keys.up || keyCode === keys.down, stepDirection = keyCode === keys.left || keyCode === keys.up ? 1 : -1, granularity = 10, diff = (isY ? chart.plotHeight : chart.plotWidth) / granularity * stepDirection, r = Math.random() * 10, startPos = {
      x: target.offsetLeft + chart.plotLeft + chart.plotWidth / 2 + r,
      y: target.offsetTop + chart.plotTop + chart.plotHeight / 2 + r
    }, endPos = isY ? { x: startPos.x, y: startPos.y + diff } : { x: startPos.x + diff, y: startPos.y };
    [
      getFakeMouseEvent("mousedown", startPos),
      getFakeMouseEvent("mousemove", endPos),
      getFakeMouseEvent("mouseup", endPos)
    ].forEach((e) => target.dispatchEvent(e));
    return keyboardNavigationHandler.response.success;
  }
  /**
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler
   * @param {global.KeyboardEvent} event
   * @return {number} Response code
   */
  onMapKbdTab(keyboardNavigationHandler, event) {
    const chart = this.chart;
    const response = keyboardNavigationHandler.response;
    const isBackwards = event.shiftKey;
    const isMoveOutOfRange = isBackwards && !this.focusedMapNavButtonIx || !isBackwards && this.focusedMapNavButtonIx;
    chart.mapNavigation.navButtons[this.focusedMapNavButtonIx].setState(0);
    if (isMoveOutOfRange) {
      if (chart.mapView) {
        chart.mapView.zoomBy();
      }
      return response[isBackwards ? "prev" : "next"];
    }
    this.focusedMapNavButtonIx += isBackwards ? -1 : 1;
    const button = chart.mapNavigation.navButtons[this.focusedMapNavButtonIx];
    chart.setFocusToElement(button.box, button.element);
    button.setState(2);
    return response.success;
  }
  /**
   * Called on map button click.
   * @private
   * @param {Highcharts.KeyboardNavigationHandler} keyboardNavigationHandler The handler context object
   * @return {number} Response code
   */
  onMapKbdClick(keyboardNavigationHandler) {
    const el = this.chart.mapNavigation.navButtons[this.focusedMapNavButtonIx].element;
    this.fakeClickEvent(el);
    return keyboardNavigationHandler.response.success;
  }
  /**
   * @private
   * @param {number} direction
   */
  onMapNavInit(direction) {
    const chart = this.chart, zoomIn = chart.mapNavigation.navButtons[0], zoomOut = chart.mapNavigation.navButtons[1], initialButton = direction > 0 ? zoomIn : zoomOut;
    chart.setFocusToElement(initialButton.box, initialButton.element);
    initialButton.setState(2);
    this.focusedMapNavButtonIx = direction > 0 ? 0 : 1;
  }
  /**
   * Get keyboard navigation handler for a simple chart button. Provide the
   * button reference for the chart, and a function to call on click.
   *
   * @private
   * @param {string} buttonProp The property on chart referencing the button.
   * @return {Highcharts.KeyboardNavigationHandler} The module object
   */
  simpleButtonNavigation(buttonProp, proxyProp, onClick) {
    const keys = this.keyCodes, component = this, chart = this.chart;
    return new KeyboardNavigationHandler(chart, {
      keyCodeMap: [
        [
          [keys.tab, keys.up, keys.down, keys.left, keys.right],
          function(keyCode, e) {
            const isBackwards = keyCode === keys.tab && e.shiftKey || keyCode === keys.left || keyCode === keys.up;
            return this.response[isBackwards ? "prev" : "next"];
          }
        ],
        [
          [keys.space, keys.enter],
          function() {
            const res = onClick(this, chart);
            return pick$10(res, this.response.success);
          }
        ]
      ],
      validate: function() {
        const hasButton = chart[buttonProp] && chart[buttonProp].box && component[proxyProp].innerElement;
        return hasButton;
      },
      init: function() {
        chart.setFocusToElement(chart[buttonProp].box, component[proxyProp].innerElement);
      }
    });
  }
  /**
   * Get keyboard navigation handlers for this component.
   * @return {Array<Highcharts.KeyboardNavigationHandler>}
   *         List of module objects
   */
  getKeyboardNavigation() {
    return [
      this.simpleButtonNavigation("resetZoomButton", "resetZoomProxyButton", function(_handler, chart) {
        chart.zoomOut();
      }),
      this.simpleButtonNavigation("drillUpButton", "drillUpProxyButton", function(handler, chart) {
        chart.drillUp();
        return handler.response.prev;
      }),
      this.getMapZoomNavigation()
    ];
  }
}
const { doc: doc$b, isMS, win: win$4 } = Highcharts;
function isHighContrastModeActive() {
  const isEdge = /(Edg)/.test(win$4.navigator.userAgent);
  if (win$4.matchMedia && isEdge) {
    return win$4.matchMedia("(-ms-high-contrast: active)").matches;
  }
  if (isMS && win$4.getComputedStyle) {
    const testDiv = doc$b.createElement("div");
    const imageSrc = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
    testDiv.style.backgroundImage = `url(${imageSrc})`;
    doc$b.body.appendChild(testDiv);
    const bi = (testDiv.currentStyle || win$4.getComputedStyle(testDiv)).backgroundImage;
    doc$b.body.removeChild(testDiv);
    return bi === "none";
  }
  return win$4.matchMedia && win$4.matchMedia("(forced-colors: active)").matches;
}
function setHighContrastTheme(chart) {
  chart.highContrastModeActive = true;
  const theme2 = chart.options.accessibility.highContrastTheme;
  chart.update(theme2, false);
  const hasCustomColors = theme2.colors?.length > 1;
  chart.series.forEach(function(s) {
    const plotOpts = theme2.plotOptions[s.type] || {};
    const fillColor = hasCustomColors && s.colorIndex !== void 0 ? theme2.colors[s.colorIndex] : plotOpts.color || "window";
    const seriesOptions = {
      color: plotOpts.color || "windowText",
      colors: hasCustomColors ? theme2.colors : [plotOpts.color || "windowText"],
      borderColor: plotOpts.borderColor || "window",
      fillColor
    };
    s.update(seriesOptions, false);
    if (s.points) {
      s.points.forEach(function(p) {
        if (p.options && p.options.color) {
          p.update({
            color: plotOpts.color || "windowText",
            borderColor: plotOpts.borderColor || "window"
          }, false);
        }
      });
    }
  });
  chart.redraw();
}
const whcm = {
  isHighContrastModeActive,
  setHighContrastTheme
};
const theme = {
  chart: {
    backgroundColor: "window"
  },
  title: {
    style: {
      color: "windowText"
    }
  },
  subtitle: {
    style: {
      color: "windowText"
    }
  },
  colorAxis: {
    minColor: "windowText",
    maxColor: "windowText",
    stops: [],
    dataClasses: []
  },
  colors: ["windowText"],
  xAxis: {
    gridLineColor: "windowText",
    labels: {
      style: {
        color: "windowText"
      }
    },
    lineColor: "windowText",
    minorGridLineColor: "windowText",
    tickColor: "windowText",
    title: {
      style: {
        color: "windowText"
      }
    }
  },
  yAxis: {
    gridLineColor: "windowText",
    labels: {
      style: {
        color: "windowText"
      }
    },
    lineColor: "windowText",
    minorGridLineColor: "windowText",
    tickColor: "windowText",
    title: {
      style: {
        color: "windowText"
      }
    }
  },
  tooltip: {
    backgroundColor: "window",
    borderColor: "windowText",
    style: {
      color: "windowText"
    }
  },
  plotOptions: {
    series: {
      lineColor: "windowText",
      fillColor: "window",
      borderColor: "windowText",
      edgeColor: "windowText",
      borderWidth: 1,
      dataLabels: {
        connectorColor: "windowText",
        color: "windowText",
        style: {
          color: "windowText",
          textOutline: "none"
        }
      },
      marker: {
        lineColor: "windowText",
        fillColor: "windowText"
      }
    },
    pie: {
      color: "window",
      colors: ["window"],
      borderColor: "windowText",
      borderWidth: 1
    },
    boxplot: {
      fillColor: "window"
    },
    candlestick: {
      lineColor: "windowText",
      fillColor: "window"
    },
    errorbar: {
      fillColor: "window"
    }
  },
  legend: {
    backgroundColor: "window",
    itemStyle: {
      color: "windowText"
    },
    itemHoverStyle: {
      color: "windowText"
    },
    itemHiddenStyle: {
      color: "#555"
    },
    title: {
      style: {
        color: "windowText"
      }
    }
  },
  credits: {
    style: {
      color: "windowText"
    }
  },
  drilldown: {
    activeAxisLabelStyle: {
      color: "windowText"
    },
    activeDataLabelStyle: {
      color: "windowText"
    }
  },
  navigation: {
    buttonOptions: {
      symbolStroke: "windowText",
      theme: {
        fill: "window"
      }
    }
  },
  rangeSelector: {
    buttonTheme: {
      fill: "window",
      stroke: "windowText",
      style: {
        color: "windowText"
      },
      states: {
        hover: {
          fill: "window",
          stroke: "windowText",
          style: {
            color: "windowText"
          }
        },
        select: {
          fill: "#444",
          stroke: "windowText",
          style: {
            color: "windowText"
          }
        }
      }
    },
    inputBoxBorderColor: "windowText",
    inputStyle: {
      backgroundColor: "window",
      color: "windowText"
    },
    labelStyle: {
      color: "windowText"
    }
  },
  navigator: {
    handles: {
      backgroundColor: "window",
      borderColor: "windowText"
    },
    outlineColor: "windowText",
    maskFill: "transparent",
    series: {
      color: "windowText",
      lineColor: "windowText"
    },
    xAxis: {
      gridLineColor: "windowText"
    }
  },
  scrollbar: {
    barBackgroundColor: "#444",
    barBorderColor: "windowText",
    buttonArrowColor: "windowText",
    buttonBackgroundColor: "window",
    buttonBorderColor: "windowText",
    rifleColor: "windowText",
    trackBackgroundColor: "window",
    trackBorderColor: "windowText"
  }
};
const Options = {
  /**
   * Options for configuring accessibility for the chart. Requires the
   * [accessibility module](https://code.highcharts.com/modules/accessibility.js)
   * to be loaded. For a description of the module and information
   * on its features, see
   * [Highcharts Accessibility](https://www.highcharts.com/docs/accessibility/accessibility-module).
   *
   * @since        5.0.0
   * @requires     modules/accessibility
   * @optionparent accessibility
   */
  accessibility: {
    /**
     * Enable accessibility functionality for the chart. For more
     * information on how to include these features, and why this is
     * recommended, see [Highcharts Accessibility](https://www.highcharts.com/docs/accessibility/accessibility-module).
     *
     * Highcharts will by default emit a warning to the console if
     * the [accessibility module](https://code.highcharts.com/modules/accessibility.js)
     * is not loaded. Setting this option to `false` will override
     * and silence the warning.
     *
     * Once the module is loaded, setting this option to `false`
     * will disable the module for this chart.
     *
     * @since 5.0.0
     */
    enabled: true,
    /**
     * Accessibility options for the screen reader information sections
     * added before and after the chart.
     *
     * @since 8.0.0
     */
    screenReaderSection: {
      /**
       * Function to run upon clicking the "View as Data Table" link in
       * the screen reader region.
       *
       * By default Highcharts will insert and set focus to a data table
       * representation of the chart.
       *
       * @type      {Highcharts.ScreenReaderClickCallbackFunction}
       * @since 8.0.0
       * @apioption accessibility.screenReaderSection.onViewDataTableClick
       */
      /**
       * Function to run upon clicking the "Play as sound" button in
       * the screen reader region.
       *
       * By default Highcharts will call the `chart.sonify` function.
       *
       * @type      {Highcharts.ScreenReaderClickCallbackFunction}
       * @since 8.0.1
       * @apioption accessibility.screenReaderSection.onPlayAsSoundClick
       */
      /**
       * A formatter function to create the HTML contents of the hidden
       * screen reader information region before the chart. Receives one
       * argument, `chart`, referring to the chart object. Should return a
       * string with the HTML content of the region. By default this
       * returns an automatic description of the chart based on
       * [beforeChartFormat](#accessibility.screenReaderSection.beforeChartFormat).
       *
       * @type      {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Chart>}
       * @since 8.0.0
       * @apioption accessibility.screenReaderSection.beforeChartFormatter
       */
      /**
       * Format for the screen reader information region before the chart.
       * Supported HTML tags are `<h1-6>`, `<p>`, `<div>`, `<a>`, `<ul>`,
       * `<ol>`, `<li>`, and `<button>`. Attributes are not supported,
       * except for id on `<div>`, `<a>`, and `<button>`. Id is required
       * on `<a>` and `<button>` in the format `<tag id="abcd">`. Numbers,
       * lower- and uppercase letters, "-" and "#" are valid characters in
       * IDs.
       *
       * The headingTagName is an auto-detected heading (h1-h6) that
       * corresponds to the heading level below the previous heading in
       * the DOM.
       *
       * Set to empty string to remove the region altogether.
       *
       * @since 8.0.0
       */
      beforeChartFormat: "<{headingTagName}>{chartTitle}</{headingTagName}><div>{typeDescription}</div><div>{chartSubtitle}</div><div>{chartLongdesc}</div><div>{playAsSoundButton}</div><div>{viewTableButton}</div><div>{xAxisDescription}</div><div>{yAxisDescription}</div><div>{annotationsTitle}{annotationsList}</div>",
      /**
       * A formatter function to create the HTML contents of the hidden
       * screen reader information region after the chart. Analogous to
       * [beforeChartFormatter](#accessibility.screenReaderSection.beforeChartFormatter).
       *
       * @type      {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Chart>}
       * @since 8.0.0
       * @apioption accessibility.screenReaderSection.afterChartFormatter
       */
      /**
       * Format for the screen reader information region after the chart.
       * Analogous to [beforeChartFormat](#accessibility.screenReaderSection.beforeChartFormat).
       *
       * @since 8.0.0
       */
      afterChartFormat: "{endOfChartMarker}",
      /**
       * Date format to use to describe range of datetime axes.
       *
       * For an overview of the replacement codes, see
       * [dateFormat](/class-reference/Highcharts.Time#dateFormat).
       *
       * @see [point.dateFormat](#accessibility.point.dateFormat)
       *
       * @since 8.0.0
       */
      axisRangeDateFormat: "%Y-%m-%d %H:%M:%S"
    },
    /**
     * Accessibility options global to all data series. Individual series
     * can also have specific [accessibility options](#plotOptions.series.accessibility)
     * set.
     *
     * @since 8.0.0
     */
    series: {
      /**
       * Formatter function to use instead of the default for series
       * descriptions. Receives one argument, `series`, referring to the
       * series to describe. Should return a string with the description
       * of the series for a screen reader user. If `false` is returned,
       * the default formatter will be used for that series.
       *
       * @see [series.descriptionFormat](#accessibility.series.descriptionFormat)
       * @see [series.description](#plotOptions.series.description)
       *
       * @type      {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Series>}
       * @since 8.0.0
       * @apioption accessibility.series.descriptionFormatter
       */
      /**
       * Format to use for describing the data series group to assistive
       * technology - including screen readers.
       *
       * The series context and its subproperties are available under the
       * variable `{series}`, for example `{series.name}` for the series
       * name, and `{series.points.length}` for the number of data points.
       *
       * The chart context and its subproperties are available under the
       * variable `{chart}`, for example `{chart.series.length}` for the
       * number of series in the chart.
       *
       * `{seriesDescription}` refers to the automatic description of the
       * series type and number of points added by Highcharts by default.
       * `{authorDescription}` refers to the description added in
       * [series.description](#plotOptions.series.description) if one is
       * present. `{axisDescription}` refers to the description added if
       * the chart has multiple X or Y axes.
       *
       * Note that if [series.descriptionFormatter](#accessibility.series.descriptionFormatter)
       * is declared it will take precedence, and this option will be
       * overridden.
       *
       * @sample highcharts/accessibility/advanced-accessible
       *  Accessible low-medium-high chart
       *
       * @type      {string}
       * @since 10.1.0
       */
      descriptionFormat: "{seriesDescription}{authorDescription}{axisDescription}",
      /**
       * Whether or not to add series descriptions to charts with a single
       * series.
       *
       * @since 8.0.0
       */
      describeSingleSeries: false,
      /**
       * When a series contains more points than this, we no longer expose
       * information about individual points to screen readers.
       * Note that the keyboard navigation remains functional, but points
       * won't have accessible descriptions unless handled separately.
       *
       * Set to `false` to disable.
       *
       * @type  {boolean|number}
       * @since 8.0.0
       */
      pointDescriptionEnabledThreshold: 200
    },
    /**
     * Options for descriptions of individual data points.
     *
     * @since 8.0.0
     */
    point: {
      /**
       * Date format to use for points on datetime axes when describing
       * them to screen reader users.
       *
       * Defaults to the same format as in tooltip.
       *
       * For an overview of the replacement codes, see
       * [dateFormat](/class-reference/Highcharts.Time#dateFormat).
       *
       * @see [dateFormatter](#accessibility.point.dateFormatter)
       *
       * @type      {string}
       * @since 8.0.0
       * @apioption accessibility.point.dateFormat
       */
      /**
       * Formatter function to determine the date/time format used with
       * points on datetime axes when describing them to screen reader
       * users. Receives one argument, `point`, referring to the point
       * to describe. Should return a date format string compatible with
       * [dateFormat](/class-reference/Highcharts.Time#dateFormat).
       *
       * @see [dateFormat](#accessibility.point.dateFormat)
       *
       * @type      {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Point>}
       * @since 8.0.0
       * @apioption accessibility.point.dateFormatter
       */
      /**
       * Prefix to add to the values in the point descriptions. Uses
       * [tooltip.valuePrefix](#tooltip.valuePrefix) if not defined.
       *
       * @type        {string}
       * @since 8.0.0
       * @apioption   accessibility.point.valuePrefix
       */
      /**
       * Suffix to add to the values in the point descriptions. Uses
       * [tooltip.valueSuffix](#tooltip.valueSuffix) if not defined.
       *
       * @type        {string}
       * @since 8.0.0
       * @apioption   accessibility.point.valueSuffix
       */
      /**
       * Decimals to use for the values in the point descriptions. Uses
       * [tooltip.valueDecimals](#tooltip.valueDecimals) if not defined.
       *
       * @type        {number}
       * @since 8.0.0
       * @apioption   accessibility.point.valueDecimals
       */
      /**
       * A [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
       * to use instead of the default for point descriptions.
       *
       * The context of the format string is the point instance.
       *
       * As opposed to [accessibility.point.valueDescriptionFormat](#accessibility.point.valueDescriptionFormat),
       * this option replaces the whole description.
       *
       * @type      {string}
       * @since 11.1.0
       * @sample highcharts/demo/advanced-accessible
       *      Description format
       * @apioption accessibility.point.descriptionFormat
       */
      /**
       * Formatter function to use instead of the default for point
       * descriptions.
       *
       * Receives one argument, `point`, referring to the point to
       * describe. Should return a string with the description of the
       * point for a screen reader user. If `false` is returned, the
       * default formatter will be used for that point.
       *
       * Note: Prefer using [accessibility.point.valueDescriptionFormat](#accessibility.point.valueDescriptionFormat)
       * instead if possible, as default functionality such as describing
       * annotations will be preserved.
       *
       * @see [accessibility.point.valueDescriptionFormat](#accessibility.point.valueDescriptionFormat)
       * @see [point.accessibility.description](#series.line.data.accessibility.description)
       *
       * @type      {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Point>}
       * @since 8.0.0
       * @apioption accessibility.point.descriptionFormatter
       */
      /**
       * Format to use for describing the values of data points
       * to assistive technology - including screen readers.
       * The point context is available as `{point}`.
       *
       * Other available context variables include `{index}`, `{value}`, and `{xDescription}`.
       *
       * Additionally, the series name, annotation info, and
       * description added in `point.accessibility.description`
       * is added by default if relevant. To override this, use the
       * [accessibility.point.descriptionFormatter](#accessibility.point.descriptionFormatter)
       * option.
       *
       * @see [point.accessibility.description](#series.line.data.accessibility.description)
       * @see [accessibility.point.descriptionFormatter](#accessibility.point.descriptionFormatter)
       *
       * @type      {string}
       * @since 8.0.1
       */
      valueDescriptionFormat: "{xDescription}{separator}{value}.",
      /**
       * Whether or not to describe points with the value `null` to
       * assistive technology, such as screen readers.
       *
       * @sample {highmaps} maps/demo/all-areas-as-null
       *         Accessible map with null points
       *
       * @type      {boolean}
       * @since 10.1.0
       */
      describeNull: true
    },
    /**
     * Amount of landmarks/regions to create for screen reader users. More
     * landmarks can make navigation with screen readers easier, but can
     * be distracting if there are lots of charts on the page. Three modes
     * are available:
     *  - `all`: Adds regions for all series, legend, information
     *      region.
     *  - `one`: Adds a single landmark per chart.
     *  - `disabled`: No landmarks are added.
     *
     * @since 7.1.0
     * @validvalue ["all", "one", "disabled"]
     */
    landmarkVerbosity: "all",
    /**
     * Link the chart to an HTML element describing the contents of the
     * chart.
     *
     * It is always recommended to describe charts using visible text, to
     * improve SEO as well as accessibility for users with disabilities.
     * This option lets an HTML element with a description be linked to the
     * chart, so that screen reader users can connect the two.
     *
     * By setting this option to a string, Highcharts runs the string as an
     * HTML selector query on the entire document. If there is only a single
     * match, this element is linked to the chart. The content of the linked
     * element will be included in the chart description for screen reader
     * users.
     *
     * By default, the chart looks for an adjacent sibling element with the
     * `highcharts-description` class.
     *
     * The feature can be disabled by setting the option to an empty string,
     * or overridden by providing the
     * [accessibility.description](#accessibility.description) option.
     * Alternatively, the HTML element to link can be passed in directly as
     * an HTML node.
     *
     * If you need the description to be part of the exported image,
     * consider using the [caption](#caption) feature.
     *
     * If you need the description to be hidden visually, use the
     * [accessibility.description](#accessibility.description) option.
     *
     * @see [caption](#caption)
     * @see [description](#accessibility.description)
     * @see [typeDescription](#accessibility.typeDescription)
     *
     * @sample highcharts/accessibility/accessible-line
     *         Accessible line chart
     *
     * @type  {string|Highcharts.HTMLDOMElement}
     * @since 8.0.0
     */
    linkedDescription: '*[data-highcharts-chart="{index}"] + .highcharts-description',
    // eslint-disable-line
    /**
     * A hook for adding custom components to the accessibility module.
     * Should be an object mapping component names to instances of classes
     * inheriting from the Highcharts.AccessibilityComponent base class.
     * Remember to add the component to the
     * [keyboardNavigation.order](#accessibility.keyboardNavigation.order)
     * for the keyboard navigation to be usable.
     *
     * @sample highcharts/accessibility/custom-component
     *         Custom accessibility component
     *
     * @type      {*}
     * @since     7.1.0
     * @apioption accessibility.customComponents
     */
    /**
     * Theme to apply to the chart when Windows High Contrast Mode is
     * detected. By default, a high contrast theme matching the high
     * contrast system colors is used.
     *
     * @type      {*}
     * @since     7.1.3
     * @apioption accessibility.highContrastTheme
     */
    /**
     * Controls how [highContrastTheme](#accessibility.highContrastTheme)
     * is applied.
     *
     * The default option is `auto`, which applies the high contrast theme
     * the user's system has a high contrast theme active.
     *
     * @since 11.4.0
     */
    highContrastMode: "auto",
    /**
     * A text description of the chart.
     *
     * **Note: Prefer using [linkedDescription](#accessibility.linkedDescription)
     * or [caption](#caption.text) instead.**
     *
     * If the Accessibility module is loaded, this option is included by
     * default as a long description of the chart in the hidden screen
     * reader information region.
     *
     * Note: Since Highcharts now supports captions and linked descriptions,
     * it is preferred to define the description using those methods, as a
     * visible caption/description benefits all users. If the
     * `accessibility.description` option is defined, the linked description
     * is ignored, and the caption is hidden from screen reader users.
     *
     * @see [linkedDescription](#accessibility.linkedDescription)
     * @see [caption](#caption)
     * @see [typeDescription](#accessibility.typeDescription)
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption accessibility.description
     */
    /**
     * A text description of the chart type.
     *
     * If the Accessibility module is loaded, this will be included in the
     * description of the chart in the screen reader information region.
     *
     * Highcharts will by default attempt to guess the chart type, but for
     * more complex charts it is recommended to specify this property for
     * clarity.
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption accessibility.typeDescription
     */
    /**
     * Options for keyboard navigation.
     *
     * @declare Highcharts.KeyboardNavigationOptionsObject
     * @since   5.0.0
     */
    keyboardNavigation: {
      /**
       * Enable keyboard navigation for the chart.
       *
       * @since 5.0.0
       */
      enabled: true,
      /**
       * Options for the focus border drawn around elements while
       * navigating through them.
       *
       * @sample highcharts/accessibility/custom-focus
       *         Custom focus ring
       *
       * @declare Highcharts.KeyboardNavigationFocusBorderOptionsObject
       * @since   6.0.3
       */
      focusBorder: {
        /**
         * Enable/disable focus border for chart.
         *
         * @since 6.0.3
         */
        enabled: true,
        /**
         * Hide the browser's default focus indicator.
         *
         * @since 6.0.4
         */
        hideBrowserFocusOutline: true,
        /**
         * Style options for the focus border drawn around elements
         * while navigating through them. Note that some browsers in
         * addition draw their own borders for focused elements. These
         * automatic borders cannot be styled by Highcharts.
         *
         * In styled mode, the border is given the
         * `.highcharts-focus-border` class.
         *
         * @type    {Highcharts.CSSObject}
         * @since   6.0.3
         */
        style: {
          /** @internal */
          color: "#334eff",
          /** @internal */
          lineWidth: 2,
          /** @internal */
          borderRadius: 3
        },
        /**
         * Focus border margin around the elements.
         *
         * @since 6.0.3
         */
        margin: 2
      },
      /**
       * Order of tab navigation in the chart. Determines which elements
       * are tabbed to first. Available elements are: `series`, `zoom`,
       * `rangeSelector`, `navigator`, `chartMenu`, `legend` and `container`.
       * In addition, any custom components can be added here. Adding
       * `container` first in order will make the keyboard focus stop on
       * the chart container first, requiring the user to tab again to
       * enter the chart.
       *
       * @type  {Array<string>}
       * @since 7.1.0
       */
      order: [
        "series",
        "zoom",
        "rangeSelector",
        "navigator",
        "legend",
        "chartMenu"
      ],
      /**
       * Whether or not to wrap around when reaching the end of arrow-key
       * navigation for an element in the chart.
       * @since 7.1.0
       */
      wrapAround: true,
      /**
       * Options for the keyboard navigation of data points and series.
       *
       * @declare Highcharts.KeyboardNavigationSeriesNavigationOptionsObject
       * @since 8.0.0
       */
      seriesNavigation: {
        /**
         * Set the keyboard navigation mode for the chart. Can be
         * "normal" or "serialize". In normal mode, left/right arrow
         * keys move between points in a series, while up/down arrow
         * keys move between series. Up/down navigation acts
         * intelligently to figure out which series makes sense to move
         * to from any given point.
         *
         * In "serialize" mode, points are instead navigated as a single
         * list. Left/right behaves as in "normal" mode. Up/down arrow
         * keys will behave like left/right. This can be useful for
         * unifying navigation behavior with/without screen readers
         * enabled.
         *
         * @type       {string}
         * @default    normal
         * @since 8.0.0
         * @validvalue ["normal", "serialize"]
         * @apioption  accessibility.keyboardNavigation.seriesNavigation.mode
         */
        /**
         * Skip null points when navigating through points with the
         * keyboard. By default this is the opposite of
         * [series.nullInteraction](https://api.highcharts.com/highcharts/plotOptions.series.nullInteraction).
         *
         * @since 8.0.0
         */
        skipNullPoints: void 0,
        /**
         * When a series contains more points than this, we no longer
         * allow keyboard navigation for it.
         *
         * Set to `false` to disable.
         *
         * @type  {boolean|number}
         * @since 8.0.0
         */
        pointNavigationEnabledThreshold: false,
        /**
         * Remember which point was focused even after navigating away
         * from the series, so that when navigating back to the series
         * you start at the last focused point.
         *
         * @type  {boolean}
         * @since 10.1.0
         */
        rememberPointFocus: false
      }
    },
    /**
     * Options for announcing new data to screen reader users. Useful
     * for dynamic data applications and drilldown.
     *
     * Keep in mind that frequent announcements will not be useful to
     * users, as they won't have time to explore the new data. For these
     * applications, consider making snapshots of the data accessible, and
     * do the announcements in batches.
     *
     * @declare Highcharts.AccessibilityAnnounceNewDataOptionsObject
     * @since   7.1.0
     */
    announceNewData: {
      /**
       * Optional formatter callback for the announcement. Receives
       * up to three arguments. The first argument is always an array
       * of all series that received updates. If an announcement is
       * already queued, the series that received updates for that
       * announcement are also included in this array. The second
       * argument is provided if `chart.addSeries` was called, and
       * there is a new series. In that case, this argument is a
       * reference to the new series. The third argument, similarly,
       * is provided if `series.addPoint` was called, and there is a
       * new point. In that case, this argument is a reference to the
       * new point.
       *
       * The function should return a string with the text to announce
       * to the user. Return empty string to not announce anything.
       * Return `false` to use the default announcement format.
       *
       * @sample highcharts/accessibility/custom-dynamic
       *         High priority live alerts
       *
       * @type      {Highcharts.AccessibilityAnnouncementFormatter}
       * @apioption accessibility.announceNewData.announcementFormatter
       */
      /**
       * Enable announcing new data to screen reader users
       * @sample highcharts/accessibility/accessible-dynamic
       *         Dynamic data accessible
       */
      enabled: false,
      /**
       * Minimum interval between announcements in milliseconds. If
       * new data arrives before this amount of time has passed, it is
       * queued for announcement. If another new data event happens
       * while an announcement is queued, the queued announcement is
       * dropped, and the latest announcement is queued instead. Set
       * to 0 to allow all announcements, but be warned that frequent
       * announcements are disturbing to users.
       */
      minAnnounceInterval: 5e3,
      /**
       * Choose whether or not the announcements should interrupt the
       * screen reader. If not enabled, the user will be notified once
       * idle. It is recommended not to enable this setting unless
       * there is a specific reason to do so.
       */
      interruptUser: false
    }
  },
  /**
   * Accessibility options for a data point.
   *
   * @declare   Highcharts.PointAccessibilityOptionsObject
   * @since     7.1.0
   * @apioption series.line.data.accessibility
   */
  /**
   * Provide a description of the data point, announced to screen readers.
   *
   * @type      {string}
   * @since     7.1.0
   * @apioption series.line.data.accessibility.description
   */
  /**
   * Set to false to disable accessibility functionality for a specific point.
   * The point will not be included in keyboard navigation, and will not be
   * exposed to assistive technology.
   *
   * @type      {boolean}
   * @since 9.0.1
   * @apioption series.line.data.accessibility.enabled
   */
  /**
   * Accessibility options for a series.
   *
   * @declare    Highcharts.SeriesAccessibilityOptionsObject
   * @since      7.1.0
   * @requires   modules/accessibility
   * @apioption  plotOptions.series.accessibility
   */
  /**
   * Enable/disable accessibility functionality for a specific series.
   *
   * @type       {boolean}
   * @since      7.1.0
   * @apioption  plotOptions.series.accessibility.enabled
   */
  /**
   * Provide a description of the series, announced to screen readers.
   *
   * @type       {string}
   * @since      7.1.0
   * @apioption  plotOptions.series.accessibility.description
   */
  /**
   * Format to use for describing the data series group to assistive
   * technology - including screen readers.
   *
   * @see [series.descriptionFormat](#accessibility.series.descriptionFormat)
   * @type       {string}
   * @since 11.0.0
   * @apioption  plotOptions.series.accessibility.descriptionFormat
   */
  /**
   * Expose only the series element to screen readers, not its points.
   *
   * @type       {boolean}
   * @since      7.1.0
   * @apioption  plotOptions.series.accessibility.exposeAsGroupOnly
   */
  /**
   * Point accessibility options for a series.
   *
   * @extends    accessibility.point
   * @since 9.3.0
   * @requires   modules/accessibility
   * @apioption  plotOptions.series.accessibility.point
   */
  /**
   * Formatter function to use instead of the default for point
   * descriptions. Same as `accessibility.point.descriptionFormatter`, but
   * applies to a series instead of the whole chart.
   *
   * Note: Prefer using [accessibility.point.valueDescriptionFormat](#plotOptions.series.accessibility.point.valueDescriptionFormat)
   * instead if possible, as default functionality such as describing
   * annotations will be preserved.
   *
   * @see [accessibility.point.valueDescriptionFormat](#plotOptions.series.accessibility.point.valueDescriptionFormat)
   * @see [point.accessibility.description](#series.line.data.accessibility.description)
   * @see [accessibility.point.descriptionFormatter](#accessibility.point.descriptionFormatter)
   *
   * @type      {Highcharts.ScreenReaderFormatterCallbackFunction<Highcharts.Point>}
   * @since 9.3.0
   * @apioption plotOptions.series.accessibility.point.descriptionFormatter
   */
  /**
   * Keyboard navigation for a series
   *
   * @declare    Highcharts.SeriesAccessibilityKeyboardNavigationOptionsObject
   * @since      7.1.0
   * @apioption  plotOptions.series.accessibility.keyboardNavigation
   */
  /**
   * Enable/disable keyboard navigation support for a specific series.
   *
   * @type       {boolean}
   * @since      7.1.0
   * @apioption  plotOptions.series.accessibility.keyboardNavigation.enabled
   */
  /**
   * Accessibility options for an annotation label.
   *
   * @declare    Highcharts.AnnotationLabelAccessibilityOptionsObject
   * @since 8.0.1
   * @requires   modules/accessibility
   * @apioption  annotations.labelOptions.accessibility
   */
  /**
   * Description of an annotation label for screen readers and other assistive
   * technology.
   *
   * @type       {string}
   * @since 8.0.1
   * @apioption  annotations.labelOptions.accessibility.description
   */
  /**
   * Accessibility options for an axis. Requires the accessibility module.
   *
   * @declare    Highcharts.AxisAccessibilityOptionsObject
   * @since      7.1.0
   * @requires   modules/accessibility
   * @apioption  xAxis.accessibility
   */
  /**
   * Enable axis accessibility features, including axis information in the
   * screen reader information region. If this is disabled on the xAxis, the
   * x values are not exposed to screen readers for the individual data points
   * by default.
   *
   * @type       {boolean}
   * @since      7.1.0
   * @apioption  xAxis.accessibility.enabled
   */
  /**
   * Description for an axis to expose to screen reader users.
   *
   * @type       {string}
   * @since      7.1.0
   * @apioption  xAxis.accessibility.description
   */
  /**
   * Range description for an axis. Overrides the default range description.
   * Set to empty to disable range description for this axis.
   *
   * @type       {string}
   * @since      7.1.0
   * @apioption  xAxis.accessibility.rangeDescription
   */
  /**
   * @optionparent legend
   */
  legend: {
    /**
     * Accessibility options for the legend. Requires the Accessibility
     * module.
     *
     * @since     7.1.0
     * @requires  modules/accessibility
     */
    accessibility: {
      /**
       * Enable accessibility support for the legend.
       *
       * @since  7.1.0
       */
      enabled: true,
      /**
       * Options for keyboard navigation for the legend.
       *
       * @since     7.1.0
       * @requires  modules/accessibility
       */
      keyboardNavigation: {
        /**
         * Enable keyboard navigation for the legend.
         *
         * @see [accessibility.keyboardNavigation](#accessibility.keyboardNavigation.enabled)
         *
         * @since  7.1.0
         */
        enabled: true
      }
    }
  },
  /**
   * @optionparent exporting
   */
  exporting: {
    /**
     * Accessibility options for the exporting menu. Requires the
     * Accessibility module.
     *
     * @since    7.1.0
     * @requires modules/accessibility
     */
    accessibility: {
      /**
       * Enable accessibility support for the export menu.
       *
       * @since 7.1.0
       */
      enabled: true
    }
  },
  /**
   * @optionparent navigator
   */
  navigator: {
    /**
     * Accessibility options for the navigator. Requires the
     * Accessibility module.
     *
     * @since 11.2.0
     * @requires modules/accessibility
     */
    accessibility: {
      /**
       * Enable accessibility support for the navigator.
       *
       * @since 11.2.0
       */
      enabled: true
    }
  }
};
const langOptions = {
  /**
   * Configure the accessibility strings in the chart. Requires the
   * [accessibility module](https://code.highcharts.com/modules/accessibility.js)
   * to be loaded. For a description of the module and information on its
   * features, see
   * [Highcharts Accessibility](https://www.highcharts.com/docs/chart-concepts/accessibility).
   *
   * The lang options use [Format Strings](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#format-strings)
   * with variables that are replaced at run time. These variables should be
   * used when available, to avoid duplicating text that is defined elsewhere.
   *
   * For more dynamic control over the accessibility functionality, see
   * [accessibility.point.descriptionFormatter](#accessibility.point.descriptionFormatter),
   * [accessibility.series.descriptionFormatter](#accessibility.series.descriptionFormatter),
   * and
   * [accessibility.screenReaderSection.beforeChartFormatter](#accessibility.screenReaderSection.beforeChartFormatter).
   *
   * @since        6.0.6
   * @optionparent lang.accessibility
   */
  accessibility: {
    /**
     * @deprecated 10.2.1
     * @type       {string}
     * @apioption  lang.accessibility.resetZoomButton
     */
    /**
     * Default title of the chart for assistive technology, for charts
     * without a chart title.
     */
    defaultChartTitle: "Chart",
    /**
     * Accessible label for the chart container HTML element.
     * `{title}` refers to the chart title.
     */
    chartContainerLabel: "{title}. Highcharts interactive chart.",
    /**
     * Accessible label for the chart SVG element.
     * `{chartTitle}` refers to the chart title.
     */
    svgContainerLabel: "Interactive chart",
    /**
     * Accessible label for the drill-up button.
     * `{buttonText}` refers to the visual text on the button.
     */
    drillUpButton: "{buttonText}",
    /**
     * Accessible label for the chart credits.
     * `{creditsStr}` refers to the visual text in the credits.
     */
    credits: "Chart credits: {creditsStr}",
    /**
     * Thousands separator to use when formatting numbers for screen
     * readers. Note that many screen readers will not handle space as a
     * thousands separator, and will consider "11 700" as two numbers.
     *
     * Set to `null` to use the separator defined in
     * [lang.thousandsSep](lang.thousandsSep).
     *
     * @since 7.1.0
     */
    thousandsSep: ",",
    /**
     * Title element text for the chart SVG element. Leave this
     * empty to disable adding the title element. Browsers will display
     * this content when hovering over elements in the chart. Assistive
     * technology may use this element to label the chart.
     *
     * @since 6.0.8
     */
    svgContainerTitle: "",
    /**
     * Set a label on the container wrapping the SVG.
     *
     * @see [chartContainerLabel](#lang.accessibility.chartContainerLabel)
     *
     * @since 8.0.0
     */
    graphicContainerLabel: "",
    /**
     * Language options for the screen reader information sections added
     * before and after the charts.
     *
     * @since 8.0.0
     */
    screenReaderSection: {
      beforeRegionLabel: "",
      afterRegionLabel: "",
      /**
       * Language options for annotation descriptions.
       *
       * @since 8.0.1
       */
      annotations: {
        heading: "Chart annotations summary",
        descriptionSinglePoint: "{annotationText}. Related to {annotationPoint}",
        descriptionMultiplePoints: "{annotationText}. Related to {annotationPoint}{#each additionalAnnotationPoints}, also related to {this}{/each}",
        descriptionNoPoints: "{annotationText}"
      },
      /**
       * Label for the end of the chart. Announced by screen readers.
       *
       * @since 8.0.0
       */
      endOfChartMarker: "End of interactive chart."
    },
    /**
     * Language options for sonification.
     *
     * @since 8.0.1
     */
    sonification: {
      playAsSoundButtonText: "Play as sound, {chartTitle}",
      playAsSoundClickAnnouncement: "Play"
    },
    /**
     * Language options for accessibility of the legend.
     *
     * @since 8.0.0
     */
    legend: {
      /**
       * Accessible label for the legend, for charts where there is no
       * legend title defined.
       */
      legendLabelNoTitle: "Toggle series visibility, {chartTitle}",
      /**
       * Accessible label for the legend, for charts where there is a
       * legend title defined. `{legendTitle}` refers to the visual text
       * in the legend title.
       */
      legendLabel: "Chart legend: {legendTitle}",
      /**
       * Accessible label for individual legend items. `{itemName}` refers
       * to the visual text in the legend for that item.
       */
      legendItem: "Show {itemName}"
    },
    /**
     * Chart and map zoom accessibility language options.
     *
     * @since 8.0.0
     */
    zoom: {
      mapZoomIn: "Zoom chart",
      mapZoomOut: "Zoom out chart",
      resetZoomButton: "Reset zoom"
    },
    /**
     * Range selector language options for accessibility.
     *
     * @since 8.0.0
     */
    rangeSelector: {
      dropdownLabel: "{rangeTitle}",
      minInputLabel: "Select start date.",
      maxInputLabel: "Select end date.",
      clickButtonAnnouncement: "Viewing {axisRangeDescription}"
    },
    /**
     * Navigator language options for accessibility.
     *
     * @since 11.2.0
     */
    navigator: {
      /**
       * Label for the navigator handles.
       *
       * Receives `handleIx` and `chart` as context.
       * `handleIx` refers to the index of the navigator handle.
       */
      handleLabel: "{#eq handleIx 0}Start, percent{else}End, percent{/eq}",
      /**
       * Label for the navigator region.
       *
       * Receives `chart` as context.
       */
      groupLabel: "Axis zoom",
      /**
       * Announcement for assistive technology when navigator values
       * are changed.
       *
       * Receives `axisRangeDescription` and `chart` as context.
       * `axisRangeDescription` corresponds to the range description
       * defined in [lang.accessibility.axis](#lang.accessibility.axis)
       */
      changeAnnouncement: "{axisRangeDescription}"
    },
    /**
     * Accessibility language options for the data table.
     *
     * @since 8.0.0
     */
    table: {
      viewAsDataTableButtonText: "View as data table, {chartTitle}",
      tableSummary: "Table representation of chart."
    },
    /**
     * Default announcement for new data in charts. If addPoint or
     * addSeries is used, and only one series/point is added, the
     * `newPointAnnounce` and `newSeriesAnnounce` strings are used.
     * The `...Single` versions will be used if there is only one chart
     * on the page, and the `...Multiple` versions will be used if there
     * are multiple charts on the page. For all other new data events,
     * the `newDataAnnounce` string will be used.
     *
     * @since 7.1.0
     */
    announceNewData: {
      newDataAnnounce: "Updated data for chart {chartTitle}",
      newSeriesAnnounceSingle: "New data series: {seriesDesc}",
      newPointAnnounceSingle: "New data point: {pointDesc}",
      newSeriesAnnounceMultiple: "New data series in chart {chartTitle}: {seriesDesc}",
      newPointAnnounceMultiple: "New data point in chart {chartTitle}: {pointDesc}"
    },
    /**
     * Descriptions of lesser known series types. The relevant
     * description is added to the screen reader information region
     * when these series types are used.
     *
     * @since 6.0.6
     */
    seriesTypeDescriptions: {
      boxplot: "Box plot charts are typically used to display groups of statistical data. Each data point in the chart can have up to 5 values: minimum, lower quartile, median, upper quartile, and maximum.",
      arearange: "Arearange charts are line charts displaying a range between a lower and higher value for each point.",
      areasplinerange: "These charts are line charts displaying a range between a lower and higher value for each point.",
      bubble: "Bubble charts are scatter charts where each data point also has a size value.",
      columnrange: "Columnrange charts are column charts displaying a range between a lower and higher value for each point.",
      errorbar: "Errorbar series are used to display the variability of the data.",
      funnel: "Funnel charts are used to display reduction of data in stages.",
      pyramid: "Pyramid charts consist of a single pyramid with item heights corresponding to each point value.",
      waterfall: "A waterfall chart is a column chart where each column contributes towards a total end value."
    },
    /**
     * Chart type description strings. This is added to the chart
     * information region.
     *
     * If there is only a single series type used in the chart, we use
     * the format string for the series type, or default if missing.
     * There is one format string for cases where there is only a single
     * series in the chart, and one for multiple series of the same
     * type.
     *
     * @since 6.0.6
     */
    chartTypes: {
      /* eslint-disable max-len */
      emptyChart: "Empty chart",
      mapTypeDescription: "Map of {mapTitle} with {numSeries} data series.",
      unknownMap: "Map of unspecified region with {numSeries} data series.",
      combinationChart: "Combination chart with {numSeries} data series.",
      defaultSingle: "Chart with {numPoints} data {#eq numPoints 1}point{else}points{/eq}.",
      defaultMultiple: "Chart with {numSeries} data series.",
      splineSingle: "Line chart with {numPoints} data {#eq numPoints 1}point{else}points{/eq}.",
      splineMultiple: "Line chart with {numSeries} lines.",
      lineSingle: "Line chart with {numPoints} data {#eq numPoints 1}point{else}points{/eq}.",
      lineMultiple: "Line chart with {numSeries} lines.",
      columnSingle: "Bar chart with {numPoints} {#eq numPoints 1}bar{else}bars{/eq}.",
      columnMultiple: "Bar chart with {numSeries} data series.",
      barSingle: "Bar chart with {numPoints} {#eq numPoints 1}bar{else}bars{/eq}.",
      barMultiple: "Bar chart with {numSeries} data series.",
      pieSingle: "Pie chart with {numPoints} {#eq numPoints 1}slice{else}slices{/eq}.",
      pieMultiple: "Pie chart with {numSeries} pies.",
      scatterSingle: "Scatter chart with {numPoints} {#eq numPoints 1}point{else}points{/eq}.",
      scatterMultiple: "Scatter chart with {numSeries} data series.",
      boxplotSingle: "Boxplot with {numPoints} {#eq numPoints 1}box{else}boxes{/eq}.",
      boxplotMultiple: "Boxplot with {numSeries} data series.",
      bubbleSingle: "Bubble chart with {numPoints} {#eq numPoints 1}bubbles{else}bubble{/eq}.",
      bubbleMultiple: "Bubble chart with {numSeries} data series."
    },
    /* eslint-enable max-len */
    /**
     * Axis description format strings.
     *
     * @since 6.0.6
     */
    axis: {
      /* eslint-disable max-len */
      xAxisDescriptionSingular: "The chart has 1 X axis displaying {names[0]}. {ranges[0]}",
      xAxisDescriptionPlural: "The chart has {numAxes} X axes displaying {#each names}{#unless @first},{/unless}{#if @last} and{/if} {this}{/each}.",
      yAxisDescriptionSingular: "The chart has 1 Y axis displaying {names[0]}. {ranges[0]}",
      yAxisDescriptionPlural: "The chart has {numAxes} Y axes displaying {#each names}{#unless @first},{/unless}{#if @last} and{/if} {this}{/each}.",
      timeRangeDays: "Data range: {range} days.",
      timeRangeHours: "Data range: {range} hours.",
      timeRangeMinutes: "Data range: {range} minutes.",
      timeRangeSeconds: "Data range: {range} seconds.",
      rangeFromTo: "Data ranges from {rangeFrom} to {rangeTo}.",
      rangeCategories: "Data range: {numCategories} categories."
    },
    /* eslint-enable max-len */
    /**
     * Exporting menu format strings for accessibility module.
     *
     * @since 6.0.6
     */
    exporting: {
      chartMenuLabel: "Chart menu",
      menuButtonLabel: "View chart menu, {chartTitle}"
    },
    /**
     * Lang configuration for different series types. For more dynamic
     * control over the series element descriptions, see
     * [accessibility.seriesDescriptionFormatter](#accessibility.seriesDescriptionFormatter).
     *
     * @since 6.0.6
     */
    series: {
      /**
       * Lang configuration for the series main summary. Each series
       * type has two modes:
       *
       * 1. This series type is the only series type used in the
       *    chart
       *
       * 2. This is a combination chart with multiple series types
       *
       * If a definition does not exist for the specific series type
       * and mode, the 'default' lang definitions are used.
       *
       * Chart and its subproperties can be accessed with the `{chart}` variable.
       * The series and its subproperties can be accessed with the `{series}` variable.
       *
       * The series index (starting from 1) can be accessed with the `{seriesNumber}` variable.
       *
       * @since 6.0.6
       */
      summary: {
        /* eslint-disable max-len */
        "default": "{series.name}, series {seriesNumber} of {chart.series.length} with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        defaultCombination: "{series.name}, series {seriesNumber} of {chart.series.length} with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        line: "{series.name}, line {seriesNumber} of {chart.series.length} with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        lineCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Line with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        spline: "{series.name}, line {seriesNumber} of {chart.series.length} with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        splineCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Line with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        column: "{series.name}, bar series {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}bar{else}bars{/eq}.",
        columnCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Bar series with {series.points.length} {#eq series.points.length 1}bar{else}bars{/eq}.",
        bar: "{series.name}, bar series {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}bar{else}bars{/eq}.",
        barCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Bar series with {series.points.length} {#eq series.points.length 1}bar{else}bars{/eq}.",
        pie: "{series.name}, pie {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}slice{else}slices{/eq}.",
        pieCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Pie with {series.points.length} {#eq series.points.length 1}slice{else}slices{/eq}.",
        scatter: "{series.name}, scatter plot {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}point{else}points{/eq}.",
        scatterCombination: "{series.name}, series {seriesNumber} of {chart.series.length}, scatter plot with {series.points.length} {#eq series.points.length 1}point{else}points{/eq}.",
        boxplot: "{series.name}, boxplot {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}box{else}boxes{/eq}.",
        boxplotCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Boxplot with {series.points.length} {#eq series.points.length 1}box{else}boxes{/eq}.",
        bubble: "{series.name}, bubble series {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}bubble{else}bubbles{/eq}.",
        bubbleCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Bubble series with {series.points.length} {#eq series.points.length 1}bubble{else}bubbles{/eq}.",
        map: "{series.name}, map {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}area{else}areas{/eq}.",
        mapCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Map with {series.points.length} {#eq series.points.length 1}area{else}areas{/eq}.",
        mapline: "{series.name}, line {seriesNumber} of {chart.series.length} with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        maplineCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Line with {series.points.length} data {#eq series.points.length 1}point{else}points{/eq}.",
        mapbubble: "{series.name}, bubble series {seriesNumber} of {chart.series.length} with {series.points.length} {#eq series.points.length 1}bubble{else}bubbles{/eq}.",
        mapbubbleCombination: "{series.name}, series {seriesNumber} of {chart.series.length}. Bubble series with {series.points.length} {#eq series.points.length 1}bubble{else}bubbles{/eq}."
      },
      /* eslint-enable max-len */
      /**
       * User supplied description text. This is added in the point
       * comment description by default if present.
       *
       * `{description}` refers to the value given in
       * [point.accessibility.description](#series.line.data.accessibility.description).
       *
       * @since 6.0.6
       */
      description: "{description}",
      /**
       * X-axis description for series if there are multiple xAxes in
       * the chart.
       *
       * @since 6.0.6
       */
      xAxisDescription: "X axis, {name}",
      /**
       * Y-axis description for series if there are multiple yAxes in
       * the chart.
       *
       * @since 6.0.6
       */
      yAxisDescription: "Y axis, {name}",
      /**
       * Description for the value of null points.
       *
       * @since 8.0.0
       */
      nullPointValue: "No value",
      /**
       * Description for annotations on a point, as it is made available
       * to assistive technology.
       *
       * @since 8.0.1
       */
      pointAnnotationsDescription: "{#each annotations}Annotation: {this}{/each}"
    }
  }
};
const { error: error$3, pick: pick$$ } = Utilities;
function traverseSetOption(root, optionAsArray, val) {
  let opt = root, prop, i = 0;
  for (; i < optionAsArray.length - 1; ++i) {
    prop = optionAsArray[i];
    opt = opt[prop] = pick$$(opt[prop], {});
  }
  opt[optionAsArray[optionAsArray.length - 1]] = val;
}
function deprecateFromOptionsMap(chart, rootOldAsArray, rootNewAsArray, mapToNewOptions) {
  function getChildProp(root, propAsArray) {
    return propAsArray.reduce(function(acc, cur) {
      return acc[cur];
    }, root);
  }
  const rootOld = getChildProp(chart.options, rootOldAsArray), rootNew = getChildProp(chart.options, rootNewAsArray);
  Object.keys(mapToNewOptions).forEach(function(oldOptionKey) {
    const val = rootOld[oldOptionKey];
    if (typeof val !== "undefined") {
      traverseSetOption(rootNew, mapToNewOptions[oldOptionKey], val);
      error$3(32, false, chart, {
        [rootOldAsArray.join(".") + "." + oldOptionKey]: rootNewAsArray.join(".") + "." + mapToNewOptions[oldOptionKey].join(".")
      });
    }
  });
}
function copyDeprecatedChartOptions(chart) {
  const chartOptions = chart.options.chart, a11yOptions = chart.options.accessibility || {};
  ["description", "typeDescription"].forEach(function(prop) {
    if (chartOptions[prop]) {
      a11yOptions[prop] = chartOptions[prop];
      error$3(32, false, chart, { [`chart.${prop}`]: `use accessibility.${prop}` });
    }
  });
}
function copyDeprecatedAxisOptions(chart) {
  chart.axes.forEach(function(axis) {
    const opts = axis.options;
    if (opts && opts.description) {
      opts.accessibility = opts.accessibility || {};
      opts.accessibility.description = opts.description;
      error$3(32, false, chart, {
        "axis.description": "use axis.accessibility.description"
      });
    }
  });
}
function copyDeprecatedSeriesOptions(chart) {
  const oldToNewSeriesOptions = {
    description: ["accessibility", "description"],
    exposeElementToA11y: ["accessibility", "exposeAsGroupOnly"],
    pointDescriptionFormatter: [
      "accessibility",
      "point",
      "descriptionFormatter"
    ],
    skipKeyboardNavigation: [
      "accessibility",
      "keyboardNavigation",
      "enabled"
    ],
    "accessibility.pointDescriptionFormatter": [
      "accessibility",
      "point",
      "descriptionFormatter"
    ]
  };
  chart.series.forEach(function(series) {
    Object.keys(oldToNewSeriesOptions).forEach(function(oldOption) {
      let optionVal = series.options[oldOption];
      if (oldOption === "accessibility.pointDescriptionFormatter") {
        optionVal = series.options.accessibility && series.options.accessibility.pointDescriptionFormatter;
      }
      if (typeof optionVal !== "undefined") {
        traverseSetOption(
          series.options,
          oldToNewSeriesOptions[oldOption],
          // Note that skipKeyboardNavigation has inverted option
          // value, since we set enabled rather than disabled
          oldOption === "skipKeyboardNavigation" ? !optionVal : optionVal
        );
        error$3(32, false, chart, {
          [`series.${oldOption}`]: "series." + oldToNewSeriesOptions[oldOption].join(".")
        });
      }
    });
  });
}
function copyDeprecatedTopLevelAccessibilityOptions(chart) {
  deprecateFromOptionsMap(chart, ["accessibility"], ["accessibility"], {
    pointDateFormat: ["point", "dateFormat"],
    pointDateFormatter: ["point", "dateFormatter"],
    pointDescriptionFormatter: ["point", "descriptionFormatter"],
    pointDescriptionThreshold: [
      "series",
      "pointDescriptionEnabledThreshold"
    ],
    pointNavigationThreshold: [
      "keyboardNavigation",
      "seriesNavigation",
      "pointNavigationEnabledThreshold"
    ],
    pointValueDecimals: ["point", "valueDecimals"],
    pointValuePrefix: ["point", "valuePrefix"],
    pointValueSuffix: ["point", "valueSuffix"],
    screenReaderSectionFormatter: [
      "screenReaderSection",
      "beforeChartFormatter"
    ],
    describeSingleSeries: ["series", "describeSingleSeries"],
    seriesDescriptionFormatter: ["series", "descriptionFormatter"],
    onTableAnchorClick: ["screenReaderSection", "onViewDataTableClick"],
    axisRangeDateFormat: ["screenReaderSection", "axisRangeDateFormat"]
  });
}
function copyDeprecatedKeyboardNavigationOptions(chart) {
  deprecateFromOptionsMap(chart, ["accessibility", "keyboardNavigation"], ["accessibility", "keyboardNavigation", "seriesNavigation"], {
    skipNullPoints: ["skipNullPoints"],
    mode: ["mode"]
  });
}
function copyDeprecatedLangOptions(chart) {
  deprecateFromOptionsMap(chart, ["lang", "accessibility"], ["lang", "accessibility"], {
    legendItem: ["legend", "legendItem"],
    legendLabel: ["legend", "legendLabel"],
    mapZoomIn: ["zoom", "mapZoomIn"],
    mapZoomOut: ["zoom", "mapZoomOut"],
    resetZoomButton: ["zoom", "resetZoomButton"],
    screenReaderRegionLabel: [
      "screenReaderSection",
      "beforeRegionLabel"
    ],
    rangeSelectorButton: ["rangeSelector", "buttonText"],
    rangeSelectorMaxInput: ["rangeSelector", "maxInputLabel"],
    rangeSelectorMinInput: ["rangeSelector", "minInputLabel"],
    svgContainerEnd: ["screenReaderSection", "endOfChartMarker"],
    viewAsDataTable: ["table", "viewAsDataTableButtonText"],
    tableSummary: ["table", "tableSummary"]
  });
}
function copyDeprecatedOptions(chart) {
  copyDeprecatedChartOptions(chart);
  copyDeprecatedAxisOptions(chart);
  if (chart.series) {
    copyDeprecatedSeriesOptions(chart);
  }
  copyDeprecatedTopLevelAccessibilityOptions(chart);
  copyDeprecatedKeyboardNavigationOptions(chart);
  copyDeprecatedLangOptions(chart);
}
const { defaultOptions: defaultOptions$8 } = DefaultOptions;
const { doc: doc$a } = Highcharts;
const { addEvent: addEvent$R, extend: extend$R, fireEvent: fireEvent$k, merge: merge$10 } = Utilities;
const { removeElement } = HTMLUtilities;
class Accessibility {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.init(chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the accessibility class
   * @private
   * @param {Highcharts.Chart} chart
   *        Chart object
   */
  init(chart) {
    this.chart = chart;
    if (!doc$a?.addEventListener) {
      this.zombie = true;
      this.components = {};
      chart.renderTo.setAttribute("aria-hidden", true);
      return;
    }
    copyDeprecatedOptions(chart);
    this.proxyProvider = new ProxyProvider(this.chart);
    this.initComponents();
    this.keyboardNavigation = new KeyboardNavigation$1(chart, this.components);
  }
  /**
   * @private
   */
  initComponents() {
    const chart = this.chart;
    const proxyProvider = this.proxyProvider;
    const a11yOptions = chart.options.accessibility;
    this.components = {
      container: new ContainerComponent(),
      infoRegions: new InfoRegionsComponent(),
      legend: new LegendComponent$1(),
      chartMenu: new MenuComponent$1(),
      rangeSelector: new RangeSelectorComponent$1(),
      series: new SeriesComponent(),
      zoom: new ZoomComponent(),
      navigator: new NavigatorComponent()
    };
    if (a11yOptions.customComponents) {
      extend$R(this.components, a11yOptions.customComponents);
    }
    const components = this.components;
    this.getComponentOrder().forEach(function(componentName) {
      components[componentName].initBase(chart, proxyProvider);
      components[componentName].init();
    });
  }
  /**
   * Get order to update components in.
   * @private
   */
  getComponentOrder() {
    if (!this.components) {
      return [];
    }
    if (!this.components.series) {
      return Object.keys(this.components);
    }
    const componentsExceptSeries = Object.keys(this.components).filter((c) => c !== "series");
    return ["series"].concat(componentsExceptSeries);
  }
  /**
   * Update all components.
   */
  update() {
    const components = this.components, chart = this.chart, a11yOptions = chart.options.accessibility;
    fireEvent$k(chart, "beforeA11yUpdate");
    chart.types = this.getChartTypes();
    const kbdNavOrder = a11yOptions.keyboardNavigation.order;
    this.proxyProvider.updateGroupOrder(kbdNavOrder);
    this.getComponentOrder().forEach(function(componentName) {
      components[componentName].onChartUpdate();
      fireEvent$k(chart, "afterA11yComponentUpdate", {
        name: componentName,
        component: components[componentName]
      });
    });
    this.keyboardNavigation.update(kbdNavOrder);
    if (!chart.highContrastModeActive && a11yOptions.highContrastMode !== false && (whcm.isHighContrastModeActive() || a11yOptions.highContrastMode === true)) {
      whcm.setHighContrastTheme(chart);
    }
    fireEvent$k(chart, "afterA11yUpdate", {
      accessibility: this
    });
  }
  /**
   * Destroy all elements.
   */
  destroy() {
    const chart = this.chart || {};
    const components = this.components;
    Object.keys(components).forEach(function(componentName) {
      components[componentName].destroy();
      components[componentName].destroyBase();
    });
    if (this.proxyProvider) {
      this.proxyProvider.destroy();
    }
    if (chart.announcerContainer) {
      removeElement(chart.announcerContainer);
    }
    if (this.keyboardNavigation) {
      this.keyboardNavigation.destroy();
    }
    if (chart.renderTo) {
      chart.renderTo.setAttribute("aria-hidden", true);
    }
    if (chart.focusElement) {
      chart.focusElement.removeFocusBorder();
    }
  }
  /**
   * Return a list of the types of series we have in the chart.
   * @private
   */
  getChartTypes() {
    const types = {};
    this.chart.series.forEach(function(series) {
      types[series.type] = 1;
    });
    return Object.keys(types);
  }
}
(function(Accessibility2) {
  Accessibility2.i18nFormat = A11yI18n.i18nFormat;
  function chartOnDestroy() {
    if (this.accessibility) {
      this.accessibility.destroy();
    }
  }
  function chartOnRender() {
    if (this.a11yDirty && this.renderTo) {
      delete this.a11yDirty;
      this.updateA11yEnabled();
    }
    const a11y = this.accessibility;
    if (a11y && !a11y.zombie) {
      a11y.proxyProvider.updateProxyElementPositions();
      a11y.getComponentOrder().forEach(function(componentName) {
        a11y.components[componentName].onChartRender();
      });
    }
  }
  function chartOnUpdate(e) {
    const newOptions = e.options.accessibility;
    if (newOptions) {
      if (newOptions.customComponents) {
        this.options.accessibility.customComponents = newOptions.customComponents;
        delete newOptions.customComponents;
      }
      merge$10(true, this.options.accessibility, newOptions);
      if (this.accessibility && this.accessibility.destroy) {
        this.accessibility.destroy();
        delete this.accessibility;
      }
    }
    this.a11yDirty = true;
  }
  function chartUpdateA11yEnabled() {
    let a11y = this.accessibility;
    const accessibilityOptions = this.options.accessibility, svg2 = this.renderer.boxWrapper.element, title = this.title;
    if (accessibilityOptions && accessibilityOptions.enabled) {
      if (a11y && !a11y.zombie) {
        a11y.update();
      } else {
        this.accessibility = a11y = new Accessibility2(this);
        if (a11y && !a11y.zombie) {
          a11y.update();
        }
        if (svg2.getAttribute("role") === "img") {
          svg2.removeAttribute("role");
        }
      }
    } else if (a11y) {
      if (a11y.destroy) {
        a11y.destroy();
      }
      delete this.accessibility;
    } else {
      this.renderTo.setAttribute("role", "img");
      this.renderTo.setAttribute("aria-hidden", false);
      this.renderTo.setAttribute("aria-label", (title && title.element.textContent || "").replace(/</g, "&lt;"));
      svg2.setAttribute("aria-hidden", true);
      const description = document.getElementsByClassName("highcharts-description")[0];
      if (description) {
        description.setAttribute("aria-hidden", false);
        description.classList.remove("highcharts-linked-description");
      }
    }
  }
  function compose2(ChartClass, LegendClass, PointClass, SeriesClass, SVGElementClass, RangeSelectorClass) {
    KeyboardNavigation$1.compose(ChartClass);
    NewDataAnnouncer$1.compose(SeriesClass);
    LegendComponent$1.compose(ChartClass, LegendClass);
    MenuComponent$1.compose(ChartClass);
    SeriesComponent.compose(ChartClass, PointClass, SeriesClass);
    A11yI18n.compose(ChartClass);
    FocusBorderComposition$1.compose(ChartClass, SVGElementClass);
    if (RangeSelectorClass) {
      RangeSelectorComponent$1.compose(ChartClass, RangeSelectorClass);
    }
    const chartProto = ChartClass.prototype;
    if (!chartProto.updateA11yEnabled) {
      chartProto.updateA11yEnabled = chartUpdateA11yEnabled;
      addEvent$R(ChartClass, "destroy", chartOnDestroy);
      addEvent$R(ChartClass, "render", chartOnRender);
      addEvent$R(ChartClass, "update", chartOnUpdate);
      ["addSeries", "init"].forEach((event) => {
        addEvent$R(ChartClass, event, function() {
          this.a11yDirty = true;
        });
      });
      ["afterApplyDrilldown", "drillupall"].forEach((event) => {
        addEvent$R(ChartClass, event, function chartOnAfterDrilldown() {
          const a11y = this.accessibility;
          if (a11y && !a11y.zombie) {
            a11y.update();
          }
        });
      });
      addEvent$R(PointClass, "update", pointOnUpdate);
      ["update", "updatedData", "remove"].forEach((event) => {
        addEvent$R(SeriesClass, event, function() {
          if (this.chart.accessibility) {
            this.chart.a11yDirty = true;
          }
        });
      });
    }
  }
  Accessibility2.compose = compose2;
  function pointOnUpdate() {
    if (this.series.chart.accessibility) {
      this.series.chart.a11yDirty = true;
    }
  }
})(Accessibility || (Accessibility = {}));
merge$10(true, defaultOptions$8, Options, {
  accessibility: {
    highContrastTheme: theme
  },
  lang: langOptions
});
const Accessibility$1 = Accessibility;
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/accessibility
 * @requires highcharts
 *
 * Accessibility module
 *
 * (c) 2010-2025 Highsoft AS
 * Author: Oystein Moseng
 *
 * License: www.highcharts.com/license
 */
const G$f = Highcharts;
G$f.i18nFormat = Accessibility$1.i18nFormat;
G$f.A11yChartUtilities = ChartUtilities;
G$f.A11yHTMLUtilities = HTMLUtilities;
G$f.AccessibilityComponent = AccessibilityComponent;
G$f.KeyboardNavigationHandler = KeyboardNavigationHandler;
G$f.SeriesAccessibilityDescriber = SeriesDescriber;
Accessibility$1.compose(G$f.Chart, G$f.Legend, G$f.Point, G$f.Series, G$f.SVGElement, G$f.RangeSelector);
const { addEvent: addEvent$Q, erase: erase$2, find: find$7, fireEvent: fireEvent$j, pick: pick$_, wrap: wrap$e } = Utilities;
function chartAddAnnotation(userOptions, redraw) {
  const annotation = this.initAnnotation(userOptions);
  this.options.annotations.push(annotation.options);
  if (pick$_(redraw, true)) {
    annotation.redraw();
    annotation.graphic.attr({
      opacity: 1
    });
  }
  return annotation;
}
function chartCallback() {
  const chart = this;
  chart.plotBoxClip = this.renderer.clipRect(this.plotBox);
  chart.controlPointsGroup = chart.renderer.g("control-points").attr({ zIndex: 99 }).clip(chart.plotBoxClip).add();
  chart.options.annotations.forEach((annotationOptions, i) => {
    if (
      // Verify that it has not been previously added in a responsive rule
      !chart.annotations.some((annotation) => annotation.options === annotationOptions)
    ) {
      const annotation = chart.initAnnotation(annotationOptions);
      chart.options.annotations[i] = annotation.options;
    }
  });
  chart.drawAnnotations();
  addEvent$Q(chart, "redraw", chart.drawAnnotations);
  addEvent$Q(chart, "destroy", function() {
    chart.plotBoxClip.destroy();
    chart.controlPointsGroup.destroy();
  });
  addEvent$Q(chart, "exportData", function(event) {
    const annotations = chart.annotations, csvColumnHeaderFormatter = (this.options.exporting && this.options.exporting.csv || {}).columnHeaderFormatter, multiLevelHeaders = !event.dataRows[1].xValues, annotationHeader = chart.options.lang && chart.options.lang.exportData && chart.options.lang.exportData.annotationHeader, columnHeaderFormatter = function(index) {
      let s;
      if (csvColumnHeaderFormatter) {
        s = csvColumnHeaderFormatter(index);
        if (s !== false) {
          return s;
        }
      }
      s = annotationHeader + " " + index;
      if (multiLevelHeaders) {
        return {
          columnTitle: s,
          topLevelColumnTitle: s
        };
      }
      return s;
    }, startRowLength = event.dataRows[0].length, annotationSeparator = chart.options.exporting && chart.options.exporting.csv && chart.options.exporting.csv.annotations && chart.options.exporting.csv.annotations.itemDelimiter, joinAnnotations = chart.options.exporting && chart.options.exporting.csv && chart.options.exporting.csv.annotations && chart.options.exporting.csv.annotations.join;
    annotations.forEach((annotation) => {
      if (annotation.options.labelOptions && annotation.options.labelOptions.includeInDataExport) {
        annotation.labels.forEach((label) => {
          if (label.options.text) {
            const annotationText = label.options.text;
            label.points.forEach((points) => {
              const annotationX = points.x, xAxisIndex = points.series.xAxis ? points.series.xAxis.index : -1;
              let wasAdded = false;
              if (xAxisIndex === -1) {
                const n = event.dataRows[0].length, newRow = new Array(n);
                for (let i = 0; i < n; ++i) {
                  newRow[i] = "";
                }
                newRow.push(annotationText);
                newRow.xValues = [];
                newRow.xValues[xAxisIndex] = annotationX;
                event.dataRows.push(newRow);
                wasAdded = true;
              }
              if (!wasAdded) {
                event.dataRows.forEach((row) => {
                  if (!wasAdded && row.xValues && xAxisIndex !== void 0 && annotationX === row.xValues[xAxisIndex]) {
                    if (joinAnnotations && row.length > startRowLength) {
                      row[row.length - 1] += annotationSeparator + annotationText;
                    } else {
                      row.push(annotationText);
                    }
                    wasAdded = true;
                  }
                });
              }
              if (!wasAdded) {
                const n = event.dataRows[0].length, newRow = new Array(n);
                for (let i = 0; i < n; ++i) {
                  newRow[i] = "";
                }
                newRow[0] = annotationX;
                newRow.push(annotationText);
                newRow.xValues = [];
                if (xAxisIndex !== void 0) {
                  newRow.xValues[xAxisIndex] = annotationX;
                }
                event.dataRows.push(newRow);
              }
            });
          }
        });
      }
    });
    let maxRowLen = 0;
    event.dataRows.forEach((row) => {
      maxRowLen = Math.max(maxRowLen, row.length);
    });
    const newRows = maxRowLen - event.dataRows[0].length;
    for (let i = 0; i < newRows; i++) {
      const header = columnHeaderFormatter(i + 1);
      if (multiLevelHeaders) {
        event.dataRows[0].push(header.topLevelColumnTitle);
        event.dataRows[1].push(header.columnTitle);
      } else {
        event.dataRows[0].push(header);
      }
    }
  });
}
function chartDrawAnnotations() {
  this.plotBoxClip.attr(this.plotBox);
  this.annotations.forEach((annotation) => {
    annotation.redraw();
    annotation.graphic.animate({
      opacity: 1
    }, annotation.animationConfig);
  });
}
function chartRemoveAnnotation(idOrAnnotation) {
  const annotations = this.annotations, annotation = idOrAnnotation.coll === "annotations" ? idOrAnnotation : find$7(annotations, function(annotation2) {
    return annotation2.options.id === idOrAnnotation;
  });
  if (annotation) {
    fireEvent$j(annotation, "remove");
    erase$2(this.options.annotations, annotation.options);
    erase$2(annotations, annotation);
    annotation.destroy();
  }
}
function onChartAfterInit$1() {
  const chart = this;
  chart.annotations = [];
  if (!this.options.annotations) {
    this.options.annotations = [];
  }
}
function wrapPointerOnContainerMouseDown(proceed) {
  if (!this.chart.hasDraggedAnnotation) {
    proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  }
}
var AnnotationChart;
(function(AnnotationChart2) {
  function compose2(AnnotationClass, ChartClass, PointerClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.addAnnotation) {
      const pointerProto = PointerClass.prototype;
      addEvent$Q(ChartClass, "afterInit", onChartAfterInit$1);
      chartProto.addAnnotation = chartAddAnnotation;
      chartProto.callbacks.push(chartCallback);
      chartProto.collectionsWithInit.annotations = [chartAddAnnotation];
      chartProto.collectionsWithUpdate.push("annotations");
      chartProto.drawAnnotations = chartDrawAnnotations;
      chartProto.removeAnnotation = chartRemoveAnnotation;
      chartProto.initAnnotation = function chartInitAnnotation(userOptions) {
        const Constructor = AnnotationClass.types[userOptions.type] || AnnotationClass, annotation = new Constructor(this, userOptions);
        this.annotations.push(annotation);
        return annotation;
      };
      wrap$e(pointerProto, "onContainerMouseDown", wrapPointerOnContainerMouseDown);
    }
  }
  AnnotationChart2.compose = compose2;
})(AnnotationChart || (AnnotationChart = {}));
const AnnotationChart$1 = AnnotationChart;
const { defined: defined$C } = Utilities;
const AnnotationDefaults = {
  /**
   * Sets an ID for an annotation. Can be user later when
   * removing an annotation in [Chart#removeAnnotation(id)](
   * /class-reference/Highcharts.Chart#removeAnnotation) method.
   *
   * @type      {number|string}
   * @apioption annotations.id
   */
  /**
   * Whether the annotation is visible.
   *
   * @sample highcharts/annotations/visible/
   *         Set annotation visibility
   */
  visible: true,
  /**
   * Enable or disable the initial animation when a series is
   * displayed for the `annotation`. The animation can also be set
   * as a configuration object. Please note that this option only
   * applies to the initial animation.
   * For other animations, see [chart.animation](#chart.animation)
   * and the animation parameter under the API methods.
   * The following properties are supported:
   *
   * - `defer`: The animation delay time in milliseconds.
   *
   * @sample {highcharts} highcharts/annotations/defer/
   *          Animation defer settings
   * @type {boolean|Partial<Highcharts.AnimationOptionsObject>}
   * @since 8.2.0
   */
  animation: {},
  /**
   * Whether to hide the part of the annotation
   * that is outside the plot area.
   *
   * @sample highcharts/annotations/label-crop-overflow/
   *         Crop line annotation
   * @type  {boolean}
   * @since 9.3.0
   */
  crop: true,
  /**
   * The animation delay time in milliseconds.
   * Set to `0` renders annotation immediately.
   * As `undefined` inherits defer time from the [series.animation.defer](#plotOptions.series.animation.defer).
   *
   * @type      {number}
   * @since 8.2.0
   * @apioption annotations.animation.defer
   */
  /**
   * Allow an annotation to be draggable by a user. Possible
   * values are `'x'`, `'xy'`, `'y'` and `''` (disabled).
   *
   * @sample highcharts/annotations/draggable/
   *         Annotations draggable: 'xy'
   *
   * @type {Highcharts.AnnotationDraggableValue}
   */
  draggable: "xy",
  /**
   * Options for annotation's labels. Each label inherits options
   * from the labelOptions object. An option from the labelOptions
   * can be overwritten by config for a specific label.
   *
   * @requires modules/annotations
   */
  labelOptions: {
    /**
     * The alignment of the annotation's label. If right,
     * the right side of the label should be touching the point.
     *
     * @sample highcharts/annotations/label-position/
     *         Set labels position
     *
     * @type {Highcharts.AlignValue}
     */
    align: "center",
    /**
     * Whether to allow the annotation's labels to overlap.
     * To make the labels less sensitive for overlapping,
     * the can be set to 0.
     *
     * @sample highcharts/annotations/tooltip-like/
     *         Hide overlapping labels
     */
    allowOverlap: false,
    /**
     * The background color or gradient for the annotation's
     * label.
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     *
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    backgroundColor: "rgba(0, 0, 0, 0.75)",
    /**
     * The border color for the annotation's label.
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     *
     * @type {Highcharts.ColorString}
     */
    borderColor: "#000000",
    /**
     * The border radius in pixels for the annotation's label.
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     */
    borderRadius: 3,
    /**
     * The border width in pixels for the annotation's label
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     */
    borderWidth: 1,
    /**
     * A class name for styling by CSS.
     *
     * @sample highcharts/css/annotations
     *         Styled mode annotations
     *
     * @since 6.0.5
     */
    className: "highcharts-no-tooltip",
    /**
     * Whether to hide the annotation's label
     * that is outside the plot area.
     *
     * @sample highcharts/annotations/label-crop-overflow/
     *         Crop or justify labels
     */
    crop: false,
    /**
     * The label's pixel distance from the point.
     *
     * @sample highcharts/annotations/label-position/
     *         Set labels position
     *
     * @type      {number}
     * @apioption annotations.labelOptions.distance
     */
    /**
     * A
     * [format](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * string for the data label.
     *
     * @see [plotOptions.series.dataLabels.format](plotOptions.series.dataLabels.format.html)
     *
     * @sample highcharts/annotations/label-text/
     *         Set labels text
     *
     * @type      {string}
     * @apioption annotations.labelOptions.format
     */
    /**
     * Alias for the format option.
     *
     * @see [format](annotations.labelOptions.format.html)
     *
     * @sample highcharts/annotations/label-text/
     *         Set labels text
     *
     * @type      {string}
     * @apioption annotations.labelOptions.text
     */
    /**
     * Callback JavaScript function to format the annotation's
     * label. Note that if a `format` or `text` are defined,
     * the format or text take precedence and the formatter is
     * ignored. `This` refers to a point object.
     *
     * @sample highcharts/annotations/label-text/
     *         Set labels text
     *
     * @type    {Highcharts.FormatterCallbackFunction<Highcharts.Point>}
     * @default function () { return defined(this.y) ? this.y : 'Annotation label'; }
     */
    formatter: function() {
      return defined$C(this.y) ? "" + this.y : "Annotation label";
    },
    /**
     * Whether the annotation is visible in the exported data
     * table.
     *
     * @sample highcharts/annotations/include-in-data-export/
     *         Do not include in the data export
     *
     * @since 8.2.0
     * @requires modules/export-data
     */
    includeInDataExport: true,
    /**
     * How to handle the annotation's label that flow outside
     * the plot area. The justify option aligns the label inside
     * the plot area.
     *
     * @sample highcharts/annotations/label-crop-overflow/
     *         Crop or justify labels
     *
     * @validvalue ["allow", "justify"]
     */
    overflow: "justify",
    /**
     * When either the borderWidth or the backgroundColor is
     * set, this is the padding within the box.
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     */
    padding: 5,
    /**
     * The shadow of the box. The shadow can be an object
     * configuration containing `color`, `offsetX`, `offsetY`,
     * `opacity` and `width`.
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     *
     * @type {boolean|Highcharts.ShadowOptionsObject}
     */
    shadow: false,
    /**
     * The name of a symbol to use for the border around the
     * label. Symbols are predefined functions on the Renderer
     * object.
     *
     * @sample highcharts/annotations/shapes/
     *         Available shapes for labels
     */
    shape: "callout",
    /**
     * Styles for the annotation's label.
     *
     * @see [plotOptions.series.dataLabels.style](plotOptions.series.dataLabels.style.html)
     *
     * @sample highcharts/annotations/label-presentation/
     *         Set labels graphic options
     *
     * @type {Highcharts.CSSObject}
     */
    style: {
      /** @ignore */
      fontSize: "0.7em",
      /** @ignore */
      fontWeight: "normal",
      /** @ignore */
      color: "contrast"
    },
    /**
     * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
     * to render the annotation's label.
     */
    useHTML: false,
    /**
     * The vertical alignment of the annotation's label.
     *
     * @sample highcharts/annotations/label-position/
     *         Set labels position
     *
     * @type {Highcharts.VerticalAlignValue}
     */
    verticalAlign: "bottom",
    /**
     * The x position offset of the label relative to the point.
     * Note that if a `distance` is defined, the distance takes
     * precedence over `x` and `y` options.
     *
     * @sample highcharts/annotations/label-position/
     *         Set labels position
     */
    x: 0,
    /**
     * The y position offset of the label relative to the point.
     * Note that if a `distance` is defined, the distance takes
     * precedence over `x` and `y` options.
     *
     * @sample highcharts/annotations/label-position/
     *         Set labels position
     */
    y: -16
  },
  /**
   * An array of labels for the annotation. For options that apply
   * to multiple labels, they can be added to the
   * [labelOptions](annotations.labelOptions.html).
   *
   * @type      {Array<*>}
   * @extends   annotations.labelOptions
   * @apioption annotations.labels
   */
  /**
   * This option defines the point to which the label will be
   * connected. It can be either the point which exists in the
   * series - it is referenced by the point's id - or a new point
   * with defined x, y properties and optionally axes.
   *
   * @sample highcharts/annotations/mock-point/
   *         Attach annotation to a mock point
   * @sample highcharts/annotations/mock-points/
   *         Attach annotation to a mock point with different ways
   *
   * @declare   Highcharts.AnnotationMockPointOptionsObject
   * @type      {
   *               string|
   *               Highcharts.AnnotationMockPointOptionsObject|
   *               Highcharts.AnnotationMockPointFunction
   *            }
   * @requires  modules/annotations
   * @apioption annotations.labels.point
   */
  /**
   * An array of shapes for the annotation. For options that apply
   * to multiple shapes, then can be added to the
   * [shapeOptions](annotations.shapeOptions.html).
   *
   * @type      {Array<*>}
   * @extends   annotations.shapeOptions
   * @apioption annotations.shapes
   */
  /**
   * This option defines the point to which the shape will be
   * connected. It can be either the point which exists in the
   * series - it is referenced by the point's id - or a new point
   * with defined x, y properties and optionally axes.
   *
   * @sample highcharts/annotations/mock-points/
   *         Attach annotation to a mock point with different ways
   *
   * @declare   Highcharts.AnnotationMockPointOptionsObject
   * @type      {
   *               string|
   *               Highcharts.AnnotationMockPointOptionsObject|
   *               Highcharts.AnnotationMockPointFunction
   *            }
   * @extends   annotations.labels.point
   * @requires  modules/annotations
   * @apioption annotations.shapes.point
   */
  /**
   * An array of points for the shape
   * or a callback function that returns that shape point.
   *
   * This option is available
   * for shapes which can use multiple points such as path. A
   * point can be either a point object or a point's id.
   *
   * @see [annotations.shapes.point](annotations.shapes.point.html)
   *
   * @type      {Array<Highcharts.AnnotationShapePointOptions>}
   * @extends   annotations.labels.point
   * @apioption annotations.shapes.points
   */
  /**
   * The URL for an image to use as the annotation shape. Note,
   * type has to be set to `'image'`.
   *
   * @see [annotations.shapes.type](annotations.shapes.type)
   * @sample highcharts/annotations/shape-src/
   *         Define a marker image url for annotations
   *
   * @type      {string}
   * @apioption annotations.shapes.src
   */
  /**
   * Id of the marker which will be drawn at the final vertex of
   * the path. Custom markers can be defined in defs property.
   *
   * @see [defs.markers](defs.markers.html)
   *
   * @sample highcharts/annotations/custom-markers/
   *         Define a custom marker for annotations
   *
   * @type      {string}
   * @apioption annotations.shapes.markerEnd
   */
  /**
   * Id of the marker which will be drawn at the first vertex of
   * the path. Custom markers can be defined in defs property.
   *
   * @see [defs.markers](defs.markers.html)
   *
   * @sample {highcharts} highcharts/annotations/custom-markers/
   *         Define a custom marker for annotations
   *
   * @type      {string}
   * @apioption annotations.shapes.markerStart
   */
  /**
   * Options for annotation's shapes. Each shape inherits options
   * from the shapeOptions object. An option from the shapeOptions
   * can be overwritten by config for a specific shape.
   *
   * @requires  modules/annotations
   */
  shapeOptions: {
    /**
     *
     * The radius of the shape in y direction.
     * Used for the ellipse.
     *
     * @sample highcharts/annotations/ellipse/
     *         Ellipse annotation
     *
     * @type      {number}
     * @apioption annotations.shapeOptions.ry
     **/
    /**
     *
     * The xAxis index to which the points should be attached.
     * Used for the ellipse.
     *
     * @type      {number}
     * @apioption annotations.shapeOptions.xAxis
     **/
    /**
     * The yAxis index to which the points should be attached.
     * Used for the ellipse.
     *
     * @type      {number}
     * @apioption annotations.shapeOptions.yAxis
     **/
    /**
     * The width of the shape.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     *
     * @type      {number}
     * @apioption annotations.shapeOptions.width
     **/
    /**
     * The height of the shape.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     *
     * @type      {number}
     * @apioption annotations.shapeOptions.height
     */
    /**
     * The type of the shape.
     * Available options are circle, rect and ellipse.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     *
     * @sample highcharts/annotations/ellipse/
     *         Ellipse annotation
     *
     * @type      {string}
     * @default   rect
     * @apioption annotations.shapeOptions.type
     */
    /**
     * The URL for an image to use as the annotation shape.
     * Note, type has to be set to `'image'`.
     *
     * @see [annotations.shapeOptions.type](annotations.shapeOptions.type)
     * @sample highcharts/annotations/shape-src/
     *         Define a marker image url for annotations
     *
     * @type      {string}
     * @apioption annotations.shapeOptions.src
     */
    /**
     * Name of the dash style to use for the shape's stroke.
     *
     * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     *
     * @type      {Highcharts.DashStyleValue}
     * @apioption annotations.shapeOptions.dashStyle
     */
    /**
     * The color of the shape's stroke.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     *
     * @type {Highcharts.ColorString}
     */
    stroke: "rgba(0, 0, 0, 0.75)",
    /**
     * The pixel stroke width of the shape.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     */
    strokeWidth: 1,
    /**
     * The color of the shape's fill.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     *
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    fill: "rgba(0, 0, 0, 0.75)",
    /**
     * The radius of the shape.
     *
     * @sample highcharts/annotations/shape/
     *         Basic shape annotation
     */
    r: 0,
    /**
     * Defines additional snapping area around an annotation
     * making this annotation to focus. Defined in pixels.
     */
    snap: 2
  },
  /**
   * Options for annotation's control points. Each control point
   * inherits options from controlPointOptions object.
   * Options from the controlPointOptions can be overwritten
   * by options in a specific control point.
   *
   * @declare  Highcharts.AnnotationControlPointOptionsObject
   * @requires modules/annotations
   */
  controlPointOptions: {
    /**
     * @type      {Highcharts.AnnotationControlPointPositionerFunction}
     * @apioption annotations.controlPointOptions.positioner
     */
    /**
     * @type {Highcharts.Dictionary<Function>}
     */
    events: {},
    /**
     * @type {Highcharts.SVGAttributes}
     */
    style: {
      cursor: "pointer",
      fill: "#ffffff",
      stroke: "#000000",
      "stroke-width": 2
    },
    height: 10,
    symbol: "circle",
    visible: false,
    width: 10
  },
  /**
   * Event callback when annotation is added to the chart.
   *
   * @type      {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
   * @since     7.1.0
   * @apioption annotations.events.add
   */
  /**
   * Event callback when annotation is updated (e.g. drag and
   * dropped or resized by control points).
   *
   * @type      {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
   * @since     7.1.0
   * @apioption annotations.events.afterUpdate
   */
  /**
   * Fires when the annotation is clicked.
   *
   * @type      {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
   * @since     7.1.0
   * @apioption annotations.events.click
   */
  /**
   * Fires when the annotation is dragged.
   *
   * @type      {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
   * @apioption annotations.events.drag
   */
  /**
   * Event callback when annotation is removed from the chart.
   *
   * @type      {Highcharts.EventCallbackFunction<Highcharts.Annotation>}
   * @since     7.1.0
   * @apioption annotations.events.remove
   */
  /**
   * Events available in annotations.
   *
   * @requires modules/annotations
   */
  events: {},
  /**
   * The Z index of the annotation.
   */
  zIndex: 6
};
const { doc: doc$9, isTouchDevice: isTouchDevice$1 } = Highcharts;
const { addEvent: addEvent$P, fireEvent: fireEvent$i, objectEach: objectEach$d, pick: pick$Z, removeEvent: removeEvent$4 } = Utilities;
class EventEmitter {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Add emitter events.
   * @private
   */
  addEvents() {
    const emitter = this, addMouseDownEvent = function(element) {
      addEvent$P(element, isTouchDevice$1 ? "touchstart" : "mousedown", (e) => {
        emitter.onMouseDown(e);
      }, { passive: false });
    };
    addMouseDownEvent(this.graphic.element);
    (emitter.labels || []).forEach((label) => {
      if (label.options.useHTML && label.graphic.text && !label.graphic.text.foreignObject) {
        addMouseDownEvent(label.graphic.text.element);
      }
    });
    objectEach$d(emitter.options.events, (event, type) => {
      const eventHandler = function(e) {
        if (type !== "click" || !emitter.cancelClick) {
          event.call(emitter, emitter.chart.pointer?.normalize(e), emitter.target);
        }
      };
      if ((emitter.nonDOMEvents || []).indexOf(type) === -1) {
        addEvent$P(emitter.graphic.element, type, eventHandler, { passive: false });
        if (emitter.graphic.div) {
          addEvent$P(emitter.graphic.div, type, eventHandler, { passive: false });
        }
      } else {
        addEvent$P(emitter, type, eventHandler, { passive: false });
      }
    });
    if (emitter.options.draggable) {
      addEvent$P(emitter, "drag", emitter.onDrag);
      if (!emitter.graphic.renderer.styledMode) {
        const cssPointer = {
          cursor: {
            x: "ew-resize",
            y: "ns-resize",
            xy: "move"
          }[emitter.options.draggable]
        };
        emitter.graphic.css(cssPointer);
        (emitter.labels || []).forEach((label) => {
          if (label.options.useHTML && label.graphic.text && !label.graphic.text.foreignObject) {
            label.graphic.text.css(cssPointer);
          }
        });
      }
    }
    if (!emitter.isUpdating) {
      fireEvent$i(emitter, "add");
    }
  }
  /**
   * Destroy the event emitter.
   */
  destroy() {
    this.removeDocEvents();
    removeEvent$4(this);
    this.hcEvents = null;
  }
  /**
   * Map mouse move event to the radians.
   * @private
   */
  mouseMoveToRadians(e, cx, cy) {
    let prevDy = e.prevChartY - cy, prevDx = e.prevChartX - cx, dy = e.chartY - cy, dx = e.chartX - cx, temp;
    if (this.chart.inverted) {
      temp = prevDx;
      prevDx = prevDy;
      prevDy = temp;
      temp = dx;
      dx = dy;
      dy = temp;
    }
    return Math.atan2(dy, dx) - Math.atan2(prevDy, prevDx);
  }
  /**
   * Map mouse move to the scale factors.
   * @private
   */
  mouseMoveToScale(e, cx, cy) {
    const prevDx = e.prevChartX - cx, prevDy = e.prevChartY - cy, dx = e.chartX - cx, dy = e.chartY - cy;
    let sx = (dx || 1) / (prevDx || 1), sy = (dy || 1) / (prevDy || 1);
    if (this.chart.inverted) {
      const temp = sy;
      sy = sx;
      sx = temp;
    }
    return {
      x: sx,
      y: sy
    };
  }
  /**
   * Map mouse move event to the distance between two following events.
   * @private
   */
  mouseMoveToTranslation(e) {
    let dx = e.chartX - e.prevChartX, dy = e.chartY - e.prevChartY, temp;
    if (this.chart.inverted) {
      temp = dy;
      dy = dx;
      dx = temp;
    }
    return {
      x: dx,
      y: dy
    };
  }
  /**
   * Drag and drop event. All basic annotations should share this
   * capability as well as the extended ones.
   * @private
   */
  onDrag(e) {
    if (this.chart.isInsidePlot(e.chartX - this.chart.plotLeft, e.chartY - this.chart.plotTop, {
      visiblePlotOnly: true
    })) {
      const translation = this.mouseMoveToTranslation(e);
      if (this.options.draggable === "x") {
        translation.y = 0;
      }
      if (this.options.draggable === "y") {
        translation.x = 0;
      }
      const emitter = this;
      if (emitter.points.length) {
        emitter.translate(translation.x, translation.y);
      } else {
        emitter.shapes.forEach((shape) => shape.translate(translation.x, translation.y));
        emitter.labels.forEach((label) => label.translate(translation.x, translation.y));
      }
      this.redraw(false);
    }
  }
  /**
   * Mouse down handler.
   * @private
   */
  onMouseDown(e) {
    if (e.preventDefault) {
      e.preventDefault();
    }
    if (e.button === 2) {
      return;
    }
    const emitter = this, pointer = emitter.chart.pointer, firesTouchEvents = e?.sourceCapabilities?.firesTouchEvents || false;
    e = pointer?.normalize(e) || e;
    let prevChartX = e.chartX, prevChartY = e.chartY;
    emitter.cancelClick = false;
    emitter.chart.hasDraggedAnnotation = true;
    emitter.removeDrag = addEvent$P(doc$9, isTouchDevice$1 || firesTouchEvents ? "touchmove" : "mousemove", function(e2) {
      emitter.hasDragged = true;
      e2 = pointer?.normalize(e2) || e2;
      e2.prevChartX = prevChartX;
      e2.prevChartY = prevChartY;
      fireEvent$i(emitter, "drag", e2);
      prevChartX = e2.chartX;
      prevChartY = e2.chartY;
    }, isTouchDevice$1 || firesTouchEvents ? { passive: false } : void 0);
    emitter.removeMouseUp = addEvent$P(doc$9, isTouchDevice$1 || firesTouchEvents ? "touchend" : "mouseup", function() {
      const annotation = pick$Z(emitter.target && emitter.target.annotation, emitter.target);
      if (annotation) {
        annotation.cancelClick = emitter.hasDragged;
      }
      emitter.cancelClick = emitter.hasDragged;
      emitter.chart.hasDraggedAnnotation = false;
      if (emitter.hasDragged) {
        fireEvent$i(pick$Z(
          annotation,
          // #15952
          emitter
        ), "afterUpdate");
      }
      emitter.hasDragged = false;
      emitter.onMouseUp();
    }, isTouchDevice$1 || firesTouchEvents ? { passive: false } : void 0);
  }
  /**
   * Mouse up handler.
   */
  onMouseUp() {
    this.removeDocEvents();
  }
  /**
   * Remove emitter document events.
   * @private
   */
  removeDocEvents() {
    if (this.removeDrag) {
      this.removeDrag = this.removeDrag();
    }
    if (this.removeMouseUp) {
      this.removeMouseUp = this.removeMouseUp();
    }
  }
}
const { merge: merge$$, pick: pick$Y } = Utilities;
class ControlPoint extends EventEmitter {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, target, options2, index) {
    super();
    this.nonDOMEvents = ["drag"];
    this.chart = chart;
    this.target = target;
    this.options = options2;
    this.index = pick$Y(options2.index, index);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Destroy the control point.
   * @private
   */
  destroy() {
    super.destroy();
    if (this.graphic) {
      this.graphic = this.graphic.destroy();
    }
    this.chart = null;
    this.target = null;
    this.options = null;
  }
  /**
   * Redraw the control point.
   * @private
   * @param {boolean} [animation]
   */
  redraw(animation) {
    this.graphic[animation ? "animate" : "attr"](this.options.positioner.call(this, this.target));
  }
  /**
   * Render the control point.
   * @private
   */
  render() {
    const chart = this.chart, options2 = this.options;
    this.graphic = chart.renderer.symbol(options2.symbol, 0, 0, options2.width, options2.height).add(chart.controlPointsGroup).css(options2.style);
    this.setVisibility(options2.visible);
    this.addEvents();
  }
  /**
   * Set the visibility of the control point.
   *
   * @function Highcharts.AnnotationControlPoint#setVisibility
   *
   * @param {boolean} visible
   * Visibility of the control point.
   *
   */
  setVisibility(visible) {
    this.graphic[visible ? "show" : "hide"]();
    this.options.visible = visible;
  }
  /**
   * Update the control point.
   *
   * @function Highcharts.AnnotationControlPoint#update
   *
   * @param {Partial<Highcharts.AnnotationControlPointOptionsObject>} userOptions
   * New options for the control point.
   */
  update(userOptions) {
    const chart = this.chart, target = this.target, index = this.index, options2 = merge$$(true, this.options, userOptions);
    this.destroy();
    this.constructor(chart, target, options2, index);
    this.render(chart.controlPointsGroup);
    this.redraw();
  }
}
const { series: { prototype: seriesProto$2 } } = SeriesRegistry$1;
const { defined: defined$B, fireEvent: fireEvent$h } = Utilities;
class MockPoint {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * Create a mock point from a real Highcharts point.
   *
   * @private
   * @static
   *
   * @param {Highcharts.Point} point
   *
   * @return {Highcharts.AnnotationMockPoint}
   * A mock point instance.
   */
  static fromPoint(point) {
    return new MockPoint(point.series.chart, null, {
      x: point.x,
      y: point.y,
      xAxis: point.series.xAxis,
      yAxis: point.series.yAxis
    });
  }
  /**
   * Get the pixel position from the point like object.
   *
   * @private
   * @static
   *
   * @param {Highcharts.AnnotationPointType} point
   *
   * @param {boolean} [paneCoordinates]
   *        Whether the pixel position should be relative
   *
   * @return {Highcharts.PositionObject} pixel position
   */
  static pointToPixels(point, paneCoordinates) {
    const series = point.series, chart = series.chart;
    let x = point.plotX || 0, y = point.plotY || 0, plotBox;
    if (chart.inverted) {
      if (point.mock) {
        x = point.plotY;
        y = point.plotX;
      } else {
        x = chart.plotWidth - (point.plotY || 0);
        y = chart.plotHeight - (point.plotX || 0);
      }
    }
    if (series && !paneCoordinates) {
      plotBox = series.getPlotBox();
      x += plotBox.translateX;
      y += plotBox.translateY;
    }
    return {
      x,
      y
    };
  }
  /**
   * Get fresh mock point options from the point like object.
   *
   * @private
   * @static
   *
   * @param {Highcharts.AnnotationPointType} point
   *
   * @return {Highcharts.AnnotationMockPointOptionsObject}
   * A mock point's options.
   */
  static pointToOptions(point) {
    return {
      x: point.x,
      y: point.y,
      xAxis: point.series.xAxis,
      yAxis: point.series.yAxis
    };
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, target, options2) {
    this.mock = true;
    this.point = this;
    this.series = {
      visible: true,
      chart,
      getPlotBox: seriesProto$2.getPlotBox
    };
    this.target = target || null;
    this.options = options2;
    this.applyOptions(this.getOptions());
  }
  /**
   * Apply options for the point.
   * @private
   * @param {Highcharts.AnnotationMockPointOptionsObject} options
   */
  applyOptions(options2) {
    this.command = options2.command;
    this.setAxis(options2, "x");
    this.setAxis(options2, "y");
    this.refresh();
  }
  /**
   * Get the point's options.
   * @private
   * @return {Highcharts.AnnotationMockPointOptionsObject}
   * The mock point's options.
   */
  getOptions() {
    return this.hasDynamicOptions() ? this.options(this.target) : this.options;
  }
  /**
   * Check if the point has dynamic options.
   * @private
   * @return {boolean}
   * A positive flag if the point has dynamic options.
   */
  hasDynamicOptions() {
    return typeof this.options === "function";
  }
  /**
   * Check if the point is inside its pane.
   * @private
   * @return {boolean} A flag indicating whether the point is inside the pane.
   */
  isInsidePlot() {
    const plotX = this.plotX, plotY = this.plotY, xAxis2 = this.series.xAxis, yAxis2 = this.series.yAxis, e = {
      x: plotX,
      y: plotY,
      isInsidePlot: true,
      options: {}
    };
    if (xAxis2) {
      e.isInsidePlot = defined$B(plotX) && plotX >= 0 && plotX <= xAxis2.len;
    }
    if (yAxis2) {
      e.isInsidePlot = e.isInsidePlot && defined$B(plotY) && plotY >= 0 && plotY <= yAxis2.len;
    }
    fireEvent$h(this.series.chart, "afterIsInsidePlot", e);
    return e.isInsidePlot;
  }
  /**
   * Refresh point values and coordinates based on its options.
   * @private
   */
  refresh() {
    const series = this.series, xAxis2 = series.xAxis, yAxis2 = series.yAxis, options2 = this.getOptions();
    if (xAxis2) {
      this.x = options2.x;
      this.plotX = xAxis2.toPixels(options2.x, true);
    } else {
      this.x = void 0;
      this.plotX = options2.x;
    }
    if (yAxis2) {
      this.y = options2.y;
      this.plotY = yAxis2.toPixels(options2.y, true);
    } else {
      this.y = null;
      this.plotY = options2.y;
    }
    this.isInside = this.isInsidePlot();
  }
  /**
   * Refresh point options based on its plot coordinates.
   * @private
   */
  refreshOptions() {
    const series = this.series, xAxis2 = series.xAxis, yAxis2 = series.yAxis;
    this.x = this.options.x = xAxis2 ? this.options.x = xAxis2.toValue(this.plotX, true) : this.plotX;
    this.y = this.options.y = yAxis2 ? yAxis2.toValue(this.plotY, true) : this.plotY;
  }
  /**
   * Rotate the point.
   * @private
   * @param {number} cx origin x rotation
   * @param {number} cy origin y rotation
   * @param {number} radians
   */
  rotate(cx, cy, radians) {
    if (!this.hasDynamicOptions()) {
      const cos2 = Math.cos(radians), sin2 = Math.sin(radians), x = this.plotX - cx, y = this.plotY - cy, tx = x * cos2 - y * sin2, ty = x * sin2 + y * cos2;
      this.plotX = tx + cx;
      this.plotY = ty + cy;
      this.refreshOptions();
    }
  }
  /**
   * Scale the point.
   *
   * @private
   *
   * @param {number} cx
   * Origin x transformation.
   *
   * @param {number} cy
   * Origin y transformation.
   *
   * @param {number} sx
   * Scale factor x.
   *
   * @param {number} sy
   * Scale factor y.
   */
  scale(cx, cy, sx, sy) {
    if (!this.hasDynamicOptions()) {
      const x = this.plotX * sx, y = this.plotY * sy, tx = (1 - sx) * cx, ty = (1 - sy) * cy;
      this.plotX = tx + x;
      this.plotY = ty + y;
      this.refreshOptions();
    }
  }
  /**
   * Set x or y axis.
   * @private
   * @param {Highcharts.AnnotationMockPointOptionsObject} options
   * @param {string} xOrY
   * 'x' or 'y' string literal
   */
  setAxis(options2, xOrY) {
    const axisName = xOrY + "Axis", axisOptions = options2[axisName], chart = this.series.chart;
    this.series[axisName] = typeof axisOptions === "object" ? axisOptions : defined$B(axisOptions) ? chart[axisName][axisOptions] || // @todo v--- (axisName)[axisOptions] ?
    chart.get(axisOptions) : null;
  }
  /**
   * Transform the mock point to an anchor (relative position on the chart).
   * @private
   * @return {Array<number>}
   * A quadruple of numbers which denotes x, y, width and height of the box
   **/
  toAnchor() {
    const anchor = [this.plotX, this.plotY, 0, 0];
    if (this.series.chart.inverted) {
      anchor[0] = this.plotY;
      anchor[1] = this.plotX;
    }
    return anchor;
  }
  /**
   * Translate the point.
   *
   * @private
   *
   * @param {number|undefined} cx
   * Origin x transformation.
   *
   * @param {number|undefined} cy
   * Origin y transformation.
   *
   * @param {number} dx
   * Translation for x coordinate.
   *
   * @param {number} dy
   * Translation for y coordinate.
   **/
  translate(_cx, _cy, dx, dy) {
    if (!this.hasDynamicOptions()) {
      this.plotX += dx;
      this.plotY += dy;
      this.refreshOptions();
    }
  }
}
var ControlTarget;
(function(ControlTarget2) {
  function addControlPoints() {
    const controlPoints = this.controlPoints, controlPointsOptions = this.options.controlPoints || [];
    controlPointsOptions.forEach((controlPointOptions, i) => {
      const options2 = Utilities.merge(this.options.controlPointOptions, controlPointOptions);
      if (!options2.index) {
        options2.index = i;
      }
      controlPointsOptions[i] = options2;
      controlPoints.push(new ControlPoint(this.chart, this, options2));
    });
  }
  function anchor(point2) {
    const plotBox = point2.series.getPlotBox(), chart = point2.series.chart, box = point2.mock ? point2.toAnchor() : chart.tooltip && chart.tooltip.getAnchor.call({
      chart: point2.series.chart
    }, point2) || [0, 0, 0, 0], anchor2 = {
      x: box[0] + (this.options.x || 0),
      y: box[1] + (this.options.y || 0),
      height: box[2] || 0,
      width: box[3] || 0
    };
    return {
      relativePosition: anchor2,
      absolutePosition: Utilities.merge(anchor2, {
        x: anchor2.x + (point2.mock ? plotBox.translateX : chart.plotLeft),
        y: anchor2.y + (point2.mock ? plotBox.translateY : chart.plotTop)
      })
    };
  }
  function compose2(ControlTargetClass) {
    const controlProto = ControlTargetClass.prototype;
    if (!controlProto.addControlPoints) {
      Utilities.merge(true, controlProto, {
        addControlPoints,
        anchor,
        destroyControlTarget,
        getPointsOptions,
        linkPoints,
        point,
        redrawControlPoints,
        renderControlPoints,
        transform: transform2,
        transformPoint,
        translate: translate2,
        translatePoint
      });
    }
  }
  ControlTarget2.compose = compose2;
  function destroyControlTarget() {
    this.controlPoints.forEach((controlPoint) => controlPoint.destroy());
    this.chart = null;
    this.controlPoints = null;
    this.points = null;
    this.options = null;
    if (this.annotation) {
      this.annotation = null;
    }
  }
  function getPointsOptions() {
    const options2 = this.options;
    return options2.points || options2.point && Utilities.splat(options2.point);
  }
  function linkPoints() {
    const pointsOptions = this.getPointsOptions(), points = this.points, len = pointsOptions && pointsOptions.length || 0;
    let i, point2;
    for (i = 0; i < len; i++) {
      point2 = this.point(pointsOptions[i], points[i]);
      if (!point2) {
        points.length = 0;
        return;
      }
      if (point2.mock) {
        point2.refresh();
      }
      points[i] = point2;
    }
    return points;
  }
  function point(pointOptions, point2) {
    if (pointOptions && pointOptions.series) {
      return pointOptions;
    }
    if (!point2 || point2.series === null) {
      if (Utilities.isObject(pointOptions)) {
        point2 = new MockPoint(this.chart, this, pointOptions);
      } else if (Utilities.isString(pointOptions)) {
        point2 = this.chart.get(pointOptions) || null;
      } else if (typeof pointOptions === "function") {
        const pointConfig = pointOptions.call(point2, this);
        point2 = pointConfig.series ? pointConfig : new MockPoint(this.chart, this, pointOptions);
      }
    }
    return point2;
  }
  function redrawControlPoints(animation) {
    this.controlPoints.forEach((controlPoint) => controlPoint.redraw(animation));
  }
  function renderControlPoints() {
    this.controlPoints.forEach((controlPoint) => controlPoint.render());
  }
  function transform2(transformation, cx, cy, p12, p22) {
    if (this.chart.inverted) {
      const temp = cx;
      cx = cy;
      cy = temp;
    }
    this.points.forEach((_point, i) => this.transformPoint(transformation, cx, cy, p12, p22, i), this);
  }
  function transformPoint(transformation, cx, cy, p12, p22, i) {
    let point2 = this.points[i];
    if (!point2.mock) {
      point2 = this.points[i] = MockPoint.fromPoint(point2);
    }
    point2[transformation](cx, cy, p12, p22);
  }
  function translate2(dx, dy) {
    this.transform("translate", null, null, dx, dy);
  }
  function translatePoint(dx, dy, i) {
    this.transformPoint("translate", null, null, dx, dy, i);
  }
})(ControlTarget || (ControlTarget = {}));
const ControlTarget$1 = ControlTarget;
const { merge: merge$_ } = Utilities;
class Controllable {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(annotation, options2, index, itemType) {
    this.annotation = annotation;
    this.chart = annotation.chart;
    this.collection = itemType === "label" ? "labels" : "shapes";
    this.controlPoints = [];
    this.options = options2;
    this.points = [];
    this.index = index;
    this.itemType = itemType;
    this.init(annotation, options2, index);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Redirect attr usage on the controllable graphic element.
   * @private
   */
  attr(..._args) {
    this.graphic.attr.apply(this.graphic, arguments);
  }
  /**
   * Utility function for mapping item's options
   * to element's attribute
   * @private
   * @param {Highcharts.AnnotationsLabelsOptions|Highcharts.AnnotationsShapesOptions} options
   * @return {Highcharts.SVGAttributes}
   *         Mapped options.
   */
  attrsFromOptions(options2) {
    const map = this.constructor.attrsMap, attrs = {}, styledMode = this.chart.styledMode;
    let key2, mappedKey;
    for (key2 in options2) {
      mappedKey = map[key2];
      if (typeof map[key2] !== "undefined" && (!styledMode || ["fill", "stroke", "stroke-width"].indexOf(mappedKey) === -1)) {
        attrs[mappedKey] = options2[key2];
      }
    }
    return attrs;
  }
  /**
   * Destroy a controllable.
   * @private
   */
  destroy() {
    if (this.graphic) {
      this.graphic = this.graphic.destroy();
    }
    if (this.tracker) {
      this.tracker = this.tracker.destroy();
    }
    this.destroyControlTarget();
  }
  /**
   * Init the controllable
   * @private
   */
  init(annotation, options2, index) {
    this.annotation = annotation;
    this.chart = annotation.chart;
    this.options = options2;
    this.points = [];
    this.controlPoints = [];
    this.index = index;
    this.linkPoints();
    this.addControlPoints();
  }
  /**
   * Redraw a controllable.
   * @private
   */
  redraw(animation) {
    this.redrawControlPoints(animation);
  }
  /**
   * Render a controllable.
   * @private
   */
  render(_parentGroup) {
    if (this.options.className && this.graphic) {
      this.graphic.addClass(this.options.className);
    }
    this.renderControlPoints();
  }
  /**
   * Rotate a controllable.
   * @private
   * @param {number} cx
   *        Origin x rotation
   * @param {number} cy
   *        Origin y rotation
   * @param {number} radians
   **/
  rotate(cx, cy, radians) {
    this.transform("rotate", cx, cy, radians);
  }
  /**
   * Scale a controllable.
   * @private
   * @param {number} cx
   *        Origin x rotation
   * @param {number} cy
   *        Origin y rotation
   * @param {number} sx
   *        Scale factor x
   * @param {number} sy
   *        Scale factor y
   */
  scale(cx, cy, sx, sy) {
    this.transform("scale", cx, cy, sx, sy);
  }
  /**
   * Set control points' visibility.
   * @private
   */
  setControlPointsVisibility(visible) {
    this.controlPoints.forEach((controlPoint) => {
      controlPoint.setVisibility(visible);
    });
  }
  /**
   * Check if a controllable should be rendered/redrawn.
   * @private
   * @return {boolean}
   *         Whether a controllable should be drawn.
   */
  shouldBeDrawn() {
    return !!this.points.length;
  }
  /**
   * Translate shape within controllable item.
   * Replaces `controllable.translate` method.
   * @private
   * @param {number} dx
   *        Translation for x coordinate
   * @param {number} dy
   *        Translation for y coordinate
   * @param {boolean|undefined} translateSecondPoint
   *        If the shape has two points attached to it, this option allows you
   *        to translate also the second point.
   */
  translateShape(dx, dy, translateSecondPoint) {
    const chart = this.annotation.chart, shapeOptions = this.annotation.userOptions, annotationIndex = chart.annotations.indexOf(this.annotation), chartOptions = chart.options.annotations[annotationIndex];
    this.translatePoint(dx, dy, 0);
    if (translateSecondPoint) {
      this.translatePoint(dx, dy, 1);
    }
    chartOptions[this.collection][this.index].point = this.options.point;
    shapeOptions[this.collection][this.index].point = this.options.point;
  }
  /**
   * Update a controllable.
   * @private
   */
  update(newOptions) {
    const annotation = this.annotation, options2 = merge$_(true, this.options, newOptions), parentGroup = this.graphic.parentGroup, Constructor = this.constructor;
    this.destroy();
    const newControllable = new Constructor(annotation, options2, this.index, this.itemType);
    merge$_(true, this, newControllable);
    this.render(parentGroup);
    this.redraw();
  }
}
ControlTarget$1.compose(Controllable);
const defaultMarkers$1 = {
  /**
   * @type {Highcharts.ASTNode}
   */
  arrow: {
    tagName: "marker",
    attributes: {
      id: "arrow",
      refY: 5,
      refX: 9,
      markerWidth: 10,
      markerHeight: 10
    },
    /**
     * @type {Array<Highcharts.DefsOptions>}
     */
    children: [{
      tagName: "path",
      attributes: {
        d: "M 0 0 L 10 5 L 0 10 Z",
        // Triangle (used as an arrow)
        "stroke-width": 0
      }
    }]
  },
  /**
   * @type {Highcharts.ASTNode}
   */
  "reverse-arrow": {
    tagName: "marker",
    attributes: {
      id: "reverse-arrow",
      refY: 5,
      refX: 1,
      markerWidth: 10,
      markerHeight: 10
    },
    children: [{
      tagName: "path",
      attributes: {
        // Reverse triangle (used as an arrow)
        d: "M 0 5 L 10 0 L 10 10 Z",
        "stroke-width": 0
      }
    }]
  }
};
const ControllableDefaults = {
  defaultMarkers: defaultMarkers$1
};
const { defaultMarkers } = ControllableDefaults;
const { addEvent: addEvent$O, defined: defined$A, extend: extend$Q, merge: merge$Z, uniqueKey: uniqueKey$3 } = Utilities;
const markerEndSetter = createMarkerSetter("marker-end");
const markerStartSetter = createMarkerSetter("marker-start");
const TRACKER_FILL = "rgba(192,192,192," + (Highcharts.svg ? 1e-4 : 2e-3) + ")";
function createMarkerSetter(markerType) {
  return function(value) {
    this.attr(markerType, "url(#" + value + ")");
  };
}
function onChartAfterGetContainer() {
  this.options.defs = merge$Z(defaultMarkers, this.options.defs || {});
}
function svgRendererAddMarker(id, markerOptions) {
  const options2 = { attributes: { id } };
  const attrs = {
    stroke: markerOptions.color || "none",
    fill: markerOptions.color || "rgba(0, 0, 0, 0.75)"
  };
  options2.children = markerOptions.children && markerOptions.children.map(function(child) {
    return merge$Z(attrs, child);
  });
  const ast = merge$Z(true, {
    attributes: {
      markerWidth: 20,
      markerHeight: 20,
      refX: 0,
      refY: 0,
      orient: "auto"
    }
  }, markerOptions, options2);
  const marker = this.definition(ast);
  marker.id = id;
  return marker;
}
class ControllablePath extends Controllable {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(ChartClass, SVGRendererClass) {
    const svgRendererProto = SVGRendererClass.prototype;
    if (!svgRendererProto.addMarker) {
      addEvent$O(ChartClass, "afterGetContainer", onChartAfterGetContainer);
      svgRendererProto.addMarker = svgRendererAddMarker;
    }
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(annotation, options2, index) {
    super(annotation, options2, index, "shape");
    this.type = "path";
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Map the controllable path to 'd' path attribute.
   *
   * @return {Highcharts.SVGPathArray|null}
   * A path's d attribute.
   */
  toD() {
    const dOption = this.options.d;
    if (dOption) {
      return typeof dOption === "function" ? dOption.call(this) : dOption;
    }
    const points = this.points, len = points.length, d = [];
    let showPath = len, point = points[0], position = showPath && this.anchor(point).absolutePosition, pointIndex = 0, command;
    if (position) {
      d.push(["M", position.x, position.y]);
      while (++pointIndex < len && showPath) {
        point = points[pointIndex];
        command = point.command || "L";
        position = this.anchor(point).absolutePosition;
        if (command === "M") {
          d.push([command, position.x, position.y]);
        } else if (command === "L") {
          d.push([command, position.x, position.y]);
        } else if (command === "Z") {
          d.push([command]);
        }
        showPath = point.series.visible;
      }
    }
    return showPath && this.graphic ? this.chart.renderer.crispLine(d, this.graphic.strokeWidth()) : null;
  }
  shouldBeDrawn() {
    return super.shouldBeDrawn() || !!this.options.d;
  }
  render(parent) {
    const options2 = this.options, attrs = this.attrsFromOptions(options2);
    this.graphic = this.annotation.chart.renderer.path([["M", 0, 0]]).attr(attrs).add(parent);
    this.tracker = this.annotation.chart.renderer.path([["M", 0, 0]]).addClass("highcharts-tracker-line").attr({
      zIndex: 2
    }).add(parent);
    if (!this.annotation.chart.styledMode) {
      this.tracker.attr({
        "stroke-linejoin": "round",
        // #1225
        stroke: TRACKER_FILL,
        fill: TRACKER_FILL,
        "stroke-width": this.graphic.strokeWidth() + options2.snap * 2
      });
    }
    super.render();
    extend$Q(this.graphic, { markerStartSetter, markerEndSetter });
    this.setMarkers(this);
  }
  redraw(animation) {
    if (this.graphic) {
      const d = this.toD(), action = animation ? "animate" : "attr";
      if (d) {
        this.graphic[action]({ d });
        this.tracker[action]({ d });
      } else {
        this.graphic.attr({ d: "M 0 " + -9e9 });
        this.tracker.attr({ d: "M 0 " + -9e9 });
      }
      this.graphic.placed = this.tracker.placed = !!d;
    }
    super.redraw(animation);
  }
  /**
   * Set markers.
   * @private
   * @param {Highcharts.AnnotationControllablePath} item
   */
  setMarkers(item) {
    const itemOptions = item.options, chart = item.chart, defs2 = chart.options.defs, fill = itemOptions.fill, color2 = defined$A(fill) && fill !== "none" ? fill : itemOptions.stroke;
    const setMarker = function(markerType) {
      const markerId = itemOptions[markerType];
      let def, predefinedMarker, key2, marker;
      if (markerId) {
        for (key2 in defs2) {
          def = defs2[key2];
          if ((markerId === (def.attributes && def.attributes.id) || // Legacy, for
          // unit-tests/annotations/annotations-shapes
          markerId === def.id) && def.tagName === "marker") {
            predefinedMarker = def;
            break;
          }
        }
        if (predefinedMarker) {
          marker = item[markerType] = chart.renderer.addMarker((itemOptions.id || uniqueKey$3()) + "-" + markerId, merge$Z(predefinedMarker, { color: color2 }));
          item.attr(markerType, marker.getAttribute("id"));
        }
      }
    };
    ["markerStart", "markerEnd"].forEach(setMarker);
  }
}
ControllablePath.attrsMap = {
  dashStyle: "dashstyle",
  strokeWidth: "stroke-width",
  stroke: "stroke",
  fill: "fill",
  zIndex: "zIndex"
};
const { merge: merge$Y } = Utilities;
class ControllableRect extends Controllable {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(annotation, options2, index) {
    super(annotation, options2, index, "shape");
    this.type = "rect";
    this.translate = super.translateShape;
  }
  /* *
   *
   *  Functions
   *
   * */
  render(parent) {
    const attrs = this.attrsFromOptions(this.options);
    this.graphic = this.annotation.chart.renderer.rect(0, -9e9, 0, 0).attr(attrs).add(parent);
    super.render();
  }
  redraw(animation) {
    if (this.graphic) {
      const position = this.anchor(this.points[0]).absolutePosition;
      if (position) {
        this.graphic[animation ? "animate" : "attr"]({
          x: position.x,
          y: position.y,
          width: this.options.width,
          height: this.options.height
        });
      } else {
        this.attr({
          x: 0,
          y: -9e9
        });
      }
      this.graphic.placed = Boolean(position);
    }
    super.redraw(animation);
  }
}
ControllableRect.attrsMap = merge$Y(ControllablePath.attrsMap, {
  width: "width",
  height: "height"
});
const { merge: merge$X } = Utilities;
class ControllableCircle extends Controllable {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(annotation, options2, index) {
    super(annotation, options2, index, "shape");
    this.type = "circle";
    this.translate = super.translateShape;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  redraw(animation) {
    if (this.graphic) {
      const position = this.anchor(this.points[0]).absolutePosition;
      if (position) {
        this.graphic[animation ? "animate" : "attr"]({
          x: position.x,
          y: position.y,
          r: this.options.r
        });
      } else {
        this.graphic.attr({
          x: 0,
          y: -9e9
        });
      }
      this.graphic.placed = !!position;
    }
    super.redraw.call(this, animation);
  }
  /**
   * @private
   */
  render(parent) {
    const attrs = this.attrsFromOptions(this.options);
    this.graphic = this.annotation.chart.renderer.circle(0, -9e9, 0).attr(attrs).add(parent);
    super.render();
  }
  /**
   * Set the radius.
   * @private
   * @param {number} r
   *        A radius to be set
   */
  setRadius(r) {
    this.options.r = r;
  }
}
ControllableCircle.attrsMap = merge$X(ControllablePath.attrsMap, { r: "r" });
const { merge: merge$W, defined: defined$z } = Utilities;
class ControllableEllipse extends Controllable {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(annotation, options2, index) {
    super(annotation, options2, index, "shape");
    this.type = "ellipse";
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  init(annotation, options2, index) {
    if (defined$z(options2.yAxis)) {
      options2.points.forEach((point) => {
        point.yAxis = options2.yAxis;
      });
    }
    if (defined$z(options2.xAxis)) {
      options2.points.forEach((point) => {
        point.xAxis = options2.xAxis;
      });
    }
    super.init(annotation, options2, index);
  }
  /**
   * Render the element
   * @private
   * @param parent
   *        Parent SVG element.
   */
  render(parent) {
    this.graphic = this.annotation.chart.renderer.createElement("ellipse").attr(this.attrsFromOptions(this.options)).add(parent);
    super.render();
  }
  /**
   * Translate the points. Mostly used to handle dragging of the ellipse.
   * @private
   */
  translate(dx, dy) {
    super.translateShape(dx, dy, true);
  }
  /**
   * Get the distance from the line to the point.
   * @private
   * @param point1
   *        First point which is on the line
   * @param point2
   *        Second point
   * @param x0
   *        Point's x value from which you want to calculate the distance from
   * @param y0
   *        Point's y value from which you want to calculate the distance from
   */
  getDistanceFromLine(point1, point2, x0, y0) {
    return Math.abs((point2.y - point1.y) * x0 - (point2.x - point1.x) * y0 + point2.x * point1.y - point2.y * point1.x) / Math.sqrt((point2.y - point1.y) * (point2.y - point1.y) + (point2.x - point1.x) * (point2.x - point1.x));
  }
  /**
   * The function calculates the svg attributes of the ellipse, and returns
   * all parameters necessary to draw the ellipse.
   * @private
   * @param position
   *        Absolute position of the first point in points array
   * @param position2
   *        Absolute position of the second point in points array
   */
  getAttrs(position, position2) {
    const x1 = position.x, y1 = position.y, x2 = position2.x, y2 = position2.y, cx = (x1 + x2) / 2, cy = (y1 + y2) / 2, rx = Math.sqrt((x1 - x2) * (x1 - x2) / 4 + (y1 - y2) * (y1 - y2) / 4), tan = (y2 - y1) / (x2 - x1);
    let angle = Math.atan(tan) * 180 / Math.PI;
    if (cx < x1) {
      angle += 180;
    }
    const ry = this.getRY();
    return { cx, cy, rx, ry, angle };
  }
  /**
   * Get the value of minor radius of the ellipse.
   * @private
   */
  getRY() {
    const yAxis2 = this.getYAxis();
    return defined$z(yAxis2) ? Math.abs(yAxis2.toPixels(this.options.ry) - yAxis2.toPixels(0)) : this.options.ry;
  }
  /**
   * Get the yAxis object to which the ellipse is pinned.
   * @private
   */
  getYAxis() {
    const yAxisIndex = this.options.yAxis;
    return this.chart.yAxis[yAxisIndex];
  }
  /**
   * Get the absolute coordinates of the MockPoint
   * @private
   * @param point
   *        MockPoint that is added through options
   */
  getAbsolutePosition(point) {
    return this.anchor(point).absolutePosition;
  }
  /**
   * Redraw the element
   * @private
   * @param animation
   *        Display an animation
   */
  redraw(animation) {
    if (this.graphic) {
      const position = this.getAbsolutePosition(this.points[0]), position2 = this.getAbsolutePosition(this.points[1]), attrs = this.getAttrs(position, position2);
      if (position) {
        this.graphic[animation ? "animate" : "attr"]({
          cx: attrs.cx,
          cy: attrs.cy,
          rx: attrs.rx,
          ry: attrs.ry,
          rotation: attrs.angle,
          rotationOriginX: attrs.cx,
          rotationOriginY: attrs.cy
        });
      } else {
        this.graphic.attr({
          x: 0,
          y: -9e9
        });
      }
      this.graphic.placed = Boolean(position);
    }
    super.redraw(animation);
  }
  /**
   * Set the radius Y.
   * @private
   * @param {number} ry
   *        A radius in y direction to be set
   */
  setYRadius(ry) {
    const shapes = this.annotation.userOptions.shapes;
    this.options.ry = ry;
    if (shapes && shapes[0]) {
      shapes[0].ry = ry;
      shapes[0].ry = ry;
    }
  }
}
ControllableEllipse.attrsMap = merge$W(ControllablePath.attrsMap, {
  ry: "ry"
});
const { format: format$3 } = Templating;
const { extend: extend$P, getAlignFactor: getAlignFactor$1, isNumber: isNumber$A, pick: pick$X } = Utilities;
function symbolConnector(x, y, w, h, options2) {
  const anchorX = options2 && options2.anchorX, anchorY = options2 && options2.anchorY;
  let path, yOffset, lateral = w / 2;
  if (isNumber$A(anchorX) && isNumber$A(anchorY)) {
    path = [["M", anchorX, anchorY]];
    yOffset = y - anchorY;
    if (yOffset < 0) {
      yOffset = -h - yOffset;
    }
    if (yOffset < w) {
      lateral = anchorX < x + w / 2 ? yOffset : w - yOffset;
    }
    if (anchorY > y + h) {
      path.push(["L", x + lateral, y + h]);
    } else if (anchorY < y) {
      path.push(["L", x + lateral, y]);
    } else if (anchorX < x) {
      path.push(["L", x, y + h / 2]);
    } else if (anchorX > x + w) {
      path.push(["L", x + w, y + h / 2]);
    }
  }
  return path || [];
}
class ControllableLabel extends Controllable {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * Returns new aligned position based alignment options and box to align to.
   * It is almost a one-to-one copy from SVGElement.prototype.align
   * except it does not use and mutate an element
   *
   * @param {Highcharts.AnnotationAlignObject} alignOptions
   *
   * @param {Highcharts.BBoxObject} box
   *
   * @return {Highcharts.PositionObject}
   * Aligned position.
   */
  static alignedPosition(alignOptions, box) {
    return {
      x: Math.round((box.x || 0) + (alignOptions.x || 0) + (box.width - (alignOptions.width || 0)) * getAlignFactor$1(alignOptions.align)),
      y: Math.round((box.y || 0) + (alignOptions.y || 0) + (box.height - (alignOptions.height || 0)) * getAlignFactor$1(alignOptions.verticalAlign))
    };
  }
  static compose(SVGRendererClass) {
    const symbols2 = SVGRendererClass.prototype.symbols;
    symbols2.connector = symbolConnector;
  }
  /**
   * Returns new alignment options for a label if the label is outside the
   * plot area. It is almost a one-to-one copy from
   * Series.prototype.justifyDataLabel except it does not mutate the label and
   * it works with absolute instead of relative position.
   */
  static justifiedOptions(chart, label, alignOptions, alignAttr) {
    const align = alignOptions.align, verticalAlign = alignOptions.verticalAlign, padding = label.box ? 0 : label.padding || 0, bBox = label.getBBox(), options2 = {
      align,
      verticalAlign,
      x: alignOptions.x,
      y: alignOptions.y,
      width: label.width,
      height: label.height
    }, x = (alignAttr.x || 0) - chart.plotLeft, y = (alignAttr.y || 0) - chart.plotTop;
    let off;
    off = x + padding;
    if (off < 0) {
      if (align === "right") {
        options2.align = "left";
      } else {
        options2.x = (options2.x || 0) - off;
      }
    }
    off = x + bBox.width - padding;
    if (off > chart.plotWidth) {
      if (align === "left") {
        options2.align = "right";
      } else {
        options2.x = (options2.x || 0) + chart.plotWidth - off;
      }
    }
    off = y + padding;
    if (off < 0) {
      if (verticalAlign === "bottom") {
        options2.verticalAlign = "top";
      } else {
        options2.y = (options2.y || 0) - off;
      }
    }
    off = y + bBox.height - padding;
    if (off > chart.plotHeight) {
      if (verticalAlign === "top") {
        options2.verticalAlign = "bottom";
      } else {
        options2.y = (options2.y || 0) + chart.plotHeight - off;
      }
    }
    return options2;
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(annotation, options2, index) {
    super(annotation, options2, index, "label");
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Translate the point of the label by deltaX and deltaY translations.
   * The point is the label's anchor.
   *
   * @param {number} dx translation for x coordinate
   * @param {number} dy translation for y coordinate
   */
  translatePoint(dx, dy) {
    super.translatePoint(dx, dy, 0);
  }
  /**
   * Translate x and y position relative to the label's anchor.
   *
   * @param {number} dx translation for x coordinate
   * @param {number} dy translation for y coordinate
   */
  translate(dx, dy) {
    const chart = this.annotation.chart, labelOptions = this.annotation.userOptions, annotationIndex = chart.annotations.indexOf(this.annotation), chartAnnotations = chart.options.annotations, chartOptions = chartAnnotations[annotationIndex];
    if (chart.inverted) {
      const temp = dx;
      dx = dy;
      dy = temp;
    }
    this.options.x += dx;
    this.options.y += dy;
    chartOptions[this.collection][this.index].x = this.options.x;
    chartOptions[this.collection][this.index].y = this.options.y;
    labelOptions[this.collection][this.index].x = this.options.x;
    labelOptions[this.collection][this.index].y = this.options.y;
  }
  render(parent) {
    const options2 = this.options, attrs = this.attrsFromOptions(options2), style = options2.style;
    this.graphic = this.annotation.chart.renderer.label(
      "",
      0,
      -9999,
      // #10055
      options2.shape,
      null,
      null,
      options2.useHTML,
      null,
      "annotation-label"
    ).attr(attrs).add(parent);
    if (!this.annotation.chart.styledMode) {
      if (style.color === "contrast") {
        style.color = this.annotation.chart.renderer.getContrast(ControllableLabel.shapesWithoutBackground.indexOf(options2.shape) > -1 ? "#FFFFFF" : options2.backgroundColor);
      }
      this.graphic.css(options2.style).shadow(options2.shadow);
    }
    this.graphic.labelrank = options2.labelrank;
    super.render();
  }
  redraw(animation) {
    const options2 = this.options, text = this.text || options2.format || options2.text, label = this.graphic, point = this.points[0];
    if (!label) {
      this.redraw(animation);
      return;
    }
    label.attr({
      text: text ? format$3(String(text), point, this.annotation.chart) : options2.formatter.call(point, this)
    });
    const anchor = this.anchor(point);
    const attrs = this.position(anchor);
    if (attrs) {
      label.alignAttr = attrs;
      attrs.anchorX = anchor.absolutePosition.x;
      attrs.anchorY = anchor.absolutePosition.y;
      label[animation ? "animate" : "attr"](attrs);
    } else {
      label.attr({
        x: 0,
        y: -9999
        // #10055
      });
    }
    label.placed = !!attrs;
    super.redraw(animation);
  }
  /**
   * All basic shapes don't support alignTo() method except label.
   * For a controllable label, we need to subtract translation from
   * options.
   */
  anchor(_point) {
    const anchor = super.anchor.apply(this, arguments), x = this.options.x || 0, y = this.options.y || 0;
    anchor.absolutePosition.x -= x;
    anchor.absolutePosition.y -= y;
    anchor.relativePosition.x -= x;
    anchor.relativePosition.y -= y;
    return anchor;
  }
  /**
   * Returns the label position relative to its anchor.
   */
  position(anchor) {
    const item = this.graphic, chart = this.annotation.chart, tooltip = chart.tooltip, point = this.points[0], itemOptions = this.options, anchorAbsolutePosition = anchor.absolutePosition, anchorRelativePosition = anchor.relativePosition;
    let itemPosition, alignTo, itemPosRelativeX, itemPosRelativeY, showItem = point.series.visible && MockPoint.prototype.isInsidePlot.call(point);
    if (item && showItem) {
      const { width = 0, height = 0 } = item;
      if (itemOptions.distance && tooltip) {
        itemPosition = tooltip.getPosition.call({
          chart,
          distance: pick$X(itemOptions.distance, 16),
          getPlayingField: tooltip.getPlayingField,
          pointer: tooltip.pointer
        }, width, height, {
          plotX: anchorRelativePosition.x,
          plotY: anchorRelativePosition.y,
          negative: point.negative,
          ttBelow: point.ttBelow,
          h: anchorRelativePosition.height || anchorRelativePosition.width
        });
      } else if (itemOptions.positioner) {
        itemPosition = itemOptions.positioner.call(this);
      } else {
        alignTo = {
          x: anchorAbsolutePosition.x,
          y: anchorAbsolutePosition.y,
          width: 0,
          height: 0
        };
        itemPosition = ControllableLabel.alignedPosition(extend$P(itemOptions, {
          width,
          height
        }), alignTo);
        if (this.options.overflow === "justify") {
          itemPosition = ControllableLabel.alignedPosition(ControllableLabel.justifiedOptions(chart, item, itemOptions, itemPosition), alignTo);
        }
      }
      if (itemOptions.crop) {
        itemPosRelativeX = itemPosition.x - chart.plotLeft;
        itemPosRelativeY = itemPosition.y - chart.plotTop;
        showItem = chart.isInsidePlot(itemPosRelativeX, itemPosRelativeY) && chart.isInsidePlot(itemPosRelativeX + width, itemPosRelativeY + height);
      }
    }
    return showItem ? itemPosition : null;
  }
}
ControllableLabel.attrsMap = {
  backgroundColor: "fill",
  borderColor: "stroke",
  borderWidth: "stroke-width",
  zIndex: "zIndex",
  borderRadius: "r",
  padding: "padding"
};
ControllableLabel.shapesWithoutBackground = ["connector"];
class ControllableImage extends Controllable {
  /* *
   *
   *  Constructors
   *
   * */
  constructor(annotation, options2, index) {
    super(annotation, options2, index, "shape");
    this.type = "image";
    this.translate = super.translateShape;
  }
  render(parent) {
    const attrs = this.attrsFromOptions(this.options), options2 = this.options;
    this.graphic = this.annotation.chart.renderer.image(options2.src, 0, -9e9, options2.width, options2.height).attr(attrs).add(parent);
    this.graphic.width = options2.width;
    this.graphic.height = options2.height;
    super.render();
  }
  redraw(animation) {
    if (this.graphic) {
      const anchor = this.anchor(this.points[0]), position = ControllableLabel.prototype.position.call(this, anchor);
      if (position) {
        this.graphic[animation ? "animate" : "attr"]({
          x: position.x,
          y: position.y
        });
      } else {
        this.graphic.attr({
          x: 0,
          y: -9e9
        });
      }
      this.graphic.placed = Boolean(position);
    }
    super.redraw(animation);
  }
}
ControllableImage.attrsMap = {
  width: "width",
  height: "height",
  zIndex: "zIndex"
};
const { addEvent: addEvent$N, createElement: createElement$5 } = Utilities;
class BaseForm {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(parentDiv, iconsURL) {
    this.iconsURL = iconsURL;
    this.container = this.createPopupContainer(parentDiv);
    this.closeButton = this.addCloseButton();
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Create popup div container.
   *
   * @param {HTMLElement} parentDiv
   * Parent div to attach popup.
   *
   * @param  {string} className
   * Class name of the popup.
   *
   * @return {HTMLElement}
   * Popup div.
   */
  createPopupContainer(parentDiv, className = "highcharts-popup highcharts-no-tooltip") {
    return createElement$5("div", { className }, void 0, parentDiv);
  }
  /**
   * Create HTML element and attach click event to close popup.
   *
   * @param {string} className
   * Class name of the close button.
   *
   * @return {HTMLElement}
   * Close button.
   */
  addCloseButton(className = "highcharts-popup-close") {
    const popup = this, iconsURL = this.iconsURL;
    const closeButton = createElement$5("button", { className }, void 0, this.container);
    closeButton.style["background-image"] = "url(" + (iconsURL.match(/png|svg|jpeg|jpg|gif/ig) ? iconsURL : iconsURL + "close.svg") + ")";
    ["click", "touchstart"].forEach((eventName) => {
      addEvent$N(closeButton, eventName, popup.closeButtonEvents.bind(popup));
    });
    addEvent$N(document, "keydown", function(event) {
      if (event.code === "Escape") {
        popup.closeButtonEvents();
      }
    });
    return closeButton;
  }
  /**
   * Close button events.
   * @return {void}
   */
  closeButtonEvents() {
    this.closePopup();
  }
  /**
   * Reset content of the current popup and show.
   *
   * @param {string} toolbarClass
   * Class name of the toolbar which styles should be reset.
   */
  showPopup(toolbarClass = "highcharts-annotation-toolbar") {
    const popupDiv = this.container, popupCloseButton = this.closeButton;
    this.type = void 0;
    popupDiv.innerHTML = AST.emptyHTML;
    if (popupDiv.className.indexOf(toolbarClass) >= 0) {
      popupDiv.classList.remove(toolbarClass);
      popupDiv.removeAttribute("style");
    }
    popupDiv.appendChild(popupCloseButton);
    popupDiv.style.display = "block";
    popupDiv.style.height = "";
  }
  /**
   * Hide popup.
   */
  closePopup() {
    this.container.style.display = "none";
  }
}
const { doc: doc$8, isFirefox } = Highcharts;
const { createElement: createElement$4, isArray: isArray$d, isObject: isObject$c, objectEach: objectEach$c, pick: pick$W, stableSort: stableSort$4 } = Utilities;
function addForm$1(chart, options2, callback, isInit) {
  if (!chart) {
    return;
  }
  const popupDiv = this.container, lang2 = this.lang;
  let lhsCol = createElement$4("h2", {
    className: "highcharts-popup-main-title"
  }, void 0, popupDiv);
  lhsCol.appendChild(doc$8.createTextNode(lang2[options2.langKey] || options2.langKey || ""));
  lhsCol = createElement$4("div", {
    className: "highcharts-popup-lhs-col highcharts-popup-lhs-full"
  }, void 0, popupDiv);
  const bottomRow = createElement$4("div", {
    className: "highcharts-popup-bottom-row"
  }, void 0, popupDiv);
  addFormFields$1.call(this, lhsCol, chart, "", options2, [], true);
  this.addButton(bottomRow, isInit ? lang2.addButton || "Add" : lang2.saveButton || "Save", isInit ? "add" : "save", popupDiv, callback);
}
function addToolbar(chart, options2, callback) {
  const lang2 = this.lang, popupDiv = this.container, showForm = this.showForm, toolbarClass = "highcharts-annotation-toolbar";
  if (popupDiv.className.indexOf(toolbarClass) === -1) {
    popupDiv.className += " " + toolbarClass + " highcharts-no-mousewheel";
  }
  if (chart) {
    popupDiv.style.top = chart.plotTop + 10 + "px";
  }
  const label = createElement$4("p", {
    className: "highcharts-annotation-label"
  }, void 0, popupDiv);
  label.setAttribute("aria-label", "Annotation type");
  label.appendChild(doc$8.createTextNode(pick$W(
    // Advanced annotations:
    lang2[options2.langKey] || options2.langKey,
    // Basic shapes:
    options2.shapes && options2.shapes[0].type,
    ""
  )));
  let button = this.addButton(popupDiv, lang2.editButton || "Edit", "edit", popupDiv, () => {
    showForm.call(this, "annotation-edit", chart, options2, callback);
  });
  button.className += " highcharts-annotation-edit-button";
  button.style["background-image"] = "url(" + this.iconsURL + "edit.svg)";
  button = this.addButton(popupDiv, lang2.removeButton || "Remove", "remove", popupDiv, callback);
  button.className += " highcharts-annotation-remove-button";
  button.style["background-image"] = "url(" + this.iconsURL + "destroy.svg)";
}
function addFormFields$1(parentDiv, chart, parentNode, options2, storage, isRoot) {
  if (!chart) {
    return;
  }
  const addInput = this.addInput, lang2 = this.lang;
  let parentFullName, titleName;
  objectEach$c(options2, (value, option) => {
    parentFullName = parentNode !== "" ? parentNode + "." + option : option;
    if (isObject$c(value)) {
      if (
        // Value is object of options
        !isArray$d(value) || // Array of objects with params. i.e labels in Fibonacci
        isArray$d(value) && isObject$c(value[0])
      ) {
        titleName = lang2[option] || option;
        if (!titleName.match(/\d/g)) {
          storage.push([
            true,
            titleName,
            parentDiv
          ]);
        }
        addFormFields$1.call(this, parentDiv, chart, parentFullName, value, storage, false);
      } else {
        storage.push([
          this,
          parentFullName,
          "annotation",
          parentDiv,
          value
        ]);
      }
    }
  });
  if (isRoot) {
    stableSort$4(storage, (a) => a[1].match(/format/g) ? -1 : 1);
    if (isFirefox) {
      storage.reverse();
    }
    storage.forEach((genInput) => {
      if (genInput[0] === true) {
        createElement$4("span", {
          className: "highcharts-annotation-title"
        }, void 0, genInput[2]).appendChild(doc$8.createTextNode(genInput[1]));
      } else {
        genInput[4] = {
          value: genInput[4][0],
          type: genInput[4][1]
        };
        addInput.apply(genInput[0], genInput.splice(1));
      }
    });
  }
}
const PopupAnnotations = {
  addForm: addForm$1,
  addToolbar
};
const { doc: doc$7 } = Highcharts;
const { seriesTypes: seriesTypes$1 } = SeriesRegistry$1;
const { addEvent: addEvent$M, createElement: createElement$3, defined: defined$y, isArray: isArray$c, isObject: isObject$b, objectEach: objectEach$b, stableSort: stableSort$3 } = Utilities;
var DropdownProperties;
(function(DropdownProperties2) {
  DropdownProperties2[DropdownProperties2["params.algorithm"] = 0] = "params.algorithm";
  DropdownProperties2[DropdownProperties2["params.average"] = 1] = "params.average";
})(DropdownProperties || (DropdownProperties = {}));
const dropdownParameters = {
  "algorithm-pivotpoints": ["standard", "fibonacci", "camarilla"],
  "average-disparityindex": ["sma", "ema", "dema", "tema", "wma"]
};
function addColsContainer(container) {
  const lhsCol = createElement$3("div", {
    className: "highcharts-popup-lhs-col"
  }, void 0, container);
  const rhsCol = createElement$3("div", {
    className: "highcharts-popup-rhs-col"
  }, void 0, container);
  createElement$3("div", {
    className: "highcharts-popup-rhs-col-wrapper"
  }, void 0, rhsCol);
  return {
    lhsCol,
    rhsCol
  };
}
function addForm(chart, _options, callback) {
  const lang2 = this.lang;
  let buttonParentDiv;
  if (!chart) {
    return;
  }
  this.tabs.init.call(this, chart);
  const tabsContainers = this.container.querySelectorAll(".highcharts-tab-item-content");
  addColsContainer(tabsContainers[0]);
  addSearchBox.call(this, chart, tabsContainers[0]);
  addIndicatorList.call(this, chart, tabsContainers[0], "add");
  buttonParentDiv = tabsContainers[0].querySelectorAll(".highcharts-popup-rhs-col")[0];
  this.addButton(buttonParentDiv, lang2.addButton || "add", "add", buttonParentDiv, callback);
  addColsContainer(tabsContainers[1]);
  addIndicatorList.call(this, chart, tabsContainers[1], "edit");
  buttonParentDiv = tabsContainers[1].querySelectorAll(".highcharts-popup-rhs-col")[0];
  this.addButton(buttonParentDiv, lang2.saveButton || "save", "edit", buttonParentDiv, callback);
  this.addButton(buttonParentDiv, lang2.removeButton || "remove", "remove", buttonParentDiv, callback);
}
function addFormFields(chart, series, seriesType, rhsColWrapper) {
  const fields2 = series.params || series.options.params;
  rhsColWrapper.innerHTML = AST.emptyHTML;
  createElement$3("h3", {
    className: "highcharts-indicator-title"
  }, void 0, rhsColWrapper).appendChild(doc$7.createTextNode(getNameType(series, seriesType).indicatorFullName));
  createElement$3("input", {
    type: "hidden",
    name: "highcharts-type-" + seriesType,
    value: seriesType
  }, void 0, rhsColWrapper);
  listAllSeries.call(this, seriesType, "series", chart, rhsColWrapper, series, series.linkedParent && series.linkedParent.options.id);
  if (fields2.volumeSeriesID) {
    listAllSeries.call(this, seriesType, "volume", chart, rhsColWrapper, series, series.linkedParent && fields2.volumeSeriesID);
  }
  addParamInputs.call(this, chart, "params", fields2, seriesType, rhsColWrapper);
}
function addIndicatorList(chart, parentDiv, listType, filter) {
  function selectIndicator(series2, indicatorType) {
    const button = rhsColWrapper.parentNode.children[1];
    addFormFields.call(popup, chart, series2, indicatorType, rhsColWrapper);
    if (button) {
      button.style.display = "block";
    }
    if (isEdit && series2.options) {
      createElement$3("input", {
        type: "hidden",
        name: "highcharts-id-" + indicatorType,
        value: series2.options.id
      }, void 0, rhsColWrapper).setAttribute("highcharts-data-series-id", series2.options.id);
    }
  }
  const popup = this, lang2 = popup.lang, lhsCol = parentDiv.querySelectorAll(".highcharts-popup-lhs-col")[0], rhsCol = parentDiv.querySelectorAll(".highcharts-popup-rhs-col")[0], isEdit = listType === "edit", series = isEdit ? chart.series : (
    // EDIT mode
    chart.options.plotOptions || {}
  );
  if (!chart && series) {
    return;
  }
  let item, filteredSeriesArray = [];
  if (!isEdit && !isArray$c(series)) {
    filteredSeriesArray = filterSeries.call(this, series, filter);
  } else if (isArray$c(series)) {
    filteredSeriesArray = filterSeriesArray.call(this, series);
  }
  stableSort$3(filteredSeriesArray, (a, b) => {
    const seriesAName = a.indicatorFullName.toLowerCase(), seriesBName = b.indicatorFullName.toLowerCase();
    return seriesAName < seriesBName ? -1 : seriesAName > seriesBName ? 1 : 0;
  });
  if (lhsCol.children[1]) {
    lhsCol.children[1].remove();
  }
  const indicatorList = createElement$3("ul", {
    className: "highcharts-indicator-list"
  }, void 0, lhsCol);
  const rhsColWrapper = rhsCol.querySelectorAll(".highcharts-popup-rhs-col-wrapper")[0];
  filteredSeriesArray.forEach((seriesSet) => {
    const { indicatorFullName, indicatorType, series: series2 } = seriesSet;
    item = createElement$3("li", {
      className: "highcharts-indicator-list"
    }, void 0, indicatorList);
    const btn = createElement$3("button", {
      className: "highcharts-indicator-list-item",
      textContent: indicatorFullName
    }, void 0, item);
    ["click", "touchstart"].forEach((eventName) => {
      addEvent$M(btn, eventName, function() {
        selectIndicator(series2, indicatorType);
      });
    });
  });
  if (filteredSeriesArray.length > 0) {
    const { series: series2, indicatorType } = filteredSeriesArray[0];
    selectIndicator(series2, indicatorType);
  } else if (!isEdit) {
    AST.setElementHTML(rhsColWrapper.parentNode.children[0], lang2.noFilterMatch || "");
    rhsColWrapper.parentNode.children[1].style.display = "none";
  }
}
function addParamInputs(chart, parentNode, fields2, type, parentDiv) {
  if (!chart) {
    return;
  }
  const addInput = this.addInput;
  objectEach$b(fields2, (value, fieldName) => {
    const parentFullName = parentNode + "." + fieldName;
    if (defined$y(value) && // Skip if field is unnecessary, #15362
    parentFullName) {
      if (isObject$b(value)) {
        addInput.call(this, parentFullName, type, parentDiv, {});
        addParamInputs.call(this, chart, parentFullName, value, type, parentDiv);
      }
      if (parentFullName in DropdownProperties) {
        const selectBox = addSelection.call(this, type, parentFullName, parentDiv);
        addSelectionOptions.call(this, chart, parentNode, selectBox, type, fieldName, value);
      } else if (
        // Skip volume field which is created by addFormFields.
        parentFullName !== "params.volumeSeriesID" && !isArray$c(value)
      ) {
        addInput.call(
          this,
          parentFullName,
          type,
          parentDiv,
          {
            value,
            type: "number"
          }
          // All inputs are text type
        );
      }
    }
  });
}
function addSearchBox(chart, parentDiv) {
  const popup = this, lhsCol = parentDiv.querySelectorAll(".highcharts-popup-lhs-col")[0], options2 = "searchIndicators", inputAttributes = {
    value: "",
    type: "text",
    htmlFor: "search-indicators",
    labelClassName: "highcharts-input-search-indicators-label"
  }, clearFilterText = this.lang.clearFilter, inputWrapper = createElement$3("div", {
    className: "highcharts-input-wrapper"
  }, void 0, lhsCol);
  const handleInputChange = function(inputText) {
    addIndicatorList.call(popup, chart, popup.container, "add", inputText);
  };
  const input = this.addInput(options2, "input", inputWrapper, inputAttributes), button = createElement$3("a", {
    textContent: clearFilterText
  }, void 0, inputWrapper);
  input.classList.add("highcharts-input-search-indicators");
  button.classList.add("clear-filter-button");
  addEvent$M(input, "input", function() {
    handleInputChange(this.value);
    if (this.value.length) {
      button.style.display = "inline-block";
    } else {
      button.style.display = "none";
    }
  });
  ["click", "touchstart"].forEach((eventName) => {
    addEvent$M(button, eventName, function() {
      input.value = "";
      handleInputChange("");
      button.style.display = "none";
    });
  });
}
function addSelection(indicatorType, optionName, parentDiv) {
  const optionParamList = optionName.split("."), labelText = optionParamList[optionParamList.length - 1], selectName = "highcharts-" + optionName + "-type-" + indicatorType, lang2 = this.lang;
  createElement$3("label", {
    htmlFor: selectName
  }, null, parentDiv).appendChild(doc$7.createTextNode(lang2[labelText] || optionName));
  const selectBox = createElement$3("select", {
    name: selectName,
    className: "highcharts-popup-field",
    id: "highcharts-select-" + optionName
  }, null, parentDiv);
  selectBox.setAttribute("id", "highcharts-select-" + optionName);
  return selectBox;
}
function addSelectionOptions(chart, optionName, selectBox, indicatorType, parameterName, selectedOption, currentSeries) {
  if (optionName === "series" || optionName === "volume") {
    chart.series.forEach((series) => {
      const seriesOptions = series.options, seriesName = seriesOptions.name || seriesOptions.params ? series.name : seriesOptions.id || "";
      if (seriesOptions.id !== "highcharts-navigator-series" && seriesOptions.id !== (currentSeries && currentSeries.options && currentSeries.options.id)) {
        if (!defined$y(selectedOption) && optionName === "volume" && series.type === "column") {
          selectedOption = seriesOptions.id;
        }
        createElement$3("option", {
          value: seriesOptions.id
        }, void 0, selectBox).appendChild(doc$7.createTextNode(seriesName));
      }
    });
  } else if (indicatorType && parameterName) {
    const dropdownKey = parameterName + "-" + indicatorType, parameterOption = dropdownParameters[dropdownKey];
    parameterOption.forEach((element) => {
      createElement$3("option", {
        value: element
      }, void 0, selectBox).appendChild(doc$7.createTextNode(element));
    });
  }
  if (defined$y(selectedOption)) {
    selectBox.value = selectedOption;
  }
}
function filterSeries(series, filter) {
  const popup = this, lang2 = popup.chart && popup.chart.options.lang, indicatorAliases = lang2 && lang2.navigation && lang2.navigation.popup && lang2.navigation.popup.indicatorAliases, filteredSeriesArray = [];
  let filteredSeries;
  objectEach$b(series, (series2, value) => {
    const seriesOptions = series2 && series2.options;
    if (series2.params || seriesOptions && seriesOptions.params) {
      const { indicatorFullName, indicatorType } = getNameType(series2, value);
      if (filter) {
        const validFilter = filter.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
        const regex = new RegExp(validFilter, "i"), alias = indicatorAliases && indicatorAliases[indicatorType] && indicatorAliases[indicatorType].join(" ") || "";
        if (indicatorFullName.match(regex) || alias.match(regex)) {
          filteredSeries = {
            indicatorFullName,
            indicatorType,
            series: series2
          };
          filteredSeriesArray.push(filteredSeries);
        }
      } else {
        filteredSeries = {
          indicatorFullName,
          indicatorType,
          series: series2
        };
        filteredSeriesArray.push(filteredSeries);
      }
    }
  });
  return filteredSeriesArray;
}
function filterSeriesArray(series) {
  const filteredSeriesArray = [];
  series.forEach((series2) => {
    if (series2.is("sma")) {
      filteredSeriesArray.push({
        indicatorFullName: series2.name,
        indicatorType: series2.type,
        series: series2
      });
    }
  });
  return filteredSeriesArray;
}
function getAmount() {
  let counter = 0;
  this.series.forEach((serie) => {
    if (serie.params || serie.options.params) {
      counter++;
    }
  });
  return counter;
}
function getNameType(series, indicatorType) {
  const options2 = series.options;
  let seriesName = seriesTypes$1[indicatorType] && seriesTypes$1[indicatorType].prototype.nameBase || indicatorType.toUpperCase(), seriesType = indicatorType;
  if (options2 && options2.type) {
    seriesType = series.options.type;
    seriesName = series.name;
  }
  return {
    indicatorFullName: seriesName,
    indicatorType: seriesType
  };
}
function listAllSeries(indicatorType, optionName, chart, parentDiv, currentSeries, selectedOption) {
  const popup = this;
  if (!chart) {
    return;
  }
  const selectBox = addSelection.call(popup, indicatorType, optionName, parentDiv);
  addSelectionOptions.call(popup, chart, optionName, selectBox, void 0, void 0, void 0, currentSeries);
  if (defined$y(selectedOption)) {
    selectBox.value = selectedOption;
  }
}
const PopupIndicators = {
  addForm,
  getAmount
};
const { doc: doc$6 } = Highcharts;
const { addEvent: addEvent$L, createElement: createElement$2 } = Utilities;
function addContentItem() {
  const popupDiv = this.container;
  return createElement$2("div", {
    // #12100
    className: "highcharts-tab-item-content highcharts-no-mousewheel"
  }, void 0, popupDiv);
}
function addMenuItem(tabName, disableTab) {
  const popupDiv = this.container, lang2 = this.lang;
  let className = "highcharts-tab-item";
  if (disableTab === 0) {
    className += " highcharts-tab-disabled";
  }
  const menuItem = createElement$2("button", {
    className
  }, void 0, popupDiv);
  menuItem.appendChild(doc$6.createTextNode(lang2[tabName + "Button"] || tabName));
  menuItem.setAttribute("highcharts-data-tab-type", tabName);
  return menuItem;
}
function deselectAll() {
  const popupDiv = this.container, tabs = popupDiv.querySelectorAll(".highcharts-tab-item"), tabsContent = popupDiv.querySelectorAll(".highcharts-tab-item-content");
  for (let i = 0; i < tabs.length; i++) {
    tabs[i].classList.remove("highcharts-tab-item-active");
    tabsContent[i].classList.remove("highcharts-tab-item-show");
  }
}
function init$B(chart) {
  if (!chart) {
    return;
  }
  const indicatorsCount = this.indicators.getAmount.call(chart);
  const firstTab = addMenuItem.call(this, "add");
  addMenuItem.call(this, "edit", indicatorsCount);
  addContentItem.call(this);
  addContentItem.call(this);
  switchTabs.call(this, indicatorsCount);
  selectTab.call(this, firstTab, 0);
}
function selectTab(tab, index) {
  const allTabs = this.container.querySelectorAll(".highcharts-tab-item-content");
  tab.className += " highcharts-tab-item-active";
  allTabs[index].className += " highcharts-tab-item-show";
}
function switchTabs(disableTab) {
  const popup = this, popupDiv = this.container, tabs = popupDiv.querySelectorAll(".highcharts-tab-item");
  tabs.forEach((tab, i) => {
    if (disableTab === 0 && tab.getAttribute("highcharts-data-tab-type") === "edit") {
      return;
    }
    ["click", "touchstart"].forEach((eventName) => {
      addEvent$L(tab, eventName, function() {
        deselectAll.call(popup);
        selectTab.call(popup, this, i);
      });
    });
  });
}
const PopupTabs = {
  init: init$B
};
const { doc: doc$5 } = Highcharts;
const { getOptions: getOptions$1 } = DefaultOptions;
const { addEvent: addEvent$K, createElement: createElement$1, extend: extend$O, fireEvent: fireEvent$g, pick: pick$V } = Utilities;
function getFields(parentDiv, type) {
  const inputList = Array.prototype.slice.call(parentDiv.querySelectorAll("input")), selectList = Array.prototype.slice.call(parentDiv.querySelectorAll("select")), optionSeries = "#highcharts-select-series > option:checked", optionVolume = "#highcharts-select-volume > option:checked", linkedTo = parentDiv.querySelectorAll(optionSeries)[0], volumeTo = parentDiv.querySelectorAll(optionVolume)[0];
  const fieldsOutput = {
    actionType: type,
    linkedTo: linkedTo && linkedTo.getAttribute("value") || "",
    fields: {}
  };
  inputList.forEach((input) => {
    const param = input.getAttribute("highcharts-data-name"), seriesId = input.getAttribute("highcharts-data-series-id");
    if (seriesId) {
      fieldsOutput.seriesId = input.value;
    } else if (param) {
      fieldsOutput.fields[param] = input.value;
    } else {
      fieldsOutput.type = input.value;
    }
  });
  selectList.forEach((select) => {
    const id = select.id;
    if (id !== "highcharts-select-series" && id !== "highcharts-select-volume") {
      const parameter = id.split("highcharts-select-")[1];
      fieldsOutput.fields[parameter] = select.value;
    }
  });
  if (volumeTo) {
    fieldsOutput.fields["params.volumeSeriesID"] = volumeTo.getAttribute("value") || "";
  }
  return fieldsOutput;
}
class Popup extends BaseForm {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(parentDiv, iconsURL, chart) {
    super(parentDiv, iconsURL);
    this.chart = chart;
    this.lang = (getOptions$1().lang.navigation || {}).popup || {};
    addEvent$K(this.container, "mousedown", () => {
      const activeAnnotation = chart && chart.navigationBindings && chart.navigationBindings.activeAnnotation;
      if (activeAnnotation) {
        activeAnnotation.cancelClick = true;
        const unbind = addEvent$K(doc$5, "click", () => {
          setTimeout(() => {
            activeAnnotation.cancelClick = false;
          }, 0);
          unbind();
        });
      }
    });
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Create input with label.
   *
   * @private
   *
   * @param {string} option
   *        Chain of fields i.e params.styles.fontSize separated by the dot.
   *
   * @param {string} indicatorType
   *        Type of the indicator i.e. sma, ema...
   *
   * @param {HTMLDOMElement} parentDiv
   *        HTML parent element.
   *
   * @param {Highcharts.InputAttributes} inputAttributes
   *        Attributes of the input.
   *
   * @return {HTMLInputElement}
   *         Return created input element.
   */
  addInput(option, indicatorType, parentDiv, inputAttributes) {
    const optionParamList = option.split("."), optionName = optionParamList[optionParamList.length - 1], lang2 = this.lang, inputName = "highcharts-" + indicatorType + "-" + pick$V(inputAttributes.htmlFor, optionName);
    if (!optionName.match(/^\d+$/)) {
      createElement$1("label", {
        htmlFor: inputName,
        className: inputAttributes.labelClassName
      }, void 0, parentDiv).appendChild(doc$5.createTextNode(lang2[optionName] || optionName));
    }
    const input = createElement$1("input", {
      name: inputName,
      value: inputAttributes.value,
      type: inputAttributes.type,
      className: "highcharts-popup-field"
    }, void 0, parentDiv);
    input.setAttribute("highcharts-data-name", option);
    return input;
  }
  closeButtonEvents() {
    if (this.chart) {
      const navigationBindings = this.chart.navigationBindings;
      fireEvent$g(navigationBindings, "closePopup");
      if (navigationBindings && navigationBindings.selectedButtonElement) {
        fireEvent$g(navigationBindings, "deselectButton", { button: navigationBindings.selectedButtonElement });
      }
    } else {
      super.closeButtonEvents();
    }
  }
  /**
   * Create button.
   * @private
   * @param {Highcharts.HTMLDOMElement} parentDiv
   * Container where elements should be added
   * @param {string} label
   * Text placed as button label
   * @param {string} type
   * add | edit | remove
   * @param {Function} callback
   * On click callback
   * @param {Highcharts.HTMLDOMElement} fieldsDiv
   * Container where inputs are generated
   * @return {Highcharts.HTMLDOMElement}
   * HTML button
   */
  addButton(parentDiv, label, type, fieldsDiv, callback) {
    const button = createElement$1("button", void 0, void 0, parentDiv);
    button.appendChild(doc$5.createTextNode(label));
    if (callback) {
      ["click", "touchstart"].forEach((eventName) => {
        addEvent$K(button, eventName, () => {
          this.closePopup();
          return callback(getFields(fieldsDiv, type));
        });
      });
    }
    return button;
  }
  /**
   * Create content and show popup.
   * @private
   * @param {string} - type of popup i.e indicators
   * @param {Highcharts.Chart} - chart
   * @param {Highcharts.AnnotationsOptions} - options
   * @param {Function} - on click callback
   */
  showForm(type, chart, options2, callback) {
    if (!chart) {
      return;
    }
    this.showPopup();
    if (type === "indicators") {
      this.indicators.addForm.call(this, chart, options2, callback);
    }
    if (type === "annotation-toolbar") {
      this.annotations.addToolbar.call(this, chart, options2, callback);
    }
    if (type === "annotation-edit") {
      this.annotations.addForm.call(this, chart, options2, callback);
    }
    if (type === "flag") {
      this.annotations.addForm.call(this, chart, options2, callback, true);
    }
    this.type = type;
    this.container.style.height = this.container.offsetHeight + "px";
  }
}
extend$O(Popup.prototype, {
  annotations: PopupAnnotations,
  indicators: PopupIndicators,
  tabs: PopupTabs
});
const { composed: composed$j } = Highcharts;
const { addEvent: addEvent$J, pushUnique: pushUnique$j, wrap: wrap$d } = Utilities;
function compose$h(NagivationBindingsClass, PointerClass) {
  if (pushUnique$j(composed$j, "Popup")) {
    addEvent$J(NagivationBindingsClass, "closePopup", onNavigationBindingsClosePopup$1);
    addEvent$J(NagivationBindingsClass, "showPopup", onNavigationBindingsShowPopup);
    wrap$d(PointerClass.prototype, "onContainerMouseDown", wrapPointerOnContainerMouserDown);
  }
}
function onNavigationBindingsClosePopup$1() {
  if (this.popup) {
    this.popup.closePopup();
  }
}
function onNavigationBindingsShowPopup(config2) {
  if (!this.popup) {
    this.popup = new Popup(this.chart.container, this.chart.options.navigation.iconsURL || this.chart.options.stockTools && this.chart.options.stockTools.gui.iconsURL || "https://code.highcharts.com/12.2.0/gfx/stock-icons/", this.chart);
  }
  this.popup.showForm(config2.formType, this.chart, config2.options, config2.onSubmit);
}
function wrapPointerOnContainerMouserDown(proceed, e) {
  if (!this.inClass(e.target, "highcharts-popup")) {
    proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  }
}
const PopupComposition = {
  compose: compose$h
};
const { getDeferredAnimation } = animationExports;
const { destroyObjectProperties, erase: erase$1, fireEvent: fireEvent$f, merge: merge$V, pick: pick$U, splat: splat$b } = Utilities;
function adjustVisibility(item) {
  const label = item.graphic, hasVisiblePoints = item.points.some((point) => point.series.visible !== false && point.visible !== false);
  if (label) {
    if (!hasVisiblePoints) {
      label.hide();
    } else if (label.visibility === "hidden") {
      label.show();
    }
  }
}
function getLabelsAndShapesOptions(baseOptions, newOptions) {
  const mergedOptions = {};
  ["labels", "shapes"].forEach((name) => {
    const someBaseOptions = baseOptions[name], newOptionsValue = newOptions[name];
    if (someBaseOptions) {
      if (newOptionsValue) {
        mergedOptions[name] = splat$b(newOptionsValue).map((basicOptions, i) => merge$V(someBaseOptions[i], basicOptions));
      } else {
        mergedOptions[name] = baseOptions[name];
      }
    }
  });
  return mergedOptions;
}
class Annotation extends EventEmitter {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static compose(ChartClass, NavigationBindingsClass, PointerClass, SVGRendererClass) {
    AnnotationChart$1.compose(Annotation, ChartClass, PointerClass);
    ControllableLabel.compose(SVGRendererClass);
    ControllablePath.compose(ChartClass, SVGRendererClass);
    NavigationBindingsClass.compose(Annotation, ChartClass);
    PopupComposition.compose(NavigationBindingsClass, PointerClass);
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(chart, userOptions) {
    super();
    this.coll = "annotations";
    this.chart = chart;
    this.points = [];
    this.controlPoints = [];
    this.coll = "annotations";
    this.index = -1;
    this.labels = [];
    this.shapes = [];
    this.options = merge$V(this.defaultOptions, userOptions);
    this.userOptions = userOptions;
    const labelsAndShapes = getLabelsAndShapesOptions(this.options, userOptions);
    this.options.labels = labelsAndShapes.labels;
    this.options.shapes = labelsAndShapes.shapes;
    this.init(chart, this.options);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  addClipPaths() {
    this.setClipAxes();
    if (this.clipXAxis && this.clipYAxis && this.options.crop) {
      this.clipRect = this.chart.renderer.clipRect(this.getClipBox());
    }
  }
  /**
   * @private
   */
  addLabels() {
    const labelsOptions = this.options.labels || [];
    labelsOptions.forEach((labelOptions, i) => {
      const label = this.initLabel(labelOptions, i);
      merge$V(true, labelsOptions[i], label.options);
    });
  }
  /**
   * @private
   */
  addShapes() {
    const shapes = this.options.shapes || [];
    shapes.forEach((shapeOptions, i) => {
      const shape = this.initShape(shapeOptions, i);
      merge$V(true, shapes[i], shape.options);
    });
  }
  /**
   * Destroy the annotation. This function does not touch the chart
   * that the annotation belongs to (all annotations are kept in
   * the chart.annotations array) - it is recommended to use
   * {@link Highcharts.Chart#removeAnnotation} instead.
   * @private
   */
  destroy() {
    const chart = this.chart, destroyItem = function(item) {
      item.destroy();
    };
    this.labels.forEach(destroyItem);
    this.shapes.forEach(destroyItem);
    this.clipXAxis = null;
    this.clipYAxis = null;
    erase$1(chart.labelCollectors, this.labelCollector);
    super.destroy();
    this.destroyControlTarget();
    destroyObjectProperties(this, chart);
  }
  /**
   * Destroy a single item.
   * @private
   */
  destroyItem(item) {
    erase$1(this[item.itemType + "s"], item);
    item.destroy();
  }
  /**
   * @private
   */
  getClipBox() {
    if (this.clipXAxis && this.clipYAxis) {
      return {
        x: this.clipXAxis.left,
        y: this.clipYAxis.top,
        width: this.clipXAxis.width,
        height: this.clipYAxis.height
      };
    }
  }
  /**
   * Initialize the annotation properties.
   * @private
   */
  initProperties(chart, userOptions) {
    this.setOptions(userOptions);
    const labelsAndShapes = getLabelsAndShapesOptions(this.options, userOptions);
    this.options.labels = labelsAndShapes.labels;
    this.options.shapes = labelsAndShapes.shapes;
    this.chart = chart;
    this.points = [];
    this.controlPoints = [];
    this.coll = "annotations";
    this.userOptions = userOptions;
    this.labels = [];
    this.shapes = [];
  }
  /**
   * Initialize the annotation.
   * @private
   */
  init(_annotationOrChart, _userOptions, index = this.index) {
    const chart = this.chart, animOptions = this.options.animation;
    this.index = index;
    this.linkPoints();
    this.addControlPoints();
    this.addShapes();
    this.addLabels();
    this.setLabelCollector();
    this.animationConfig = getDeferredAnimation(chart, animOptions);
  }
  /**
   * Initialisation of a single label
   * @private
   */
  initLabel(labelOptions, index) {
    const options2 = merge$V(this.options.labelOptions, {
      controlPointOptions: this.options.controlPointOptions
    }, labelOptions), label = new ControllableLabel(this, options2, index);
    label.itemType = "label";
    this.labels.push(label);
    return label;
  }
  /**
   * Initialisation of a single shape
   * @private
   * @param {Object} shapeOptions
   * a config object for a single shape
   * @param {number} index
   * annotation may have many shapes, this is the shape's index saved in
   * shapes.index.
   */
  initShape(shapeOptions, index) {
    const options2 = merge$V(this.options.shapeOptions, {
      controlPointOptions: this.options.controlPointOptions
    }, shapeOptions), shape = new Annotation.shapesMap[options2.type](this, options2, index);
    shape.itemType = "shape";
    this.shapes.push(shape);
    return shape;
  }
  /**
   * @private
   */
  redraw(animation) {
    this.linkPoints();
    if (!this.graphic) {
      this.render();
    }
    if (this.clipRect) {
      this.clipRect.animate(this.getClipBox());
    }
    this.redrawItems(this.shapes, animation);
    this.redrawItems(this.labels, animation);
    this.redrawControlPoints(animation);
  }
  /**
   * Redraw a single item.
   * @private
   */
  redrawItem(item, animation) {
    item.linkPoints();
    if (!item.shouldBeDrawn()) {
      this.destroyItem(item);
    } else {
      if (!item.graphic) {
        this.renderItem(item);
      }
      item.redraw(pick$U(animation, true) && item.graphic.placed);
      if (item.points.length) {
        adjustVisibility(item);
      }
    }
  }
  /**
   * @private
   */
  redrawItems(items, animation) {
    let i = items.length;
    while (i--) {
      this.redrawItem(items[i], animation);
    }
  }
  /**
   * See {@link Highcharts.Chart#removeAnnotation}.
   * @private
   */
  remove() {
    return this.chart.removeAnnotation(this);
  }
  /**
   * @private
   */
  render() {
    const renderer = this.chart.renderer;
    this.graphic = renderer.g("annotation").attr({
      opacity: 0,
      zIndex: this.options.zIndex,
      visibility: this.options.visible ? "inherit" : "hidden"
    }).add();
    this.shapesGroup = renderer.g("annotation-shapes").add(this.graphic);
    if (this.options.crop) {
      this.shapesGroup.clip(this.chart.plotBoxClip);
    }
    this.labelsGroup = renderer.g("annotation-labels").attr({
      // `hideOverlappingLabels` requires translation
      translateX: 0,
      translateY: 0
    }).add(this.graphic);
    this.addClipPaths();
    if (this.clipRect) {
      this.graphic.clip(this.clipRect);
    }
    this.renderItems(this.shapes);
    this.renderItems(this.labels);
    this.addEvents();
    this.renderControlPoints();
  }
  /**
   * @private
   */
  renderItem(item) {
    item.render(item.itemType === "label" ? this.labelsGroup : this.shapesGroup);
  }
  /**
   * @private
   */
  renderItems(items) {
    let i = items.length;
    while (i--) {
      this.renderItem(items[i]);
    }
  }
  /**
   * @private
   */
  setClipAxes() {
    const xAxes = this.chart.xAxis, yAxes = this.chart.yAxis, linkedAxes = (this.options.labels || []).concat(this.options.shapes || []).reduce((axes, labelOrShape) => {
      const point = labelOrShape && (labelOrShape.point || labelOrShape.points && labelOrShape.points[0]);
      return [
        xAxes[point && point.xAxis] || axes[0],
        yAxes[point && point.yAxis] || axes[1]
      ];
    }, []);
    this.clipXAxis = linkedAxes[0];
    this.clipYAxis = linkedAxes[1];
  }
  /**
   * @private
   */
  setControlPointsVisibility(visible) {
    const setItemControlPointsVisibility = function(item) {
      item.setControlPointsVisibility(visible);
    };
    this.controlPoints.forEach((controlPoint) => {
      controlPoint.setVisibility(visible);
    });
    this.shapes.forEach(setItemControlPointsVisibility);
    this.labels.forEach(setItemControlPointsVisibility);
  }
  /**
   * @private
   */
  setLabelCollector() {
    const annotation = this;
    annotation.labelCollector = function() {
      return annotation.labels.reduce(function(labels, label) {
        if (!label.options.allowOverlap) {
          labels.push(label.graphic);
        }
        return labels;
      }, []);
    };
    annotation.chart.labelCollectors.push(annotation.labelCollector);
  }
  /**
   * Set an annotation options.
   * @private
   * @param {Highcharts.AnnotationsOptions} userOptions
   *        User options for an annotation
   */
  setOptions(userOptions) {
    this.options = merge$V(this.defaultOptions, userOptions);
  }
  /**
   * Set the annotation's visibility.
   * @private
   * @param {boolean} [visible]
   * Whether to show or hide an annotation. If the param is omitted, the
   * annotation's visibility is toggled.
   */
  setVisibility(visible) {
    const options2 = this.options, navigation2 = this.chart.navigationBindings, visibility = pick$U(visible, !options2.visible);
    this.graphic.attr("visibility", visibility ? "inherit" : "hidden");
    if (!visibility) {
      const setItemControlPointsVisibility = function(item) {
        item.setControlPointsVisibility(visibility);
      };
      this.shapes.forEach(setItemControlPointsVisibility);
      this.labels.forEach(setItemControlPointsVisibility);
      if (navigation2.activeAnnotation === this && navigation2.popup && navigation2.popup.type === "annotation-toolbar") {
        fireEvent$f(navigation2, "closePopup");
      }
    }
    options2.visible = visibility;
  }
  /**
   * Updates an annotation.
   *
   * @function Highcharts.Annotation#update
   *
   * @param {Partial<Highcharts.AnnotationsOptions>} userOptions
   *        New user options for the annotation.
   *
   */
  update(userOptions, redraw) {
    const chart = this.chart, labelsAndShapes = getLabelsAndShapesOptions(this.userOptions, userOptions), userOptionsIndex = chart.annotations.indexOf(this), options2 = merge$V(true, this.userOptions, userOptions);
    options2.labels = labelsAndShapes.labels;
    options2.shapes = labelsAndShapes.shapes;
    this.destroy();
    this.initProperties(chart, options2);
    this.init(chart, options2);
    chart.options.annotations[userOptionsIndex] = this.options;
    this.isUpdating = true;
    if (pick$U(redraw, true)) {
      chart.drawAnnotations();
    }
    fireEvent$f(this, "afterUpdate");
    this.isUpdating = false;
  }
}
Annotation.ControlPoint = ControlPoint;
Annotation.MockPoint = MockPoint;
Annotation.shapesMap = {
  "rect": ControllableRect,
  "circle": ControllableCircle,
  "ellipse": ControllableEllipse,
  "path": ControllablePath,
  "image": ControllableImage
};
Annotation.types = {};
Annotation.prototype.defaultOptions = AnnotationDefaults;
Annotation.prototype.nonDOMEvents = ["add", "afterUpdate", "drag", "remove"];
ControlTarget$1.compose(Annotation);
var ChartNavigationComposition;
(function(ChartNavigationComposition2) {
  function compose2(chart) {
    if (!chart.navigation) {
      chart.navigation = new Additions(chart);
    }
    return chart;
  }
  ChartNavigationComposition2.compose = compose2;
  class Additions {
    /* *
     *
     *  Constructor
     *
     * */
    constructor(chart) {
      this.updates = [];
      this.chart = chart;
    }
    /* *
     *
     *  Functions
     *
     * */
    /**
     * Registers an `update()` method in the `chart.navigation` object.
     *
     * @private
     * @param {UpdateFunction} updateFn
     * The `update()` method that will be called in `chart.update()`.
     */
    addUpdate(updateFn) {
      this.chart.navigation.updates.push(updateFn);
    }
    /**
     * @private
     */
    update(options2, redraw) {
      this.updates.forEach((updateFn) => {
        updateFn.call(this.chart, options2, redraw);
      });
    }
  }
  ChartNavigationComposition2.Additions = Additions;
})(ChartNavigationComposition || (ChartNavigationComposition = {}));
const ChartNavigationComposition$1 = ChartNavigationComposition;
const { getAssignedAxis: getAssignedAxis$1 } = NavigationBindingUtilities;
const { isNumber: isNumber$z, merge: merge$U } = Utilities;
const lang$3 = {
  /**
   * Configure the Popup strings in the chart. Requires the
   * `annotations.js` or `annotations-advanced.src.js` module to be
   * loaded.
   * @since   7.0.0
   * @product highcharts highstock
   */
  navigation: {
    /**
     * Translations for all field names used in popup.
     *
     * @product highcharts highstock
     */
    popup: {
      simpleShapes: "Simple shapes",
      lines: "Lines",
      circle: "Circle",
      ellipse: "Ellipse",
      rectangle: "Rectangle",
      label: "Label",
      shapeOptions: "Shape options",
      typeOptions: "Details",
      fill: "Fill",
      format: "Text",
      strokeWidth: "Line width",
      stroke: "Line color",
      title: "Title",
      name: "Name",
      labelOptions: "Label options",
      labels: "Labels",
      backgroundColor: "Background color",
      backgroundColors: "Background colors",
      borderColor: "Border color",
      borderRadius: "Border radius",
      borderWidth: "Border width",
      style: "Style",
      padding: "Padding",
      fontSize: "Font size",
      color: "Color",
      height: "Height",
      shapes: "Shape options"
    }
  }
};
const navigation$1 = {
  /**
   * A CSS class name where all bindings will be attached to. Multiple
   * charts on the same page should have separate class names to prevent
   * duplicating events.
   *
   * Default value of versions < 7.0.4 `highcharts-bindings-wrapper`
   *
   * @since     7.0.0
   * @type      {string}
   */
  bindingsClassName: "highcharts-bindings-container",
  /**
   * Bindings definitions for custom HTML buttons. Each binding implements
   * simple event-driven interface:
   *
   * - `className`: classname used to bind event to
   *
   * - `init`: initial event, fired on button click
   *
   * - `start`: fired on first click on a chart
   *
   * - `steps`: array of sequential events fired one after another on each
   *   of users clicks
   *
   * - `end`: last event to be called after last step event
   *
   * @type         {Highcharts.Dictionary<Highcharts.NavigationBindingsOptionsObject>|*}
   *
   * @sample {highstock} stock/stocktools/stocktools-thresholds
   *               Custom bindings
   * @sample {highcharts} highcharts/annotations/bindings/
   *               Simple binding
   * @sample {highcharts} highcharts/annotations/bindings-custom-annotation/
   *               Custom annotation binding
   *
   * @since        7.0.0
   * @requires     modules/annotations
   * @product      highcharts highstock
   */
  bindings: {
    /**
     * A circle annotation bindings. Includes `start` and one event in
     * `steps` array.
     *
     * @type    {Highcharts.NavigationBindingsOptionsObject}
     * @default {"className": "highcharts-circle-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
     */
    circleAnnotation: {
      /** @ignore-option */
      className: "highcharts-circle-annotation",
      /** @ignore-option */
      start: function(e) {
        const coords = this.chart.pointer?.getCoordinates(e), coordsX = coords && getAssignedAxis$1(coords.xAxis), coordsY = coords && getAssignedAxis$1(coords.yAxis), navigation2 = this.chart.options.navigation;
        if (!coordsX || !coordsY) {
          return;
        }
        return this.chart.addAnnotation(merge$U({
          langKey: "circle",
          type: "basicAnnotation",
          shapes: [{
            type: "circle",
            point: {
              x: coordsX.value,
              y: coordsY.value,
              xAxis: coordsX.axis.index,
              yAxis: coordsY.axis.index
            },
            r: 5
          }]
        }, navigation2.annotationsOptions, navigation2.bindings.circleAnnotation.annotationsOptions));
      },
      /** @ignore-option */
      steps: [
        function(e, annotation) {
          const shapes = annotation.options.shapes, mockPointOpts = shapes && shapes[0] && shapes[0].point || {};
          let distance;
          if (isNumber$z(mockPointOpts.xAxis) && isNumber$z(mockPointOpts.yAxis)) {
            const inverted = this.chart.inverted, x = this.chart.xAxis[mockPointOpts.xAxis].toPixels(mockPointOpts.x), y = this.chart.yAxis[mockPointOpts.yAxis].toPixels(mockPointOpts.y);
            distance = Math.max(Math.sqrt(Math.pow(inverted ? y - e.chartX : x - e.chartX, 2) + Math.pow(inverted ? x - e.chartY : y - e.chartY, 2)), 5);
          }
          annotation.update({
            shapes: [{
              r: distance
            }]
          });
        }
      ]
    },
    /**
     * A ellipse annotation bindings. Includes `start` and two events in
     * `steps` array. First updates the second point, responsible for a
     * rx width, and second updates the ry width.
     *
     * @type    {Highcharts.NavigationBindingsOptionsObject}
     * @default {"className": "highcharts-ellipse-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
     */
    ellipseAnnotation: {
      className: "highcharts-ellipse-annotation",
      start: function(e) {
        const coords = this.chart.pointer?.getCoordinates(e), coordsX = coords && getAssignedAxis$1(coords.xAxis), coordsY = coords && getAssignedAxis$1(coords.yAxis), navigation2 = this.chart.options.navigation;
        if (!coordsX || !coordsY) {
          return;
        }
        return this.chart.addAnnotation(merge$U({
          langKey: "ellipse",
          type: "basicAnnotation",
          shapes: [
            {
              type: "ellipse",
              xAxis: coordsX.axis.index,
              yAxis: coordsY.axis.index,
              points: [{
                x: coordsX.value,
                y: coordsY.value
              }, {
                x: coordsX.value,
                y: coordsY.value
              }],
              ry: 1
            }
          ]
        }, navigation2.annotationsOptions, navigation2.bindings.ellipseAnnotation.annotationsOptions));
      },
      steps: [
        function(e, annotation) {
          const target = annotation.shapes[0], position = target.getAbsolutePosition(target.points[1]);
          target.translatePoint(e.chartX - position.x, e.chartY - position.y, 1);
          target.redraw(false);
        },
        function(e, annotation) {
          const target = annotation.shapes[0], position = target.getAbsolutePosition(target.points[0]), position2 = target.getAbsolutePosition(target.points[1]), newR = target.getDistanceFromLine(position, position2, e.chartX, e.chartY), yAxis2 = target.getYAxis(), newRY = Math.abs(yAxis2.toValue(0) - yAxis2.toValue(newR));
          target.setYRadius(newRY);
          target.redraw(false);
        }
      ]
    },
    /**
     * A rectangle annotation bindings. Includes `start` and one event
     * in `steps` array.
     *
     * @type    {Highcharts.NavigationBindingsOptionsObject}
     * @default {"className": "highcharts-rectangle-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
     */
    rectangleAnnotation: {
      /** @ignore-option */
      className: "highcharts-rectangle-annotation",
      /** @ignore-option */
      start: function(e) {
        const coords = this.chart.pointer?.getCoordinates(e), coordsX = coords && getAssignedAxis$1(coords.xAxis), coordsY = coords && getAssignedAxis$1(coords.yAxis);
        if (!coordsX || !coordsY) {
          return;
        }
        const x = coordsX.value, y = coordsY.value, xAxis2 = coordsX.axis.index, yAxis2 = coordsY.axis.index, navigation2 = this.chart.options.navigation;
        return this.chart.addAnnotation(merge$U({
          langKey: "rectangle",
          type: "basicAnnotation",
          shapes: [{
            type: "path",
            points: [
              { xAxis: xAxis2, yAxis: yAxis2, x, y },
              { xAxis: xAxis2, yAxis: yAxis2, x, y },
              { xAxis: xAxis2, yAxis: yAxis2, x, y },
              { xAxis: xAxis2, yAxis: yAxis2, x, y },
              { command: "Z" }
            ]
          }]
        }, navigation2.annotationsOptions, navigation2.bindings.rectangleAnnotation.annotationsOptions));
      },
      /** @ignore-option */
      steps: [
        function(e, annotation) {
          const shapes = annotation.options.shapes, points = shapes && shapes[0] && shapes[0].points || [], coords = this.chart.pointer?.getCoordinates(e), coordsX = coords && getAssignedAxis$1(coords.xAxis), coordsY = coords && getAssignedAxis$1(coords.yAxis);
          if (coordsX && coordsY) {
            const x = coordsX.value, y = coordsY.value;
            points[1].x = x;
            points[2].x = x;
            points[2].y = y;
            points[3].y = y;
            annotation.update({
              shapes: [{
                points
              }]
            });
          }
        }
      ]
    },
    /**
     * A label annotation bindings. Includes `start` event only.
     *
     * @type    {Highcharts.NavigationBindingsOptionsObject}
     * @default {"className": "highcharts-label-annotation", "start": function() {}, "steps": [function() {}], "annotationsOptions": {}}
     */
    labelAnnotation: {
      /** @ignore-option */
      className: "highcharts-label-annotation",
      /** @ignore-option */
      start: function(e) {
        const coords = this.chart.pointer?.getCoordinates(e), coordsX = coords && getAssignedAxis$1(coords.xAxis), coordsY = coords && getAssignedAxis$1(coords.yAxis), navigation2 = this.chart.options.navigation;
        if (!coordsX || !coordsY) {
          return;
        }
        return this.chart.addAnnotation(merge$U({
          langKey: "label",
          type: "basicAnnotation",
          labelOptions: {
            format: "{y:.2f}",
            overflow: "none",
            crop: true
          },
          labels: [{
            point: {
              xAxis: coordsX.axis.index,
              yAxis: coordsY.axis.index,
              x: coordsX.value,
              y: coordsY.value
            }
          }]
        }, navigation2.annotationsOptions, navigation2.bindings.labelAnnotation.annotationsOptions));
      }
    }
  },
  /**
   * Path where Highcharts will look for icons. Change this to use icons
   * from a different server.
   *
   * @type      {string}
   * @default   https://code.highcharts.com/12.2.0/gfx/stock-icons/
   * @since     7.1.3
   * @apioption navigation.iconsURL
   */
  /**
   * A `showPopup` event. Fired when selecting for example an annotation.
   *
   * @type      {Function}
   * @apioption navigation.events.showPopup
   */
  /**
   * A `closePopup` event. Fired when Popup should be hidden, for example
   * when clicking on an annotation again.
   *
   * @type      {Function}
   * @apioption navigation.events.closePopup
   */
  /**
   * Event fired on a button click.
   *
   * @type      {Function}
   * @sample    highcharts/annotations/gui/
   *            Change icon in a dropddown on event
   * @sample    highcharts/annotations/gui-buttons/
   *            Change button class on event
   * @apioption navigation.events.selectButton
   */
  /**
   * Event fired when button state should change, for example after
   * adding an annotation.
   *
   * @type      {Function}
   * @sample    highcharts/annotations/gui/
   *            Change icon in a dropddown on event
   * @sample    highcharts/annotations/gui-buttons/
   *            Change button class on event
   * @apioption navigation.events.deselectButton
   */
  /**
   * Events to communicate between Stock Tools and custom GUI.
   *
   * @since        7.0.0
   * @product      highcharts highstock
   * @optionparent navigation.events
   */
  events: {},
  /**
   * Additional options to be merged into all annotations.
   *
   * @sample stock/stocktools/navigation-annotation-options
   *         Set red color of all line annotations
   *
   * @type      {Highcharts.AnnotationsOptions}
   * @extends   annotations
   * @exclude   crookedLine, elliottWave, fibonacci, infinityLine,
   *            measure, pitchfork, tunnel, verticalLine, basicAnnotation
   * @requires     modules/annotations
   * @apioption navigation.annotationsOptions
   */
  annotationsOptions: {
    animation: {
      defer: 0
    }
  }
};
const NavigationBindingDefaults = {
  lang: lang$3,
  navigation: navigation$1
};
const { setOptions: setOptions$2 } = DefaultOptions;
const { format: format$2 } = Templating;
const { composed: composed$i, doc: doc$4, win: win$3 } = Highcharts;
const { getAssignedAxis, getFieldType } = NavigationBindingUtilities;
const { addEvent: addEvent$I, attr, defined: defined$x, fireEvent: fireEvent$e, isArray: isArray$b, isFunction: isFunction$1, isNumber: isNumber$y, isObject: isObject$a, merge: merge$T, objectEach: objectEach$a, pick: pick$T, pushUnique: pushUnique$i } = Utilities;
function closestPolyfill(el, s) {
  const ElementProto = win$3.Element.prototype, elementMatches = ElementProto.matches || ElementProto.msMatchesSelector || ElementProto.webkitMatchesSelector;
  let ret = null;
  if (ElementProto.closest) {
    ret = ElementProto.closest.call(el, s);
  } else {
    do {
      if (elementMatches.call(el, s)) {
        return el;
      }
      el = el.parentElement || el.parentNode;
    } while (el !== null && el.nodeType === 1);
  }
  return ret;
}
function onAnnotationRemove() {
  if (this.chart.navigationBindings) {
    this.chart.navigationBindings.deselectAnnotation();
  }
}
function onChartDestroy$1() {
  if (this.navigationBindings) {
    this.navigationBindings.destroy();
  }
}
function onChartLoad$1() {
  const options2 = this.options;
  if (options2 && options2.navigation && options2.navigation.bindings) {
    this.navigationBindings = new NavigationBindings(this, options2.navigation);
    this.navigationBindings.initEvents();
    this.navigationBindings.initUpdate();
  }
}
function onChartRender$3() {
  const navigationBindings = this.navigationBindings, disabledClassName = "highcharts-disabled-btn";
  if (this && navigationBindings) {
    let buttonsEnabled = false;
    this.series.forEach((series) => {
      if (!series.options.isInternal && series.visible) {
        buttonsEnabled = true;
      }
    });
    if (this.navigationBindings && this.navigationBindings.container && this.navigationBindings.container[0]) {
      const container = this.navigationBindings.container[0];
      objectEach$a(navigationBindings.boundClassNames, (value, key2) => {
        const buttonNode = container.querySelectorAll("." + key2);
        if (buttonNode) {
          for (let i = 0; i < buttonNode.length; i++) {
            const button = buttonNode[i], cls = button.className;
            if (value.noDataState === "normal") {
              if (cls.indexOf(disabledClassName) !== -1) {
                button.classList.remove(disabledClassName);
              }
            } else if (!buttonsEnabled) {
              if (cls.indexOf(disabledClassName) === -1) {
                button.className += " " + disabledClassName;
              }
            } else {
              if (cls.indexOf(disabledClassName) !== -1) {
                button.classList.remove(disabledClassName);
              }
            }
          }
        }
      });
    }
  }
}
function onNavigationBindingsClosePopup() {
  this.deselectAnnotation();
}
function onNavigationBindingsDeselectButton() {
  this.selectedButtonElement = null;
}
function selectableAnnotation(annotationType) {
  const originalClick = annotationType.prototype.defaultOptions.events && annotationType.prototype.defaultOptions.events.click;
  function selectAndShowPopup(eventArguments) {
    const annotation = this, navigation2 = annotation.chart.navigationBindings, prevAnnotation = navigation2.activeAnnotation;
    if (originalClick) {
      originalClick.call(annotation, eventArguments);
    }
    if (prevAnnotation !== annotation) {
      navigation2.deselectAnnotation();
      navigation2.activeAnnotation = annotation;
      annotation.setControlPointsVisibility(true);
      fireEvent$e(navigation2, "showPopup", {
        annotation,
        formType: "annotation-toolbar",
        options: navigation2.annotationToFields(annotation),
        onSubmit: function(data) {
          if (data.actionType === "remove") {
            navigation2.activeAnnotation = false;
            navigation2.chart.removeAnnotation(annotation);
          } else {
            const config2 = {};
            navigation2.fieldsToOptions(data.fields, config2);
            navigation2.deselectAnnotation();
            const typeOptions = config2.typeOptions;
            if (annotation.options.type === "measure") {
              typeOptions.crosshairY.enabled = typeOptions.crosshairY.strokeWidth !== 0;
              typeOptions.crosshairX.enabled = typeOptions.crosshairX.strokeWidth !== 0;
            }
            annotation.update(config2);
          }
        }
      });
    } else {
      fireEvent$e(navigation2, "closePopup");
    }
    eventArguments.activeAnnotation = true;
  }
  let touchStartX, touchStartY;
  function saveCoords(e) {
    touchStartX = e.touches[0].clientX;
    touchStartY = e.touches[0].clientY;
  }
  function checkForTouchmove(e) {
    const hasMoved = touchStartX ? Math.sqrt(Math.pow(touchStartX - e.changedTouches[0].clientX, 2) + Math.pow(touchStartY - e.changedTouches[0].clientY, 2)) >= 4 : false;
    if (!hasMoved) {
      selectAndShowPopup.call(this, e);
    }
  }
  merge$T(true, annotationType.prototype.defaultOptions.events, {
    click: selectAndShowPopup,
    touchstart: saveCoords,
    touchend: checkForTouchmove
  });
}
class NavigationBindings {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AnnotationClass, ChartClass) {
    if (pushUnique$i(composed$i, "NavigationBindings")) {
      addEvent$I(AnnotationClass, "remove", onAnnotationRemove);
      selectableAnnotation(AnnotationClass);
      objectEach$a(AnnotationClass.types, (annotationType) => {
        selectableAnnotation(annotationType);
      });
      addEvent$I(ChartClass, "destroy", onChartDestroy$1);
      addEvent$I(ChartClass, "load", onChartLoad$1);
      addEvent$I(ChartClass, "render", onChartRender$3);
      addEvent$I(NavigationBindings, "closePopup", onNavigationBindingsClosePopup);
      addEvent$I(NavigationBindings, "deselectButton", onNavigationBindingsDeselectButton);
      setOptions$2(NavigationBindingDefaults);
    }
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, options2) {
    this.boundClassNames = void 0;
    this.chart = chart;
    this.options = options2;
    this.eventsToUnbind = [];
    this.container = this.chart.container.getElementsByClassName(this.options.bindingsClassName || "");
    if (!this.container.length) {
      this.container = doc$4.getElementsByClassName(this.options.bindingsClassName || "");
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  getCoords(e) {
    const coords = this.chart.pointer?.getCoordinates(e);
    return [
      coords && getAssignedAxis(coords.xAxis),
      coords && getAssignedAxis(coords.yAxis)
    ];
  }
  /**
   * Init all events connected to NavigationBindings.
   *
   * @private
   * @function Highcharts.NavigationBindings#initEvents
   */
  initEvents() {
    const navigation2 = this, chart = navigation2.chart, bindingsContainer = navigation2.container, options2 = navigation2.options;
    navigation2.boundClassNames = {};
    objectEach$a(options2.bindings || {}, (value) => {
      navigation2.boundClassNames[value.className] = value;
    });
    [].forEach.call(bindingsContainer, (subContainer) => {
      navigation2.eventsToUnbind.push(addEvent$I(subContainer, "click", (event) => {
        const bindings = navigation2.getButtonEvents(subContainer, event);
        if (bindings && !bindings.button.classList.contains("highcharts-disabled-btn")) {
          navigation2.bindingsButtonClick(bindings.button, bindings.events, event);
        }
      }));
    });
    objectEach$a(options2.events || {}, (callback, eventName) => {
      if (isFunction$1(callback)) {
        navigation2.eventsToUnbind.push(addEvent$I(navigation2, eventName, callback, { passive: false }));
      }
    });
    navigation2.eventsToUnbind.push(addEvent$I(chart.container, "click", function(e) {
      if (!chart.cancelClick && chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop, {
        visiblePlotOnly: true
      })) {
        navigation2.bindingsChartClick(this, e);
      }
    }));
    navigation2.eventsToUnbind.push(addEvent$I(chart.container, Highcharts.isTouchDevice ? "touchmove" : "mousemove", function(e) {
      navigation2.bindingsContainerMouseMove(this, e);
    }, Highcharts.isTouchDevice ? { passive: false } : void 0));
  }
  /**
   * Common chart.update() delegation, shared between bindings and exporting.
   *
   * @private
   * @function Highcharts.NavigationBindings#initUpdate
   */
  initUpdate() {
    const navigation2 = this;
    ChartNavigationComposition$1.compose(this.chart).navigation.addUpdate((options2) => {
      navigation2.update(options2);
    });
  }
  /**
   * Hook for click on a button, method selects/unselects buttons,
   * then calls `bindings.init` callback.
   *
   * @private
   * @function Highcharts.NavigationBindings#bindingsButtonClick
   *
   * @param {Highcharts.HTMLDOMElement} [button]
   *        Clicked button
   *
   * @param {Object} events
   *        Events passed down from bindings (`init`, `start`, `step`, `end`)
   *
   * @param {Highcharts.PointerEventObject} clickEvent
   *        Browser's click event
   */
  bindingsButtonClick(button, events, clickEvent) {
    const navigation2 = this, chart = navigation2.chart, svgContainer = chart.renderer.boxWrapper;
    let shouldEventBeFired = true;
    if (navigation2.selectedButtonElement) {
      if (navigation2.selectedButtonElement.classList === button.classList) {
        shouldEventBeFired = false;
      }
      fireEvent$e(navigation2, "deselectButton", { button: navigation2.selectedButtonElement });
      if (navigation2.nextEvent) {
        if (navigation2.currentUserDetails && navigation2.currentUserDetails.coll === "annotations") {
          chart.removeAnnotation(navigation2.currentUserDetails);
        }
        navigation2.mouseMoveEvent = navigation2.nextEvent = false;
      }
    }
    if (shouldEventBeFired) {
      navigation2.selectedButton = events;
      navigation2.selectedButtonElement = button;
      fireEvent$e(navigation2, "selectButton", { button });
      if (events.init) {
        events.init.call(navigation2, button, clickEvent);
      }
      if (events.start || events.steps) {
        chart.renderer.boxWrapper.addClass("highcharts-draw-mode");
      }
    } else {
      chart.stockTools && button.classList.remove("highcharts-active");
      svgContainer.removeClass("highcharts-draw-mode");
      navigation2.nextEvent = false;
      navigation2.mouseMoveEvent = false;
      navigation2.selectedButton = null;
    }
  }
  /**
   * Hook for click on a chart, first click on a chart calls `start` event,
   * then on all subsequent clicks iterate over `steps` array.
   * When finished, calls `end` event.
   *
   * @private
   * @function Highcharts.NavigationBindings#bindingsChartClick
   *
   * @param {Highcharts.Chart} chart
   *        Chart that click was performed on.
   *
   * @param {Highcharts.PointerEventObject} clickEvent
   *        Browser's click event.
   */
  bindingsChartClick(chart, clickEvent) {
    chart = this.chart;
    const navigation2 = this, activeAnnotation = navigation2.activeAnnotation, selectedButton = navigation2.selectedButton, svgContainer = chart.renderer.boxWrapper;
    if (activeAnnotation) {
      if (!activeAnnotation.cancelClick && // #15729
      !clickEvent.activeAnnotation && // Element could be removed in the child action, e.g. button
      clickEvent.target.parentNode && // TO DO: Polyfill for IE11?
      !closestPolyfill(clickEvent.target, ".highcharts-popup")) {
        fireEvent$e(navigation2, "closePopup");
      } else if (activeAnnotation.cancelClick) {
        setTimeout(() => {
          activeAnnotation.cancelClick = false;
        }, 0);
      }
    }
    if (!selectedButton || !selectedButton.start) {
      return;
    }
    if (!navigation2.nextEvent) {
      navigation2.currentUserDetails = selectedButton.start.call(navigation2, clickEvent);
      if (navigation2.currentUserDetails && selectedButton.steps) {
        navigation2.stepIndex = 0;
        navigation2.steps = true;
        navigation2.mouseMoveEvent = navigation2.nextEvent = selectedButton.steps[navigation2.stepIndex];
      } else {
        fireEvent$e(navigation2, "deselectButton", { button: navigation2.selectedButtonElement });
        svgContainer.removeClass("highcharts-draw-mode");
        navigation2.steps = false;
        navigation2.selectedButton = null;
        if (selectedButton.end) {
          selectedButton.end.call(navigation2, clickEvent, navigation2.currentUserDetails);
        }
      }
    } else {
      navigation2.nextEvent(clickEvent, navigation2.currentUserDetails);
      if (navigation2.steps) {
        navigation2.stepIndex++;
        if (selectedButton.steps[navigation2.stepIndex]) {
          navigation2.mouseMoveEvent = navigation2.nextEvent = selectedButton.steps[navigation2.stepIndex];
        } else {
          fireEvent$e(navigation2, "deselectButton", { button: navigation2.selectedButtonElement });
          svgContainer.removeClass("highcharts-draw-mode");
          if (selectedButton.end) {
            selectedButton.end.call(navigation2, clickEvent, navigation2.currentUserDetails);
          }
          navigation2.nextEvent = false;
          navigation2.mouseMoveEvent = false;
          navigation2.selectedButton = null;
        }
      }
    }
  }
  /**
   * Hook for mouse move on a chart's container. It calls current step.
   *
   * @private
   * @function Highcharts.NavigationBindings#bindingsContainerMouseMove
   *
   * @param {Highcharts.HTMLDOMElement} container
   *        Chart's container.
   *
   * @param {global.Event} moveEvent
   *        Browser's move event.
   */
  bindingsContainerMouseMove(_container, moveEvent) {
    if (this.mouseMoveEvent) {
      this.mouseMoveEvent(moveEvent, this.currentUserDetails);
    }
  }
  /**
   * Translate fields (e.g. `params.period` or `marker.styles.color`) to
   * Highcharts options object (e.g. `{ params: { period } }`).
   *
   * @private
   * @function Highcharts.NavigationBindings#fieldsToOptions<T>
   *
   * @param {Highcharts.Dictionary<string>} fields
   *        Fields from popup form.
   *
   * @param {T} config
   *        Default config to be modified.
   *
   * @return {T}
   *         Modified config
   */
  fieldsToOptions(fields2, config2) {
    objectEach$a(fields2, (value, field2) => {
      const parsedValue = parseFloat(value), path = field2.split("."), pathLength = path.length - 1;
      if (isNumber$y(parsedValue) && !value.match(/px|em/g) && !field2.match(/format/g)) {
        value = parsedValue;
      }
      if (value !== "undefined") {
        let parent = config2;
        path.forEach((name, index) => {
          if (name !== "__proto__" && name !== "constructor") {
            const nextName = pick$T(path[index + 1], "");
            if (pathLength === index) {
              parent[name] = value;
            } else if (!parent[name]) {
              parent[name] = nextName.match(/\d/g) ? [] : {};
              parent = parent[name];
            } else {
              parent = parent[name];
            }
          }
        });
      }
    });
    return config2;
  }
  /**
   * Shorthand method to deselect an annotation.
   *
   * @function Highcharts.NavigationBindings#deselectAnnotation
   */
  deselectAnnotation() {
    if (this.activeAnnotation) {
      this.activeAnnotation.setControlPointsVisibility(false);
      this.activeAnnotation = false;
    }
  }
  /**
   * Generates API config for popup in the same format as options for
   * Annotation object.
   *
   * @function Highcharts.NavigationBindings#annotationToFields
   *
   * @param {Highcharts.Annotation} annotation
   *        Annotations object
   *
   * @return {Highcharts.Dictionary<string>}
   *         Annotation options to be displayed in popup box
   */
  annotationToFields(annotation) {
    const options2 = annotation.options, editables = NavigationBindings.annotationsEditable, nestedEditables = editables.nestedOptions, type = pick$T(options2.type, options2.shapes && options2.shapes[0] && options2.shapes[0].type, options2.labels && options2.labels[0] && options2.labels[0].type, "label"), nonEditables = NavigationBindings.annotationsNonEditable[options2.langKey] || [], visualOptions = {
      langKey: options2.langKey,
      type
    };
    function traverse(option, key2, parentEditables, parent, parentKey) {
      let nextParent;
      if (parentEditables && defined$x(option) && nonEditables.indexOf(key2) === -1 && ((parentEditables.indexOf && parentEditables.indexOf(key2)) >= 0 || parentEditables[key2] || // Nested array
      parentEditables === true)) {
        if (isArray$b(option)) {
          parent[key2] = [];
          option.forEach((arrayOption, i) => {
            if (!isObject$a(arrayOption)) {
              traverse(arrayOption, 0, nestedEditables[key2], parent[key2], key2);
            } else {
              parent[key2][i] = {};
              objectEach$a(arrayOption, (nestedOption, nestedKey) => {
                traverse(nestedOption, nestedKey, nestedEditables[key2], parent[key2][i], key2);
              });
            }
          });
        } else if (isObject$a(option)) {
          nextParent = {};
          if (isArray$b(parent)) {
            parent.push(nextParent);
            nextParent[key2] = {};
            nextParent = nextParent[key2];
          } else {
            parent[key2] = nextParent;
          }
          objectEach$a(option, (nestedOption, nestedKey) => {
            traverse(nestedOption, nestedKey, key2 === 0 ? parentEditables : nestedEditables[key2], nextParent, key2);
          });
        } else {
          if (key2 === "format") {
            parent[key2] = [
              format$2(option, annotation.labels[0].points[0]).toString(),
              "text"
            ];
          } else if (isArray$b(parent)) {
            parent.push([option, getFieldType(parentKey, option)]);
          } else {
            parent[key2] = [option, getFieldType(key2, option)];
          }
        }
      }
    }
    objectEach$a(options2, (option, key2) => {
      if (key2 === "typeOptions") {
        visualOptions[key2] = {};
        objectEach$a(options2[key2], (typeOption, typeKey) => {
          traverse(typeOption, typeKey, nestedEditables, visualOptions[key2], typeKey);
        });
      } else {
        traverse(option, key2, editables[type], visualOptions, key2);
      }
    });
    return visualOptions;
  }
  /**
   * Get all class names for all parents in the element. Iterates until finds
   * main container.
   *
   * @private
   * @function Highcharts.NavigationBindings#getClickedClassNames
   *
   * @param {Highcharts.HTMLDOMElement} container
   * Container that event is bound to.
   *
   * @param {global.Event} event
   * Browser's event.
   *
   * @return {Array<Array<string, Highcharts.HTMLDOMElement>>}
   * Array of class names with corresponding elements
   */
  getClickedClassNames(container, event) {
    let element = event.target, classNames = [], elemClassName;
    while (element && element.tagName) {
      elemClassName = attr(element, "class");
      if (elemClassName) {
        classNames = classNames.concat(elemClassName.split(" ").map((name) => [name, element]));
      }
      element = element.parentNode;
      if (element === container) {
        return classNames;
      }
    }
    return classNames;
  }
  /**
   * Get events bound to a button. It's a custom event delegation to find all
   * events connected to the element.
   *
   * @private
   * @function Highcharts.NavigationBindings#getButtonEvents
   *
   * @param {Highcharts.HTMLDOMElement} container
   *        Container that event is bound to.
   *
   * @param {global.Event} event
   *        Browser's event.
   *
   * @return {Object}
   *         Object with events (init, start, steps, and end)
   */
  getButtonEvents(container, event) {
    const navigation2 = this, classNames = this.getClickedClassNames(container, event);
    let bindings;
    classNames.forEach((className) => {
      if (navigation2.boundClassNames[className[0]] && !bindings) {
        bindings = {
          events: navigation2.boundClassNames[className[0]],
          button: className[1]
        };
      }
    });
    return bindings;
  }
  /**
   * Bindings are just events, so the whole update process is simply
   * removing old events and adding new ones.
   *
   * @private
   * @function Highcharts.NavigationBindings#update
   */
  update(options2) {
    this.options = merge$T(true, this.options, options2);
    this.removeEvents();
    this.initEvents();
  }
  /**
   * Remove all events created in the navigation.
   *
   * @private
   * @function Highcharts.NavigationBindings#removeEvents
   */
  removeEvents() {
    this.eventsToUnbind.forEach((unbinder) => unbinder());
  }
  /**
   * @private
   * @function Highcharts.NavigationBindings#destroy
   */
  destroy() {
    this.removeEvents();
  }
}
NavigationBindings.annotationsEditable = {
  // `typeOptions` are always available
  // Nested and shared options:
  nestedOptions: {
    labelOptions: ["style", "format", "backgroundColor"],
    labels: ["style"],
    label: ["style"],
    style: ["fontSize", "color"],
    background: ["fill", "strokeWidth", "stroke"],
    innerBackground: ["fill", "strokeWidth", "stroke"],
    outerBackground: ["fill", "strokeWidth", "stroke"],
    shapeOptions: ["fill", "strokeWidth", "stroke"],
    shapes: ["fill", "strokeWidth", "stroke"],
    line: ["strokeWidth", "stroke"],
    backgroundColors: [true],
    connector: ["fill", "strokeWidth", "stroke"],
    crosshairX: ["strokeWidth", "stroke"],
    crosshairY: ["strokeWidth", "stroke"]
  },
  // Simple shapes:
  circle: ["shapes"],
  ellipse: ["shapes"],
  verticalLine: [],
  label: ["labelOptions"],
  // Measure
  measure: ["background", "crosshairY", "crosshairX"],
  // Others:
  fibonacci: [],
  tunnel: ["background", "line", "height"],
  pitchfork: ["innerBackground", "outerBackground"],
  rect: ["shapes"],
  // Crooked lines, elliots, arrows etc:
  crookedLine: [],
  basicAnnotation: ["shapes", "labelOptions"]
};
NavigationBindings.annotationsNonEditable = {
  rectangle: ["crosshairX", "crosshairY", "labelOptions"],
  ellipse: ["labelOptions"],
  circle: ["labelOptions"]
};
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/annotations
 * @requires highcharts
 *
 * Annotations module
 *
 * (c) 2009-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$e = Highcharts;
G$e.Annotation = G$e.Annotation || Annotation;
G$e.NavigationBindings = G$e.NavigationBindings || NavigationBindings;
G$e.Annotation.compose(G$e.Chart, G$e.NavigationBindings, G$e.Pointer, G$e.SVGRenderer);
const { addEvent: addEvent$H, correctFloat: correctFloat$5, defined: defined$w, pick: pick$S } = Utilities;
function chartGetHoverPane(eventArgs) {
  const chart = this;
  let hoverPane;
  if (eventArgs) {
    chart.pane.forEach((pane2) => {
      const x = eventArgs.chartX - chart.plotLeft, y = eventArgs.chartY - chart.plotTop;
      if (isInsidePane(x, y, pane2.center)) {
        hoverPane = pane2;
      }
    });
  }
  return hoverPane;
}
function compose$g(ChartClass, PointerClass) {
  const chartProto = ChartClass.prototype;
  if (!chartProto.getHoverPane) {
    chartProto.collectionsWithUpdate.push("pane");
    chartProto.getHoverPane = chartGetHoverPane;
    addEvent$H(ChartClass, "afterIsInsidePlot", onChartAfterIsInsiderPlot);
    addEvent$H(PointerClass, "afterGetHoverData", onPointerAfterGetHoverData);
    addEvent$H(PointerClass, "beforeGetHoverData", onPointerBeforeGetHoverData);
  }
}
function isInsidePane(x, y, center, startAngle, endAngle) {
  let insideSlice = true;
  const cx = center[0], cy = center[1];
  const distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
  if (defined$w(startAngle) && defined$w(endAngle)) {
    const angle = Math.atan2(correctFloat$5(y - cy, 8), correctFloat$5(x - cx, 8));
    if (endAngle !== startAngle) {
      if (startAngle > endAngle) {
        insideSlice = angle >= startAngle && angle <= Math.PI || angle <= endAngle && angle >= -Math.PI;
      } else {
        insideSlice = angle >= startAngle && angle <= correctFloat$5(endAngle, 8);
      }
    }
  }
  return distance <= Math.ceil(center[2] / 2) && insideSlice;
}
function onChartAfterIsInsiderPlot(e) {
  const chart = this;
  if (chart.polar) {
    if (e.options.inverted) {
      [e.x, e.y] = [e.y, e.x];
    }
    e.isInsidePlot = chart.pane.some((pane2) => isInsidePane(e.x, e.y, pane2.center, pane2.axis && pane2.axis.normalizedStartAngleRad, pane2.axis && pane2.axis.normalizedEndAngleRad));
  }
}
function onPointerAfterGetHoverData(eventArgs) {
  const chart = this.chart;
  if (eventArgs.hoverPoint && eventArgs.hoverPoint.plotX && eventArgs.hoverPoint.plotY && chart.hoverPane && !isInsidePane(eventArgs.hoverPoint.plotX, eventArgs.hoverPoint.plotY, chart.hoverPane.center)) {
    eventArgs.hoverPoint = void 0;
  }
}
function onPointerBeforeGetHoverData(eventArgs) {
  const chart = this.chart;
  if (chart.polar) {
    chart.hoverPane = chart.getHoverPane(eventArgs);
    eventArgs.filter = function(s) {
      return s.visible && !(!eventArgs.shared && s.directTouch) && // #3821
      pick$S(s.options.enableMouseTracking, true) && (!chart.hoverPane || s.xAxis.pane === chart.hoverPane);
    };
  } else {
    chart.hoverPane = void 0;
  }
}
const PaneComposition = {
  compose: compose$g
};
const background = {
  /**
   * The class name for this background.
   *
   * @sample {highcharts} highcharts/css/pane/
   *         Panes styled by CSS
   * @sample {highstock} highcharts/css/pane/
   *         Panes styled by CSS
   * @sample {highmaps} highcharts/css/pane/
   *         Panes styled by CSS
   *
   * @type      {string}
   * @default   highcharts-pane
   * @since     5.0.0
   * @apioption pane.background.className
   */
  /**
   * The shape of the pane background. When `solid`, the background
   * is circular. When `arc`, the background extends only from the min
   * to the max of the value axis.
   *
   * @type    {Highcharts.PaneBackgroundShapeValue}
   * @since   2.3.0
   * @product highcharts
   */
  shape: "circle",
  /**
   * The border radius of the pane background when the shape is `arc`. Can be
   * a number (pixels) or a percentage string.
   *
   * @since 11.4.2
   * @sample  highcharts/series-solidgauge/pane-borderradius
   *          Circular gauge and pane with equal border radius
   * @product highcharts
   * @type    {number|string}
   */
  borderRadius: 0,
  /**
   * The pixel border width of the pane background.
   *
   * @since 2.3.0
   * @product highcharts
   */
  borderWidth: 1,
  /**
   * The pane background border color.
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since   2.3.0
   * @product highcharts
   */
  borderColor: "#cccccc",
  /**
   * The background color or gradient for the pane.
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [[0, #ffffff], [1, #e6e6e6]] }
   * @since   2.3.0
   * @product highcharts
   */
  backgroundColor: {
    /** @ignore-option */
    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
    /** @ignore-option */
    stops: [
      [
        0,
        "#ffffff"
        /* Palette.backgroundColor */
      ],
      [
        1,
        "#e6e6e6"
        /* Palette.neutralColor10 */
      ]
    ]
  },
  /** @ignore-option */
  from: -Number.MAX_VALUE,
  // Corrected to axis min
  /**
   * The inner radius of the pane background. Can be either numeric
   * (pixels) or a percentage string.
   *
   * @type    {number|string}
   * @since   2.3.0
   * @product highcharts
   */
  innerRadius: 0,
  /** @ignore-option */
  to: Number.MAX_VALUE,
  // Corrected to axis max
  /**
   * The outer radius of the circular pane background. Can be either
   * numeric (pixels) or a percentage string.
   *
   * @type     {number|string}
   * @since    2.3.0
   * @product  highcharts
   */
  outerRadius: "105%"
};
const pane = {
  /**
   * The end angle of the polar X axis or gauge value axis, given in
   * degrees where 0 is north. Defaults to [startAngle](#pane.startAngle)
   * + 360.
   *
   * @sample {highcharts} highcharts/demo/gauge-vu-meter/
   *         VU-meter with custom start and end angle
   *
   * @type      {number}
   * @since     2.3.0
   * @product   highcharts
   * @apioption pane.endAngle
   */
  /**
   * The center of a polar chart or angular gauge, given as an array
   * of [x, y] positions. Positions can be given as integers that
   * transform to pixels, or as percentages of the plot area size.
   *
   * @sample {highcharts} highcharts/demo/gauge-vu-meter/
   *         Two gauges with different center
   *
   * @type    {Array<string|number>}
   * @default ["50%", "50%"]
   * @since   2.3.0
   * @product highcharts
   */
  center: ["50%", "50%"],
  /**
   * The size of the pane, either as a number defining pixels, or a
   * percentage defining a percentage of the available plot area (the
   * smallest of the plot height or plot width).
   *
   * @sample {highcharts} highcharts/demo/gauge-vu-meter/
   *         Smaller size
   *
   * @type    {number|string}
   * @product highcharts
   */
  size: "85%",
  /**
   * The inner size of the pane, either as a number defining pixels, or a
   * percentage defining a percentage of the pane's size.
   *
   * @sample {highcharts} highcharts/series-polar/column-inverted-inner
   *         The inner size set to 20%
   *
   * @type    {number|string}
   * @product highcharts
   */
  innerSize: "0%",
  /**
   * The start angle of the polar X axis or gauge axis, given in degrees
   * where 0 is north. Defaults to 0.
   *
   * @sample {highcharts} highcharts/demo/gauge-vu-meter/
   *         VU-meter with custom start and end angle
   *
   * @since   2.3.0
   * @product highcharts
   */
  startAngle: 0
};
const PaneDefaults = {
  pane,
  background
};
const { extend: extend$N, merge: merge$S, splat: splat$a } = Utilities;
class Pane {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(options2, chart) {
    this.coll = "pane";
    this.init(options2, chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the Pane object
   *
   * @private
   * @function Highcharts.Pane#init
   *
   * @param {Highcharts.PaneOptions} options
   *
   * @param {Highcharts.Chart} chart
   */
  init(options2, chart) {
    this.chart = chart;
    this.background = [];
    chart.pane.push(this);
    this.setOptions(options2);
  }
  /**
   * @private
   * @function Highcharts.Pane#setOptions
   *
   * @param {Highcharts.PaneOptions} options
   */
  setOptions(options2) {
    this.options = options2 = merge$S(PaneDefaults.pane, this.chart.angular ? { background: {} } : void 0, options2);
  }
  /**
   * Render the pane with its backgrounds.
   *
   * @private
   * @function Highcharts.Pane#render
   */
  render() {
    const options2 = this.options, renderer = this.chart.renderer;
    if (!this.group) {
      this.group = renderer.g("pane-group").attr({ zIndex: options2.zIndex || 0 }).add();
    }
    this.updateCenter();
    let backgroundOption = this.options.background;
    if (backgroundOption) {
      backgroundOption = splat$a(backgroundOption);
      const len = Math.max(backgroundOption.length, this.background.length || 0);
      for (let i = 0; i < len; i++) {
        if (backgroundOption[i] && this.axis) {
          this.renderBackground(merge$S(PaneDefaults.background, backgroundOption[i]), i);
        } else if (this.background[i]) {
          this.background[i] = this.background[i].destroy();
          this.background.splice(i, 1);
        }
      }
    }
  }
  /**
   * Render an individual pane background.
   *
   * @private
   * @function Highcharts.Pane#renderBackground
   *
   * @param {Highcharts.PaneBackgroundOptions} backgroundOptions
   *        Background options
   *
   * @param {number} i
   *        The index of the background in this.backgrounds
   */
  renderBackground(backgroundOptions, i) {
    const attribs = {
      "class": "highcharts-pane " + (backgroundOptions.className || "")
    };
    let method = "animate";
    if (!this.chart.styledMode) {
      extend$N(attribs, {
        "fill": backgroundOptions.backgroundColor,
        "stroke": backgroundOptions.borderColor,
        "stroke-width": backgroundOptions.borderWidth
      });
    }
    if (!this.background[i]) {
      this.background[i] = this.chart.renderer.path().add(this.group);
      method = "attr";
    }
    this.background[i][method]({
      "d": this.axis.getPlotBandPath(backgroundOptions.from, backgroundOptions.to, backgroundOptions)
    }).attr(attribs);
  }
  /**
   * Gets the center for the pane and its axis.
   *
   * @private
   * @function Highcharts.Pane#updateCenter
   * @param {Highcharts.Axis} [axis]
   */
  updateCenter(axis) {
    this.center = (axis || this.axis || {}).center = CU.getCenter.call(this);
  }
  /**
   * Destroy the pane item
   *
   * @ignore
   * @private
   * @function Highcharts.Pane#destroy
   * /
  destroy: function () {
      erase(this.chart.pane, this);
      this.background.forEach(function (background) {
          background.destroy();
      });
      this.background.length = 0;
      this.group = this.group.destroy();
  },
  */
  /**
   * Update the pane item with new options
   *
   * @private
   * @function Highcharts.Pane#update
   * @param {Highcharts.PaneOptions} options
   *        New pane options
   * @param {boolean} [redraw]
   */
  update(options2, redraw) {
    merge$S(true, this.options, options2);
    this.setOptions(this.options);
    this.render();
    this.chart.axes.forEach(function(axis) {
      if (axis.pane === this) {
        axis.pane = null;
        axis.update({}, redraw);
      }
    }, this);
  }
}
Pane.compose = PaneComposition.compose;
const { area: { prototype: { pointClass: AreaPoint, pointClass: { prototype: areaProto$1 } } } } = SeriesRegistry$1.seriesTypes;
const { defined: defined$v, isNumber: isNumber$x } = Utilities;
let AreaRangePoint$1 = class AreaRangePoint2 extends AreaPoint {
  /**
   * Range series only. The high or maximum value for each data point.
   * @name Highcharts.Point#high
   * @type {number|undefined}
   */
  /**
   * Range series only. The low or minimum value for each data point.
   * @name Highcharts.Point#low
   * @type {number|undefined}
   */
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  setState() {
    const prevState = this.state, series = this.series, isPolar = series.chart.polar;
    if (!defined$v(this.plotHigh)) {
      this.plotHigh = series.yAxis.toPixels(this.high, true);
    }
    if (!defined$v(this.plotLow)) {
      this.plotLow = this.plotY = series.yAxis.toPixels(this.low, true);
    }
    series.lowerStateMarkerGraphic = series.stateMarkerGraphic;
    series.stateMarkerGraphic = series.upperStateMarkerGraphic;
    this.graphic = this.graphics && this.graphics[1];
    this.plotY = this.plotHigh;
    if (isPolar && isNumber$x(this.plotHighX)) {
      this.plotX = this.plotHighX;
    }
    areaProto$1.setState.apply(this, arguments);
    this.state = prevState;
    this.plotY = this.plotLow;
    this.graphic = this.graphics && this.graphics[0];
    if (isPolar && isNumber$x(this.plotLowX)) {
      this.plotX = this.plotLowX;
    }
    series.upperStateMarkerGraphic = series.stateMarkerGraphic;
    series.stateMarkerGraphic = series.lowerStateMarkerGraphic;
    series.lowerStateMarkerGraphic = void 0;
    const originalSettings = series.modifyMarkerSettings();
    areaProto$1.setState.apply(this, arguments);
    series.restoreMarkerSettings(originalSettings);
  }
  haloPath() {
    const isPolar = this.series.chart.polar;
    let path = [];
    this.plotY = this.plotLow;
    if (isPolar && isNumber$x(this.plotLowX)) {
      this.plotX = this.plotLowX;
    }
    if (this.isInside) {
      path = areaProto$1.haloPath.apply(this, arguments);
    }
    this.plotY = this.plotHigh;
    if (isPolar && isNumber$x(this.plotHighX)) {
      this.plotX = this.plotHighX;
    }
    if (this.isTopInside) {
      path = path.concat(areaProto$1.haloPath.apply(this, arguments));
    }
    return path;
  }
  isValid() {
    return isNumber$x(this.low) && isNumber$x(this.high);
  }
};
const { noop: noop$d } = Highcharts;
const { area: AreaSeries$1, area: { prototype: areaProto }, column: { prototype: columnProto$4 } } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$G, defined: defined$u, extend: extend$M, isArray: isArray$a, isNumber: isNumber$w, pick: pick$R, merge: merge$R } = Utilities;
const areaRangeSeriesOptions = {
  /**
   * @see [fillColor](#plotOptions.arearange.fillColor)
   * @see [fillOpacity](#plotOptions.arearange.fillOpacity)
   *
   * @apioption plotOptions.arearange.color
   */
  /**
   * @default   low
   * @apioption plotOptions.arearange.colorKey
   */
  /**
   * @see [color](#plotOptions.arearange.color)
   * @see [fillOpacity](#plotOptions.arearange.fillOpacity)
   *
   * @apioption plotOptions.arearange.fillColor
   */
  /**
   * @see [color](#plotOptions.arearange.color)
   * @see [fillColor](#plotOptions.arearange.fillColor)
   *
   * @default   {highcharts} 0.75
   * @default   {highstock} 0.75
   * @apioption plotOptions.arearange.fillOpacity
   */
  /**
   * Whether to apply a drop shadow to the graph line. Since 2.3 the
   * shadow can be an object configuration containing `color`, `offsetX`,
   * `offsetY`, `opacity` and `width`.
   *
   * @type      {boolean|Highcharts.ShadowOptionsObject}
   * @product   highcharts
   * @apioption plotOptions.arearange.shadow
   */
  /**
   * Pixel width of the arearange graph line.
   *
   * @since 2.3.0
   *
   * @private
   */
  lineWidth: 1,
  /**
   * @type {number|null}
   */
  threshold: null,
  tooltip: {
    pointFormat: '<span style="color:{series.color}">●</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
  },
  /**
   * Whether the whole area or just the line should respond to mouseover
   * tooltips and other mouse or touch events.
   *
   * @since 2.3.0
   *
   * @private
   */
  trackByArea: true,
  /**
   * Extended data labels for range series types. Range series data
   * labels use no `x` and `y` options. Instead, they have `xLow`,
   * `xHigh`, `yLow` and `yHigh` options to allow the higher and lower
   * data label sets individually.
   *
   * @declare Highcharts.SeriesAreaRangeDataLabelsOptionsObject
   * @exclude x, y
   * @since   2.3.0
   * @product highcharts highstock
   *
   * @private
   */
  dataLabels: {
    align: void 0,
    verticalAlign: void 0,
    /**
     * X offset of the lower data labels relative to the point value.
     *
     * @sample highcharts/plotoptions/arearange-datalabels/
     *         Data labels on range series
     * @sample highcharts/plotoptions/arearange-datalabels/
     *         Data labels on range series
     */
    xLow: 0,
    /**
     * X offset of the higher data labels relative to the point value.
     *
     * @sample highcharts/plotoptions/arearange-datalabels/
     *         Data labels on range series
     */
    xHigh: 0,
    /**
     * Y offset of the lower data labels relative to the point value.
     *
     * @sample highcharts/plotoptions/arearange-datalabels/
     *         Data labels on range series
     */
    yLow: 0,
    /**
     * Y offset of the higher data labels relative to the point value.
     *
     * @sample highcharts/plotoptions/arearange-datalabels/
     *         Data labels on range series
     */
    yHigh: 0
  }
};
let AreaRangeSeries$2 = class AreaRangeSeries2 extends AreaSeries$1 {
  /* *
   *
   *  Functions
   *
   * */
  toYData(point) {
    return [point.low, point.high];
  }
  /**
   * Translate a point's plotHigh from the internal angle and radius measures
   * to true plotHigh coordinates. This is an addition of the toXY method
   * found in Polar.js, because it runs too early for arearanges to be
   * considered (#3419).
   * @private
   */
  highToXY(point) {
    const chart = this.chart, xy = this.xAxis.postTranslate(point.rectPlotX || 0, this.yAxis.len - (point.plotHigh || 0));
    point.plotHighX = xy.x - chart.plotLeft;
    point.plotHigh = xy.y - chart.plotTop;
    point.plotLowX = point.plotX;
  }
  /**
   * Extend the line series' getSegmentPath method by applying the segment
   * path to both lower and higher values of the range.
   * @private
   */
  getGraphPath(points) {
    const highPoints = [], highAreaPoints = [], getGraphPath = areaProto.getGraphPath, options2 = this.options, polar = this.chart.polar, connectEnds = polar && options2.connectEnds !== false, connectNulls = options2.connectNulls;
    let i, point, pointShim, step = options2.step;
    points = points || this.points;
    i = points.length;
    while (i--) {
      point = points[i];
      const highAreaPoint = polar ? {
        plotX: point.rectPlotX,
        plotY: point.yBottom,
        doCurve: false
        // #5186, gaps in areasplinerange fill
      } : {
        plotX: point.plotX,
        plotY: point.plotY,
        doCurve: false
        // #5186, gaps in areasplinerange fill
      };
      if (!point.isNull && !connectEnds && !connectNulls && (!points[i + 1] || points[i + 1].isNull)) {
        highAreaPoints.push(highAreaPoint);
      }
      pointShim = {
        polarPlotY: point.polarPlotY,
        rectPlotX: point.rectPlotX,
        yBottom: point.yBottom,
        // `plotHighX` is for polar charts
        plotX: pick$R(point.plotHighX, point.plotX),
        plotY: point.plotHigh,
        isNull: point.isNull
      };
      highAreaPoints.push(pointShim);
      highPoints.push(pointShim);
      if (!point.isNull && !connectEnds && !connectNulls && (!points[i - 1] || points[i - 1].isNull)) {
        highAreaPoints.push(highAreaPoint);
      }
    }
    const lowerPath = getGraphPath.call(this, points);
    if (step) {
      if (step === true) {
        step = "left";
      }
      options2.step = {
        left: "right",
        center: "center",
        right: "left"
      }[step];
    }
    const higherPath = getGraphPath.call(this, highPoints);
    const higherAreaPath = getGraphPath.call(this, highAreaPoints);
    options2.step = step;
    const linePath = [].concat(lowerPath, higherPath);
    if (!this.chart.polar && higherAreaPath[0] && higherAreaPath[0][0] === "M") {
      higherAreaPath[0] = [
        "L",
        higherAreaPath[0][1],
        higherAreaPath[0][2]
      ];
    }
    this.graphPath = linePath;
    this.areaPath = lowerPath.concat(higherAreaPath);
    linePath.isArea = true;
    linePath.xMap = lowerPath.xMap;
    this.areaPath.xMap = lowerPath.xMap;
    return linePath;
  }
  /**
   * Extend the basic drawDataLabels method by running it for both lower and
   * higher values.
   * @private
   */
  drawDataLabels() {
    const data = this.points, length = data.length, originalDataLabels = [], dataLabelOptions = this.options.dataLabels, inverted = this.chart.inverted;
    let i, point, up, upperDataLabelOptions, lowerDataLabelOptions;
    if (dataLabelOptions) {
      if (isArray$a(dataLabelOptions)) {
        upperDataLabelOptions = dataLabelOptions[0] || {
          enabled: false
        };
        lowerDataLabelOptions = dataLabelOptions[1] || {
          enabled: false
        };
      } else {
        upperDataLabelOptions = extend$M({}, dataLabelOptions);
        upperDataLabelOptions.x = dataLabelOptions.xHigh;
        upperDataLabelOptions.y = dataLabelOptions.yHigh;
        lowerDataLabelOptions = extend$M({}, dataLabelOptions);
        lowerDataLabelOptions.x = dataLabelOptions.xLow;
        lowerDataLabelOptions.y = dataLabelOptions.yLow;
      }
      if (upperDataLabelOptions.enabled || this.hasDataLabels?.()) {
        i = length;
        while (i--) {
          point = data[i];
          if (point) {
            const { plotHigh = 0, plotLow = 0 } = point;
            up = upperDataLabelOptions.inside ? plotHigh < plotLow : plotHigh > plotLow;
            point.y = point.high;
            point._plotY = point.plotY;
            point.plotY = plotHigh;
            originalDataLabels[i] = point.dataLabel;
            point.dataLabel = point.dataLabelUpper;
            point.below = up;
            if (inverted) {
              if (!upperDataLabelOptions.align) {
                upperDataLabelOptions.align = up ? "right" : "left";
              }
            } else {
              if (!upperDataLabelOptions.verticalAlign) {
                upperDataLabelOptions.verticalAlign = up ? "top" : "bottom";
              }
            }
          }
        }
        this.options.dataLabels = upperDataLabelOptions;
        if (areaProto.drawDataLabels) {
          areaProto.drawDataLabels.apply(this, arguments);
        }
        i = length;
        while (i--) {
          point = data[i];
          if (point) {
            point.dataLabelUpper = point.dataLabel;
            point.dataLabel = originalDataLabels[i];
            delete point.dataLabels;
            point.y = point.low;
            point.plotY = point._plotY;
          }
        }
      }
      if (lowerDataLabelOptions.enabled || this.hasDataLabels?.()) {
        i = length;
        while (i--) {
          point = data[i];
          if (point) {
            const { plotHigh = 0, plotLow = 0 } = point;
            up = lowerDataLabelOptions.inside ? plotHigh < plotLow : plotHigh > plotLow;
            point.below = !up;
            if (inverted) {
              if (!lowerDataLabelOptions.align) {
                lowerDataLabelOptions.align = up ? "left" : "right";
              }
            } else {
              if (!lowerDataLabelOptions.verticalAlign) {
                lowerDataLabelOptions.verticalAlign = up ? "bottom" : "top";
              }
            }
          }
        }
        this.options.dataLabels = lowerDataLabelOptions;
        if (areaProto.drawDataLabels) {
          areaProto.drawDataLabels.apply(this, arguments);
        }
      }
      if (upperDataLabelOptions.enabled) {
        i = length;
        while (i--) {
          point = data[i];
          if (point) {
            point.dataLabels = [
              point.dataLabelUpper,
              point.dataLabel
            ].filter(function(label) {
              return !!label;
            });
          }
        }
      }
      this.options.dataLabels = dataLabelOptions;
    }
  }
  alignDataLabel() {
    columnProto$4.alignDataLabel.apply(this, arguments);
  }
  modifyMarkerSettings() {
    const series = this, originalMarkerSettings = {
      marker: series.options.marker,
      symbol: series.symbol
    };
    if (series.options.lowMarker) {
      const { options: { marker, lowMarker } } = series;
      series.options.marker = merge$R(marker, lowMarker);
      if (lowMarker.symbol) {
        series.symbol = lowMarker.symbol;
      }
    }
    return originalMarkerSettings;
  }
  restoreMarkerSettings(originalSettings) {
    const series = this;
    series.options.marker = originalSettings.marker;
    series.symbol = originalSettings.symbol;
  }
  drawPoints() {
    const series = this, pointLength = series.points.length;
    let i, point;
    const originalSettings = series.modifyMarkerSettings();
    areaProto.drawPoints.apply(series, arguments);
    series.restoreMarkerSettings(originalSettings);
    i = 0;
    while (i < pointLength) {
      point = series.points[i];
      point.graphics = point.graphics || [];
      point.origProps = {
        plotY: point.plotY,
        plotX: point.plotX,
        isInside: point.isInside,
        negative: point.negative,
        zone: point.zone,
        y: point.y
      };
      if (point.graphic || point.graphics[0]) {
        point.graphics[0] = point.graphic;
      }
      point.graphic = point.graphics[1];
      point.plotY = point.plotHigh;
      if (defined$u(point.plotHighX)) {
        point.plotX = point.plotHighX;
      }
      point.y = pick$R(point.high, point.origProps.y);
      point.negative = point.y < (series.options.threshold || 0);
      if (series.zones.length) {
        point.zone = point.getZone();
      }
      if (!series.chart.polar) {
        point.isInside = point.isTopInside = typeof point.plotY !== "undefined" && point.plotY >= 0 && point.plotY <= series.yAxis.len && // #3519
        point.plotX >= 0 && point.plotX <= series.xAxis.len;
      }
      i++;
    }
    areaProto.drawPoints.apply(series, arguments);
    i = 0;
    while (i < pointLength) {
      point = series.points[i];
      point.graphics = point.graphics || [];
      if (point.graphic || point.graphics[1]) {
        point.graphics[1] = point.graphic;
      }
      point.graphic = point.graphics[0];
      if (point.origProps) {
        extend$M(point, point.origProps);
        delete point.origProps;
      }
      i++;
    }
  }
  hasMarkerChanged(options2, oldOptions) {
    const lowMarker = options2.lowMarker, oldMarker = oldOptions.lowMarker || {};
    return lowMarker && (lowMarker.enabled === false || oldMarker.symbol !== lowMarker.symbol || // #10870, #15946
    oldMarker.height !== lowMarker.height || // #16274
    oldMarker.width !== lowMarker.width) || super.hasMarkerChanged(options2, oldOptions);
  }
};
AreaRangeSeries$2.defaultOptions = merge$R(AreaSeries$1.defaultOptions, areaRangeSeriesOptions);
addEvent$G(AreaRangeSeries$2, "afterTranslate", function() {
  if (this.pointArrayMap.join(",") === "low,high") {
    this.points.forEach((point) => {
      const high2 = point.high, plotY = point.plotY;
      if (point.isNull) {
        point.plotY = void 0;
      } else {
        point.plotLow = plotY;
        point.plotHigh = isNumber$w(high2) ? this.yAxis.translate(this.dataModify ? this.dataModify.modifyValue(high2) : high2, false, true, void 0, true) : void 0;
        if (this.dataModify) {
          point.yBottom = point.plotHigh;
        }
      }
    });
  }
}, { order: 0 });
addEvent$G(AreaRangeSeries$2, "afterTranslate", function() {
  this.points.forEach((point) => {
    if (this.chart.polar) {
      this.highToXY(point);
      point.plotLow = point.plotY;
      point.tooltipPos = [
        ((point.plotHighX || 0) + (point.plotLowX || 0)) / 2,
        ((point.plotHigh || 0) + (point.plotLow || 0)) / 2
      ];
    } else {
      const tooltipPos = point.pos(false, point.plotLow), posHigh = point.pos(false, point.plotHigh);
      if (tooltipPos && posHigh) {
        tooltipPos[0] = (tooltipPos[0] + posHigh[0]) / 2;
        tooltipPos[1] = (tooltipPos[1] + posHigh[1]) / 2;
      }
      point.tooltipPos = tooltipPos;
    }
  });
}, { order: 3 });
extend$M(AreaRangeSeries$2.prototype, {
  deferTranslatePolar: true,
  pointArrayMap: ["low", "high"],
  pointClass: AreaRangePoint$1,
  pointValKey: "low",
  setStackedPoints: noop$d
});
SeriesRegistry$1.registerSeriesType("arearange", AreaRangeSeries$2);
const { spline: { prototype: splineProto } } = SeriesRegistry$1.seriesTypes;
const { merge: merge$Q, extend: extend$L } = Utilities;
class AreaSplineRangeSeries extends AreaRangeSeries$2 {
}
AreaSplineRangeSeries.defaultOptions = merge$Q(AreaRangeSeries$2.defaultOptions);
extend$L(AreaSplineRangeSeries.prototype, {
  getPointSpline: splineProto.getPointSpline
});
SeriesRegistry$1.registerSeriesType("areasplinerange", AreaSplineRangeSeries);
const BoxPlotSeriesDefaults = {
  /**
   * @type {number|null}
   */
  threshold: null,
  tooltip: {
    pointFormat: '<span style="color:{point.color}">●</span> <b>{series.name}</b><br/>Maximum: {point.high}<br/>Upper quartile: {point.q3}<br/>Median: {point.median}<br/>Lower quartile: {point.q1}<br/>Minimum: {point.low}<br/>'
  },
  /**
   * The length of the whiskers, the horizontal lines marking low and
   * high values. It can be a numerical pixel value, or a percentage
   * value of the box width. Set `0` to disable whiskers.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   *
   * @type    {number|string}
   * @since   3.0
   * @product highcharts
   */
  whiskerLength: "50%",
  /**
   * The fill color of the box.
   *
   * In styled mode, the fill color can be set with the
   * `.highcharts-boxplot-box` class.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default #ffffff
   * @since   3.0
   * @product highcharts
   */
  fillColor: "#ffffff",
  /**
   * The width of the line surrounding the box. If any of
   * [stemWidth](#plotOptions.boxplot.stemWidth),
   * [medianWidth](#plotOptions.boxplot.medianWidth)
   * or [whiskerWidth](#plotOptions.boxplot.whiskerWidth) are `null`,
   * the lineWidth also applies to these lines.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @since   3.0
   * @product highcharts
   */
  lineWidth: 1,
  /**
   * The color of the median line. If `undefined`, the general series
   * color applies.
   *
   * In styled mode, the median stroke width can be set with the
   * `.highcharts-boxplot-median` class.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.medianColor
   */
  /**
   * The pixel width of the median line. If `null`, the
   * [lineWidth](#plotOptions.boxplot.lineWidth) is used.
   *
   * In styled mode, the median stroke width can be set with the
   * `.highcharts-boxplot-median` class.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   *
   * @type    {number|null}
   * @since   3.0
   * @product highcharts
   */
  medianWidth: 2,
  /*
  // States are not working and are removed from docs.
  // Refer to: #2340
  states: {
      hover: {
          brightness: -0.3
      }
  },
  */
  /**
   * The color of the stem, the vertical line extending from the box to
   * the whiskers. If `undefined`, the series color is used.
   *
   * In styled mode, the stem stroke can be set with the
   * `.highcharts-boxplot-stem` class.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.stemColor
   */
  /**
   * The dash style of the box.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   *
   * @type      {Highcharts.DashStyleValue}
   * @default   Solid
   * @since 8.1.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.boxDashStyle
   */
  /**
   * The dash style of the median.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   *
   * @type      {Highcharts.DashStyleValue}
   * @default   Solid
   * @since 8.1.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.medianDashStyle
   */
  /**
   * The dash style of the stem, the vertical line extending from the
   * box to the whiskers.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @type      {Highcharts.DashStyleValue}
   * @default   Solid
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.stemDashStyle
   */
  /**
   * The dash style of the whiskers.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   *
   * @type      {Highcharts.DashStyleValue}
   * @default   Solid
   * @since 8.1.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.whiskerDashStyle
   */
  /**
   * The width of the stem, the vertical line extending from the box to
   * the whiskers. If `undefined`, the width is inherited from the
   * [lineWidth](#plotOptions.boxplot.lineWidth) option.
   *
   * In styled mode, the stem stroke width can be set with the
   * `.highcharts-boxplot-stem` class.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @type      {number}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.stemWidth
   */
  /**
   * @default   high
   * @apioption plotOptions.boxplot.colorKey
   */
  /**
   * The color of the whiskers, the horizontal lines marking low and high
   * values. When `undefined`, the general series color is used.
   *
   * In styled mode, the whisker stroke can be set with the
   * `.highcharts-boxplot-whisker` class .
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.boxplot.whiskerColor
   */
  /**
   * The line width of the whiskers, the horizontal lines marking low and
   * high values. When `undefined`, the general
   * [lineWidth](#plotOptions.boxplot.lineWidth) applies.
   *
   * In styled mode, the whisker stroke width can be set with the
   * `.highcharts-boxplot-whisker` class.
   *
   * @sample {highcharts} highcharts/plotoptions/box-plot-styling/
   *         Box plot styling
   * @sample {highcharts} highcharts/css/boxplot/
   *         Box plot in styled mode
   *
   * @since   3.0
   * @product highcharts
   */
  whiskerWidth: 2
};
const { noop: noop$c } = Highcharts;
const { crisp: crisp$5, extend: extend$K, merge: merge$P, pick: pick$Q, relativeLength: relativeLength$9 } = Utilities;
class BoxPlotSeries extends ColumnSeries$f {
  /* *
   *
   *  Functions
   *
   * */
  // Get presentational attributes
  pointAttribs() {
    return {};
  }
  // Get an SVGPath object for both whiskers
  getWhiskerPair(halfWidth, stemX, upperWhiskerLength, lowerWhiskerLength, point) {
    const strokeWidth = point.whiskers.strokeWidth(), getWhisker = (xLen, yPos) => {
      const halfLen = relativeLength$9(xLen, 2 * halfWidth) / 2, crispedYPos = crisp$5(yPos, strokeWidth);
      return [
        [
          "M",
          crisp$5(stemX - halfLen),
          crispedYPos
        ],
        [
          "L",
          crisp$5(stemX + halfLen),
          crispedYPos
        ]
      ];
    };
    return [
      ...getWhisker(upperWhiskerLength, point.highPlot),
      ...getWhisker(lowerWhiskerLength, point.lowPlot)
    ];
  }
  // Translate data points from raw values x and y to plotX and plotY
  translate() {
    const series = this, yAxis2 = series.yAxis, pointArrayMap = series.pointArrayMap;
    super.translate.apply(series);
    series.points.forEach(function(point) {
      pointArrayMap.forEach(function(key2) {
        if (point[key2] !== null) {
          point[key2 + "Plot"] = yAxis2.translate(point[key2], 0, 1, 0, 1);
        }
      });
      point.plotHigh = point.highPlot;
    });
  }
  /**
   * Draw the data points
   * @private
   */
  drawPoints() {
    const series = this, points = series.points, options2 = series.options, chart = series.chart, renderer = chart.renderer, doQuartiles = series.doQuartiles !== false, whiskerLength = series.options.whiskerLength;
    let q1Plot, q3Plot, highPlot, lowPlot, medianPlot, medianPath, boxPath, graphic, width, x, right;
    for (const point of points) {
      graphic = point.graphic;
      const verb = graphic ? "animate" : "attr", shapeArgs = point.shapeArgs, boxAttr = {}, stemAttr = {}, whiskersAttr = {}, medianAttr = {}, color2 = point.color || series.color, pointWhiskerLength = point.options.whiskerLength || whiskerLength;
      if (typeof point.plotY !== "undefined") {
        width = shapeArgs.width;
        x = shapeArgs.x;
        right = x + width;
        q1Plot = doQuartiles ? point.q1Plot : point.lowPlot;
        q3Plot = doQuartiles ? point.q3Plot : point.lowPlot;
        highPlot = point.highPlot;
        lowPlot = point.lowPlot;
        if (!graphic) {
          point.graphic = graphic = renderer.g("point").add(series.group);
          point.stem = renderer.path().addClass("highcharts-boxplot-stem").add(graphic);
          if (whiskerLength) {
            point.whiskers = renderer.path().addClass("highcharts-boxplot-whisker").add(graphic);
          }
          if (doQuartiles) {
            point.box = renderer.path(boxPath).addClass("highcharts-boxplot-box").add(graphic);
          }
          point.medianShape = renderer.path(medianPath).addClass("highcharts-boxplot-median").add(graphic);
        }
        if (!chart.styledMode) {
          stemAttr.stroke = point.stemColor || options2.stemColor || color2;
          stemAttr["stroke-width"] = pick$Q(point.stemWidth, options2.stemWidth, options2.lineWidth);
          stemAttr.dashstyle = point.stemDashStyle || options2.stemDashStyle || options2.dashStyle;
          point.stem.attr(stemAttr);
          if (pointWhiskerLength) {
            whiskersAttr.stroke = point.whiskerColor || options2.whiskerColor || color2;
            whiskersAttr["stroke-width"] = pick$Q(point.whiskerWidth, options2.whiskerWidth, options2.lineWidth);
            whiskersAttr.dashstyle = point.whiskerDashStyle || options2.whiskerDashStyle || options2.dashStyle;
            point.whiskers.attr(whiskersAttr);
          }
          if (doQuartiles) {
            boxAttr.fill = point.fillColor || options2.fillColor || color2;
            boxAttr.stroke = options2.lineColor || color2;
            boxAttr["stroke-width"] = options2.lineWidth || 0;
            boxAttr.dashstyle = point.boxDashStyle || options2.boxDashStyle || options2.dashStyle;
            point.box.attr(boxAttr);
          }
          medianAttr.stroke = point.medianColor || options2.medianColor || color2;
          medianAttr["stroke-width"] = pick$Q(point.medianWidth, options2.medianWidth, options2.lineWidth);
          medianAttr.dashstyle = point.medianDashStyle || options2.medianDashStyle || options2.dashStyle;
          point.medianShape.attr(medianAttr);
        }
        let d;
        const stemX = crisp$5((point.plotX || 0) + (series.pointXOffset || 0) + (series.barW || 0) / 2, point.stem.strokeWidth());
        d = [
          // Stem up
          ["M", stemX, q3Plot],
          ["L", stemX, highPlot],
          // Stem down
          ["M", stemX, q1Plot],
          ["L", stemX, lowPlot]
        ];
        point.stem[verb]({ d });
        if (doQuartiles) {
          const boxStrokeWidth = point.box.strokeWidth();
          q1Plot = crisp$5(q1Plot, boxStrokeWidth);
          q3Plot = crisp$5(q3Plot, boxStrokeWidth);
          x = crisp$5(x, boxStrokeWidth);
          right = crisp$5(right, boxStrokeWidth);
          d = [
            ["M", x, q3Plot],
            ["L", x, q1Plot],
            ["L", right, q1Plot],
            ["L", right, q3Plot],
            ["L", x, q3Plot],
            ["Z"]
          ];
          point.box[verb]({ d });
        }
        if (pointWhiskerLength) {
          const halfWidth = width / 2, whiskers = this.getWhiskerPair(halfWidth, stemX, point.upperWhiskerLength ?? options2.upperWhiskerLength ?? pointWhiskerLength, point.lowerWhiskerLength ?? options2.lowerWhiskerLength ?? pointWhiskerLength, point);
          point.whiskers[verb]({ d: whiskers });
        }
        medianPlot = crisp$5(point.medianPlot, point.medianShape.strokeWidth());
        d = [
          ["M", x, medianPlot],
          ["L", right, medianPlot]
        ];
        point.medianShape[verb]({ d });
      }
    }
  }
  // Return a plain array for speedy calculation
  toYData(point) {
    return [point.low, point.q1, point.median, point.q3, point.high];
  }
}
BoxPlotSeries.defaultOptions = merge$P(ColumnSeries$f.defaultOptions, BoxPlotSeriesDefaults);
extend$K(BoxPlotSeries.prototype, {
  // Array point configs are mapped to this
  pointArrayMap: ["low", "q1", "median", "q3", "high"],
  // Defines the top of the tracker
  pointValKey: "high",
  // Disable data labels for box plot
  drawDataLabels: noop$c,
  setStackedPoints: noop$c
  // #3890
});
SeriesRegistry$1.registerSeriesType("boxplot", BoxPlotSeries);
const BubbleLegendDefaults = {
  /**
   * The color of the ranges borders, can be also defined for an
   * individual range.
   *
   * @sample highcharts/bubble-legend/similartoseries/
   *         Similar look to the bubble series
   * @sample highcharts/bubble-legend/bordercolor/
   *         Individual bubble border color
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  borderColor: void 0,
  /**
   * The width of the ranges borders in pixels, can be also
   * defined for an individual range.
   */
  borderWidth: 2,
  /**
   * An additional class name to apply to the bubble legend'
   * circle graphical elements. This option does not replace
   * default class names of the graphical element.
   *
   * @sample {highcharts} highcharts/css/bubble-legend/
   *         Styling by CSS
   *
   * @type {string}
   */
  className: void 0,
  /**
   * The main color of the bubble legend. Applies to ranges, if
   * individual color is not defined.
   *
   * @sample highcharts/bubble-legend/similartoseries/
   *         Similar look to the bubble series
   * @sample highcharts/bubble-legend/color/
   *         Individual bubble color
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  color: void 0,
  /**
   * An additional class name to apply to the bubble legend's
   * connector graphical elements. This option does not replace
   * default class names of the graphical element.
   *
   * @sample {highcharts} highcharts/css/bubble-legend/
   *         Styling by CSS
   *
   * @type {string}
   */
  connectorClassName: void 0,
  /**
   * The color of the connector, can be also defined
   * for an individual range.
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  connectorColor: void 0,
  /**
   * The length of the connectors in pixels. If labels are
   * centered, the distance is reduced to 0.
   *
   * @sample highcharts/bubble-legend/connectorandlabels/
   *         Increased connector length
   */
  connectorDistance: 60,
  /**
   * The width of the connectors in pixels.
   *
   * @sample highcharts/bubble-legend/connectorandlabels/
   *         Increased connector width
   */
  connectorWidth: 1,
  /**
   * Enable or disable the bubble legend.
   */
  enabled: false,
  /**
   * Options for the bubble legend labels.
   */
  labels: {
    /**
     * An additional class name to apply to the bubble legend
     * label graphical elements. This option does not replace
     * default class names of the graphical element.
     *
     * @sample {highcharts} highcharts/css/bubble-legend/
     *         Styling by CSS
     *
     * @type {string}
     */
    className: void 0,
    /**
     * Whether to allow data labels to overlap.
     */
    allowOverlap: false,
    /**
     * A format string for the bubble legend labels. Available
     * variables are the same as for `formatter`.
     *
     * @sample highcharts/bubble-legend/format/
     *         Add a unit
     *
     * @type {string}
     */
    format: "",
    /**
     * Available `this` properties are:
     *
     * - `this.value`: The bubble value.
     *
     * - `this.radius`: The radius of the bubble range.
     *
     * - `this.center`: The center y position of the range.
     *
     * @type {Highcharts.FormatterCallbackFunction<Highcharts.BubbleLegendFormatterContextObject>}
     */
    formatter: void 0,
    /**
     * The alignment of the labels compared to the bubble
     * legend. Can be one of `left`, `center` or `right`.
     *
     * @sample highcharts/bubble-legend/connectorandlabels/
     *         Labels on left
     *
     * @type {Highcharts.AlignValue}
     */
    align: "right",
    /**
     * CSS styles for the labels.
     *
     * @type {Highcharts.CSSObject}
     */
    style: {
      /** @ignore-option */
      fontSize: "0.9em",
      /** @ignore-option */
      color: "#000000"
      /* Palette.neutralColor100 */
    },
    /**
     * The x position offset of the label relative to the
     * connector.
     */
    x: 0,
    /**
     * The y position offset of the label relative to the
     * connector.
     */
    y: 0
  },
  /**
   * Maximum bubble legend range size. If values for ranges are
   * not specified, the `minSize` and the `maxSize` are calculated
   * from bubble series.
   */
  maxSize: 60,
  // Number
  /**
   * Minimum bubble legend range size. If values for ranges are
   * not specified, the `minSize` and the `maxSize` are calculated
   * from bubble series.
   */
  minSize: 10,
  // Number
  /**
   * The position of the bubble legend in the legend.
   * @sample highcharts/bubble-legend/connectorandlabels/
   *         Bubble legend as last item in legend
   */
  legendIndex: 0,
  // Number
  /**
   * Options for specific range. One range consists of bubble,
   * label and connector.
   *
   * @sample highcharts/bubble-legend/ranges/
   *         Manually defined ranges
   * @sample highcharts/bubble-legend/autoranges/
   *         Auto calculated ranges
   *
   * @type {Array<*>}
   */
  ranges: {
    /**
     * Range size value, similar to bubble Z data.
     * @type {number}
     */
    value: void 0,
    /**
     * The color of the border for individual range.
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    borderColor: void 0,
    /**
     * The color of the bubble for individual range.
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    color: void 0,
    /**
     * The color of the connector for individual range.
     * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     */
    connectorColor: void 0
  },
  /**
   * Whether the bubble legend range value should be represented
   * by the area or the width of the bubble. The default, area,
   * corresponds best to the human perception of the size of each
   * bubble.
   *
   * @sample highcharts/bubble-legend/ranges/
   *         Size by width
   *
   * @type {Highcharts.BubbleSizeByValue}
   */
  sizeBy: "area",
  /**
   * When this is true, the absolute value of z determines the
   * size of the bubble. This means that with the default
   * zThreshold of 0, a bubble of value -1 will have the same size
   * as a bubble of value 1, while a bubble of value 0 will have a
   * smaller size according to minSize.
   */
  sizeByAbsoluteValue: false,
  /**
   * Define the visual z index of the bubble legend.
   */
  zIndex: 1,
  /**
   * Ranges with lower value than zThreshold are skipped.
   */
  zThreshold: 0
};
const { noop: noop$b } = Highcharts;
const { arrayMax: arrayMax$4, arrayMin: arrayMin$3, isNumber: isNumber$v, merge: merge$O, pick: pick$P, stableSort: stableSort$2 } = Utilities;
class BubbleLegendItem {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(options2, legend) {
    this.setState = noop$b;
    this.init(options2, legend);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Create basic bubbleLegend properties similar to item in legend.
   * @private
   */
  init(options2, legend) {
    this.options = options2;
    this.visible = true;
    this.chart = legend.chart;
    this.legend = legend;
  }
  /**
   * Depending on the position option, add bubbleLegend to legend items.
   *
   * @private
   *
   * @param {Array<(Highcharts.Point|Highcharts.Series)>} items
   *        All legend items
   */
  addToLegend(items) {
    items.splice(this.options.legendIndex, 0, this);
  }
  /**
   * Calculate ranges, sizes and call the next steps of bubbleLegend
   * creation.
   *
   * @private
   *
   * @param {Highcharts.Legend} legend
   *        Legend instance
   */
  drawLegendSymbol(legend) {
    const itemDistance = pick$P(legend.options.itemDistance, 20), legendItem = this.legendItem || {}, options2 = this.options, ranges = options2.ranges, connectorDistance = options2.connectorDistance;
    let connectorSpace;
    if (!ranges || !ranges.length || !isNumber$v(ranges[0].value)) {
      legend.options.bubbleLegend.autoRanges = true;
      return;
    }
    stableSort$2(ranges, function(a, b) {
      return b.value - a.value;
    });
    this.ranges = ranges;
    this.setOptions();
    this.render();
    const maxLabel = this.getMaxLabelSize(), radius = this.ranges[0].radius, size = radius * 2;
    connectorSpace = connectorDistance - radius + maxLabel.width;
    connectorSpace = connectorSpace > 0 ? connectorSpace : 0;
    this.maxLabel = maxLabel;
    this.movementX = options2.labels.align === "left" ? connectorSpace : 0;
    legendItem.labelWidth = size + connectorSpace + itemDistance;
    legendItem.labelHeight = size + maxLabel.height / 2;
  }
  /**
   * Set style options for each bubbleLegend range.
   * @private
   */
  setOptions() {
    const ranges = this.ranges, options2 = this.options, series = this.chart.series[options2.seriesIndex], baseline = this.legend.baseline, bubbleAttribs = {
      zIndex: options2.zIndex,
      "stroke-width": options2.borderWidth
    }, connectorAttribs = {
      zIndex: options2.zIndex,
      "stroke-width": options2.connectorWidth
    }, labelAttribs = {
      align: this.legend.options.rtl || options2.labels.align === "left" ? "right" : "left",
      zIndex: options2.zIndex
    }, fillOpacity = series.options.marker.fillOpacity, styledMode = this.chart.styledMode;
    ranges.forEach(function(range2, i) {
      if (!styledMode) {
        bubbleAttribs.stroke = pick$P(range2.borderColor, options2.borderColor, series.color);
        bubbleAttribs.fill = range2.color || options2.color;
        if (!bubbleAttribs.fill) {
          bubbleAttribs.fill = series.color;
          bubbleAttribs["fill-opacity"] = fillOpacity ?? 1;
        }
        connectorAttribs.stroke = pick$P(range2.connectorColor, options2.connectorColor, series.color);
      }
      ranges[i].radius = this.getRangeRadius(range2.value);
      ranges[i] = merge$O(ranges[i], {
        center: ranges[0].radius - ranges[i].radius + baseline
      });
      if (!styledMode) {
        merge$O(true, ranges[i], {
          bubbleAttribs: merge$O(bubbleAttribs),
          connectorAttribs: merge$O(connectorAttribs),
          labelAttribs
        });
      }
    }, this);
  }
  /**
   * Calculate radius for each bubble range,
   * used code from BubbleSeries.js 'getRadius' method.
   *
   * @private
   *
   * @param {number} value
   *        Range value
   *
   * @return {number|null}
   *         Radius for one range
   */
  getRangeRadius(value) {
    const options2 = this.options, seriesIndex = this.options.seriesIndex, bubbleSeries = this.chart.series[seriesIndex], zMax = options2.ranges[0].value, zMin = options2.ranges[options2.ranges.length - 1].value, minSize = options2.minSize, maxSize = options2.maxSize;
    return bubbleSeries.getRadius.call(this, zMin, zMax, minSize, maxSize, value);
  }
  /**
   * Render the legendItem group.
   * @private
   */
  render() {
    const legendItem = this.legendItem || {}, renderer = this.chart.renderer, zThreshold = this.options.zThreshold;
    if (!this.symbols) {
      this.symbols = {
        connectors: [],
        bubbleItems: [],
        labels: []
      };
    }
    legendItem.symbol = renderer.g("bubble-legend");
    legendItem.label = renderer.g("bubble-legend-item").css(this.legend.itemStyle || {});
    legendItem.symbol.translateX = 0;
    legendItem.symbol.translateY = 0;
    legendItem.symbol.add(legendItem.label);
    legendItem.label.add(legendItem.group);
    for (const range2 of this.ranges) {
      if (range2.value >= zThreshold) {
        this.renderRange(range2);
      }
    }
    this.hideOverlappingLabels();
  }
  /**
   * Render one range, consisting of bubble symbol, connector and label.
   *
   * @private
   *
   * @param {Highcharts.LegendBubbleLegendRangesOptions} range
   *        Range options
   */
  renderRange(range2) {
    const mainRange = this.ranges[0], legend = this.legend, options2 = this.options, labelsOptions = options2.labels, chart = this.chart, bubbleSeries = chart.series[options2.seriesIndex], renderer = chart.renderer, symbols2 = this.symbols, labels = symbols2.labels, elementCenter = range2.center, absoluteRadius = Math.abs(range2.radius), connectorDistance = options2.connectorDistance || 0, labelsAlign = labelsOptions.align, rtl = legend.options.rtl, borderWidth = options2.borderWidth, connectorWidth = options2.connectorWidth, posX = mainRange.radius || 0, posY = elementCenter - absoluteRadius - borderWidth / 2 + connectorWidth / 2, crispMovement = (posY % 1 ? 1 : 0.5) - (connectorWidth % 2 ? 0 : 0.5), styledMode = renderer.styledMode;
    let connectorLength = rtl || labelsAlign === "left" ? -connectorDistance : connectorDistance;
    if (labelsAlign === "center") {
      connectorLength = 0;
      options2.connectorDistance = 0;
      range2.labelAttribs.align = "center";
    }
    symbols2.bubbleItems.push(renderer.circle(posX, elementCenter + crispMovement, absoluteRadius).attr(styledMode ? {} : range2.bubbleAttribs).addClass((styledMode ? "highcharts-color-" + bubbleSeries.colorIndex + " " : "") + "highcharts-bubble-legend-symbol " + (options2.className || "")).add(this.legendItem.symbol));
    symbols2.connectors.push(renderer.path(renderer.crispLine([
      ["M", posX, posY],
      ["L", posX + connectorLength, posY]
    ], options2.connectorWidth)).attr(styledMode ? {} : range2.connectorAttribs).addClass((styledMode ? "highcharts-color-" + this.options.seriesIndex + " " : "") + "highcharts-bubble-legend-connectors " + (options2.connectorClassName || "")).add(this.legendItem.symbol));
    const label = renderer.text(this.formatLabel(range2)).attr(styledMode ? {} : range2.labelAttribs).css(styledMode ? {} : labelsOptions.style).addClass("highcharts-bubble-legend-labels " + (options2.labels.className || "")).add(this.legendItem.symbol);
    const position = {
      x: posX + connectorLength + options2.labels.x,
      y: posY + options2.labels.y + label.getBBox().height * 0.4
    };
    label.attr(position);
    labels.push(label);
    label.placed = true;
    label.alignAttr = position;
  }
  /**
   * Get the label which takes up the most space.
   * @private
   */
  getMaxLabelSize() {
    const labels = this.symbols.labels;
    let maxLabel, labelSize;
    labels.forEach(function(label) {
      labelSize = label.getBBox(true);
      if (maxLabel) {
        maxLabel = labelSize.width > maxLabel.width ? labelSize : maxLabel;
      } else {
        maxLabel = labelSize;
      }
    });
    return maxLabel || {};
  }
  /**
   * Get formatted label for range.
   *
   * @private
   *
   * @param {Highcharts.LegendBubbleLegendRangesOptions} range
   *        Range options
   *
   * @return {string}
   *         Range label text
   */
  formatLabel(range2) {
    const options2 = this.options, formatter = options2.labels.formatter, format2 = options2.labels.format;
    const { numberFormatter } = this.chart;
    return format2 ? Templating.format(format2, range2, this.chart) : formatter ? formatter.call(range2) : numberFormatter(range2.value, 1);
  }
  /**
   * By using default chart 'hideOverlappingLabels' method, hide or show
   * labels and connectors.
   * @private
   */
  hideOverlappingLabels() {
    const chart = this.chart, allowOverlap = this.options.labels.allowOverlap, symbols2 = this.symbols;
    if (!allowOverlap && symbols2) {
      chart.hideOverlappingLabels(symbols2.labels);
      symbols2.labels.forEach(function(label, index) {
        if (!label.newOpacity) {
          symbols2.connectors[index].hide();
        } else if (label.newOpacity !== label.oldOpacity) {
          symbols2.connectors[index].show();
        }
      });
    }
  }
  /**
   * Calculate ranges from created series.
   *
   * @private
   *
   * @return {Array<Highcharts.LegendBubbleLegendRangesOptions>}
   *         Array of range objects
   */
  getRanges() {
    const bubbleLegend = this.legend.bubbleLegend, series = bubbleLegend.chart.series, rangesOptions = bubbleLegend.options.ranges;
    let ranges, zData, minZ = Number.MAX_VALUE, maxZ = -Number.MAX_VALUE;
    series.forEach(function(s) {
      if (s.isBubble && !s.ignoreSeries) {
        zData = s.getColumn("z").filter(isNumber$v);
        if (zData.length) {
          minZ = pick$P(s.options.zMin, Math.min(minZ, Math.max(arrayMin$3(zData), s.options.displayNegative === false ? s.options.zThreshold : -Number.MAX_VALUE)));
          maxZ = pick$P(s.options.zMax, Math.max(maxZ, arrayMax$4(zData)));
        }
      }
    });
    if (minZ === maxZ) {
      ranges = [{ value: maxZ }];
    } else {
      ranges = [
        { value: minZ },
        { value: (minZ + maxZ) / 2 },
        { value: maxZ, autoRanges: true }
      ];
    }
    if (rangesOptions.length && rangesOptions[0].radius) {
      ranges.reverse();
    }
    ranges.forEach(function(range2, i) {
      if (rangesOptions && rangesOptions[i]) {
        ranges[i] = merge$O(rangesOptions[i], range2);
      }
    });
    return ranges;
  }
  /**
   * Calculate bubble legend sizes from rendered series.
   *
   * @private
   *
   * @return {Array<number,number>}
   *         Calculated min and max bubble sizes
   */
  predictBubbleSizes() {
    const chart = this.chart, legendOptions = chart.legend.options, floating = legendOptions.floating, horizontal = legendOptions.layout === "horizontal", lastLineHeight = horizontal ? chart.legend.lastLineHeight : 0, plotSizeX = chart.plotSizeX, plotSizeY = chart.plotSizeY, bubbleSeries = chart.series[this.options.seriesIndex], pxSizes = bubbleSeries.getPxExtremes(), minSize = Math.ceil(pxSizes.minPxSize), maxPxSize = Math.ceil(pxSizes.maxPxSize), plotSize = Math.min(plotSizeY, plotSizeX);
    let calculatedSize, maxSize = bubbleSeries.options.maxSize;
    if (floating || !/%$/.test(maxSize)) {
      calculatedSize = maxPxSize;
    } else {
      maxSize = parseFloat(maxSize);
      calculatedSize = (plotSize + lastLineHeight) * maxSize / 100 / (maxSize / 100 + 1);
      if (horizontal && plotSizeY - calculatedSize >= plotSizeX || !horizontal && plotSizeX - calculatedSize >= plotSizeY) {
        calculatedSize = maxPxSize;
      }
    }
    return [minSize, Math.ceil(calculatedSize)];
  }
  /**
   * Correct ranges with calculated sizes.
   * @private
   */
  updateRanges(min2, max2) {
    const bubbleLegendOptions = this.legend.options.bubbleLegend;
    bubbleLegendOptions.minSize = min2;
    bubbleLegendOptions.maxSize = max2;
    bubbleLegendOptions.ranges = this.getRanges();
  }
  /**
   * Because of the possibility of creating another legend line, predicted
   * bubble legend sizes may differ by a few pixels, so it is necessary to
   * correct them.
   * @private
   */
  correctSizes() {
    const legend = this.legend, chart = this.chart, bubbleSeries = chart.series[this.options.seriesIndex], pxSizes = bubbleSeries.getPxExtremes(), bubbleSeriesSize = pxSizes.maxPxSize, bubbleLegendSize = this.options.maxSize;
    if (Math.abs(Math.ceil(bubbleSeriesSize) - bubbleLegendSize) > 1) {
      this.updateRanges(this.options.minSize, pxSizes.maxPxSize);
      legend.render();
    }
  }
}
const { setOptions: setOptions$1 } = DefaultOptions;
const { composed: composed$h } = Highcharts;
const { addEvent: addEvent$F, objectEach: objectEach$9, pushUnique: pushUnique$h, wrap: wrap$c } = Utilities;
function chartDrawChartBox(proceed, options2, callback) {
  const chart = this, legend = chart.legend, bubbleSeries = getVisibleBubbleSeriesIndex(chart) >= 0;
  let bubbleLegendOptions, bubbleSizes, legendItem;
  if (legend && legend.options.enabled && legend.bubbleLegend && legend.options.bubbleLegend.autoRanges && bubbleSeries) {
    bubbleLegendOptions = legend.bubbleLegend.options;
    bubbleSizes = legend.bubbleLegend.predictBubbleSizes();
    legend.bubbleLegend.updateRanges(bubbleSizes[0], bubbleSizes[1]);
    if (!bubbleLegendOptions.placed) {
      legend.group.placed = false;
      legend.allItems.forEach((item) => {
        legendItem = item.legendItem || {};
        if (legendItem.group) {
          legendItem.group.translateY = void 0;
        }
      });
    }
    legend.render();
    if (!bubbleLegendOptions.placed) {
      chart.getMargins();
      chart.axes.forEach((axis) => {
        axis.setScale();
        axis.updateNames();
        objectEach$9(axis.ticks, function(tick) {
          tick.isNew = true;
          tick.isNewLabel = true;
        });
      });
      chart.getMargins();
    }
    bubbleLegendOptions.placed = true;
    proceed.call(chart, options2, callback);
    legend.bubbleLegend.correctSizes();
    retranslateItems(legend, getLinesHeights(legend));
  } else {
    proceed.call(chart, options2, callback);
    if (legend && legend.options.enabled && legend.bubbleLegend) {
      legend.render();
      retranslateItems(legend, getLinesHeights(legend));
    }
  }
}
function compose$f(ChartClass, LegendClass) {
  if (pushUnique$h(composed$h, "Series.BubbleLegend")) {
    setOptions$1({
      // Set default bubble legend options
      legend: {
        bubbleLegend: BubbleLegendDefaults
      }
    });
    wrap$c(ChartClass.prototype, "drawChartBox", chartDrawChartBox);
    addEvent$F(LegendClass, "afterGetAllItems", onLegendAfterGetAllItems);
    addEvent$F(LegendClass, "itemClick", onLegendItemClick);
  }
}
function getVisibleBubbleSeriesIndex(chart) {
  const series = chart.series;
  let i = 0;
  while (i < series.length) {
    if (series[i] && series[i].isBubble && series[i].visible && series[i].dataTable.rowCount) {
      return i;
    }
    i++;
  }
  return -1;
}
function getLinesHeights(legend) {
  const items = legend.allItems, lines = [], length = items.length;
  let lastLine, legendItem, legendItem2, i = 0, j = 0;
  for (i = 0; i < length; i++) {
    legendItem = items[i].legendItem || {};
    legendItem2 = (items[i + 1] || {}).legendItem || {};
    if (legendItem.labelHeight) {
      items[i].itemHeight = legendItem.labelHeight;
    }
    if (
      // Line break
      items[i] === items[length - 1] || legendItem.y !== legendItem2.y
    ) {
      lines.push({ height: 0 });
      lastLine = lines[lines.length - 1];
      for (j; j <= i; j++) {
        if (items[j].itemHeight > lastLine.height) {
          lastLine.height = items[j].itemHeight;
        }
      }
      lastLine.step = i;
    }
  }
  return lines;
}
function onLegendAfterGetAllItems(e) {
  const legend = this, bubbleLegend = legend.bubbleLegend, legendOptions = legend.options, options2 = legendOptions.bubbleLegend, bubbleSeriesIndex = getVisibleBubbleSeriesIndex(legend.chart);
  if (bubbleLegend && bubbleLegend.ranges && bubbleLegend.ranges.length) {
    if (options2.ranges.length) {
      options2.autoRanges = !!options2.ranges[0].autoRanges;
    }
    legend.destroyItem(bubbleLegend);
  }
  if (bubbleSeriesIndex >= 0 && legendOptions.enabled && options2.enabled) {
    options2.seriesIndex = bubbleSeriesIndex;
    legend.bubbleLegend = new BubbleLegendItem(options2, legend);
    legend.bubbleLegend.addToLegend(e.allItems);
  }
}
function onLegendItemClick(e) {
  if (e.defaultPrevented) {
    return false;
  }
  const legend = this, series = e.legendItem, chart = legend.chart, visible = series.visible;
  let status;
  if (legend && legend.bubbleLegend) {
    series.visible = !visible;
    series.ignoreSeries = visible;
    status = getVisibleBubbleSeriesIndex(chart) >= 0;
    if (legend.bubbleLegend.visible !== status) {
      legend.update({
        bubbleLegend: { enabled: status }
      });
      legend.bubbleLegend.visible = status;
    }
    series.visible = visible;
  }
}
function retranslateItems(legend, lines) {
  const items = legend.allItems, rtl = legend.options.rtl;
  let orgTranslateX, orgTranslateY, movementX, legendItem, actualLine = 0;
  items.forEach((item, index) => {
    legendItem = item.legendItem || {};
    if (!legendItem.group) {
      return;
    }
    orgTranslateX = legendItem.group.translateX || 0;
    orgTranslateY = legendItem.y || 0;
    movementX = item.movementX;
    if (movementX || rtl && item.ranges) {
      movementX = rtl ? orgTranslateX - item.options.maxSize / 2 : orgTranslateX + movementX;
      legendItem.group.attr({ translateX: movementX });
    }
    if (index > lines[actualLine].step) {
      actualLine++;
    }
    legendItem.group.attr({
      translateY: Math.round(orgTranslateY + lines[actualLine].height / 2)
    });
    legendItem.y = orgTranslateY + lines[actualLine].height / 2;
  });
}
const BubbleLegendComposition = {
  compose: compose$f
};
const { seriesTypes: { scatter: { prototype: { pointClass: ScatterPoint$3 } } } } = SeriesRegistry$1;
const { extend: extend$J } = Utilities;
let BubblePoint$1 = class BubblePoint2 extends ScatterPoint$3 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * @private
   */
  haloPath(size) {
    const computedSize = (size && this.marker ? this.marker.radius || 0 : 0) + size;
    if (this.series.chart.inverted) {
      const pos = this.pos() || [0, 0], { xAxis: xAxis2, yAxis: yAxis2, chart } = this.series;
      return chart.renderer.symbols.circle(xAxis2.len - pos[1] - computedSize, yAxis2.len - pos[0] - computedSize, computedSize * 2, computedSize * 2);
    }
    return Point$3.prototype.haloPath.call(
      this,
      // #6067
      computedSize
    );
  }
};
extend$J(BubblePoint$1.prototype, {
  ttBelow: false
});
const { composed: composed$g, noop: noop$a } = Highcharts;
const { series: Series$4, seriesTypes: { column: { prototype: columnProto$3 }, scatter: ScatterSeries$3 } } = SeriesRegistry$1;
const { addEvent: addEvent$E, arrayMax: arrayMax$3, arrayMin: arrayMin$2, clamp: clamp$c, extend: extend$I, isNumber: isNumber$u, merge: merge$N, pick: pick$O, pushUnique: pushUnique$g } = Utilities;
function onAxisFoundExtremes() {
  const axisLength = this.len, { coll, isXAxis, min: min2 } = this, range2 = (this.max || 0) - (min2 || 0);
  let pxMin = 0, pxMax = axisLength, transA = axisLength / range2, hasActiveSeries;
  if (coll !== "xAxis" && coll !== "yAxis") {
    return;
  }
  this.series.forEach((series) => {
    if (series.bubblePadding && series.reserveSpace()) {
      this.allowZoomOutside = true;
      hasActiveSeries = true;
      const data = series.getColumn(isXAxis ? "x" : "y");
      if (isXAxis) {
        (series.onPoint || series).getRadii(0, 0, series);
        if (series.onPoint) {
          series.radii = series.onPoint.radii;
        }
      }
      if (range2 > 0) {
        let i = data.length;
        while (i--) {
          if (isNumber$u(data[i]) && this.dataMin <= data[i] && data[i] <= this.max) {
            const radius = series.radii && series.radii[i] || 0;
            pxMin = Math.min((data[i] - min2) * transA - radius, pxMin);
            pxMax = Math.max((data[i] - min2) * transA + radius, pxMax);
          }
        }
      }
    }
  });
  if (hasActiveSeries && range2 > 0 && !this.logarithmic) {
    pxMax -= axisLength;
    transA *= (axisLength + Math.max(0, pxMin) - // #8901
    Math.min(pxMax, axisLength)) / axisLength;
    [
      ["min", "userMin", pxMin],
      ["max", "userMax", pxMax]
    ].forEach((keys) => {
      if (typeof pick$O(this.options[keys[0]], this[keys[1]]) === "undefined") {
        this[keys[0]] += keys[2] / transA;
      }
    });
  }
}
function onAxisAfterRender() {
  const { ticks, tickPositions, dataMin = 0, dataMax = 0, categories } = this, type = this.options.type;
  if ((categories?.length || type === "category") && this.series.find((s) => s.bubblePadding)) {
    let tickCount = tickPositions.length;
    while (tickCount--) {
      const tick = ticks[tickPositions[tickCount]], pos = tick.pos || 0;
      if (pos > dataMax || pos < dataMin) {
        tick.label?.hide();
      }
    }
  }
}
let BubbleSeries$1 = class BubbleSeries2 extends ScatterSeries$3 {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AxisClass, ChartClass, LegendClass) {
    BubbleLegendComposition.compose(ChartClass, LegendClass);
    if (pushUnique$g(composed$g, "Series.Bubble")) {
      addEvent$E(AxisClass, "foundExtremes", onAxisFoundExtremes);
      addEvent$E(AxisClass, "afterRender", onAxisAfterRender);
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Perform animation on the bubbles
   * @private
   */
  animate(init2) {
    if (!init2 && this.points.length < this.options.animationLimit) {
      this.points.forEach(function(point) {
        const { graphic, plotX = 0, plotY = 0 } = point;
        if (graphic && graphic.width) {
          if (!this.hasRendered) {
            graphic.attr({
              x: plotX,
              y: plotY,
              width: 1,
              height: 1
            });
          }
          graphic.animate(this.markerAttribs(point), this.options.animation);
        }
      }, this);
    }
  }
  /**
   * Get the radius for each point based on the minSize, maxSize and each
   * point's Z value. This must be done prior to Series.translate because
   * the axis needs to add padding in accordance with the point sizes.
   * @private
   */
  getRadii() {
    const zData = this.getColumn("z"), yData = this.getColumn("y"), radii = [];
    let len, i, value, zExtremes = this.chart.bubbleZExtremes;
    const { minPxSize, maxPxSize } = this.getPxExtremes();
    if (!zExtremes) {
      let zMin = Number.MAX_VALUE;
      let zMax = -Number.MAX_VALUE;
      let valid;
      this.chart.series.forEach((otherSeries) => {
        if (otherSeries.bubblePadding && otherSeries.reserveSpace()) {
          const zExtremes2 = (otherSeries.onPoint || otherSeries).getZExtremes();
          if (zExtremes2) {
            zMin = Math.min(pick$O(zMin, zExtremes2.zMin), zExtremes2.zMin);
            zMax = Math.max(pick$O(zMax, zExtremes2.zMax), zExtremes2.zMax);
            valid = true;
          }
        }
      });
      if (valid) {
        zExtremes = { zMin, zMax };
        this.chart.bubbleZExtremes = zExtremes;
      } else {
        zExtremes = { zMin: 0, zMax: 0 };
      }
    }
    for (i = 0, len = zData.length; i < len; i++) {
      value = zData[i];
      radii.push(this.getRadius(zExtremes.zMin, zExtremes.zMax, minPxSize, maxPxSize, value, yData && yData[i]));
    }
    this.radii = radii;
  }
  /**
   * Get the individual radius for one point.
   * @private
   */
  getRadius(zMin, zMax, minSize, maxSize, value, yValue) {
    const options2 = this.options, sizeByArea = options2.sizeBy !== "width", zThreshold = options2.zThreshold;
    let zRange = zMax - zMin, pos = 0.5;
    if (yValue === null || value === null) {
      return null;
    }
    if (isNumber$u(value)) {
      if (options2.sizeByAbsoluteValue) {
        value = Math.abs(value - zThreshold);
        zMax = zRange = Math.max(zMax - zThreshold, Math.abs(zMin - zThreshold));
        zMin = 0;
      }
      if (value < zMin) {
        return minSize / 2 - 1;
      }
      if (zRange > 0) {
        pos = (value - zMin) / zRange;
      }
    }
    if (sizeByArea && pos >= 0) {
      pos = Math.sqrt(pos);
    }
    return Math.ceil(minSize + pos * (maxSize - minSize)) / 2;
  }
  /**
   * Define hasData function for non-cartesian series.
   * Returns true if the series has points at all.
   * @private
   */
  hasData() {
    return !!this.dataTable.rowCount;
  }
  /**
   * @private
   */
  markerAttribs(point, state) {
    const attr2 = super.markerAttribs(point, state), { height = 0, width = 0 } = attr2;
    return this.chart.inverted ? extend$I(attr2, {
      x: (point.plotX || 0) - width / 2,
      y: (point.plotY || 0) - height / 2
    }) : attr2;
  }
  /**
   * @private
   */
  pointAttribs(point, state) {
    const markerOptions = this.options.marker, fillOpacity = markerOptions?.fillOpacity, attr2 = Series$4.prototype.pointAttribs.call(this, point, state);
    attr2["fill-opacity"] = fillOpacity ?? 1;
    return attr2;
  }
  /**
   * Extend the base translate method to handle bubble size
   * @private
   */
  translate() {
    super.translate.call(this);
    this.getRadii();
    this.translateBubble();
  }
  translateBubble() {
    const { data, options: options2, radii } = this, { minPxSize } = this.getPxExtremes();
    let i = data.length;
    while (i--) {
      const point = data[i], radius = radii ? radii[i] : 0;
      if (this.zoneAxis === "z") {
        point.negative = (point.z || 0) < (options2.zThreshold || 0);
      }
      if (isNumber$u(radius) && radius >= minPxSize / 2) {
        point.marker = extend$I(point.marker, {
          radius,
          width: 2 * radius,
          height: 2 * radius
        });
        point.dlBox = {
          x: point.plotX - radius,
          y: point.plotY - radius,
          width: 2 * radius,
          height: 2 * radius
        };
      } else {
        point.shapeArgs = point.plotY = point.dlBox = void 0;
        point.isInside = false;
      }
    }
  }
  getPxExtremes() {
    const smallestSize = Math.min(this.chart.plotWidth, this.chart.plotHeight);
    const getPxSize = (length) => {
      let isPercent;
      if (typeof length === "string") {
        isPercent = /%$/.test(length);
        length = parseInt(length, 10);
      }
      return isPercent ? smallestSize * length / 100 : length;
    };
    const minPxSize = getPxSize(pick$O(this.options.minSize, 8));
    const maxPxSize = Math.max(getPxSize(pick$O(this.options.maxSize, "20%")), minPxSize);
    return { minPxSize, maxPxSize };
  }
  getZExtremes() {
    const options2 = this.options, zData = this.getColumn("z").filter(isNumber$u);
    if (zData.length) {
      const zMin = pick$O(options2.zMin, clamp$c(arrayMin$2(zData), options2.displayNegative === false ? options2.zThreshold || 0 : -Number.MAX_VALUE, Number.MAX_VALUE));
      const zMax = pick$O(options2.zMax, arrayMax$3(zData));
      if (isNumber$u(zMin) && isNumber$u(zMax)) {
        return { zMin, zMax };
      }
    }
  }
  /**
   * @private
   * @function Highcharts.Series#searchKDTree
   */
  searchKDTree(point, compareX, e, suppliedPointEvaluator = noop$a, suppliedBSideCheckEvaluator = noop$a) {
    suppliedPointEvaluator = (p12, p22, comparisonProp) => {
      const p1Dist = p12[comparisonProp] || 0;
      const p2Dist = p22[comparisonProp] || 0;
      let ret, flip = false;
      if (p1Dist === p2Dist) {
        ret = p12.index > p22.index ? p12 : p22;
      } else if (p1Dist < 0 && p2Dist < 0) {
        ret = p1Dist - (p12.marker?.radius || 0) >= p2Dist - (p22.marker?.radius || 0) ? p12 : p22;
        flip = true;
      } else {
        ret = p1Dist < p2Dist ? p12 : p22;
      }
      return [ret, flip];
    };
    suppliedBSideCheckEvaluator = (a, b, flip) => !flip && a > b || a < b;
    return super.searchKDTree(point, compareX, e, suppliedPointEvaluator, suppliedBSideCheckEvaluator);
  }
};
BubbleSeries$1.defaultOptions = merge$N(ScatterSeries$3.defaultOptions, {
  dataLabels: {
    formatter: function() {
      const { numberFormatter } = this.series.chart;
      const { z } = this.point;
      return isNumber$u(z) ? numberFormatter(z, -1) : "";
    },
    inside: true,
    verticalAlign: "middle"
  },
  /**
   * If there are more points in the series than the `animationLimit`, the
   * animation won't run. Animation affects overall performance and
   * doesn't work well with heavy data series.
   *
   * @since 6.1.0
   */
  animationLimit: 250,
  /**
   * Whether to display negative sized bubbles. The threshold is given
   * by the [zThreshold](#plotOptions.bubble.zThreshold) option, and negative
   * bubbles can be visualized by setting
   * [negativeColor](#plotOptions.bubble.negativeColor).
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-negative/
   *         Negative bubbles
   *
   * @type      {boolean}
   * @default   true
   * @since     3.0
   * @apioption plotOptions.bubble.displayNegative
   */
  /**
   * @extends   plotOptions.series.marker
   * @excluding enabled, enabledThreshold, height, radius, width
   */
  marker: {
    lineColor: null,
    // Inherit from series.color
    lineWidth: 1,
    /**
     * The fill opacity of the bubble markers.
     */
    fillOpacity: 0.5,
    /**
     * In bubble charts, the radius is overridden and determined based
     * on the point's data value.
     *
     * @ignore-option
     */
    radius: null,
    states: {
      hover: {
        radiusPlus: 0
      }
    },
    /**
     * A predefined shape or symbol for the marker. Possible values are
     * "circle", "square", "diamond", "triangle" and "triangle-down".
     *
     * Additionally, the URL to a graphic can be given on the form
     * `url(graphic.png)`. Note that for the image to be applied to
     * exported charts, its URL needs to be accessible by the export
     * server.
     *
     * Custom callbacks for symbol path generation can also be added to
     * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
     * used by its method name, as shown in the demo.
     *
     * @sample {highcharts} highcharts/plotoptions/bubble-symbol/
     *         Bubble chart with various symbols
     * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
     *         General chart with predefined, graphic and custom markers
     *
     * @type  {Highcharts.SymbolKeyValue|string}
     * @since 5.0.11
     */
    symbol: "circle"
  },
  /**
   * Minimum bubble size. Bubbles will automatically size between the
   * `minSize` and `maxSize` to reflect the `z` value of each bubble.
   * Can be either pixels (when no unit is given), or a percentage of
   * the smallest one of the plot width and height.
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-size/
   *         Bubble size
   *
   * @type    {number|string}
   * @since   3.0
   * @product highcharts highstock
   */
  minSize: 8,
  /**
   * Maximum bubble size. Bubbles will automatically size between the
   * `minSize` and `maxSize` to reflect the `z` value of each bubble.
   * Can be either pixels (when no unit is given), or a percentage of
   * the smallest one of the plot width and height.
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-size/
   *         Bubble size
   *
   * @type    {number|string}
   * @since   3.0
   * @product highcharts highstock
   */
  maxSize: "20%",
  /**
   * When a point's Z value is below the
   * [zThreshold](#plotOptions.bubble.zThreshold)
   * setting, this color is used.
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-negative/
   *         Negative bubbles
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.bubble.negativeColor
   */
  /**
   * Whether the bubble's value should be represented by the area or the
   * width of the bubble. The default, `area`, corresponds best to the
   * human perception of the size of each bubble.
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-sizeby/
   *         Comparison of area and size
   *
   * @type       {Highcharts.BubbleSizeByValue}
   * @default    area
   * @since      3.0.7
   * @apioption  plotOptions.bubble.sizeBy
   */
  /**
   * When this is true, the absolute value of z determines the size of
   * the bubble. This means that with the default `zThreshold` of 0, a
   * bubble of value -1 will have the same size as a bubble of value 1,
   * while a bubble of value 0 will have a smaller size according to
   * `minSize`.
   *
   * @sample    {highcharts} highcharts/plotoptions/bubble-sizebyabsolutevalue/
   *            Size by absolute value, various thresholds
   *
   * @type      {boolean}
   * @default   false
   * @since     4.1.9
   * @product   highcharts
   * @apioption plotOptions.bubble.sizeByAbsoluteValue
   */
  /**
   * When this is true, the series will not cause the Y axis to cross
   * the zero plane (or [threshold](#plotOptions.series.threshold) option)
   * unless the data actually crosses the plane.
   *
   * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
   * 3 will make the Y axis show negative values according to the
   * `minPadding` option. If `softThreshold` is `true`, the Y axis starts
   * at 0.
   *
   * @since   4.1.9
   * @product highcharts
   */
  softThreshold: false,
  states: {
    hover: {
      halo: {
        size: 5
      }
    }
  },
  tooltip: {
    pointFormat: "({point.x}, {point.y}), Size: {point.z}"
  },
  turboThreshold: 0,
  /**
   * The minimum for the Z value range. Defaults to the highest Z value
   * in the data.
   *
   * @see [zMin](#plotOptions.bubble.zMin)
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-zmin-zmax/
   *         Z has a possible range of 0-100
   *
   * @type      {number}
   * @since     4.0.3
   * @product   highcharts
   * @apioption plotOptions.bubble.zMax
   */
  /**
   * @default   z
   * @apioption plotOptions.bubble.colorKey
   */
  /**
   * The minimum for the Z value range. Defaults to the lowest Z value
   * in the data.
   *
   * @see [zMax](#plotOptions.bubble.zMax)
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-zmin-zmax/
   *         Z has a possible range of 0-100
   *
   * @type      {number}
   * @since     4.0.3
   * @product   highcharts
   * @apioption plotOptions.bubble.zMin
   */
  /**
   * When [displayNegative](#plotOptions.bubble.displayNegative) is `false`,
   * bubbles with lower Z values are skipped. When `displayNegative`
   * is `true` and a [negativeColor](#plotOptions.bubble.negativeColor)
   * is given, points with lower Z is colored.
   *
   * @sample {highcharts} highcharts/plotoptions/bubble-negative/
   *         Negative bubbles
   *
   * @since   3.0
   * @product highcharts
   */
  zThreshold: 0,
  zoneAxis: "z"
});
extend$I(BubbleSeries$1.prototype, {
  alignDataLabel: columnProto$3.alignDataLabel,
  applyZones: noop$a,
  bubblePadding: true,
  isBubble: true,
  keysAffectYAxis: ["y"],
  pointArrayMap: ["y", "z"],
  pointClass: BubblePoint$1,
  parallelArrays: ["x", "y", "z"],
  trackerGroups: ["group", "dataLabelsGroup"],
  specialGroup: "group",
  // To allow clipping (#6296)
  zoneAxis: "z"
});
addEvent$E(BubbleSeries$1, "updatedData", (e) => {
  delete e.target.chart.bubbleZExtremes;
});
addEvent$E(BubbleSeries$1, "remove", (e) => {
  delete e.target.chart.bubbleZExtremes;
});
SeriesRegistry$1.registerSeriesType("bubble", BubbleSeries$1);
const { seriesTypes: { column: { prototype: { pointClass: { prototype: columnProto$2 } } }, arearange: { prototype: { pointClass: AreaRangePoint } } } } = SeriesRegistry$1;
const { extend: extend$H, isNumber: isNumber$t } = Utilities;
class ColumnRangePoint extends AreaRangePoint {
  /* *
   *
   *  Functions
   *
   * */
  isValid() {
    return isNumber$t(this.low);
  }
}
extend$H(ColumnRangePoint.prototype, {
  setState: columnProto$2.setState
});
const { noop: noop$9 } = Highcharts;
const { seriesTypes: { arearange: AreaRangeSeries$1, column: ColumnSeries$a, column: { prototype: columnProto$1 } } } = SeriesRegistry$1;
const { addEvent: addEvent$D, clamp: clamp$b, extend: extend$G, isNumber: isNumber$s, merge: merge$M, pick: pick$N } = Utilities;
const columnRangeOptions = {
  borderRadius: {
    where: "all"
  },
  /**
   * Extended data labels for range series types. Range series data labels
   * have no `x` and `y` options. Instead, they have `xLow`, `xHigh`,
   * `yLow` and `yHigh` options to allow the higher and lower data label
   * sets individually.
   *
   * @declare   Highcharts.SeriesAreaRangeDataLabelsOptionsObject
   * @extends   plotOptions.arearange.dataLabels
   * @since     2.3.0
   * @product   highcharts highstock
   * @apioption plotOptions.columnrange.dataLabels
   */
  pointRange: null,
  legendSymbol: "rectangle",
  /** @ignore-option */
  marker: null,
  states: {
    hover: {
      /** @ignore-option */
      halo: false
    }
  }
};
class ColumnRangeSeries extends AreaRangeSeries$1 {
  /* *
   *
   *  Functions
   *
   * */
  setOptions() {
    merge$M(true, arguments[0], { stacking: void 0 });
    return AreaRangeSeries$1.prototype.setOptions.apply(this, arguments);
  }
  // Overrides from modules that may be loaded after this module
  // @todo move to compositions
  translate() {
    return columnProto$1.translate.apply(this);
  }
  // Public crispCol(): BBoxObject {
  //     return columnProto.crispCol.apply(this, arguments as any);
  // }
  // public drawPoints(): void {
  //     return columnProto.drawPoints.apply(this, arguments as any);
  // }
  // public drawTracker(): void {
  //     return columnProto.drawTracker.apply(this, arguments as any);
  // }
  // public getColumnMetrics(): ColumnMetricsObject {
  //     return columnProto.getColumnMetrics.apply(this, arguments as any);
  // }
  pointAttribs() {
    return columnProto$1.pointAttribs.apply(this, arguments);
  }
  // Public adjustForMissingColumns(): number {
  //     return columnProto.adjustForMissingColumns.apply(this, arguments);
  // }
  // public animate(): void {
  //     return columnProto.animate.apply(this, arguments as any);
  // }
  translate3dPoints() {
    return columnProto$1.translate3dPoints.apply(this, arguments);
  }
  translate3dShapes() {
    return columnProto$1.translate3dShapes.apply(this, arguments);
  }
  afterColumnTranslate() {
    const yAxis2 = this.yAxis, xAxis2 = this.xAxis, startAngleRad = xAxis2.startAngleRad, chart = this.chart, isRadial = this.xAxis.isRadial, safeDistance = Math.max(chart.chartWidth, chart.chartHeight) + 999;
    let height, heightDifference, start2, y;
    function safeBounds(pixelPos) {
      return clamp$b(pixelPos, -safeDistance, safeDistance);
    }
    this.points.forEach((point) => {
      const shapeArgs = point.shapeArgs || {}, minPointLength = this.options.minPointLength, plotY = point.plotY, plotHigh = yAxis2.translate(point.high, 0, 1, 0, 1);
      if (isNumber$s(plotHigh) && isNumber$s(plotY)) {
        point.plotHigh = safeBounds(plotHigh);
        point.plotLow = safeBounds(plotY);
        y = point.plotHigh;
        height = pick$N(point.rectPlotY, point.plotY) - point.plotHigh;
        if (Math.abs(height) < minPointLength) {
          heightDifference = minPointLength - height;
          height += heightDifference;
          y -= heightDifference / 2;
        } else if (height < 0) {
          height *= -1;
          y -= height;
        }
        if (isRadial && this.polar) {
          start2 = point.barX + startAngleRad;
          point.shapeType = "arc";
          point.shapeArgs = this.polar.arc(y + height, y, start2, start2 + point.pointWidth);
        } else {
          shapeArgs.height = height;
          shapeArgs.y = y;
          const { x = 0, width = 0 } = shapeArgs;
          point.shapeArgs = merge$M(point.shapeArgs, this.crispCol(x, y, width, height));
          point.tooltipPos = chart.inverted ? [
            yAxis2.len + yAxis2.pos - chart.plotLeft - y - height / 2,
            xAxis2.len + xAxis2.pos - chart.plotTop - x - width / 2,
            height
          ] : [
            xAxis2.left - chart.plotLeft + x + width / 2,
            yAxis2.pos - chart.plotTop + y + height / 2,
            height
          ];
        }
      }
    });
  }
}
ColumnRangeSeries.defaultOptions = merge$M(ColumnSeries$a.defaultOptions, AreaRangeSeries$1.defaultOptions, columnRangeOptions);
addEvent$D(ColumnRangeSeries, "afterColumnTranslate", function() {
  ColumnRangeSeries.prototype.afterColumnTranslate.apply(this);
}, { order: 5 });
extend$G(ColumnRangeSeries.prototype, {
  directTouch: true,
  pointClass: ColumnRangePoint,
  trackerGroups: ["group", "dataLabelsGroup"],
  adjustForMissingColumns: columnProto$1.adjustForMissingColumns,
  animate: columnProto$1.animate,
  crispCol: columnProto$1.crispCol,
  drawGraph: noop$9,
  drawPoints: columnProto$1.drawPoints,
  getSymbol: noop$9,
  drawTracker: columnProto$1.drawTracker,
  getColumnMetrics: columnProto$1.getColumnMetrics
});
SeriesRegistry$1.registerSeriesType("columnrange", ColumnRangeSeries);
const ColumnPyramidSeriesDefaults = {};
const { column: ColumnSeries$9 } = SeriesRegistry$1.seriesTypes;
const { clamp: clamp$a, merge: merge$L, pick: pick$M } = Utilities;
class ColumnPyramidSeries extends ColumnSeries$9 {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Overrides the column translate method
   * @private
   */
  translate() {
    const series = this, chart = series.chart, options2 = series.options, dense = series.dense = series.closestPointRange * series.xAxis.transA < 2, borderWidth = series.borderWidth = pick$M(
      options2.borderWidth,
      dense ? 0 : 1
      // #3635
    ), yAxis2 = series.yAxis, threshold = options2.threshold, minPointLength = pick$M(options2.minPointLength, 5), metrics = series.getColumnMetrics(), pointWidth = metrics.width, pointXOffset = series.pointXOffset = metrics.offset;
    let translatedThreshold = series.translatedThreshold = yAxis2.getThreshold(threshold), seriesBarW = series.barW = Math.max(pointWidth, 1 + 2 * borderWidth);
    if (chart.inverted) {
      translatedThreshold -= 0.5;
    }
    if (options2.pointPadding) {
      seriesBarW = Math.ceil(seriesBarW);
    }
    super.translate();
    for (const point of series.points) {
      const yBottom = pick$M(point.yBottom, translatedThreshold), safeDistance = 999 + Math.abs(yBottom), plotY = clamp$a(point.plotY, -safeDistance, yAxis2.len + safeDistance), barW = seriesBarW / 2, barY = Math.min(plotY, yBottom), barH = Math.max(plotY, yBottom) - barY;
      let barX = point.plotX + pointXOffset, stackTotal, stackHeight, topXwidth, bottomXwidth, invBarPos, x1, x2, x3, x4, y1, y2;
      if (options2.centerInCategory) {
        barX = series.adjustForMissingColumns(barX, pointWidth, point, metrics);
      }
      point.barX = barX;
      point.pointWidth = pointWidth;
      point.tooltipPos = chart.inverted ? [
        yAxis2.len + yAxis2.pos - chart.plotLeft - plotY,
        series.xAxis.len - barX - barW,
        barH
      ] : [
        barX + barW,
        plotY + yAxis2.pos - chart.plotTop,
        barH
      ];
      stackTotal = threshold + (point.total || point.y);
      if (options2.stacking === "percent") {
        stackTotal = threshold + (point.y < 0) ? -100 : 100;
      }
      const topPointY = yAxis2.toPixels(stackTotal, true);
      stackHeight = chart.plotHeight - topPointY - (chart.plotHeight - translatedThreshold);
      topXwidth = stackHeight ? barW * (barY - topPointY) / stackHeight : 0;
      bottomXwidth = stackHeight ? barW * (barY + barH - topPointY) / stackHeight : 0;
      x1 = barX - topXwidth + barW;
      x2 = barX + topXwidth + barW;
      x3 = barX + bottomXwidth + barW;
      x4 = barX - bottomXwidth + barW;
      y1 = barY - minPointLength;
      y2 = barY + barH;
      if (point.y < 0) {
        y1 = barY;
        y2 = barY + barH + minPointLength;
      }
      if (chart.inverted) {
        invBarPos = yAxis2.width - barY;
        stackHeight = topPointY - (yAxis2.width - translatedThreshold);
        topXwidth = barW * (topPointY - invBarPos) / stackHeight;
        bottomXwidth = barW * (topPointY - (invBarPos - barH)) / stackHeight;
        x1 = barX + barW + topXwidth;
        x2 = x1 - 2 * topXwidth;
        x3 = barX - bottomXwidth + barW;
        x4 = barX + bottomXwidth + barW;
        y1 = barY;
        y2 = barY + barH - minPointLength;
        if (point.y < 0) {
          y2 = barY + barH + minPointLength;
        }
      }
      point.shapeType = "path";
      point.shapeArgs = {
        x: x1,
        y: y1,
        width: x2 - x1,
        height: barH,
        // Path of pyramid
        d: [
          ["M", x1, y1],
          ["L", x2, y1],
          ["L", x3, y2],
          ["L", x4, y2],
          ["Z"]
        ]
      };
    }
  }
}
ColumnPyramidSeries.defaultOptions = merge$L(ColumnSeries$9.defaultOptions, ColumnPyramidSeriesDefaults);
SeriesRegistry$1.registerSeriesType("columnpyramid", ColumnPyramidSeries);
const ErrorBarSeriesDefaults = {
  /**
   * The main color of the bars. This can be overridden by
   * [stemColor](#plotOptions.errorbar.stemColor) and
   * [whiskerColor](#plotOptions.errorbar.whiskerColor) individually.
   *
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @default #000000
   * @since   3.0
   * @product highcharts
   */
  color: "#000000",
  grouping: false,
  /**
   * The parent series of the error bar. The default value links it to
   * the previous series. Otherwise, use the id of the parent series.
   *
   * @since   3.0
   * @product highcharts
   */
  linkedTo: ":previous",
  tooltip: {
    pointFormat: '<span style="color:{point.color}">●</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
  },
  /**
   * The line width of the whiskers, the horizontal lines marking
   * low and high values. When `null`, the general
   * [lineWidth](#plotOptions.errorbar.lineWidth) applies.
   *
   * @sample {highcharts} highcharts/plotoptions/error-bar-styling/
   *         Error bar styling
   *
   * @type    {number}
   * @since   3.0
   * @product highcharts
   */
  whiskerWidth: null
};
const { arearange: AreaRangeSeries } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$C, merge: merge$K, extend: extend$F } = Utilities;
class ErrorBarSeries extends BoxPlotSeries {
  /* *
   *
   *  Functions
   *
   * */
  getColumnMetrics() {
    const series = this;
    return series.linkedParent && series.linkedParent.columnMetrics || ColumnSeries$f.prototype.getColumnMetrics.call(series);
  }
  drawDataLabels() {
    const series = this, valKey = series.pointValKey;
    if (AreaRangeSeries) {
      AreaRangeSeries.prototype.drawDataLabels.call(series);
      for (const point of series.points) {
        point.y = point[valKey];
      }
    }
  }
  toYData(point) {
    return [point.low, point.high];
  }
}
ErrorBarSeries.defaultOptions = merge$K(BoxPlotSeries.defaultOptions, ErrorBarSeriesDefaults);
addEvent$C(ErrorBarSeries, "afterTranslate", function() {
  for (const point of this.points) {
    point.plotLow = point.plotY;
  }
}, { order: 0 });
extend$F(ErrorBarSeries.prototype, {
  pointArrayMap: ["low", "high"],
  // Array point configs are mapped to this
  pointValKey: "high",
  // Defines the top of the tracker
  doQuartiles: false
});
SeriesRegistry$1.registerSeriesType("errorbar", ErrorBarSeries);
const { series: { prototype: { pointClass: Point$2 } } } = SeriesRegistry$1;
class GaugePoint extends Point$2 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Don't do any hover colors or anything
   * @private
   */
  setState(state) {
    this.state = state;
  }
}
const { noop: noop$8 } = Highcharts;
const { series: Series$3, seriesTypes: { column: ColumnSeries$8 } } = SeriesRegistry$1;
const { clamp: clamp$9, isNumber: isNumber$r, extend: extend$E, merge: merge$J, pick: pick$L, pInt: pInt$1, defined: defined$t } = Utilities;
let GaugeSeries$1 = class GaugeSeries2 extends Series$3 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Calculate paths etc
   * @private
   */
  translate() {
    const series = this, yAxis2 = series.yAxis, options2 = series.options, center = yAxis2.center;
    series.generatePoints();
    series.points.forEach((point) => {
      const dialOptions = merge$J(options2.dial, point.dial), radius = pInt$1(dialOptions.radius) * center[2] / 200, baseLength = pInt$1(dialOptions.baseLength) * radius / 100, rearLength = pInt$1(dialOptions.rearLength) * radius / 100, baseWidth = dialOptions.baseWidth, topWidth = dialOptions.topWidth;
      let overshoot = options2.overshoot, rotation = yAxis2.startAngleRad + yAxis2.translate(point.y, void 0, void 0, void 0, true);
      if (isNumber$r(overshoot) || options2.wrap === false) {
        overshoot = isNumber$r(overshoot) ? overshoot / 180 * Math.PI : 0;
        rotation = clamp$9(rotation, yAxis2.startAngleRad - overshoot, yAxis2.endAngleRad + overshoot);
      }
      rotation = rotation * 180 / Math.PI;
      point.shapeType = "path";
      const d = dialOptions.path || [
        ["M", -rearLength, -baseWidth / 2],
        ["L", baseLength, -baseWidth / 2],
        ["L", radius, -topWidth / 2],
        ["L", radius, topWidth / 2],
        ["L", baseLength, baseWidth / 2],
        ["L", -rearLength, baseWidth / 2],
        ["Z"]
      ];
      point.shapeArgs = {
        d,
        translateX: center[0],
        translateY: center[1],
        rotation
      };
      point.plotX = center[0];
      point.plotY = center[1];
      if (defined$t(point.y) && yAxis2.max - yAxis2.min) {
        point.percentage = (point.y - yAxis2.min) / (yAxis2.max - yAxis2.min) * 100;
      }
    });
  }
  /**
   * Draw the points where each point is one needle
   * @private
   */
  drawPoints() {
    const series = this, chart = series.chart, center = series.yAxis.center, pivot = series.pivot, options2 = series.options, pivotOptions = options2.pivot, renderer = chart.renderer;
    series.points.forEach((point) => {
      const graphic = point.graphic, shapeArgs = point.shapeArgs, d = shapeArgs.d, dialOptions = merge$J(options2.dial, point.dial);
      if (graphic) {
        graphic.animate(shapeArgs);
        shapeArgs.d = d;
      } else {
        point.graphic = renderer[point.shapeType](shapeArgs).addClass("highcharts-dial").add(series.group);
      }
      if (!chart.styledMode) {
        point.graphic[graphic ? "animate" : "attr"]({
          stroke: dialOptions.borderColor,
          "stroke-width": dialOptions.borderWidth,
          fill: dialOptions.backgroundColor
        });
      }
    });
    if (pivot) {
      pivot.animate({
        translateX: center[0],
        translateY: center[1]
      });
    } else if (pivotOptions) {
      series.pivot = renderer.circle(0, 0, pivotOptions.radius).attr({
        zIndex: 2
      }).addClass("highcharts-pivot").translate(center[0], center[1]).add(series.group);
      if (!chart.styledMode) {
        series.pivot.attr({
          fill: pivotOptions.backgroundColor,
          stroke: pivotOptions.borderColor,
          "stroke-width": pivotOptions.borderWidth
        });
      }
    }
  }
  /**
   * Animate the arrow up from startAngle
   * @private
   */
  animate(init2) {
    const series = this;
    if (!init2) {
      series.points.forEach((point) => {
        const graphic = point.graphic;
        if (graphic) {
          graphic.attr({
            rotation: series.yAxis.startAngleRad * 180 / Math.PI
          });
          graphic.animate({
            rotation: point.shapeArgs.rotation
          }, series.options.animation);
        }
      });
    }
  }
  /**
   * @private
   */
  render() {
    this.group = this.plotGroup("group", "series", this.visible ? "inherit" : "hidden", this.options.zIndex, this.chart.seriesGroup);
    Series$3.prototype.render.call(this);
    this.group.clip(this.chart.clipRect);
  }
  /**
   * Extend the basic setData method by running processData and generatePoints
   * immediately, in order to access the points from the legend.
   * @private
   */
  setData(data, redraw) {
    Series$3.prototype.setData.call(this, data, false);
    this.processData();
    this.generatePoints();
    if (pick$L(redraw, true)) {
      this.chart.redraw();
    }
  }
  /**
   * Define hasData function for non-cartesian series.
   * Returns true if the series has points at all.
   * @private
   */
  hasData() {
    return !!this.points.length;
  }
};
GaugeSeries$1.defaultOptions = merge$J(Series$3.defaultOptions, {
  /**
   * When this option is `true`, the dial will wrap around the axes.
   * For instance, in a full-range gauge going from 0 to 360, a value
   * of 400 will point to 40\. When `wrap` is `false`, the dial stops
   * at 360.
   *
   * @see [overshoot](#plotOptions.gauge.overshoot)
   *
   * @type      {boolean}
   * @default   true
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.gauge.wrap
   */
  /**
   * Data labels for the gauge. For gauges, the data labels are
   * enabled by default and shown in a bordered box below the point.
   *
   * @since   2.3.0
   * @product highcharts
   */
  dataLabels: {
    borderColor: "#cccccc",
    borderRadius: 3,
    borderWidth: 1,
    crop: false,
    defer: false,
    enabled: true,
    verticalAlign: "top",
    y: 15,
    zIndex: 2
  },
  /**
   * Options for the dial or arrow pointer of the gauge.
   *
   * In styled mode, the dial is styled with the
   * `.highcharts-gauge-series .highcharts-dial` rule.
   *
   * @sample {highcharts} highcharts/css/gauge/
   *         Styled mode
   *
   * @type    {*}
   * @since   2.3.0
   * @product highcharts
   */
  dial: {
    /**
     * The background or fill color of the gauge's dial.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @default   #000000
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.backgroundColor
     */
    backgroundColor: "#000000",
    /**
     * The length of the dial's base part, relative to the total
     * radius or length of the dial.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {string}
     * @default   70%
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.baseLength
     */
    baseLength: "70%",
    /**
     * The pixel width of the base of the gauge dial. The base is
     * the part closest to the pivot, defined by baseLength.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {number}
     * @default   3
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.baseWidth
     */
    baseWidth: 3,
    /**
     * The border color or stroke of the gauge's dial. By default,
     * the borderWidth is 0, so this must be set in addition to a
     * custom border color.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @default   #cccccc
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.borderColor
     */
    borderColor: "#cccccc",
    /**
     * The width of the gauge dial border in pixels.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {number}
     * @default   0
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.borderWidth
     */
    borderWidth: 0,
    /**
     * An array with an SVG path for the custom dial.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-path/
     *         Dial options demonstrated
     *
     * @type      {Highcharts.SVGPathArray}
     * @since 10.2.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.path
     */
    /**
     * The radius or length of the dial, in percentages relative to
     * the radius of the gauge itself.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {string}
     * @default   80%
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.radius
     */
    radius: "80%",
    /**
     * The length of the dial's rear end, the part that extends out
     * on the other side of the pivot. Relative to the dial's
     * length.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {string}
     * @default   10%
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.rearLength
     */
    rearLength: "10%",
    /**
     * The width of the top of the dial, closest to the perimeter.
     * The pivot narrows in from the base to the top.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-dial/
     *         Dial options demonstrated
     *
     * @type      {number}
     * @default   1
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.dial.topWidth
     */
    topWidth: 1
  },
  /**
   * Allow the dial to overshoot the end of the perimeter axis by
   * this many degrees. Say if the gauge axis goes from 0 to 60, a
   * value of 100, or 1000, will show 5 degrees beyond the end of the
   * axis when this option is set to 5.
   *
   * @see [wrap](#plotOptions.gauge.wrap)
   *
   * @sample {highcharts} highcharts/plotoptions/gauge-overshoot/
   *         Allow 5 degrees overshoot
   *
   * @type      {number}
   * @since     3.0.10
   * @product   highcharts
   * @apioption plotOptions.gauge.overshoot
   */
  /**
   * Options for the pivot or the center point of the gauge.
   *
   * In styled mode, the pivot is styled with the
   * `.highcharts-gauge-series .highcharts-pivot` rule.
   *
   * @sample {highcharts} highcharts/css/gauge/
   *         Styled mode
   *
   * @type    {*}
   * @since   2.3.0
   * @product highcharts
   */
  pivot: {
    /**
     * The pixel radius of the pivot.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
     *         Pivot options demonstrated
     *
     * @type      {number}
     * @default   5
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.pivot.radius
     */
    radius: 5,
    /**
     * The border or stroke width of the pivot.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
     *         Pivot options demonstrated
     *
     * @type      {number}
     * @default   0
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.pivot.borderWidth
     */
    borderWidth: 0,
    /**
     * The border or stroke color of the pivot. In able to change
     * this, the borderWidth must also be set to something other
     * than the default 0.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
     *         Pivot options demonstrated
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @default   #cccccc
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.pivot.borderColor
     */
    borderColor: "#cccccc",
    /**
     * The background color or fill of the pivot.
     *
     * @sample {highcharts} highcharts/plotoptions/gauge-pivot/
     *         Pivot options demonstrated
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @default   #000000
     * @since     2.3.0
     * @product   highcharts
     * @apioption plotOptions.gauge.pivot.backgroundColor
     */
    backgroundColor: "#000000"
    /* Palette.neutralColor100 */
  },
  tooltip: {
    headerFormat: ""
  },
  /**
   * Whether to display this particular series or series type in the
   * legend. Defaults to false for gauge series.
   *
   * @since   2.3.0
   * @product highcharts
   */
  showInLegend: false
  // Prototype members
});
extend$E(GaugeSeries$1.prototype, {
  // `chart.angular` will be set to true when a gauge series is present, and
  // this will be used on the axes
  angular: true,
  directTouch: true,
  // #5063
  drawGraph: noop$8,
  drawTracker: ColumnSeries$8.prototype.drawTracker,
  fixedBox: true,
  forceDL: true,
  noSharedTooltip: true,
  pointClass: GaugePoint,
  trackerGroups: ["group", "dataLabelsGroup"]
});
SeriesRegistry$1.registerSeriesType("gauge", GaugeSeries$1);
const { composed: composed$f } = Highcharts;
const { addEvent: addEvent$B, pushUnique: pushUnique$f } = Utilities;
function compose$e(ChartClass) {
  if (pushUnique$f(composed$f, "DragNodes")) {
    addEvent$B(ChartClass, "load", onChartLoad);
  }
}
function onChartLoad() {
  const chart = this;
  let mousedownUnbinder, mousemoveUnbinder, mouseupUnbinder, point;
  if (chart.container) {
    mousedownUnbinder = addEvent$B(chart.container, "mousedown", (event) => {
      if (mousemoveUnbinder) {
        mousemoveUnbinder();
      }
      if (mouseupUnbinder) {
        mouseupUnbinder();
      }
      point = chart.hoverPoint;
      if (point && point.series && point.series.hasDraggableNodes && point.series.options.draggable) {
        point.series.onMouseDown(point, event);
        mousemoveUnbinder = addEvent$B(chart.container, "mousemove", (e) => point && point.series && point.series.onMouseMove(point, e));
        mouseupUnbinder = addEvent$B(chart.container.ownerDocument, "mouseup", (e) => {
          mousemoveUnbinder();
          mouseupUnbinder();
          return point && point.series && point.series.onMouseUp(point, e);
        });
      }
    });
  }
  addEvent$B(chart, "destroy", function() {
    mousedownUnbinder();
  });
}
function onMouseDown(point, event) {
  const normalizedEvent = this.chart.pointer?.normalize(event) || event;
  point.fixedPosition = {
    chartX: normalizedEvent.chartX,
    chartY: normalizedEvent.chartY,
    plotX: point.plotX,
    plotY: point.plotY
  };
  point.inDragMode = true;
}
function onMouseMove(point, event) {
  if (point.fixedPosition && point.inDragMode) {
    const series = this, chart = series.chart, normalizedEvent = chart.pointer?.normalize(event) || event, diffX = point.fixedPosition.chartX - normalizedEvent.chartX, diffY = point.fixedPosition.chartY - normalizedEvent.chartY, graphLayoutsLookup = chart.graphLayoutsLookup;
    let newPlotX, newPlotY;
    if (Math.abs(diffX) > 5 || Math.abs(diffY) > 5) {
      newPlotX = point.fixedPosition.plotX - diffX;
      newPlotY = point.fixedPosition.plotY - diffY;
      if (chart.isInsidePlot(newPlotX, newPlotY)) {
        point.plotX = newPlotX;
        point.plotY = newPlotY;
        point.hasDragged = true;
        this.redrawHalo(point);
        graphLayoutsLookup.forEach((layout) => {
          layout.restartSimulation();
        });
      }
    }
  }
}
function onMouseUp(point) {
  if (point.fixedPosition) {
    if (point.hasDragged) {
      if (this.layout.enableSimulation) {
        this.layout.start();
      } else {
        this.chart.redraw();
      }
    }
    point.inDragMode = point.hasDragged = false;
    if (!this.options.fixedDraggable) {
      delete point.fixedPosition;
    }
  }
}
function redrawHalo(point) {
  if (point && this.halo) {
    this.halo.attr({
      d: point.haloPath(this.options.states.hover.halo.size)
    });
  }
}
const DragNodesComposition = {
  compose: compose$e,
  onMouseDown,
  onMouseMove,
  onMouseUp,
  redrawHalo
};
const { setAnimation } = animationExports;
const { composed: composed$e } = Highcharts;
const { addEvent: addEvent$A, pushUnique: pushUnique$e } = Utilities;
const integrations = {};
const layouts = {};
function compose$d(ChartClass) {
  if (pushUnique$e(composed$e, "GraphLayout")) {
    addEvent$A(ChartClass, "afterPrint", onChartAfterPrint);
    addEvent$A(ChartClass, "beforePrint", onChartBeforePrint);
    addEvent$A(ChartClass, "predraw", onChartPredraw);
    addEvent$A(ChartClass, "render", onChartRender$2);
  }
}
function onChartAfterPrint() {
  if (this.graphLayoutsLookup) {
    this.graphLayoutsLookup.forEach((layout) => {
      layout.updateSimulation();
    });
    this.redraw();
  }
}
function onChartBeforePrint() {
  if (this.graphLayoutsLookup) {
    this.graphLayoutsLookup.forEach((layout) => {
      layout.updateSimulation(false);
    });
    this.redraw();
  }
}
function onChartPredraw() {
  if (this.graphLayoutsLookup) {
    this.graphLayoutsLookup.forEach((layout) => {
      layout.stop();
    });
  }
}
function onChartRender$2() {
  let systemsStable, afterRender = false;
  const layoutStep = (layout) => {
    if (layout.maxIterations-- && isFinite(layout.temperature) && !layout.isStable() && !layout.enableSimulation) {
      if (layout.beforeStep) {
        layout.beforeStep();
      }
      layout.step();
      systemsStable = false;
      afterRender = true;
    }
  };
  if (this.graphLayoutsLookup) {
    setAnimation(false, this);
    this.graphLayoutsLookup.forEach((layout) => layout.start());
    while (!systemsStable) {
      systemsStable = true;
      this.graphLayoutsLookup.forEach(layoutStep);
    }
    if (afterRender) {
      this.series.forEach((series) => {
        if (series && series.layout) {
          series.render();
        }
      });
    }
  }
}
const GraphLayoutComposition = {
  compose: compose$d,
  integrations,
  layouts
};
const { seriesTypes: { bubble: { prototype: { pointClass: BubblePoint } } } } = SeriesRegistry$1;
class PackedBubblePoint extends BubblePoint {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Destroy point.
   * Then remove point from the layout.
   * @private
   */
  destroy() {
    if (this.series?.layout) {
      this.series.layout.removeElementFromCollection(this, this.series.layout.nodes);
    }
    return Point$3.prototype.destroy.apply(this, arguments);
  }
  firePointEvent() {
    const series = this.series, seriesOptions = series.options;
    if (this.isParentNode && seriesOptions.parentNode) {
      const temp = seriesOptions.allowPointSelect;
      seriesOptions.allowPointSelect = seriesOptions.parentNode.allowPointSelect;
      Point$3.prototype.firePointEvent.apply(this, arguments);
      seriesOptions.allowPointSelect = temp;
    } else {
      Point$3.prototype.firePointEvent.apply(this, arguments);
    }
  }
  select() {
    const point = this, series = this.series, chart = series.chart;
    if (point.isParentNode) {
      chart.getSelectedPoints = chart.getSelectedParentNodes;
      Point$3.prototype.select.apply(this, arguments);
      chart.getSelectedPoints = Chart$1.prototype.getSelectedPoints;
    } else {
      Point$3.prototype.select.apply(this, arguments);
    }
  }
}
const { isNumber: isNumber$q } = Utilities;
const PackedBubbleSeriesDefaults = {
  /**
   * Minimum bubble size. Bubbles will automatically size between the
   * `minSize` and `maxSize` to reflect the value of each bubble.
   * Can be either pixels (when no unit is given), or a percentage of
   * the smallest one of the plot width and height, divided by the square
   * root of total number of points.
   *
   * @sample highcharts/plotoptions/bubble-size/
   *         Bubble size
   *
   * @type {number|string}
   *
   * @private
   */
  minSize: "10%",
  /**
   * Maximum bubble size. Bubbles will automatically size between the
   * `minSize` and `maxSize` to reflect the value of each bubble.
   * Can be either pixels (when no unit is given), or a percentage of
   * the smallest one of the plot width and height, divided by the square
   * root of total number of points.
   *
   * @sample highcharts/plotoptions/bubble-size/
   *         Bubble size
   *
   * @type {number|string}
   *
   * @private
   */
  maxSize: "50%",
  sizeBy: "area",
  zoneAxis: "y",
  crisp: false,
  tooltip: {
    pointFormat: "Value: {point.value}"
  },
  /**
   * Flag to determine if nodes are draggable or not. Available for
   * graph with useSimulation set to true only.
   *
   * @since 7.1.0
   *
   * @private
   */
  draggable: true,
  /**
   * An option is giving a possibility to choose between using simulation
   * for calculating bubble positions. These reflects in both animation
   * and final position of bubbles. Simulation is also adding options to
   * the series graph based on used layout. In case of big data sets, with
   * any performance issues, it is possible to disable animation and pack
   * bubble in a simple circular way.
   *
   * @sample highcharts/series-packedbubble/spiral/
   *         useSimulation set to false
   *
   * @since 7.1.0
   *
   * @private
   */
  useSimulation: true,
  /**
   * Series options for parent nodes.
   *
   * @since 8.1.1
   *
   * @private
   */
  parentNode: {
    /**
     * Allow this series' parent nodes to be selected
     * by clicking on the graph.
     *
     * @since 8.1.1
     */
    allowPointSelect: false
  },
  /**
   *
   * @declare Highcharts.SeriesPackedBubbleDataLabelsOptionsObject
   *
   * @private
   */
  dataLabels: {
    /**
     * The
     * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * specifying what to show for _node_ in the networkgraph. In v7.0
     * defaults to `{key}`, since v7.1 defaults to `undefined` and
     * `formatter` is used instead.
     *
     * @type      {string}
     * @since     7.0.0
     * @apioption plotOptions.packedbubble.dataLabels.format
     */
    // eslint-disable-next-line valid-jsdoc
    /**
     * Callback JavaScript function to format the data label for a node.
     * Note that if a `format` is defined, the format takes precedence
     * and the formatter is ignored.
     *
     * @since 7.0.0
     */
    formatter: function() {
      const { numberFormatter } = this.series.chart;
      const { value } = this.point;
      return isNumber$q(value) ? numberFormatter(value, -1) : "";
    },
    /**
     * @type      {string}
     * @since     7.1.0
     * @apioption plotOptions.packedbubble.dataLabels.parentNodeFormat
     */
    // eslint-disable-next-line valid-jsdoc
    /**
     * @since 7.1.0
     */
    parentNodeFormatter: function() {
      return this.name || "";
    },
    /**
     * @sample {highcharts} highcharts/demo/packed-bubble-project-status/
     *         Dashboard with dataLabels on parentNodes
     *
     * @declare Highcharts.SeriesPackedBubbleDataLabelsTextPathOptionsObject
     * @since   7.1.0
     */
    parentNodeTextPath: {
      /**
       * Presentation attributes for the text path.
       *
       * @type      {Highcharts.SVGAttributes}
       * @since     7.1.0
       * @apioption plotOptions.packedbubble.dataLabels.attributes
       */
      /**
       * Enable or disable `textPath` option for link's or marker's
       * data labels.
       *
       * @since 7.1.0
       */
      enabled: true
    },
    /**
     * Options for a _node_ label text which should follow marker's
     * shape.
     *
     * **Note:** Only SVG-based renderer supports this option.
     *
     * @extends   plotOptions.series.dataLabels.textPath
     * @apioption plotOptions.packedbubble.dataLabels.textPath
     */
    padding: 0,
    style: {
      transition: "opacity 2000ms"
    }
  },
  /**
   * Options for layout algorithm when simulation is enabled. Inside there
   * are options to change the speed, padding, initial bubbles positions
   * and more.
   *
   * @extends   plotOptions.networkgraph.layoutAlgorithm
   * @excluding approximation, attractiveForce, repulsiveForce, theta
   * @since     7.1.0
   *
   * @private
   */
  layoutAlgorithm: {
    /**
     * Initial layout algorithm for positioning nodes. Can be one of
     * the built-in options ("circle", "random") or a function where
     * positions should be set on each node (`this.nodes`) as
     * `node.plotX` and `node.plotY`.
     *
     * @sample highcharts/series-networkgraph/initial-positions/
     *         Initial positions with callback
     *
     * @type {"circle"|"random"|Function}
     */
    initialPositions: "circle",
    /**
     * @sample highcharts/series-packedbubble/initial-radius/
     *         Initial radius set to 200
     *
     * @extends   plotOptions.networkgraph.layoutAlgorithm.initialPositionRadius
     * @excluding states
     */
    initialPositionRadius: 20,
    /**
     * The distance between two bubbles, when the algorithm starts to
     * treat two bubbles as overlapping. The `bubblePadding` is also the
     * expected distance between all the bubbles on simulation end.
     */
    bubblePadding: 5,
    /**
     * Whether bubbles should interact with their parentNode to keep
     * them inside.
     */
    parentNodeLimit: false,
    /**
     * Whether series should interact with each other or not. When
     * `parentNodeLimit` is set to true, thi option should be set to
     * false to avoid sticking points in wrong series parentNode.
     */
    seriesInteraction: true,
    /**
     * In case of split series, this option allows user to drag and
     * drop points between series, for changing point related series.
     *
     * @sample highcharts/demo/packed-bubble-project-status/
     *         Example of drag'n drop bubbles for bubble kanban
     */
    dragBetweenSeries: false,
    /**
     * Layout algorithm options for parent nodes.
     *
     * @extends   plotOptions.networkgraph.layoutAlgorithm
     * @excluding approximation, attractiveForce, enableSimulation,
     *            repulsiveForce, theta
     */
    parentNodeOptions: {
      maxIterations: 400,
      gravitationalConstant: 0.03,
      maxSpeed: 50,
      initialPositionRadius: 100,
      seriesInteraction: true,
      /**
       * Styling options for parentNodes markers. Similar to
       * line.marker options.
       *
       * @sample highcharts/series-packedbubble/parentnode-style/
       *         Bubble size
       *
       * @extends   plotOptions.series.marker
       * @excluding states
       */
      marker: {
        fillColor: null,
        fillOpacity: 1,
        lineWidth: null,
        lineColor: null,
        symbol: "circle"
      }
    },
    enableSimulation: true,
    /**
     * Type of the algorithm used when positioning bubbles.
     * @ignore-option
     */
    type: "packedbubble",
    /**
     * Integration type. Integration determines how forces are applied
     * on particles. The `packedbubble` integration is based on
     * the networkgraph `verlet` integration, where the new position
     * is based on a previous position without velocity:
     * `newPosition += previousPosition - newPosition`.
     *
     * @sample highcharts/series-networkgraph/forces/
     *
     * @ignore-option
     */
    integration: "packedbubble",
    maxIterations: 1e3,
    /**
     * Whether to split series into individual groups or to mix all
     * series together.
     *
     * @since   7.1.0
     * @default false
     */
    splitSeries: false,
    /**
     * Max speed that node can get in one iteration. In terms of
     * simulation, it's a maximum translation (in pixels) that a node
     * can move (in both, x and y, dimensions). While `friction` is
     * applied on all nodes, max speed is applied only for nodes that
     * move very fast, for example small or disconnected ones.
     *
     * @see [layoutAlgorithm.integration](#series.networkgraph.layoutAlgorithm.integration)
     *
     * @see [layoutAlgorithm.friction](#series.networkgraph.layoutAlgorithm.friction)
     */
    maxSpeed: 5,
    gravitationalConstant: 0.01,
    friction: -0.981
  },
  stickyTracking: false
};
function attractive$1(link, force, distanceXY) {
  const massFactor = link.getMass(), translatedX = -distanceXY.x * force * this.diffTemperature, translatedY = -distanceXY.y * force * this.diffTemperature;
  if (!link.fromNode.fixedPosition) {
    link.fromNode.plotX -= translatedX * massFactor.fromNode / link.fromNode.degree;
    link.fromNode.plotY -= translatedY * massFactor.fromNode / link.fromNode.degree;
  }
  if (!link.toNode.fixedPosition) {
    link.toNode.plotX += translatedX * massFactor.toNode / link.toNode.degree;
    link.toNode.plotY += translatedY * massFactor.toNode / link.toNode.degree;
  }
}
function attractiveForceFunction$1(d, k) {
  return (k - d) / d;
}
function barycenter$2() {
  const gravitationalConstant = this.options.gravitationalConstant || 0, xFactor = (this.barycenter.xFactor - (this.box.left + this.box.width) / 2) * gravitationalConstant, yFactor = (this.barycenter.yFactor - (this.box.top + this.box.height) / 2) * gravitationalConstant;
  this.nodes.forEach(function(node) {
    if (!node.fixedPosition) {
      node.plotX -= xFactor / node.mass / node.degree;
      node.plotY -= yFactor / node.mass / node.degree;
    }
  });
}
function getK$1(layout) {
  return Math.pow(layout.box.width * layout.box.height / layout.nodes.length, 0.5);
}
function integrate$1(layout, node) {
  const friction = -layout.options.friction, maxSpeed = layout.options.maxSpeed, prevX = node.prevX, prevY = node.prevY, frictionX = (node.plotX + node.dispX - prevX) * friction, frictionY = (node.plotY + node.dispY - prevY) * friction, abs2 = Math.abs, signX = abs2(frictionX) / (frictionX || 1), signY = abs2(frictionY) / (frictionY || 1), diffX = signX * Math.min(maxSpeed, Math.abs(frictionX)), diffY = signY * Math.min(maxSpeed, Math.abs(frictionY));
  node.prevX = node.plotX + node.dispX;
  node.prevY = node.plotY + node.dispY;
  node.plotX += diffX;
  node.plotY += diffY;
  node.temperature = layout.vectorLength({
    x: diffX,
    y: diffY
  });
}
function repulsive$2(node, force, distanceXY) {
  const factor = force * this.diffTemperature / node.mass / node.degree;
  if (!node.fixedPosition) {
    node.plotX += distanceXY.x * factor;
    node.plotY += distanceXY.y * factor;
  }
}
function repulsiveForceFunction$2(d, k) {
  return (k - d) / d * (k > d ? 1 : 0);
}
const VerletIntegration = {
  attractive: attractive$1,
  attractiveForceFunction: attractiveForceFunction$1,
  barycenter: barycenter$2,
  getK: getK$1,
  integrate: integrate$1,
  repulsive: repulsive$2,
  repulsiveForceFunction: repulsiveForceFunction$2
};
const { noop: noop$7 } = Highcharts;
function barycenter$1() {
  const layout = this, gravitationalConstant = layout.options.gravitationalConstant || 0, box = layout.box, nodes = layout.nodes, nodeCountSqrt = Math.sqrt(nodes.length);
  let centerX, centerY;
  for (const node of nodes) {
    if (!node.fixedPosition) {
      const massTimesNodeCountSqrt = node.mass * nodeCountSqrt, plotX = node.plotX || 0, plotY = node.plotY || 0, series = node.series, parentNode = series.parentNode;
      if (this.resolveSplitSeries(node) && parentNode && !node.isParentNode) {
        centerX = parentNode.plotX || 0;
        centerY = parentNode.plotY || 0;
      } else {
        centerX = box.width / 2;
        centerY = box.height / 2;
      }
      node.plotX = plotX - (plotX - centerX) * gravitationalConstant / massTimesNodeCountSqrt;
      node.plotY = plotY - (plotY - centerY) * gravitationalConstant / massTimesNodeCountSqrt;
      if (series.chart.hoverPoint === node && // If redrawHalo exists we know its a draggable series and any
      // halo present should be redrawn to update its visual position
      series.redrawHalo && series.halo) {
        series.redrawHalo(node);
      }
    }
  }
}
function repulsive$1(node, force, distanceXY, repNode) {
  const factor = force * this.diffTemperature / node.mass / node.degree, x = distanceXY.x * factor, y = distanceXY.y * factor;
  if (!node.fixedPosition) {
    node.plotX += x;
    node.plotY += y;
  }
  if (!repNode.fixedPosition) {
    repNode.plotX -= x;
    repNode.plotY -= y;
  }
}
function repulsiveForceFunction$1(d, k, node, repNode) {
  return Math.min(d, (node.marker.radius + repNode.marker.radius) / 2);
}
const PackedBubbleIntegration = {
  barycenter: barycenter$1,
  getK: noop$7,
  integrate: VerletIntegration.integrate,
  repulsive: repulsive$1,
  repulsiveForceFunction: repulsiveForceFunction$1
};
function attractive(link, force, distanceXY, distanceR) {
  const massFactor = link.getMass(), translatedX = distanceXY.x / distanceR * force, translatedY = distanceXY.y / distanceR * force;
  if (!link.fromNode.fixedPosition) {
    link.fromNode.dispX -= translatedX * massFactor.fromNode / link.fromNode.degree;
    link.fromNode.dispY -= translatedY * massFactor.fromNode / link.fromNode.degree;
  }
  if (!link.toNode.fixedPosition) {
    link.toNode.dispX += translatedX * massFactor.toNode / link.toNode.degree;
    link.toNode.dispY += translatedY * massFactor.toNode / link.toNode.degree;
  }
}
function attractiveForceFunction(d, k) {
  return d * d / k;
}
function barycenter() {
  const gravitationalConstant = this.options.gravitationalConstant, xFactor = this.barycenter.xFactor, yFactor = this.barycenter.yFactor;
  this.nodes.forEach(function(node) {
    if (!node.fixedPosition) {
      const degree = node.getDegree(), phi = degree * (1 + degree / 2);
      node.dispX += (xFactor - node.plotX) * gravitationalConstant * phi / node.degree;
      node.dispY += (yFactor - node.plotY) * gravitationalConstant * phi / node.degree;
    }
  });
}
function getK(layout) {
  return Math.pow(layout.box.width * layout.box.height / layout.nodes.length, 0.3);
}
function integrate(layout, node) {
  node.dispX += node.dispX * layout.options.friction;
  node.dispY += node.dispY * layout.options.friction;
  const distanceR = node.temperature = layout.vectorLength({
    x: node.dispX,
    y: node.dispY
  });
  if (distanceR !== 0) {
    node.plotX += node.dispX / distanceR * Math.min(Math.abs(node.dispX), layout.temperature);
    node.plotY += node.dispY / distanceR * Math.min(Math.abs(node.dispY), layout.temperature);
  }
}
function repulsive(node, force, distanceXY, distanceR) {
  node.dispX += distanceXY.x / distanceR * force / node.degree;
  node.dispY += distanceXY.y / distanceR * force / node.degree;
}
function repulsiveForceFunction(d, k) {
  return k * k / d;
}
const EulerIntegration = {
  attractive,
  attractiveForceFunction,
  barycenter,
  getK,
  integrate,
  repulsive,
  repulsiveForceFunction
};
class QuadTreeNode {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(box) {
    this.body = false;
    this.isEmpty = false;
    this.isInternal = false;
    this.nodes = [];
    this.box = box;
    this.boxSize = Math.min(box.width, box.height);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * When inserting another node into the box, that already hove one node,
   * divide the available space into another four quadrants.
   *
   * Indexes of quadrants are:
   * ```
   * -------------               -------------
   * |           |               |     |     |
   * |           |               |  0  |  1  |
   * |           |   divide()    |     |     |
   * |     1     | ----------->  -------------
   * |           |               |     |     |
   * |           |               |  3  |  2  |
   * |           |               |     |     |
   * -------------               -------------
   * ```
   */
  divideBox() {
    const halfWidth = this.box.width / 2, halfHeight = this.box.height / 2;
    this.nodes[0] = new QuadTreeNode({
      left: this.box.left,
      top: this.box.top,
      width: halfWidth,
      height: halfHeight
    });
    this.nodes[1] = new QuadTreeNode({
      left: this.box.left + halfWidth,
      top: this.box.top,
      width: halfWidth,
      height: halfHeight
    });
    this.nodes[2] = new QuadTreeNode({
      left: this.box.left + halfWidth,
      top: this.box.top + halfHeight,
      width: halfWidth,
      height: halfHeight
    });
    this.nodes[3] = new QuadTreeNode({
      left: this.box.left,
      top: this.box.top + halfHeight,
      width: halfWidth,
      height: halfHeight
    });
  }
  /**
   * Determine which of the quadrants should be used when placing node in
   * the QuadTree. Returned index is always in range `< 0 , 3 >`.
   * @private
   */
  getBoxPosition(point) {
    const left = point.plotX < this.box.left + this.box.width / 2, top = point.plotY < this.box.top + this.box.height / 2;
    let index;
    if (left) {
      if (top) {
        index = 0;
      } else {
        index = 3;
      }
    } else {
      if (top) {
        index = 1;
      } else {
        index = 2;
      }
    }
    return index;
  }
  /**
   * Insert recursively point(node) into the QuadTree. If the given
   * quadrant is already occupied, divide it into smaller quadrants.
   *
   * @param {Highcharts.Point} point
   *        Point/node to be inserted
   * @param {number} depth
   *        Max depth of the QuadTree
   */
  insert(point, depth) {
    let newQuadTreeNode;
    if (this.isInternal) {
      this.nodes[this.getBoxPosition(point)].insert(point, depth - 1);
    } else {
      this.isEmpty = false;
      if (!this.body) {
        this.isInternal = false;
        this.body = point;
      } else {
        if (depth) {
          this.isInternal = true;
          this.divideBox();
          if (this.body !== true) {
            this.nodes[this.getBoxPosition(this.body)].insert(this.body, depth - 1);
            this.body = true;
          }
          this.nodes[this.getBoxPosition(point)].insert(point, depth - 1);
        } else {
          newQuadTreeNode = new QuadTreeNode({
            top: point.plotX || NaN,
            left: point.plotY || NaN,
            // Width/height below 1px
            width: 0.1,
            height: 0.1
          });
          newQuadTreeNode.body = point;
          newQuadTreeNode.isInternal = false;
          this.nodes.push(newQuadTreeNode);
        }
      }
    }
  }
  /**
   * Each quad node requires it's mass and center position. That mass and
   * position is used to imitate real node in the layout by approximation.
   */
  updateMassAndCenter() {
    let mass = 0, plotX = 0, plotY = 0;
    if (this.isInternal) {
      for (const pointMass of this.nodes) {
        if (!pointMass.isEmpty) {
          mass += pointMass.mass;
          plotX += pointMass.plotX * pointMass.mass;
          plotY += pointMass.plotY * pointMass.mass;
        }
      }
      plotX /= mass;
      plotY /= mass;
    } else if (this.body) {
      mass = this.body.mass;
      plotX = this.body.plotX;
      plotY = this.body.plotY;
    }
    this.mass = mass;
    this.plotX = plotX;
    this.plotY = plotY;
  }
}
class QuadTree {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(x, y, width, height) {
    this.box = {
      left: x,
      top: y,
      width,
      height
    };
    this.maxDepth = 25;
    this.root = new QuadTreeNode(this.box);
    this.root.isInternal = true;
    this.root.isRoot = true;
    this.root.divideBox();
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Calculate mass of the each QuadNode in the tree.
   */
  calculateMassAndCenter() {
    this.visitNodeRecursive(null, null, function(node) {
      node.updateMassAndCenter();
    });
  }
  /**
   * Insert nodes into the QuadTree
   *
   * @param {Array<Highcharts.Point>} points
   *        Points as nodes
   */
  insertNodes(points) {
    for (const point of points) {
      this.root.insert(point, this.maxDepth);
    }
  }
  /**
   * Depth first treversal (DFS). Using `before` and `after` callbacks,
   * we can get two results: preorder and postorder traversals, reminder:
   *
   * ```
   *     (a)
   *     / \
   *   (b) (c)
   *   / \
   * (d) (e)
   * ```
   *
   * DFS (preorder): `a -> b -> d -> e -> c`
   *
   * DFS (postorder): `d -> e -> b -> c -> a`
   *
   * @param {Highcharts.QuadTreeNode|null} node
   *        QuadTree node
   * @param {Function} [beforeCallback]
   *        Function to be called before visiting children nodes.
   * @param {Function} [afterCallback]
   *        Function to be called after visiting children nodes.
   */
  visitNodeRecursive(node, beforeCallback, afterCallback) {
    let goFurther;
    if (!node) {
      node = this.root;
    }
    if (node === this.root && beforeCallback) {
      goFurther = beforeCallback(node);
    }
    if (goFurther === false) {
      return;
    }
    for (const qtNode of node.nodes) {
      if (qtNode.isInternal) {
        if (beforeCallback) {
          goFurther = beforeCallback(qtNode);
        }
        if (goFurther === false) {
          continue;
        }
        this.visitNodeRecursive(qtNode, beforeCallback, afterCallback);
      } else if (qtNode.body) {
        if (beforeCallback) {
          beforeCallback(qtNode.body);
        }
      }
      if (afterCallback) {
        afterCallback(qtNode);
      }
    }
    if (node === this.root && afterCallback) {
      afterCallback(node);
    }
  }
}
const { win: win$2 } = Highcharts;
const { clamp: clamp$8, defined: defined$s, isFunction, fireEvent: fireEvent$d, pick: pick$K } = Utilities;
class ReingoldFruchtermanLayout {
  constructor() {
    this.box = {};
    this.currentStep = 0;
    this.initialRendering = true;
    this.links = [];
    this.nodes = [];
    this.series = [];
    this.simulation = false;
  }
  static compose(ChartClass) {
    GraphLayoutComposition.compose(ChartClass);
    GraphLayoutComposition.integrations.euler = EulerIntegration;
    GraphLayoutComposition.integrations.verlet = VerletIntegration;
    GraphLayoutComposition.layouts["reingold-fruchterman"] = ReingoldFruchtermanLayout;
  }
  init(options2) {
    this.options = options2;
    this.nodes = [];
    this.links = [];
    this.series = [];
    this.box = {
      x: 0,
      y: 0,
      width: 0,
      height: 0
    };
    this.setInitialRendering(true);
    this.integration = GraphLayoutComposition.integrations[options2.integration];
    this.enableSimulation = options2.enableSimulation;
    this.attractiveForce = pick$K(options2.attractiveForce, this.integration.attractiveForceFunction);
    this.repulsiveForce = pick$K(options2.repulsiveForce, this.integration.repulsiveForceFunction);
    this.approximation = options2.approximation;
  }
  updateSimulation(enable) {
    this.enableSimulation = pick$K(enable, this.options.enableSimulation);
  }
  start() {
    const layout = this, series = this.series, options2 = this.options;
    layout.currentStep = 0;
    layout.forces = series[0] && series[0].forces || [];
    layout.chart = series[0] && series[0].chart;
    if (layout.initialRendering) {
      layout.initPositions();
      series.forEach(function(s) {
        s.finishedAnimating = true;
        s.render();
      });
    }
    layout.setK();
    layout.resetSimulation(options2);
    if (layout.enableSimulation) {
      layout.step();
    }
  }
  step() {
    const anyLayout = this, allSeries = this.series;
    this.currentStep++;
    if (this.approximation === "barnes-hut") {
      this.createQuadTree();
      this.quadTree.calculateMassAndCenter();
    }
    for (const forceName of this.forces || []) {
      anyLayout[forceName + "Forces"](this.temperature);
    }
    this.applyLimits();
    this.temperature = this.coolDown(this.startTemperature, this.diffTemperature, this.currentStep);
    this.prevSystemTemperature = this.systemTemperature;
    this.systemTemperature = this.getSystemTemperature();
    if (this.enableSimulation) {
      for (const series of allSeries) {
        if (series.chart) {
          series.render();
        }
      }
      if (this.maxIterations-- && isFinite(this.temperature) && !this.isStable()) {
        if (this.simulation) {
          win$2.cancelAnimationFrame(this.simulation);
        }
        this.simulation = win$2.requestAnimationFrame(() => this.step());
      } else {
        this.simulation = false;
        this.series.forEach((s) => {
          fireEvent$d(s, "afterSimulation");
        });
      }
    }
  }
  stop() {
    if (this.simulation) {
      win$2.cancelAnimationFrame(this.simulation);
    }
  }
  setArea(x, y, w, h) {
    this.box = {
      left: x,
      top: y,
      width: w,
      height: h
    };
  }
  setK() {
    this.k = this.options.linkLength || this.integration.getK(this);
  }
  addElementsToCollection(elements, collection) {
    for (const element of elements) {
      if (collection.indexOf(element) === -1) {
        collection.push(element);
      }
    }
  }
  removeElementFromCollection(element, collection) {
    const index = collection.indexOf(element);
    if (index !== -1) {
      collection.splice(index, 1);
    }
  }
  clear() {
    this.nodes.length = 0;
    this.links.length = 0;
    this.series.length = 0;
    this.resetSimulation();
  }
  resetSimulation() {
    this.forcedStop = false;
    this.systemTemperature = 0;
    this.setMaxIterations();
    this.setTemperature();
    this.setDiffTemperature();
  }
  restartSimulation() {
    if (!this.simulation) {
      this.setInitialRendering(false);
      if (!this.enableSimulation) {
        this.setMaxIterations(1);
      } else {
        this.start();
      }
      if (this.chart) {
        this.chart.redraw();
      }
      this.setInitialRendering(true);
    } else {
      this.resetSimulation();
    }
  }
  setMaxIterations(maxIterations) {
    this.maxIterations = pick$K(maxIterations, this.options.maxIterations);
  }
  setTemperature() {
    this.temperature = this.startTemperature = Math.sqrt(this.nodes.length);
  }
  setDiffTemperature() {
    this.diffTemperature = this.startTemperature / (this.options.maxIterations + 1);
  }
  setInitialRendering(enable) {
    this.initialRendering = enable;
  }
  createQuadTree() {
    this.quadTree = new QuadTree(this.box.left, this.box.top, this.box.width, this.box.height);
    this.quadTree.insertNodes(this.nodes);
  }
  initPositions() {
    const initialPositions = this.options.initialPositions;
    if (isFunction(initialPositions)) {
      initialPositions.call(this);
      for (const node of this.nodes) {
        if (!defined$s(node.prevX)) {
          node.prevX = node.plotX;
        }
        if (!defined$s(node.prevY)) {
          node.prevY = node.plotY;
        }
        node.dispX = 0;
        node.dispY = 0;
      }
    } else if (initialPositions === "circle") {
      this.setCircularPositions();
    } else {
      this.setRandomPositions();
    }
  }
  setCircularPositions() {
    const box = this.box, nodes = this.nodes, nodesLength = nodes.length + 1, angle = 2 * Math.PI / nodesLength, rootNodes = nodes.filter(function(node2) {
      return node2.linksTo.length === 0;
    }), visitedNodes = {}, radius = this.options.initialPositionRadius, addToNodes = (node2) => {
      for (const link of node2.linksFrom || []) {
        if (!visitedNodes[link.toNode.id]) {
          visitedNodes[link.toNode.id] = true;
          sortedNodes.push(link.toNode);
          addToNodes(link.toNode);
        }
      }
    };
    let sortedNodes = [];
    for (const rootNode of rootNodes) {
      sortedNodes.push(rootNode);
      addToNodes(rootNode);
    }
    if (!sortedNodes.length) {
      sortedNodes = nodes;
    } else {
      for (const node2 of nodes) {
        if (sortedNodes.indexOf(node2) === -1) {
          sortedNodes.push(node2);
        }
      }
    }
    let node;
    for (let i = 0, iEnd = sortedNodes.length; i < iEnd; ++i) {
      node = sortedNodes[i];
      node.plotX = node.prevX = pick$K(node.plotX, box.width / 2 + radius * Math.cos(i * angle));
      node.plotY = node.prevY = pick$K(node.plotY, box.height / 2 + radius * Math.sin(i * angle));
      node.dispX = 0;
      node.dispY = 0;
    }
  }
  setRandomPositions() {
    const box = this.box, nodes = this.nodes, nodesLength = nodes.length + 1, unrandom = (n) => {
      let rand = n * n / Math.PI;
      rand = rand - Math.floor(rand);
      return rand;
    };
    let node;
    for (let i = 0, iEnd = nodes.length; i < iEnd; ++i) {
      node = nodes[i];
      node.plotX = node.prevX = pick$K(node.plotX, box.width * unrandom(i));
      node.plotY = node.prevY = pick$K(node.plotY, box.height * unrandom(nodesLength + i));
      node.dispX = 0;
      node.dispY = 0;
    }
  }
  force(name, ...args) {
    this.integration[name].apply(this, args);
  }
  barycenterForces() {
    this.getBarycenter();
    this.force("barycenter");
  }
  getBarycenter() {
    let systemMass = 0, cx = 0, cy = 0;
    for (const node of this.nodes) {
      cx += node.plotX * node.mass;
      cy += node.plotY * node.mass;
      systemMass += node.mass;
    }
    this.barycenter = {
      x: cx,
      y: cy,
      xFactor: cx / systemMass,
      yFactor: cy / systemMass
    };
    return this.barycenter;
  }
  barnesHutApproximation(node, quadNode) {
    const distanceXY = this.getDistXY(node, quadNode), distanceR = this.vectorLength(distanceXY);
    let goDeeper, force;
    if (node !== quadNode && distanceR !== 0) {
      if (quadNode.isInternal) {
        if (quadNode.boxSize / distanceR < this.options.theta && distanceR !== 0) {
          force = this.repulsiveForce(distanceR, this.k);
          this.force("repulsive", node, force * quadNode.mass, distanceXY, distanceR);
          goDeeper = false;
        } else {
          goDeeper = true;
        }
      } else {
        force = this.repulsiveForce(distanceR, this.k);
        this.force("repulsive", node, force * quadNode.mass, distanceXY, distanceR);
      }
    }
    return goDeeper;
  }
  repulsiveForces() {
    if (this.approximation === "barnes-hut") {
      for (const node of this.nodes) {
        this.quadTree.visitNodeRecursive(null, (quadNode) => this.barnesHutApproximation(node, quadNode));
      }
    } else {
      let force, distanceR, distanceXY;
      for (const node of this.nodes) {
        for (const repNode of this.nodes) {
          if (
            // Node cannot repulse itself:
            node !== repNode && // Only close nodes affect each other:
            // layout.getDistR(node, repNode) < 2 * k &&
            // Not dragged:
            !node.fixedPosition
          ) {
            distanceXY = this.getDistXY(node, repNode);
            distanceR = this.vectorLength(distanceXY);
            if (distanceR !== 0) {
              force = this.repulsiveForce(distanceR, this.k);
              this.force("repulsive", node, force * repNode.mass, distanceXY, distanceR);
            }
          }
        }
      }
    }
  }
  attractiveForces() {
    let distanceXY, distanceR, force;
    for (const link of this.links) {
      if (link.fromNode && link.toNode) {
        distanceXY = this.getDistXY(link.fromNode, link.toNode);
        distanceR = this.vectorLength(distanceXY);
        if (distanceR !== 0) {
          force = this.attractiveForce(distanceR, this.k);
          this.force("attractive", link, force, distanceXY, distanceR);
        }
      }
    }
  }
  applyLimits() {
    const nodes = this.nodes;
    for (const node of nodes) {
      if (node.fixedPosition) {
        continue;
      }
      this.integration.integrate(this, node);
      this.applyLimitBox(node, this.box);
      node.dispX = 0;
      node.dispY = 0;
    }
  }
  /**
   * External box that nodes should fall. When hitting an edge, node
   * should stop or bounce.
   * @private
   */
  applyLimitBox(node, box) {
    const radius = node.radius;
    node.plotX = clamp$8(node.plotX, box.left + radius, box.width - radius);
    node.plotY = clamp$8(node.plotY, box.top + radius, box.height - radius);
  }
  /**
   * From "A comparison of simulated annealing cooling strategies" by
   * Nourani and Andresen work.
   * @private
   */
  coolDown(temperature, temperatureStep, currentStep) {
    return temperature - temperatureStep * currentStep;
  }
  isStable() {
    return Math.abs(this.systemTemperature - this.prevSystemTemperature) < 1e-5 || this.temperature <= 0;
  }
  getSystemTemperature() {
    let value = 0;
    for (const node of this.nodes) {
      value += node.temperature;
    }
    return value;
  }
  vectorLength(vector) {
    return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
  }
  getDistR(nodeA, nodeB) {
    const distance = this.getDistXY(nodeA, nodeB);
    return this.vectorLength(distance);
  }
  getDistXY(nodeA, nodeB) {
    const xDist = nodeA.plotX - nodeB.plotX, yDist = nodeA.plotY - nodeB.plotY;
    return {
      x: xDist,
      y: yDist,
      absX: Math.abs(xDist),
      absY: Math.abs(yDist)
    };
  }
}
const { addEvent: addEvent$z, defined: defined$r, pick: pick$J } = Utilities;
function chartGetSelectedParentNodes() {
  const allSeries = this.series, selectedParentsNodes = [];
  allSeries.forEach((series) => {
    if (series.parentNode && series.parentNode.selected) {
      selectedParentsNodes.push(series.parentNode);
    }
  });
  return selectedParentsNodes;
}
function onChartBeforeRedraw() {
  if (this.allDataPoints) {
    delete this.allDataPoints;
  }
}
class PackedBubbleLayout extends ReingoldFruchtermanLayout {
  constructor() {
    super(...arguments);
    this.index = NaN;
    this.nodes = [];
    this.series = [];
  }
  static compose(ChartClass) {
    ReingoldFruchtermanLayout.compose(ChartClass);
    GraphLayoutComposition.integrations.packedbubble = PackedBubbleIntegration;
    GraphLayoutComposition.layouts.packedbubble = PackedBubbleLayout;
    const chartProto = ChartClass.prototype;
    if (!chartProto.getSelectedParentNodes) {
      addEvent$z(ChartClass, "beforeRedraw", onChartBeforeRedraw);
      chartProto.getSelectedParentNodes = chartGetSelectedParentNodes;
    }
    if (!chartProto.allParentNodes) {
      chartProto.allParentNodes = [];
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  beforeStep() {
    if (this.options.marker) {
      this.series.forEach((series) => {
        if (series) {
          series.calculateParentRadius();
        }
      });
    }
  }
  // #14439, new stable check.
  isStable() {
    const tempDiff = Math.abs(this.prevSystemTemperature - this.systemTemperature);
    const upScaledTemperature = 10 * this.systemTemperature / Math.sqrt(this.nodes.length);
    return Math.abs(upScaledTemperature) < 1 && tempDiff < 1e-5 || this.temperature <= 0;
  }
  setCircularPositions() {
    const layout = this, box = layout.box, nodes = [
      ...layout.nodes,
      ...layout?.chart?.allParentNodes || []
    ], nodesLength = nodes.length + 1, angle = 2 * Math.PI / nodesLength, radius = layout.options.initialPositionRadius;
    let centerX, centerY, index = 0;
    for (const node of nodes) {
      if (this.resolveSplitSeries(node) && !node.isParentNode) {
        centerX = node.series.parentNode.plotX;
        centerY = node.series.parentNode.plotY;
      } else {
        centerX = box.width / 2;
        centerY = box.height / 2;
      }
      node.plotX = node.prevX = pick$J(node.plotX, centerX + radius * Math.cos(node.index || index * angle));
      node.plotY = node.prevY = pick$J(node.plotY, centerY + radius * Math.sin(node.index || index * angle));
      node.dispX = 0;
      node.dispY = 0;
      index++;
    }
  }
  repulsiveForces() {
    const layout = this, { options: options2, k } = layout, { bubblePadding = 0, seriesInteraction } = options2, nodes = [
      ...layout.nodes,
      ...layout?.chart?.allParentNodes || []
    ];
    for (const node of nodes) {
      const nodeSeries = node.series, fixedPosition = node.fixedPosition, paddedNodeRadius = (node.marker?.radius || 0) + bubblePadding;
      node.degree = node.mass;
      node.neighbours = 0;
      for (const repNode of nodes) {
        const repNodeSeries = repNode.series;
        if (
          // Node cannot repulse itself:
          node !== repNode && // Not dragged:
          !fixedPosition && (seriesInteraction || nodeSeries === repNodeSeries) && // Avoiding collision of parentNodes and parented points
          !(nodeSeries === repNodeSeries && (repNode.isParentNode || node.isParentNode))
        ) {
          const distanceXY = layout.getDistXY(node, repNode), distanceR = layout.vectorLength(distanceXY) - (paddedNodeRadius + (repNode.marker?.radius || 0));
          let forceTimesMass;
          if (distanceR < 0) {
            node.degree += 0.01;
            forceTimesMass = layout.repulsiveForce(-distanceR / Math.sqrt(++node.neighbours), k, node, repNode) * repNode.mass;
          }
          layout.force("repulsive", node, forceTimesMass || 0, distanceXY, repNode, distanceR);
        }
      }
    }
  }
  resolveSplitSeries(node) {
    const specificSeriesOpt = node.series?.options?.layoutAlgorithm?.splitSeries;
    return !defined$r(specificSeriesOpt) && node.series.chart?.options?.plotOptions?.packedbubble?.layoutAlgorithm?.splitSeries || specificSeriesOpt || false;
  }
  applyLimitBox(node, box) {
    const layout = this, factor = 0.01;
    let distanceXY, distanceR;
    if (this.resolveSplitSeries(node) && !node.isParentNode && layout.options.parentNodeLimit) {
      distanceXY = layout.getDistXY(node, node.series.parentNode);
      distanceR = node.series.parentNodeRadius - node.marker.radius - layout.vectorLength(distanceXY);
      if (distanceR < 0 && distanceR > -2 * node.marker.radius) {
        node.plotX -= distanceXY.x * factor;
        node.plotY -= distanceXY.y * factor;
      }
    }
    super.applyLimitBox(node, box);
  }
}
GraphLayoutComposition.layouts.packedbubble = PackedBubbleLayout;
const { merge: merge$I, syncTimeout: syncTimeout$2 } = Utilities;
const { animObject: animObject$5 } = animationExports;
function initDataLabelsDefer$1() {
  const dlOptions = this.options.dataLabels;
  if (!dlOptions?.defer || !this.options.layoutAlgorithm?.enableSimulation) {
    this.deferDataLabels = false;
  } else {
    syncTimeout$2(() => {
      this.deferDataLabels = false;
    }, dlOptions ? animObject$5(dlOptions.animation).defer : 0);
  }
}
function initDataLabels$1() {
  const series = this, dlOptions = series.options.dataLabels;
  if (!series.dataLabelsGroup) {
    const dataLabelsGroup = this.initDataLabelsGroup();
    if (!series.chart.styledMode && dlOptions?.style) {
      dataLabelsGroup.css(dlOptions.style);
    }
    dataLabelsGroup.attr({ opacity: 0 });
    if (series.visible) {
      dataLabelsGroup.show();
    }
    return dataLabelsGroup;
  }
  series.dataLabelsGroup.attr(merge$I({ opacity: 1 }, this.getPlotBox("data-labels")));
  return series.dataLabelsGroup;
}
const DataLabelsDeferUtils = {
  initDataLabels: initDataLabels$1,
  initDataLabelsDefer: initDataLabelsDefer$1
};
const { deg2rad: deg2rad$5 } = Highcharts;
const { addEvent: addEvent$y, merge: merge$H, uniqueKey: uniqueKey$2, defined: defined$q, extend: extend$D } = Utilities;
function setTextPath(path, textPathOptions) {
  textPathOptions = merge$H(true, {
    enabled: true,
    attributes: {
      dy: -5,
      startOffset: "50%",
      textAnchor: "middle"
    }
  }, textPathOptions);
  const url = this.renderer.url, textWrapper = this.text || this, textPath = textWrapper.textPath, { attributes, enabled } = textPathOptions;
  path = path || textPath && textPath.path;
  if (textPath) {
    textPath.undo();
  }
  if (path && enabled) {
    const undo = addEvent$y(textWrapper, "afterModifyTree", (e) => {
      if (path && enabled) {
        let textPathId = path.attr("id");
        if (!textPathId) {
          path.attr("id", textPathId = uniqueKey$2());
        }
        const textAttribs = {
          // `dx`/`dy` options must by set on <text> (parent), the
          // rest should be set on <textPath>
          x: 0,
          y: 0
        };
        if (defined$q(attributes.dx)) {
          textAttribs.dx = attributes.dx;
          delete attributes.dx;
        }
        if (defined$q(attributes.dy)) {
          textAttribs.dy = attributes.dy;
          delete attributes.dy;
        }
        textWrapper.attr(textAttribs);
        this.attr({ transform: "" });
        if (this.box) {
          this.box = this.box.destroy();
        }
        const children = e.nodes.slice(0);
        e.nodes.length = 0;
        e.nodes[0] = {
          tagName: "textPath",
          attributes: extend$D(attributes, {
            "text-anchor": attributes.textAnchor,
            href: `${url}#${textPathId}`
          }),
          children
        };
      }
    });
    textWrapper.textPath = { path, undo };
  } else {
    textWrapper.attr({ dx: 0, dy: 0 });
    delete textWrapper.textPath;
  }
  if (this.added) {
    textWrapper.textCache = "";
    this.renderer.buildText(textWrapper);
  }
  return this;
}
function setPolygon(event) {
  const bBox = event.bBox, tp = this.element?.querySelector("textPath");
  if (tp) {
    const polygon = [], { b, h } = this.renderer.fontMetrics(this.element), descender = h - b, lineCleanerRegex = new RegExp('(<tspan>|<tspan(?!\\sclass="highcharts-br")[^>]*>|<\\/tspan>)', "g"), lines = tp.innerHTML.replace(lineCleanerRegex, "").split(/<tspan class="highcharts-br"[^>]*>/), numOfLines = lines.length;
    const appendTopAndBottom = (charIndex, positionOfChar) => {
      const { x, y } = positionOfChar, rotation = (tp.getRotationOfChar(charIndex) - 90) * deg2rad$5, cosRot = Math.cos(rotation), sinRot = Math.sin(rotation);
      return [
        [
          x - descender * cosRot,
          y - descender * sinRot
        ],
        [
          x + b * cosRot,
          y + b * sinRot
        ]
      ];
    };
    for (let i = 0, lineIndex = 0; lineIndex < numOfLines; lineIndex++) {
      const line2 = lines[lineIndex], lineLen = line2.length;
      for (let lineCharIndex = 0; lineCharIndex < lineLen; lineCharIndex += 5) {
        try {
          const srcCharIndex = i + lineCharIndex + lineIndex, [lower, upper] = appendTopAndBottom(srcCharIndex, tp.getStartPositionOfChar(srcCharIndex));
          if (lineCharIndex === 0) {
            polygon.push(upper);
            polygon.push(lower);
          } else {
            if (lineIndex === 0) {
              polygon.unshift(upper);
            }
            if (lineIndex === numOfLines - 1) {
              polygon.push(lower);
            }
          }
        } catch (e) {
          break;
        }
      }
      i += lineLen - 1;
      try {
        const srcCharIndex = i + lineIndex, charPos = tp.getEndPositionOfChar(srcCharIndex), [lower, upper] = appendTopAndBottom(srcCharIndex, charPos);
        polygon.unshift(upper);
        polygon.unshift(lower);
      } catch (e) {
        break;
      }
    }
    if (polygon.length) {
      polygon.push(polygon[0].slice());
    }
    bBox.polygon = polygon;
  }
  return bBox;
}
function drawTextPath(event) {
  const labelOptions = event.labelOptions, point = event.point, textPathOptions = labelOptions[point.formatPrefix + "TextPath"] || labelOptions.textPath;
  if (textPathOptions && !labelOptions.useHTML) {
    this.setTextPath(point.getDataLabelPath?.(this) || point.graphic, textPathOptions);
    if (point.dataLabelPath && !textPathOptions.enabled) {
      point.dataLabelPath = point.dataLabelPath.destroy();
    }
  }
}
function compose$c(SVGElementClass) {
  addEvent$y(SVGElementClass, "afterGetBBox", setPolygon);
  addEvent$y(SVGElementClass, "beforeAddingDataLabel", drawTextPath);
  const svgElementProto = SVGElementClass.prototype;
  if (!svgElementProto.setTextPath) {
    svgElementProto.setTextPath = setTextPath;
  }
}
const TextPath = {
  compose: compose$c
};
const { parse: color$8 } = Color;
const { noop: noop$6 } = Highcharts;
const { series: { prototype: seriesProto$1 }, seriesTypes: { bubble: BubbleSeries } } = SeriesRegistry$1;
const { initDataLabels, initDataLabelsDefer } = DataLabelsDeferUtils;
const { addEvent: addEvent$x, clamp: clamp$7, defined: defined$p, extend: extend$C, fireEvent: fireEvent$c, isArray: isArray$9, isNumber: isNumber$p, merge: merge$G, pick: pick$I } = Utilities;
TextPath.compose(SVGElement$1);
class PackedBubbleSeries extends BubbleSeries {
  constructor() {
    super(...arguments);
    this.parentNodeMass = 0;
    this.deferDataLabels = true;
  }
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AxisClass, ChartClass, LegendClass) {
    BubbleSeries.compose(AxisClass, ChartClass, LegendClass);
    DragNodesComposition.compose(ChartClass);
    PackedBubbleLayout.compose(ChartClass);
  }
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * Create a single array of all points from all series
   * @private
   */
  accumulateAllPoints() {
    const chart = this.chart, allDataPoints = [];
    for (const series of chart.series) {
      if (series.is("packedbubble") && // #13574
      series.reserveSpace()) {
        const valueData = series.getColumn("value");
        for (let j = 0; j < valueData.length; j++) {
          allDataPoints.push([
            null,
            null,
            valueData[j],
            series.index,
            j,
            {
              id: j,
              marker: {
                radius: 0
              }
            }
          ]);
        }
      }
    }
    return allDataPoints;
  }
  /**
   * Adding the basic layout to series points.
   * @private
   */
  addLayout() {
    const layoutOptions = this.options.layoutAlgorithm = this.options.layoutAlgorithm || {}, layoutType = layoutOptions.type || "packedbubble", chartOptions = this.chart.options.chart;
    let graphLayoutsStorage = this.chart.graphLayoutsStorage, graphLayoutsLookup = this.chart.graphLayoutsLookup, layout;
    if (!graphLayoutsStorage) {
      this.chart.graphLayoutsStorage = graphLayoutsStorage = {};
      this.chart.graphLayoutsLookup = graphLayoutsLookup = [];
    }
    layout = graphLayoutsStorage[layoutType];
    if (!layout) {
      layoutOptions.enableSimulation = !defined$p(chartOptions.forExport) ? layoutOptions.enableSimulation : !chartOptions.forExport;
      graphLayoutsStorage[layoutType] = layout = new GraphLayoutComposition.layouts[layoutType]();
      layout.init(layoutOptions);
      graphLayoutsLookup.splice(layout.index, 0, layout);
    }
    this.layout = layout;
    this.points.forEach((node) => {
      node.mass = 2;
      node.degree = 1;
      node.collisionNmb = 1;
    });
    layout.setArea(0, 0, this.chart.plotWidth, this.chart.plotHeight);
    layout.addElementsToCollection([this], layout.series);
    layout.addElementsToCollection(this.points, layout.nodes);
  }
  /**
   * Function responsible for adding series layout, used for parent nodes.
   * @private
   */
  addSeriesLayout() {
    const layoutOptions = this.options.layoutAlgorithm = this.options.layoutAlgorithm || {}, layoutType = layoutOptions.type || "packedbubble", graphLayoutsStorage = this.chart.graphLayoutsStorage, graphLayoutsLookup = this.chart.graphLayoutsLookup, parentNodeOptions = merge$G(layoutOptions, layoutOptions.parentNodeOptions, {
      enableSimulation: this.layout.options.enableSimulation
    });
    let seriesLayout = graphLayoutsStorage[layoutType + "-series"];
    if (!seriesLayout) {
      graphLayoutsStorage[layoutType + "-series"] = seriesLayout = new GraphLayoutComposition.layouts[layoutType]();
      seriesLayout.init(parentNodeOptions);
      graphLayoutsLookup.splice(seriesLayout.index, 0, seriesLayout);
    }
    this.parentNodeLayout = seriesLayout;
    this.createParentNodes();
  }
  /**
   * The function responsible for calculating the parent node radius
   * based on the total surface of inside-bubbles and the group BBox
   * @private
   */
  calculateParentRadius() {
    const bBox = this.seriesBox(), parentPadding = 20, minParentRadius = 20;
    this.parentNodeRadius = clamp$7(Math.sqrt(2 * this.parentNodeMass / Math.PI) + parentPadding, minParentRadius, bBox ? Math.max(Math.sqrt(Math.pow(bBox.width, 2) + Math.pow(bBox.height, 2)) / 2 + parentPadding, minParentRadius) : Math.sqrt(2 * this.parentNodeMass / Math.PI) + parentPadding);
    if (this.parentNode) {
      this.parentNode.marker.radius = this.parentNode.radius = this.parentNodeRadius;
    }
  }
  /**
   * Calculate min and max bubble value for radius calculation.
   * @private
   */
  calculateZExtremes() {
    const chart = this.chart, allSeries = chart.series;
    let zMin = this.options.zMin, zMax = this.options.zMax, valMin = Infinity, valMax = -Infinity;
    if (zMin && zMax) {
      return [zMin, zMax];
    }
    allSeries.forEach((series) => {
      series.getColumn("value").forEach((y) => {
        if (defined$p(y)) {
          if (y > valMax) {
            valMax = y;
          }
          if (y < valMin) {
            valMin = y;
          }
        }
      });
    });
    zMin = pick$I(zMin, valMin);
    zMax = pick$I(zMax, valMax);
    return [zMin, zMax];
  }
  /**
   * Check if two bubbles overlaps.
   * @private
   */
  checkOverlap(bubble1, bubble2) {
    const diffX = bubble1[0] - bubble2[0], diffY = bubble1[1] - bubble2[1], sumRad = bubble1[2] + bubble2[2];
    return Math.sqrt(diffX * diffX + diffY * diffY) - Math.abs(sumRad) < -1e-3;
  }
  /**
   * Creating parent nodes for split series, in which all the bubbles
   * are rendered.
   * @private
   */
  createParentNodes() {
    const PackedBubblePoint2 = this.pointClass, chart = this.chart, parentNodeLayout = this.parentNodeLayout, layoutOptions = this.layout.options;
    let nodeAdded, parentNode = this.parentNode, parentMarkerOptions = {
      radius: this.parentNodeRadius,
      lineColor: this.color,
      fillColor: color$8(this.color).brighten(0.4).get()
    };
    if (layoutOptions.parentNodeOptions) {
      parentMarkerOptions = merge$G(layoutOptions.parentNodeOptions.marker || {}, parentMarkerOptions);
    }
    this.parentNodeMass = 0;
    this.points.forEach((p) => {
      this.parentNodeMass += Math.PI * Math.pow(p.marker.radius, 2);
    });
    this.calculateParentRadius();
    parentNodeLayout.nodes.forEach((node) => {
      if (node.seriesIndex === this.index) {
        nodeAdded = true;
      }
    });
    parentNodeLayout.setArea(0, 0, chart.plotWidth, chart.plotHeight);
    if (!nodeAdded) {
      if (!parentNode) {
        parentNode = new PackedBubblePoint2(this, {
          mass: this.parentNodeRadius / 2,
          marker: parentMarkerOptions,
          dataLabels: {
            inside: false
          },
          states: {
            normal: {
              marker: parentMarkerOptions
            },
            hover: {
              marker: parentMarkerOptions
            }
          },
          dataLabelOnNull: true,
          degree: this.parentNodeRadius,
          isParentNode: true,
          seriesIndex: this.index
        });
        this.chart.allParentNodes.push(parentNode);
      }
      if (this.parentNode) {
        parentNode.plotX = this.parentNode.plotX;
        parentNode.plotY = this.parentNode.plotY;
      }
      this.parentNode = parentNode;
      parentNodeLayout.addElementsToCollection([this], parentNodeLayout.series);
      parentNodeLayout.addElementsToCollection([parentNode], parentNodeLayout.nodes);
    }
  }
  /**
   * Function responsible for adding all the layouts to the chart.
   * @private
   */
  deferLayout() {
    const layoutOptions = this.options.layoutAlgorithm;
    if (!this.visible) {
      return;
    }
    this.addLayout();
    if (layoutOptions.splitSeries) {
      this.addSeriesLayout();
    }
  }
  destroy() {
    if (this.chart.graphLayoutsLookup) {
      this.chart.graphLayoutsLookup.forEach((layout) => {
        layout.removeElementFromCollection(this, layout.series);
      }, this);
    }
    if (this.parentNode && this.parentNodeLayout) {
      this.parentNodeLayout.removeElementFromCollection(this.parentNode, this.parentNodeLayout.nodes);
      if (this.parentNode.dataLabel) {
        this.parentNode.dataLabel = this.parentNode.dataLabel.destroy();
      }
    }
    seriesProto$1.destroy.apply(this, arguments);
  }
  /**
   * Packedbubble has two separate collections of nodes if split, render
   * dataLabels for both sets:
   * @private
   */
  drawDataLabels() {
    if (this.deferDataLabels) {
      return;
    }
    seriesProto$1.drawDataLabels.call(this, this.points);
    if (this.parentNode) {
      this.parentNode.formatPrefix = "parentNode";
      seriesProto$1.drawDataLabels.call(this, [this.parentNode]);
    }
  }
  /**
   * Create Background/Parent Nodes for split series.
   * @private
   */
  drawGraph() {
    if (!this.layout || !this.layout.options.splitSeries) {
      return;
    }
    const chart = this.chart, nodeMarker = this.layout.options.parentNodeOptions.marker, parentOptions = {
      fill: nodeMarker.fillColor || color$8(this.color).brighten(0.4).get(),
      opacity: nodeMarker.fillOpacity,
      stroke: nodeMarker.lineColor || this.color,
      "stroke-width": pick$I(nodeMarker.lineWidth, this.options.lineWidth)
    };
    let parentAttribs = {};
    this.parentNodesGroup = this.plotGroup("parentNodesGroup", "parentNode", this.visible ? "inherit" : "hidden", 0.1, chart.seriesGroup);
    this.group?.attr({
      zIndex: 2
    });
    this.calculateParentRadius();
    if (this.parentNode && defined$p(this.parentNode.plotX) && defined$p(this.parentNode.plotY) && defined$p(this.parentNodeRadius)) {
      parentAttribs = merge$G({
        x: this.parentNode.plotX - this.parentNodeRadius,
        y: this.parentNode.plotY - this.parentNodeRadius,
        width: this.parentNodeRadius * 2,
        height: this.parentNodeRadius * 2
      }, parentOptions);
      if (!this.parentNode.graphic) {
        this.graph = this.parentNode.graphic = chart.renderer.symbol(parentOptions.symbol).add(this.parentNodesGroup);
      }
      this.parentNode.graphic.attr(parentAttribs);
    }
  }
  drawTracker() {
    const parentNode = this.parentNode;
    let dataLabels;
    super.drawTracker();
    if (parentNode) {
      dataLabels = isArray$9(parentNode.dataLabels) ? parentNode.dataLabels : parentNode.dataLabel ? [parentNode.dataLabel] : [];
      if (parentNode.graphic) {
        parentNode.graphic.element.point = parentNode;
      }
      dataLabels.forEach((dataLabel) => {
        (dataLabel.div || dataLabel.element).point = parentNode;
      });
    }
  }
  /**
   * Calculate radius of bubbles in series.
   * @private
   */
  getPointRadius() {
    const chart = this.chart, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, seriesOptions = this.options, useSimulation = seriesOptions.useSimulation, smallestSize = Math.min(plotWidth, plotHeight), extremes = {}, radii = [], allDataPoints = chart.allDataPoints || [], allDataPointsLength = allDataPoints.length;
    let minSize, maxSize, value, radius;
    ["minSize", "maxSize"].forEach((prop) => {
      const length = parseInt(seriesOptions[prop], 10), isPercent = /%$/.test(seriesOptions[prop]);
      extremes[prop] = isPercent ? smallestSize * length / 100 : length * Math.sqrt(allDataPointsLength);
    });
    chart.minRadius = minSize = extremes.minSize / Math.sqrt(allDataPointsLength);
    chart.maxRadius = maxSize = extremes.maxSize / Math.sqrt(allDataPointsLength);
    const zExtremes = useSimulation ? this.calculateZExtremes() : [minSize, maxSize];
    allDataPoints.forEach((point, i) => {
      value = useSimulation ? clamp$7(point[2], zExtremes[0], zExtremes[1]) : point[2];
      radius = this.getRadius(zExtremes[0], zExtremes[1], minSize, maxSize, value);
      if (radius === 0) {
        radius = null;
      }
      allDataPoints[i][2] = radius;
      radii.push(radius);
    });
    this.radii = radii;
  }
  init() {
    seriesProto$1.init.apply(this, arguments);
    initDataLabelsDefer.call(this);
    this.eventsToUnbind.push(addEvent$x(this, "updatedData", function() {
      this.chart.series.forEach((s) => {
        if (s.type === this.type) {
          s.isDirty = true;
        }
      }, this);
    }));
    return this;
  }
  /**
   * Mouse up action, finalizing drag&drop.
   * @private
   * @param {Highcharts.Point} point The point that event occurred.
   */
  onMouseUp(dnPoint) {
    const point = dnPoint;
    if (point.fixedPosition && !point.removed) {
      const layout = this.layout, parentNodeLayout = this.parentNodeLayout;
      let distanceXY, distanceR;
      if (!point.isParentNode && parentNodeLayout && layout.options.dragBetweenSeries) {
        parentNodeLayout.nodes.forEach((node) => {
          if (point && point.marker && node !== point.series.parentNode) {
            distanceXY = layout.getDistXY(point, node);
            distanceR = layout.vectorLength(distanceXY) - node.marker.radius - point.marker.radius;
            if (distanceR < 0) {
              node.series.addPoint(merge$G(point.options, {
                plotX: point.plotX,
                plotY: point.plotY
              }), false);
              layout.removeElementFromCollection(point, layout.nodes);
              point.remove();
            }
          }
        });
      }
      DragNodesComposition.onMouseUp.apply(this, arguments);
    }
  }
  /**
   * This is the main function responsible
   * for positioning all of the bubbles
   * allDataPoints - bubble array, in format [pixel x value,
   * pixel y value, radius,
   * related series index, related point index]
   * @private
   * @param {Array<Highcharts.PackedBubbleData>} allDataPoints All points from all series
   * @return {Array<Highcharts.PackedBubbleData>} Positions of all bubbles
   */
  placeBubbles(allDataPoints) {
    const checkOverlap = this.checkOverlap, positionBubble = this.positionBubble, bubblePos = [];
    let stage = 1, j = 0, k = 0, calculatedBubble, arr = [], i;
    const sortedArr = allDataPoints.sort((a, b) => b[2] - a[2]);
    if (sortedArr.length) {
      bubblePos.push([
        [
          0,
          // Starting in 0,0 coordinates
          0,
          sortedArr[0][2],
          // Radius
          sortedArr[0][3],
          // Series index
          sortedArr[0][4]
        ]
        // Point index
      ]);
      if (sortedArr.length > 1) {
        bubblePos.push([
          [
            0,
            0 - sortedArr[1][2] - sortedArr[0][2],
            // Move bubble above first one
            sortedArr[1][2],
            sortedArr[1][3],
            sortedArr[1][4]
          ]
        ]);
        for (i = 2; i < sortedArr.length; i++) {
          sortedArr[i][2] = sortedArr[i][2] || 1;
          calculatedBubble = positionBubble(bubblePos[stage][j], bubblePos[stage - 1][k], sortedArr[i]);
          if (checkOverlap(calculatedBubble, bubblePos[stage][0])) {
            bubblePos.push([]);
            k = 0;
            bubblePos[stage + 1].push(positionBubble(bubblePos[stage][j], bubblePos[stage][0], sortedArr[i]));
            stage++;
            j = 0;
          } else if (stage > 1 && bubblePos[stage - 1][k + 1] && checkOverlap(calculatedBubble, bubblePos[stage - 1][k + 1])) {
            k++;
            bubblePos[stage].push(positionBubble(bubblePos[stage][j], bubblePos[stage - 1][k], sortedArr[i]));
            j++;
          } else {
            j++;
            bubblePos[stage].push(calculatedBubble);
          }
        }
      }
      this.chart.stages = bubblePos;
      this.chart.rawPositions = [].concat.apply([], bubblePos);
      this.resizeRadius();
      arr = this.chart.rawPositions;
    }
    return arr;
  }
  /**
   * Function that checks for a parentMarker and sets the correct opacity.
   * @private
   * @param {Highcharts.Pack} point
   * Candidate point for opacity correction.
   * @param {string} [state]
   * The point state, can be either `hover`, `select` or 'normal'. If
   * undefined, normal state is assumed.
   *
   * @return {Highcharts.SVGAttributes}
   * The presentational attributes to be set on the point.
   */
  pointAttribs(point, state) {
    const options2 = this.options, hasParentMarker = point && point.isParentNode;
    let markerOptions = options2.marker;
    if (hasParentMarker && options2.layoutAlgorithm && options2.layoutAlgorithm.parentNodeOptions) {
      markerOptions = options2.layoutAlgorithm.parentNodeOptions.marker;
    }
    const fillOpacity = markerOptions.fillOpacity, attr2 = seriesProto$1.pointAttribs.call(this, point, state);
    if (fillOpacity !== 1) {
      attr2["fill-opacity"] = fillOpacity;
    }
    return attr2;
  }
  /**
   * Function that is adding one bubble based on positions and sizes of
   * two other bubbles, lastBubble is the last added bubble, newOrigin is
   * the bubble for positioning new bubbles. nextBubble is the currently
   * added bubble for which we are calculating positions
   * @private
   * @param {Array<number>} lastBubble The closest last bubble
   * @param {Array<number>} newOrigin New bubble
   * @param {Array<number>} nextBubble The closest next bubble
   * @return {Array<number>} Bubble with correct positions
   */
  positionBubble(lastBubble, newOrigin, nextBubble) {
    const sqrt = Math.sqrt, asin = Math.asin, acos = Math.acos, pow = Math.pow, abs2 = Math.abs, distance = sqrt(
      // Dist between lastBubble and newOrigin
      pow(lastBubble[0] - newOrigin[0], 2) + pow(lastBubble[1] - newOrigin[1], 2)
    ), alfa = acos(
      // From cosinus theorem: alfa is an angle used for
      // calculating correct position
      (pow(distance, 2) + pow(nextBubble[2] + newOrigin[2], 2) - pow(nextBubble[2] + lastBubble[2], 2)) / (2 * (nextBubble[2] + newOrigin[2]) * distance)
    ), beta = asin(
      // From sinus theorem.
      abs2(lastBubble[0] - newOrigin[0]) / distance
    ), gamma = lastBubble[1] - newOrigin[1] < 0 ? 0 : Math.PI, delta = (lastBubble[0] - newOrigin[0]) * (lastBubble[1] - newOrigin[1]) < 0 ? 1 : -1, finalAngle = gamma + alfa + beta * delta, cosA = Math.cos(finalAngle), sinA = Math.sin(finalAngle), posX = newOrigin[0] + (newOrigin[2] + nextBubble[2]) * sinA, posY = newOrigin[1] - (newOrigin[2] + nextBubble[2]) * cosA;
    return [
      posX,
      posY,
      nextBubble[2],
      nextBubble[3],
      nextBubble[4]
    ];
  }
  render() {
    const dataLabels = [];
    seriesProto$1.render.apply(this, arguments);
    if (!this.options.dataLabels.allowOverlap) {
      this.data.forEach((point) => {
        if (isArray$9(point.dataLabels)) {
          point.dataLabels.forEach((dataLabel) => {
            dataLabels.push(dataLabel);
          });
        }
      });
      if (this.options.useSimulation) {
        this.chart.hideOverlappingLabels(dataLabels);
      }
    }
  }
  /**
   * The function responsible for resizing the bubble radius.
   * In shortcut: it is taking the initially
   * calculated positions of bubbles. Then it is calculating the min max
   * of both dimensions, creating something in shape of bBox.
   * The comparison of bBox and the size of plotArea
   * (later it may be also the size set by customer) is giving the
   * value how to recalculate the radius so it will match the size
   * @private
   */
  resizeRadius() {
    const chart = this.chart, positions = chart.rawPositions, min2 = Math.min, max2 = Math.max, plotLeft = chart.plotLeft, plotTop = chart.plotTop, chartHeight = chart.plotHeight, chartWidth = chart.plotWidth;
    let minX, maxX, minY, maxY, radius;
    minX = minY = Number.POSITIVE_INFINITY;
    maxX = maxY = Number.NEGATIVE_INFINITY;
    for (const position of positions) {
      radius = position[2];
      minX = min2(minX, position[0] - radius);
      maxX = max2(maxX, position[0] + radius);
      minY = min2(minY, position[1] - radius);
      maxY = max2(maxY, position[1] + radius);
    }
    const bBox = [maxX - minX, maxY - minY], spaceRatio = [
      (chartWidth - plotLeft) / bBox[0],
      (chartHeight - plotTop) / bBox[1]
    ], smallerDimension = min2.apply([], spaceRatio);
    if (Math.abs(smallerDimension - 1) > 1e-10) {
      for (const position of positions) {
        position[2] *= smallerDimension;
      }
      this.placeBubbles(positions);
    } else {
      chart.diffY = chartHeight / 2 + plotTop - minY - (maxY - minY) / 2;
      chart.diffX = chartWidth / 2 + plotLeft - minX - (maxX - minX) / 2;
    }
  }
  /**
   * The function responsible for calculating series bubble' s bBox.
   * Needed because of exporting failure when useSimulation
   * is set to false
   * @private
   */
  seriesBox() {
    const chart = this.chart, data = this.data, max2 = Math.max, min2 = Math.min, bBox = [
      chart.plotLeft,
      chart.plotLeft + chart.plotWidth,
      chart.plotTop,
      chart.plotTop + chart.plotHeight
    ];
    let radius;
    data.forEach((p) => {
      if (defined$p(p.plotX) && defined$p(p.plotY) && p.marker.radius) {
        radius = p.marker.radius;
        bBox[0] = min2(bBox[0], p.plotX - radius);
        bBox[1] = max2(bBox[1], p.plotX + radius);
        bBox[2] = min2(bBox[2], p.plotY - radius);
        bBox[3] = max2(bBox[3], p.plotY + radius);
      }
    });
    return isNumber$p(bBox.width / bBox.height) ? bBox : null;
  }
  /**
   * Needed because of z-indexing issue if point is added in series.group
   * @private
   */
  setVisible() {
    const series = this;
    seriesProto$1.setVisible.apply(series, arguments);
    if (series.parentNodeLayout && series.graph) {
      if (series.visible) {
        series.graph.show();
        if (series.parentNode.dataLabel) {
          series.parentNode.dataLabel.show();
        }
      } else {
        series.graph.hide();
        series.parentNodeLayout.removeElementFromCollection(series.parentNode, series.parentNodeLayout.nodes);
        if (series.parentNode.dataLabel) {
          series.parentNode.dataLabel.hide();
        }
      }
    } else if (series.layout) {
      if (series.visible) {
        series.layout.addElementsToCollection(series.points, series.layout.nodes);
      } else {
        series.points.forEach((node) => {
          series.layout.removeElementFromCollection(node, series.layout.nodes);
        });
      }
    }
  }
  /**
   * Extend the base translate method to handle bubble size,
   * and correct positioning them.
   * @private
   */
  translate() {
    const chart = this.chart, data = this.data, index = this.index, useSimulation = this.options.useSimulation;
    let point, radius, positions;
    this.generatePoints();
    if (!defined$p(chart.allDataPoints)) {
      chart.allDataPoints = this.accumulateAllPoints();
      this.getPointRadius();
    }
    if (useSimulation) {
      positions = chart.allDataPoints;
    } else {
      positions = this.placeBubbles(chart.allDataPoints);
      this.options.draggable = false;
    }
    for (const position of positions) {
      if (position[3] === index) {
        point = data[position[4]];
        radius = pick$I(position[2], void 0);
        if (!useSimulation) {
          point.plotX = position[0] - chart.plotLeft + chart.diffX;
          point.plotY = position[1] - chart.plotTop + chart.diffY;
        }
        if (isNumber$p(radius)) {
          point.marker = extend$C(point.marker, {
            radius,
            width: 2 * radius,
            height: 2 * radius
          });
          point.radius = radius;
        }
      }
    }
    if (useSimulation) {
      this.deferLayout();
    }
    fireEvent$c(this, "afterTranslate");
  }
}
PackedBubbleSeries.defaultOptions = merge$G(BubbleSeries.defaultOptions, PackedBubbleSeriesDefaults);
extend$C(PackedBubbleSeries.prototype, {
  pointClass: PackedBubblePoint,
  axisTypes: [],
  directTouch: true,
  forces: ["barycenter", "repulsive"],
  hasDraggableNodes: true,
  invertible: false,
  isCartesian: false,
  noSharedTooltip: true,
  pointArrayMap: ["value"],
  pointValKey: "value",
  requireSorting: false,
  trackerGroups: ["group", "dataLabelsGroup", "parentNodesGroup"],
  initDataLabels,
  alignDataLabel: seriesProto$1.alignDataLabel,
  indexateNodes: noop$6,
  onMouseDown: DragNodesComposition.onMouseDown,
  onMouseMove: DragNodesComposition.onMouseMove,
  redrawHalo: DragNodesComposition.redrawHalo,
  searchPoint: noop$6
  // Solving #12287
});
SeriesRegistry$1.registerSeriesType("packedbubble", PackedBubbleSeries);
const PolygonSeriesDefaults = {
  marker: {
    enabled: false,
    states: {
      hover: {
        enabled: false
      }
    }
  },
  stickyTracking: false,
  tooltip: {
    followPointer: true,
    pointFormat: ""
  },
  trackByArea: true,
  legendSymbol: "rectangle"
};
const { noop: noop$5 } = Highcharts;
const { area: AreaSeries, line: LineSeries$3, scatter: ScatterSeries$2 } = SeriesRegistry$1.seriesTypes;
const { extend: extend$B, merge: merge$F } = Utilities;
class PolygonSeries extends ScatterSeries$2 {
  /* *
   *
   *  Functions
   *
   * */
  getGraphPath() {
    const graphPath = LineSeries$3.prototype.getGraphPath.call(this);
    let i = graphPath.length + 1;
    while (i--) {
      if ((i === graphPath.length || graphPath[i][0] === "M") && i > 0) {
        graphPath.splice(i, 0, ["Z"]);
      }
    }
    this.areaPath = graphPath;
    return graphPath;
  }
  drawGraph() {
    this.options.fillColor = this.color;
    AreaSeries.prototype.drawGraph.call(this);
  }
}
PolygonSeries.defaultOptions = merge$F(ScatterSeries$2.defaultOptions, PolygonSeriesDefaults);
extend$B(PolygonSeries.prototype, {
  type: "polygon",
  drawTracker: LineSeries$3.prototype.drawTracker,
  setStackedPoints: noop$5
  // No stacking points on polygons (#5310)
});
SeriesRegistry$1.registerSeriesType("polygon", PolygonSeries);
const defaultCircularOptions = {
  gridLineWidth: 1,
  // Spokes
  labels: {
    align: void 0,
    // Auto
    x: 0,
    y: void 0
    // Auto
  },
  maxPadding: 0,
  minPadding: 0,
  showLastLabel: false,
  tickLength: 0
};
const defaultRadialGaugeOptions = {
  endOnTick: false,
  gridLineWidth: 0,
  labels: {
    align: "center",
    distance: -25,
    x: 0,
    y: void 0
    // Auto
  },
  lineWidth: 1,
  minorGridLineWidth: 0,
  minorTickInterval: "auto",
  minorTickLength: 10,
  minorTickPosition: "inside",
  minorTickWidth: 1,
  startOnTick: false,
  tickLength: 10,
  tickPixelInterval: 100,
  tickPosition: "inside",
  tickWidth: 2,
  title: {
    rotation: 0,
    text: ""
  },
  zIndex: 2
  // Behind dials, points in the series group
};
const defaultRadialOptions = {
  /**
   * In a polar chart, this is the angle of the Y axis in degrees, where
   * 0 is up and 90 is right. The angle determines the position of the
   * axis line and the labels, though the coordinate system is unaffected.
   * Since v8.0.0 this option is also applicable for X axis (inverted
   * polar).
   *
   * @sample {highcharts} highcharts/xaxis/angle/
   *         Custom X axis' angle on inverted polar chart
   * @sample {highcharts} highcharts/yaxis/angle/
   *         Dual axis polar chart
   *
   * @type      {number}
   * @default   0
   * @since     4.2.7
   * @product   highcharts
   * @apioption xAxis.angle
   */
  /**
   * Polar charts only. Whether the grid lines should draw as a polygon
   * with straight lines between categories, or as circles. Can be either
   * `circle` or `polygon`. Since v8.0.0 this option is also applicable
   * for X axis (inverted polar).
   *
   * @sample {highcharts} highcharts/demo/polar-spider/
   *         Polygon grid lines
   * @sample {highcharts} highcharts/xaxis/gridlineinterpolation/
   *         Circle and polygon on inverted polar
   * @sample {highcharts} highcharts/yaxis/gridlineinterpolation/
   *         Circle and polygon
   *
   * @type       {string}
   * @product    highcharts
   * @validvalue ["circle", "polygon"]
   * @apioption  xAxis.gridLineInterpolation
   */
  gridLineInterpolation: "circle",
  gridLineWidth: 1,
  labels: {
    align: "right",
    padding: 5,
    x: -3,
    y: -2
  },
  showLastLabel: false,
  title: {
    x: 4,
    text: null,
    rotation: 90
  }
};
const RadialAxisDefaults = {
  circular: defaultCircularOptions,
  radial: defaultRadialOptions,
  radialGauge: defaultRadialGaugeOptions
};
const { defaultOptions: defaultOptions$7 } = DefaultOptions;
const { composed: composed$d, noop: noop$4 } = Highcharts;
const { addEvent: addEvent$w, correctFloat: correctFloat$4, defined: defined$o, extend: extend$A, fireEvent: fireEvent$b, isObject: isObject$9, merge: merge$E, pick: pick$H, pushUnique: pushUnique$d, relativeLength: relativeLength$8, wrap: wrap$b } = Utilities;
var RadialAxis;
(function(RadialAxis2) {
  RadialAxis2.radialDefaultOptions = merge$E(RadialAxisDefaults);
  function beforeSetTickPositions() {
    this.autoConnect = this.isCircular && typeof pick$H(this.userMax, this.options.max) === "undefined" && correctFloat$4(this.endAngleRad - this.startAngleRad) === correctFloat$4(2 * Math.PI);
    if (!this.isCircular && this.chart.inverted) {
      this.max++;
    }
    if (this.autoConnect) {
      this.max += this.categories && 1 || this.pointRange || this.closestPointRange || 0;
    }
  }
  function compose2(AxisClass, TickClass) {
    if (pushUnique$d(composed$d, "Axis.Radial")) {
      addEvent$w(AxisClass, "afterInit", onAxisAfterInit);
      addEvent$w(AxisClass, "autoLabelAlign", onAxisAutoLabelAlign);
      addEvent$w(AxisClass, "destroy", onAxisDestroy2);
      addEvent$w(AxisClass, "init", onAxisInit2);
      addEvent$w(AxisClass, "initialAxisTranslation", onAxisInitialAxisTranslation);
      addEvent$w(TickClass, "afterGetLabelPosition", onTickAfterGetLabelPosition2);
      addEvent$w(TickClass, "afterGetPosition", onTickAfterGetPosition);
      addEvent$w(Highcharts, "setOptions", onGlobalSetOptions);
      wrap$b(TickClass.prototype, "getMarkPath", wrapTickGetMarkPath2);
    }
    return AxisClass;
  }
  RadialAxis2.compose = compose2;
  function createLabelCollector() {
    return () => {
      if (this.isRadial && this.tickPositions && // Undocumented option for now, but working
      this.options.labels && this.options.labels.allowOverlap !== true) {
        return this.tickPositions.map((pos) => this.ticks[pos]?.label).filter((label) => Boolean(label));
      }
    };
  }
  function createLabelCollectorHidden() {
    return noop$4;
  }
  function getCrosshairPosition(options2, x1, y1) {
    const center = this.pane.center;
    let value = options2.value, shapeArgs, end, x2, y2;
    if (this.isCircular) {
      if (!defined$o(value)) {
        x2 = options2.chartX || 0;
        y2 = options2.chartY || 0;
        value = this.translate(Math.atan2(y2 - y1, x2 - x1) - this.startAngleRad, true);
      } else if (options2.point) {
        shapeArgs = options2.point.shapeArgs || {};
        if (shapeArgs.start) {
          value = this.chart.inverted ? this.translate(options2.point.rectPlotY, true) : options2.point.x;
        }
      }
      end = this.getPosition(value);
      x2 = end.x;
      y2 = end.y;
    } else {
      if (!defined$o(value)) {
        x2 = options2.chartX;
        y2 = options2.chartY;
      }
      if (defined$o(x2) && defined$o(y2)) {
        y1 = center[1] + this.chart.plotTop;
        value = this.translate(Math.min(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)), center[2] / 2) - center[3] / 2, true);
      }
    }
    return [value, x2 || 0, y2 || 0];
  }
  function getLinePath(_lineWidth, radius, innerRadius) {
    const center = this.pane.center, chart = this.chart, left = this.left || 0, top = this.top || 0;
    let end, r = pick$H(radius, center[2] / 2 - this.offset), path;
    if (typeof innerRadius === "undefined") {
      innerRadius = this.horiz ? 0 : this.center && -this.center[3] / 2;
    }
    if (innerRadius) {
      r += innerRadius;
    }
    if (this.isCircular || typeof radius !== "undefined") {
      path = this.chart.renderer.symbols.arc(left + center[0], top + center[1], r, r, {
        start: this.startAngleRad,
        end: this.endAngleRad,
        open: true,
        innerR: 0
      });
      path.xBounds = [left + center[0]];
      path.yBounds = [top + center[1] - r];
    } else {
      end = this.postTranslate(this.angleRad, r);
      path = [
        [
          "M",
          this.center[0] + chart.plotLeft,
          this.center[1] + chart.plotTop
        ],
        ["L", end.x, end.y]
      ];
    }
    return path;
  }
  function getOffset2() {
    const axisProto = this.constructor.prototype;
    axisProto.getOffset.call(this);
    this.chart.axisOffset[this.side] = 0;
  }
  function getPlotBandPath(from, to, options2) {
    const chart = this.chart, radiusToPixels = (radius) => {
      if (typeof radius === "string") {
        let r = parseInt(radius, 10);
        if (percentRegex.test(radius)) {
          r = r * fullRadius / 100;
        }
        return r;
      }
      return radius;
    }, center = this.center, startAngleRad = this.startAngleRad, fullRadius = center[2] / 2, offset2 = Math.min(this.offset, 0), left = this.left || 0, top = this.top || 0, percentRegex = /%$/, isCircular = this.isCircular;
    let start2, end, angle, xOnPerimeter, open2, path, outerRadius = pick$H(radiusToPixels(options2.outerRadius), fullRadius), innerRadius = radiusToPixels(options2.innerRadius), thickness = pick$H(radiusToPixels(options2.thickness), 10);
    if (this.options.gridLineInterpolation === "polygon") {
      path = this.getPlotLinePath({ value: from }).concat(this.getPlotLinePath({ value: to, reverse: true }));
    } else {
      from = Math.max(from, this.min);
      to = Math.min(to, this.max);
      const transFrom = this.translate(from), transTo = this.translate(to);
      if (!isCircular) {
        outerRadius = transFrom || 0;
        innerRadius = transTo || 0;
      }
      if (options2.shape === "circle" || !isCircular) {
        start2 = -Math.PI / 2;
        end = Math.PI * 1.5;
        open2 = true;
      } else {
        start2 = startAngleRad + (transFrom || 0);
        end = startAngleRad + (transTo || 0);
      }
      outerRadius -= offset2;
      thickness -= offset2;
      path = chart.renderer.symbols.arc(left + center[0], top + center[1], outerRadius, outerRadius, {
        // Math is for reversed yAxis (#3606)
        start: Math.min(start2, end),
        end: Math.max(start2, end),
        innerR: pick$H(innerRadius, outerRadius - thickness),
        open: open2,
        borderRadius: options2.borderRadius
      });
      if (isCircular) {
        angle = (end + start2) / 2;
        xOnPerimeter = left + center[0] + center[2] / 2 * Math.cos(angle);
        path.xBounds = angle > -Math.PI / 2 && angle < Math.PI / 2 ? (
          // Right hemisphere
          [xOnPerimeter, chart.plotWidth]
        ) : (
          // Left hemisphere
          [0, xOnPerimeter]
        );
        path.yBounds = [
          top + center[1] + center[2] / 2 * Math.sin(angle)
        ];
        path.yBounds[0] += angle > -Math.PI && angle < 0 || angle > Math.PI ? -10 : 10;
      }
    }
    return path;
  }
  function getPlotLinePath(options2) {
    const center = this.pane.center, chart = this.chart, inverted = chart.inverted, reverse = options2.reverse, background2 = this.pane.options.background ? this.pane.options.background[0] || this.pane.options.background : {}, innerRadius = background2.innerRadius || "0%", outerRadius = background2.outerRadius || "100%", x1 = center[0] + chart.plotLeft, y1 = center[1] + chart.plotTop, height = this.height, isCrosshair = options2.isCrosshair, paneInnerR = center[3] / 2;
    let value = options2.value, innerRatio, distance, a, b, otherAxis, xy, tickPositions, crossPos, path;
    const end = this.getPosition(value);
    let x2 = end.x, y2 = end.y;
    if (isCrosshair) {
      crossPos = this.getCrosshairPosition(options2, x1, y1);
      value = crossPos[0];
      x2 = crossPos[1];
      y2 = crossPos[2];
    }
    if (this.isCircular) {
      distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
      a = typeof innerRadius === "string" ? relativeLength$8(innerRadius, 1) : innerRadius / distance;
      b = typeof outerRadius === "string" ? relativeLength$8(outerRadius, 1) : outerRadius / distance;
      if (center && paneInnerR) {
        innerRatio = paneInnerR / distance;
        if (a < innerRatio) {
          a = innerRatio;
        }
        if (b < innerRatio) {
          b = innerRatio;
        }
      }
      path = [
        ["M", x1 + a * (x2 - x1), y1 - a * (y1 - y2)],
        ["L", x2 - (1 - b) * (x2 - x1), y2 + (1 - b) * (y1 - y2)]
      ];
    } else {
      value = this.translate(value);
      if (value) {
        if (value < 0 || value > height) {
          value = 0;
        }
      }
      if (this.options.gridLineInterpolation === "circle") {
        path = this.getLinePath(0, value, paneInnerR);
      } else {
        path = [];
        chart[inverted ? "yAxis" : "xAxis"].forEach((a3) => {
          if (a3.pane === this.pane) {
            otherAxis = a3;
          }
        });
        if (otherAxis) {
          tickPositions = otherAxis.tickPositions;
          if (otherAxis.autoConnect) {
            tickPositions = tickPositions.concat([tickPositions[0]]);
          }
          if (reverse) {
            tickPositions = tickPositions.slice().reverse();
          }
          if (value) {
            value += paneInnerR;
          }
          for (let i = 0; i < tickPositions.length; i++) {
            xy = otherAxis.getPosition(tickPositions[i], value);
            path.push(i ? ["L", xy.x, xy.y] : ["M", xy.x, xy.y]);
          }
        }
      }
    }
    return path;
  }
  function getPosition(value, length) {
    const translatedVal = this.translate(value);
    return this.postTranslate(
      this.isCircular ? translatedVal : this.angleRad,
      // #2848
      // In case when translatedVal is negative, the 0 value must be
      // used instead, in order to deal with lines and labels that
      // fall out of the visible range near the center of a pane
      pick$H(this.isCircular ? length : translatedVal < 0 ? 0 : translatedVal, this.center[2] / 2) - this.offset
    );
  }
  function getTitlePosition() {
    const center = this.center, chart = this.chart, titleOptions = this.options.title;
    return {
      x: chart.plotLeft + center[0] + (titleOptions.x || 0),
      y: chart.plotTop + center[1] - {
        high: 0.5,
        middle: 0.25,
        low: 0
      }[titleOptions.align] * center[2] + (titleOptions.y || 0)
    };
  }
  function modify(axis) {
    axis.beforeSetTickPositions = beforeSetTickPositions;
    axis.createLabelCollector = createLabelCollector;
    axis.getCrosshairPosition = getCrosshairPosition;
    axis.getLinePath = getLinePath;
    axis.getOffset = getOffset2;
    axis.getPlotBandPath = getPlotBandPath;
    axis.getPlotLinePath = getPlotLinePath;
    axis.getPosition = getPosition;
    axis.getTitlePosition = getTitlePosition;
    axis.postTranslate = postTranslate;
    axis.setAxisSize = setAxisSize;
    axis.setAxisTranslation = setAxisTranslation;
    axis.setOptions = setOptions2;
  }
  function modifyAsHidden(radialAxis) {
    radialAxis.isHidden = true;
    radialAxis.createLabelCollector = createLabelCollectorHidden;
    radialAxis.getOffset = noop$4;
    radialAxis.redraw = renderHidden;
    radialAxis.render = renderHidden;
    radialAxis.setScale = noop$4;
    radialAxis.setCategories = noop$4;
    radialAxis.setTitle = noop$4;
  }
  function onAxisAfterInit() {
    const chart = this.chart, options2 = this.options, isHidden = chart.angular && this.isXAxis, pane2 = this.pane, paneOptions = pane2?.options;
    if (!isHidden && pane2 && (chart.angular || chart.polar)) {
      const fullCircle = Math.PI * 2, start2 = (pick$H(paneOptions.startAngle, 0) - 90) * Math.PI / 180, end = (pick$H(paneOptions.endAngle, pick$H(paneOptions.startAngle, 0) + 360) - 90) * Math.PI / 180;
      this.angleRad = (options2.angle || 0) * Math.PI / 180;
      this.startAngleRad = start2;
      this.endAngleRad = end;
      this.offset = options2.offset || 0;
      let normalizedStart = (start2 % fullCircle + fullCircle) % fullCircle, normalizedEnd = (end % fullCircle + fullCircle) % fullCircle;
      if (normalizedStart > Math.PI) {
        normalizedStart -= fullCircle;
      }
      if (normalizedEnd > Math.PI) {
        normalizedEnd -= fullCircle;
      }
      this.normalizedStartAngleRad = normalizedStart;
      this.normalizedEndAngleRad = normalizedEnd;
    }
  }
  function onAxisAutoLabelAlign(e) {
    if (this.isRadial) {
      e.align = void 0;
      e.preventDefault();
    }
  }
  function onAxisDestroy2() {
    if (this.chart?.labelCollectors) {
      const index = this.labelCollector ? this.chart.labelCollectors.indexOf(this.labelCollector) : -1;
      if (index >= 0) {
        this.chart.labelCollectors.splice(index, 1);
      }
    }
  }
  function onAxisInit2(e) {
    const chart = this.chart, angular = chart.angular, polar = chart.polar, isX = this.isXAxis, coll = this.coll, isHidden = angular && isX, paneIndex = e.userOptions.pane || 0, pane2 = this.pane = chart.pane && chart.pane[paneIndex];
    let isCircular;
    if (coll === "colorAxis") {
      this.isRadial = false;
      return;
    }
    if (angular) {
      if (isHidden) {
        modifyAsHidden(this);
      } else {
        modify(this);
      }
      isCircular = !isX;
    } else if (polar) {
      modify(this);
      isCircular = this.horiz;
    }
    if (angular || polar) {
      this.isRadial = true;
      if (!this.labelCollector) {
        this.labelCollector = this.createLabelCollector();
      }
      if (this.labelCollector) {
        chart.labelCollectors.push(this.labelCollector);
      }
    } else {
      this.isRadial = false;
    }
    if (pane2 && isCircular) {
      pane2.axis = this;
    }
    this.isCircular = isCircular;
  }
  function onAxisInitialAxisTranslation() {
    if (this.isRadial) {
      this.beforeSetTickPositions();
    }
  }
  function onTickAfterGetLabelPosition2(e) {
    const label = this.label;
    if (!label) {
      return;
    }
    const axis = this.axis, labelBBox = label.getBBox(), labelOptions = axis.options.labels, angle = (axis.translate(this.pos) + axis.startAngleRad + Math.PI / 2) / Math.PI * 180 % 360, correctAngle = Math.round(angle), labelYPosCorrection = !defined$o(labelOptions.y) ? -labelBBox.height * 0.3 : 0;
    let optionsY = labelOptions.y, ret, centerSlot = 20, align = labelOptions.align, labelDir = "end", reducedAngle1 = correctAngle < 0 ? correctAngle + 360 : correctAngle, reducedAngle2 = reducedAngle1, translateY = 0, translateX = 0;
    if (axis.isRadial) {
      ret = axis.getPosition(this.pos, axis.center[2] / 2 + relativeLength$8(pick$H(labelOptions.distance, -25), axis.center[2] / 2, -axis.center[2] / 2));
      if (labelOptions.rotation === "auto") {
        label.attr({
          rotation: angle
        });
      } else if (!defined$o(optionsY)) {
        optionsY = axis.chart.renderer.fontMetrics(label).b - labelBBox.height / 2;
      }
      if (!defined$o(align)) {
        if (axis.isCircular) {
          if (labelBBox.width > axis.len * axis.tickInterval / (axis.max - axis.min)) {
            centerSlot = 0;
          }
          if (angle > centerSlot && angle < 180 - centerSlot) {
            align = "left";
          } else if (angle > 180 + centerSlot && angle < 360 - centerSlot) {
            align = "right";
          } else {
            align = "center";
          }
        } else {
          align = "center";
        }
        label.attr({
          align
        });
      }
      if (align === "auto" && axis.tickPositions.length === 2 && axis.isCircular) {
        if (reducedAngle1 > 90 && reducedAngle1 < 180) {
          reducedAngle1 = 180 - reducedAngle1;
        } else if (reducedAngle1 > 270 && reducedAngle1 <= 360) {
          reducedAngle1 = 540 - reducedAngle1;
        }
        if (reducedAngle2 > 180 && reducedAngle2 <= 360) {
          reducedAngle2 = 360 - reducedAngle2;
        }
        if (axis.pane.options.startAngle === correctAngle || axis.pane.options.startAngle === correctAngle + 360 || axis.pane.options.startAngle === correctAngle - 360) {
          labelDir = "start";
        }
        if (correctAngle >= -90 && correctAngle <= 90 || correctAngle >= -360 && correctAngle <= -270 || correctAngle >= 270 && correctAngle <= 360) {
          align = labelDir === "start" ? "right" : "left";
        } else {
          align = labelDir === "start" ? "left" : "right";
        }
        if (reducedAngle2 > 70 && reducedAngle2 < 110) {
          align = "center";
        }
        if (reducedAngle1 < 15 || reducedAngle1 >= 180 && reducedAngle1 < 195) {
          translateY = labelBBox.height * 0.3;
        } else if (reducedAngle1 >= 15 && reducedAngle1 <= 35) {
          translateY = labelDir === "start" ? 0 : labelBBox.height * 0.75;
        } else if (reducedAngle1 >= 195 && reducedAngle1 <= 215) {
          translateY = labelDir === "start" ? labelBBox.height * 0.75 : 0;
        } else if (reducedAngle1 > 35 && reducedAngle1 <= 90) {
          translateY = labelDir === "start" ? -labelBBox.height * 0.25 : labelBBox.height;
        } else if (reducedAngle1 > 215 && reducedAngle1 <= 270) {
          translateY = labelDir === "start" ? labelBBox.height : -labelBBox.height * 0.25;
        }
        if (reducedAngle2 < 15) {
          translateX = labelDir === "start" ? -labelBBox.height * 0.15 : labelBBox.height * 0.15;
        } else if (reducedAngle2 > 165 && reducedAngle2 <= 180) {
          translateX = labelDir === "start" ? labelBBox.height * 0.15 : -labelBBox.height * 0.15;
        }
        label.attr({ align });
        label.translate(translateX, translateY + labelYPosCorrection);
      }
      e.pos.x = ret.x + (labelOptions.x || 0);
      e.pos.y = ret.y + (optionsY || 0);
    }
  }
  function onTickAfterGetPosition(e) {
    if (this.axis.getPosition) {
      extend$A(e.pos, this.axis.getPosition(this.pos));
    }
  }
  function onGlobalSetOptions({ options: options2 }) {
    if (options2.xAxis) {
      merge$E(true, RadialAxis2.radialDefaultOptions.circular, options2.xAxis);
    }
    if (options2.yAxis) {
      merge$E(true, RadialAxis2.radialDefaultOptions.radialGauge, options2.yAxis);
    }
  }
  function postTranslate(angle, radius) {
    const chart = this.chart, center = this.center;
    angle = this.startAngleRad + angle;
    return {
      x: chart.plotLeft + center[0] + Math.cos(angle) * radius,
      y: chart.plotTop + center[1] + Math.sin(angle) * radius
    };
  }
  function renderHidden() {
    this.isDirty = false;
  }
  function setAxisSize() {
    const axisProto = this.constructor.prototype;
    let center, start2;
    axisProto.setAxisSize.call(this);
    if (this.isRadial) {
      this.pane.updateCenter(this);
      center = this.center = this.pane.center.slice();
      if (this.isCircular) {
        this.sector = this.endAngleRad - this.startAngleRad;
      } else {
        start2 = this.postTranslate(this.angleRad, center[3] / 2);
        center[0] = start2.x - this.chart.plotLeft;
        center[1] = start2.y - this.chart.plotTop;
      }
      this.len = this.width = this.height = (center[2] - center[3]) * pick$H(this.sector, 1) / 2;
    }
  }
  function setAxisTranslation() {
    const axisProto = this.constructor.prototype;
    axisProto.setAxisTranslation.call(this);
    if (this.center) {
      if (this.isCircular) {
        this.transA = (this.endAngleRad - this.startAngleRad) / (this.max - this.min || 1);
      } else {
        this.transA = (this.center[2] - this.center[3]) / 2 / (this.max - this.min || 1);
      }
      if (this.isXAxis) {
        this.minPixelPadding = this.transA * this.minPointOffset;
      } else {
        this.minPixelPadding = 0;
      }
    }
  }
  function setOptions2(userOptions) {
    const { coll } = this;
    const { angular, inverted, polar } = this.chart;
    let defaultPolarOptions = {};
    if (angular) {
      if (!this.isXAxis) {
        defaultPolarOptions = merge$E(defaultOptions$7.yAxis, RadialAxis2.radialDefaultOptions.radialGauge);
      }
    } else if (polar) {
      defaultPolarOptions = this.horiz ? merge$E(defaultOptions$7.xAxis, RadialAxis2.radialDefaultOptions.circular) : merge$E(coll === "xAxis" ? defaultOptions$7.xAxis : defaultOptions$7.yAxis, RadialAxis2.radialDefaultOptions.radial);
    }
    if (inverted && coll === "yAxis") {
      defaultPolarOptions.stackLabels = isObject$9(defaultOptions$7.yAxis, true) ? defaultOptions$7.yAxis.stackLabels : {};
      defaultPolarOptions.reversedStacks = true;
    }
    const options2 = this.options = merge$E(defaultPolarOptions, userOptions);
    if (!options2.plotBands) {
      options2.plotBands = [];
    }
    fireEvent$b(this, "afterSetOptions");
  }
  function wrapTickGetMarkPath2(proceed, x, y, tickLength, tickWidth, horiz, renderer) {
    const axis = this.axis;
    let endPoint, ret;
    if (axis.isRadial) {
      endPoint = axis.getPosition(this.pos, axis.center[2] / 2 + tickLength);
      ret = [
        "M",
        x,
        y,
        "L",
        endPoint.x,
        endPoint.y
      ];
    } else {
      ret = proceed.call(this, x, y, tickLength, tickWidth, horiz, renderer);
    }
    return ret;
  }
})(RadialAxis || (RadialAxis = {}));
const RadialAxis$1 = RadialAxis;
const { animObject: animObject$4 } = animationExports;
const { composed: composed$c } = Highcharts;
const { addEvent: addEvent$v, defined: defined$n, find: find$6, isNumber: isNumber$o, merge: merge$D, pick: pick$G, pushUnique: pushUnique$c, relativeLength: relativeLength$7, splat: splat$9, uniqueKey: uniqueKey$1, wrap: wrap$a } = Utilities;
function clipCircle(renderer, x, y, r, innerR) {
  const id = uniqueKey$1(), clipPath = renderer.createElement("clipPath").attr({
    id
  }).add(renderer.defs), wrapper = innerR ? renderer.arc(x, y, r, innerR, 0, 2 * Math.PI).add(clipPath) : renderer.circle(x, y, r).add(clipPath);
  wrapper.id = id;
  wrapper.clipPath = clipPath;
  return wrapper;
}
function findAlignments(angle, options2) {
  let align, verticalAlign;
  if (options2.align === null) {
    if (angle > 20 && angle < 160) {
      align = "left";
    } else if (angle > 200 && angle < 340) {
      align = "right";
    } else {
      align = "center";
    }
    options2.align = align;
  }
  if (options2.verticalAlign === null) {
    if (angle < 45 || angle > 315) {
      verticalAlign = "bottom";
    } else if (angle > 135 && angle < 225) {
      verticalAlign = "top";
    } else {
      verticalAlign = "middle";
    }
    options2.verticalAlign = verticalAlign;
  }
  return options2;
}
function getConnectors(segment, index, calculateNeighbours, connectEnds) {
  const smoothing = 1.5, denom = smoothing + 1, addedNumber = connectEnds ? 1 : 0;
  let i, leftContX, leftContY, rightContX, rightContY, jointAngle;
  if (index >= 0 && index <= segment.length - 1) {
    i = index;
  } else if (index < 0) {
    i = segment.length - 1 + index;
  } else {
    i = 0;
  }
  const prevPointInd = i - 1 < 0 ? segment.length - (1 + addedNumber) : i - 1, nextPointInd = i + 1 > segment.length - 1 ? addedNumber : i + 1, previousPoint = segment[prevPointInd], nextPoint = segment[nextPointInd], previousX = previousPoint.plotX, previousY = previousPoint.plotY, nextX = nextPoint.plotX, nextY = nextPoint.plotY, plotX = segment[i].plotX, plotY = segment[i].plotY;
  leftContX = (smoothing * plotX + previousX) / denom;
  leftContY = (smoothing * plotY + previousY) / denom;
  rightContX = (smoothing * plotX + nextX) / denom;
  rightContY = (smoothing * plotY + nextY) / denom;
  const dLControlPoint = Math.sqrt(Math.pow(leftContX - plotX, 2) + Math.pow(leftContY - plotY, 2)), dRControlPoint = Math.sqrt(Math.pow(rightContX - plotX, 2) + Math.pow(rightContY - plotY, 2)), leftContAngle = Math.atan2(leftContY - plotY, leftContX - plotX), rightContAngle = Math.atan2(rightContY - plotY, rightContX - plotX);
  jointAngle = Math.PI / 2 + (leftContAngle + rightContAngle) / 2;
  if (Math.abs(leftContAngle - jointAngle) > Math.PI / 2) {
    jointAngle -= Math.PI;
  }
  leftContX = plotX + Math.cos(jointAngle) * dLControlPoint;
  leftContY = plotY + Math.sin(jointAngle) * dLControlPoint;
  rightContX = plotX + Math.cos(Math.PI + jointAngle) * dRControlPoint;
  rightContY = plotY + Math.sin(Math.PI + jointAngle) * dRControlPoint;
  const ret = {
    rightContX,
    rightContY,
    leftContX,
    leftContY,
    plotX,
    plotY
  };
  if (calculateNeighbours) {
    ret.prevPointCont = getConnectors(segment, prevPointInd, false, connectEnds);
  }
  return ret;
}
function onChartAfterDrawChartBox() {
  (this.pane || []).forEach((pane2) => {
    pane2.render();
  });
}
function onChartAfterInit(event) {
  const xAxis2 = event.args[0].xAxis, yAxis2 = event.args[0].yAxis, chart = event.args[0].chart;
  if (xAxis2 && yAxis2) {
    if (yAxis2.gridLineInterpolation === "polygon") {
      xAxis2.startOnTick = true;
      xAxis2.endOnTick = true;
    } else if (xAxis2.gridLineInterpolation === "polygon" && chart.inverted) {
      yAxis2.startOnTick = true;
      yAxis2.endOnTick = true;
    }
  }
}
function onChartCreateAxes() {
  if (!this.pane) {
    this.pane = [];
  }
  this.options.pane = splat$9(this.options.pane || {});
  this.options.pane.forEach((paneOptions) => {
    new Pane(
      // eslint-disable-line no-new
      paneOptions,
      this
    );
  }, this);
}
function onPointerGetSelectionBox(event) {
  const marker = event.args.marker, xAxis2 = this.chart.xAxis[0], yAxis2 = this.chart.yAxis[0], inverted = this.chart.inverted, radialAxis = inverted ? yAxis2 : xAxis2, linearAxis = inverted ? xAxis2 : yAxis2;
  if (this.chart.polar) {
    event.preventDefault();
    const start2 = (marker.attr ? marker.attr("start") : marker.start) - radialAxis.startAngleRad, r = marker.attr ? marker.attr("r") : marker.r, end = (marker.attr ? marker.attr("end") : marker.end) - radialAxis.startAngleRad, innerR = marker.attr ? marker.attr("innerR") : marker.innerR;
    event.result.x = start2 + radialAxis.pos;
    event.result.width = end - start2;
    event.result.y = linearAxis.len + linearAxis.pos - r;
    event.result.height = r - innerR;
  }
}
function onPointerGetSelectionMarkerAttrs(event) {
  const chart = this.chart;
  if (chart.polar && chart.hoverPane && chart.hoverPane.axis) {
    event.preventDefault();
    const center = chart.hoverPane.center, mouseDownX = chart.mouseDownX || 0, mouseDownY = chart.mouseDownY || 0, chartY = event.args.chartY, chartX = event.args.chartX, fullCircle = Math.PI * 2, startAngleRad = chart.hoverPane.axis.startAngleRad, endAngleRad = chart.hoverPane.axis.endAngleRad, linearAxis = chart.inverted ? chart.xAxis[0] : chart.yAxis[0], attrs = {};
    let shapeType = "arc";
    attrs.x = center[0] + chart.plotLeft;
    attrs.y = center[1] + chart.plotTop;
    if (this.zoomHor) {
      const paneRadRange = startAngleRad > 0 ? endAngleRad - startAngleRad : Math.abs(startAngleRad) + Math.abs(endAngleRad);
      let startAngle = Math.atan2(mouseDownY - chart.plotTop - center[1], mouseDownX - chart.plotLeft - center[0]) - startAngleRad, endAngle = Math.atan2(chartY - chart.plotTop - center[1], chartX - chart.plotLeft - center[0]) - startAngleRad;
      attrs.r = center[2] / 2;
      attrs.innerR = center[3] / 2;
      if (startAngle <= 0) {
        startAngle += fullCircle;
      }
      if (endAngle <= 0) {
        endAngle += fullCircle;
      }
      if (endAngle < startAngle) {
        endAngle = [startAngle, startAngle = endAngle][0];
      }
      if (paneRadRange < fullCircle) {
        const swapAngle = endAngleRad + (fullCircle - paneRadRange) / 2;
        if (startAngleRad + endAngle > swapAngle) {
          endAngle = startAngle;
          startAngle = startAngleRad <= 0 ? startAngleRad : 0;
        }
      }
      const start2 = attrs.start = Math.max(startAngle + startAngleRad, startAngleRad), end = attrs.end = Math.min(endAngle + startAngleRad, endAngleRad);
      if (linearAxis.options.gridLineInterpolation === "polygon") {
        const radialAxis = chart.hoverPane.axis, min2 = start2 - radialAxis.startAngleRad + radialAxis.pos, max2 = end - start2;
        let path = linearAxis.getPlotLinePath({
          value: linearAxis.max
        }), pathStart = radialAxis.toValue(min2), pathEnd = radialAxis.toValue(min2 + max2);
        if (pathStart < radialAxis.getExtremes().min) {
          const { min: min3, max: max3 } = radialAxis.getExtremes();
          pathStart = max3 - (min3 - pathStart);
        }
        if (pathEnd < radialAxis.getExtremes().min) {
          const { min: min3, max: max3 } = radialAxis.getExtremes();
          pathEnd = max3 - (min3 - pathEnd);
        }
        if (pathEnd < pathStart) {
          pathEnd = [pathStart, pathStart = pathEnd][0];
        }
        path = trimPath(path, pathStart, pathEnd, radialAxis);
        path.push([
          "L",
          center[0] + chart.plotLeft,
          chart.plotTop + center[1]
        ]);
        attrs.d = path;
        shapeType = "path";
      }
    }
    if (this.zoomVert) {
      const linearAxis2 = chart.inverted ? chart.xAxis[0] : chart.yAxis[0];
      let innerR = Math.sqrt(Math.pow(mouseDownX - chart.plotLeft - center[0], 2) + Math.pow(mouseDownY - chart.plotTop - center[1], 2)), r = Math.sqrt(Math.pow(chartX - chart.plotLeft - center[0], 2) + Math.pow(chartY - chart.plotTop - center[1], 2));
      if (r < innerR) {
        innerR = [r, r = innerR][0];
      }
      if (r > center[2] / 2) {
        r = center[2] / 2;
      }
      if (innerR < center[3] / 2) {
        innerR = center[3] / 2;
      }
      if (!this.zoomHor) {
        attrs.start = startAngleRad;
        attrs.end = endAngleRad;
      }
      attrs.r = r;
      attrs.innerR = innerR;
      if (linearAxis2.options.gridLineInterpolation === "polygon") {
        const end = linearAxis2.toValue(linearAxis2.len + linearAxis2.pos - innerR), start2 = linearAxis2.toValue(linearAxis2.len + linearAxis2.pos - r), path = linearAxis2.getPlotLinePath({
          value: start2
        }).concat(linearAxis2.getPlotLinePath({
          value: end,
          reverse: true
        }));
        attrs.d = path;
        shapeType = "path";
      }
    }
    if (this.zoomHor && this.zoomVert && linearAxis.options.gridLineInterpolation === "polygon") {
      const radialAxis = chart.hoverPane.axis, start2 = attrs.start || 0, end = attrs.end || 0, min2 = start2 - radialAxis.startAngleRad + radialAxis.pos, max2 = end - start2, pathStart = radialAxis.toValue(min2), pathEnd = radialAxis.toValue(min2 + max2);
      if (attrs.d instanceof Array) {
        let innerPath = attrs.d.slice(0, attrs.d.length / 2), outerPath = attrs.d.slice(attrs.d.length / 2, attrs.d.length);
        outerPath = [...outerPath].reverse();
        const radialAxis2 = chart.hoverPane.axis;
        innerPath = trimPath(innerPath, pathStart, pathEnd, radialAxis2);
        outerPath = trimPath(outerPath, pathStart, pathEnd, radialAxis2);
        if (outerPath) {
          outerPath[0][0] = "L";
        }
        outerPath = [...outerPath].reverse();
        attrs.d = innerPath.concat(outerPath);
        shapeType = "path";
      }
    }
    event.attrs = attrs;
    event.shapeType = shapeType;
  }
}
function onSeriesAfterInit() {
  const chart = this.chart;
  if (chart.polar) {
    this.polar = new PolarAdditions(this);
    if (chart.inverted) {
      this.isRadialSeries = true;
      if (this.is("column")) {
        this.isRadialBar = true;
      }
    }
  }
}
function onSeriesAfterTranslate() {
  if (this.chart.polar && this.xAxis) {
    const series = this, { xAxis: xAxis2, yAxis: yAxis2 } = series, chart = series.chart;
    series.kdByAngle = chart.tooltip && chart.tooltip.shared;
    if (series.kdByAngle || chart.inverted) {
      series.searchPoint = searchPointByAngleOrInverted;
    } else {
      series.options.findNearestPointBy = "xy";
    }
    const points = series.points;
    let i = points.length;
    while (i--) {
      if (!series.is("column") && !series.is("columnrange")) {
        series.polar.toXY(points[i]);
      }
      if (!chart.hasParallelCoordinates && !series.yAxis.reversed) {
        if (pick$G(points[i].y, Number.MIN_VALUE) < yAxis2.min || points[i].x < xAxis2.min || points[i].x > xAxis2.max) {
          points[i].isNull = true;
          points[i].plotY = NaN;
        } else {
          points[i].isNull = points[i].isValid && !points[i].isValid();
        }
      }
    }
    if (!this.hasClipCircleSetter) {
      this.hasClipCircleSetter = !!series.eventsToUnbind.push(addEvent$v(series, "afterRender", function() {
        let circ;
        if (chart.polar && this.options.clip !== false) {
          circ = this.yAxis.pane.center;
          if (!this.clipCircle) {
            this.clipCircle = clipCircle(chart.renderer, circ[0], circ[1], circ[2] / 2, circ[3] / 2);
          } else {
            this.clipCircle.animate({
              x: circ[0],
              y: circ[1],
              r: circ[2] / 2,
              innerR: circ[3] / 2
            });
          }
          this.group.clip(this.clipCircle);
          this.setClip = Highcharts.noop;
        }
      }));
    }
  }
}
function searchPointByAngleOrInverted(e) {
  const series = this, chart = series.chart, xAxis2 = series.xAxis, yAxis2 = series.yAxis, center = xAxis2.pane && xAxis2.pane.center, plotX = e.chartX - (center && center[0] || 0) - chart.plotLeft, plotY = e.chartY - (center && center[1] || 0) - chart.plotTop;
  const searchKDTreePoint = chart.inverted ? {
    clientX: e.chartX - yAxis2.pos,
    plotY: e.chartY - xAxis2.pos
  } : {
    clientX: 180 + Math.atan2(plotX, plotY) * (-180 / Math.PI)
  };
  return series.searchKDTree(searchKDTreePoint);
}
function trimPath(path, start2, end, radialAxis) {
  const tickInterval = radialAxis.tickInterval, ticks = radialAxis.tickPositions;
  let lastTick = find$6(ticks, (tick) => tick >= end), firstTick = find$6([...ticks].reverse(), (tick) => tick <= start2);
  if (!defined$n(lastTick)) {
    lastTick = ticks[ticks.length - 1];
  }
  if (!defined$n(firstTick)) {
    firstTick = ticks[0];
    lastTick += tickInterval;
    path[0][0] = "L";
    path.unshift(path[path.length - 3]);
  }
  path = path.slice(ticks.indexOf(firstTick), ticks.indexOf(lastTick) + 1);
  path[0][0] = "M";
  return path;
}
function wrapChartGet(proceed, id) {
  return find$6(this.pane || [], (pane2) => (
    // @todo remove id or define id type:
    pane2.options.id === id
  )) || proceed.call(this, id);
}
function wrapColumnSeriesAlignDataLabel(proceed, point, dataLabel, options2, alignTo, isNew) {
  const chart = this.chart, inside = pick$G(options2.inside, !!this.options.stacking);
  let angle, shapeArgs, labelPos;
  if (chart.polar) {
    angle = point.rectPlotX / Math.PI * 180;
    if (!chart.inverted) {
      options2 = findAlignments(angle, options2);
    } else {
      this.forceDL = chart.isInsidePlot(point.plotX, point.plotY);
      if (inside && point.shapeArgs) {
        shapeArgs = point.shapeArgs;
        labelPos = this.yAxis.postTranslate(
          // Angle
          ((shapeArgs.start || 0) + (shapeArgs.end || 0)) / 2 - this.xAxis.startAngleRad,
          // Radius
          point.barX + point.pointWidth / 2
        );
        alignTo = merge$D(alignTo, {
          x: labelPos.x - chart.plotLeft,
          y: labelPos.y - chart.plotTop
        });
      } else if (point.tooltipPos) {
        alignTo = merge$D(alignTo, {
          x: point.tooltipPos[0],
          y: point.tooltipPos[1]
        });
      }
      options2.align = pick$G(options2.align, "center");
      options2.verticalAlign = pick$G(options2.verticalAlign, "middle");
    }
    Series$9.prototype.alignDataLabel.call(this, point, dataLabel, options2, alignTo, isNew);
    if (this.isRadialBar && point.shapeArgs && point.shapeArgs.start === point.shapeArgs.end) {
      dataLabel.hide();
    } else {
      dataLabel.show();
    }
  } else {
    proceed.call(this, point, dataLabel, options2, alignTo, isNew);
  }
}
function onAfterColumnTranslate() {
  const series = this, options2 = series.options, stacking = options2.stacking, chart = series.chart, xAxis2 = series.xAxis, yAxis2 = series.yAxis, reversed = yAxis2.reversed, center = yAxis2.center, startAngleRad = xAxis2.startAngleRad, endAngleRad = xAxis2.endAngleRad, visibleRange = endAngleRad - startAngleRad;
  let threshold = options2.threshold, thresholdAngleRad = 0, points, point, i, yMin, yMax, start2 = 0, end = 0, tooltipPos, pointX, pointY, stackValues, stack, barX, innerR, r;
  if (xAxis2.isRadial) {
    points = series.points;
    i = points.length;
    yMin = yAxis2.translate(yAxis2.min);
    yMax = yAxis2.translate(yAxis2.max);
    threshold = options2.threshold || 0;
    if (chart.inverted) {
      if (isNumber$o(threshold)) {
        thresholdAngleRad = yAxis2.translate(threshold);
        if (defined$n(thresholdAngleRad)) {
          if (thresholdAngleRad < 0) {
            thresholdAngleRad = 0;
          } else if (thresholdAngleRad > visibleRange) {
            thresholdAngleRad = visibleRange;
          }
          series.translatedThreshold = thresholdAngleRad + startAngleRad;
        }
      }
    }
    while (i--) {
      point = points[i];
      barX = point.barX;
      pointX = point.x;
      pointY = point.y;
      point.shapeType = "arc";
      if (chart.inverted) {
        point.plotY = yAxis2.translate(pointY);
        if (stacking && yAxis2.stacking) {
          stack = yAxis2.stacking.stacks[(pointY < 0 ? "-" : "") + series.stackKey];
          if (series.visible && stack && stack[pointX]) {
            if (!point.isNull) {
              stackValues = stack[pointX].points[series.getStackIndicator(void 0, pointX, series.index).key];
              start2 = yAxis2.translate(stackValues[0]);
              end = yAxis2.translate(stackValues[1]);
              if (defined$n(start2)) {
                start2 = Utilities.clamp(start2, 0, visibleRange);
              }
            }
          }
        } else {
          start2 = thresholdAngleRad;
          end = point.plotY;
        }
        if (start2 > end) {
          end = [start2, start2 = end][0];
        }
        if (!reversed) {
          if (start2 < yMin) {
            start2 = yMin;
          } else if (end > yMax) {
            end = yMax;
          } else if (end < yMin || start2 > yMax) {
            start2 = end = 0;
          }
        } else {
          if (end > yMin) {
            end = yMin;
          } else if (start2 < yMax) {
            start2 = yMax;
          } else if (start2 > yMin || end < yMax) {
            start2 = end = visibleRange;
          }
        }
        if (yAxis2.min > yAxis2.max) {
          start2 = end = reversed ? visibleRange : 0;
        }
        start2 += startAngleRad;
        end += startAngleRad;
        if (center) {
          point.barX = barX += center[3] / 2;
        }
        innerR = Math.max(barX, 0);
        r = Math.max(barX + point.pointWidth, 0);
        const brOption = options2.borderRadius, brValue = typeof brOption === "object" ? brOption.radius : brOption, borderRadius = relativeLength$7(brValue || 0, r - innerR);
        point.shapeArgs = {
          x: center[0],
          y: center[1],
          r,
          innerR,
          start: start2,
          end,
          borderRadius
        };
        point.opacity = start2 === end ? 0 : void 0;
        point.plotY = (defined$n(series.translatedThreshold) && (start2 < series.translatedThreshold ? start2 : end)) - startAngleRad;
      } else {
        start2 = barX + startAngleRad;
        point.shapeArgs = series.polar.arc(point.yBottom, point.plotY, start2, start2 + point.pointWidth);
        point.shapeArgs.borderRadius = 0;
      }
      series.polar.toXY(point);
      if (chart.inverted) {
        tooltipPos = yAxis2.postTranslate(point.rectPlotY, barX + point.pointWidth / 2);
        point.tooltipPos = [
          tooltipPos.x - chart.plotLeft,
          tooltipPos.y - chart.plotTop
        ];
      } else {
        point.tooltipPos = [point.plotX, point.plotY];
      }
      if (center) {
        point.ttBelow = point.plotY > center[1];
      }
    }
  }
}
function wrapLineSeriesGetGraphPath(proceed, points) {
  const series = this;
  let firstValid, popLastPoint;
  if (this.chart.polar) {
    points = points || this.points;
    for (let i = 0; i < points.length; i++) {
      if (!points[i].isNull) {
        firstValid = i;
        break;
      }
    }
    if (this.options.connectEnds !== false && typeof firstValid !== "undefined") {
      this.connectEnds = true;
      points.splice(points.length, 0, points[firstValid]);
      popLastPoint = true;
    }
    points.forEach((point) => {
      if (typeof point.polarPlotY === "undefined") {
        series.polar.toXY(point);
      }
    });
  }
  const ret = proceed.apply(this, [].slice.call(arguments, 1));
  if (popLastPoint) {
    points.pop();
  }
  return ret;
}
function wrapPointerGetCoordinates(proceed, e) {
  const chart = this.chart;
  let ret = {
    xAxis: [],
    yAxis: []
  };
  if (chart.polar) {
    chart.axes.forEach((axis) => {
      if (axis.coll === "colorAxis") {
        return;
      }
      const isXAxis = axis.isXAxis, center = axis.center, x = e.chartX - center[0] - chart.plotLeft, y = e.chartY - center[1] - chart.plotTop;
      ret[isXAxis ? "xAxis" : "yAxis"].push({
        axis,
        value: axis.translate(isXAxis ? Math.PI - Math.atan2(x, y) : (
          // Angle
          // distance from center
          Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
        ), true)
      });
    });
  } else {
    ret = proceed.call(this, e);
  }
  return ret;
}
function wrapPointerPinch(proceed, e) {
  if (this.chart.polar) {
    return;
  }
  proceed.call(this, e);
}
function wrapSeriesAnimate(proceed, init2) {
  const series = this, chart = this.chart, group2 = this.group, markerGroup = this.markerGroup, center = this.xAxis && this.xAxis.center, plotLeft = chart.plotLeft, plotTop = chart.plotTop;
  let animation = this.options.animation, attribs, paneInnerR, graphic, shapeArgs, r, innerR;
  if (chart.polar) {
    if (series.isRadialBar) {
      if (!init2) {
        series.startAngleRad = pick$G(series.translatedThreshold, series.xAxis.startAngleRad);
        Highcharts.seriesTypes.pie.prototype.animate.call(series, init2);
      }
    } else {
      animation = animObject$4(animation);
      if (series.is("column")) {
        if (!init2) {
          paneInnerR = center[3] / 2;
          series.points.forEach((point) => {
            graphic = point.graphic;
            shapeArgs = point.shapeArgs;
            r = shapeArgs && shapeArgs.r;
            innerR = shapeArgs && shapeArgs.innerR;
            if (graphic && shapeArgs) {
              graphic.attr({
                r: paneInnerR,
                innerR: paneInnerR
              });
              graphic.animate({
                r,
                innerR
              }, series.options.animation);
            }
          });
        }
      } else {
        if (init2) {
          attribs = {
            translateX: center[0] + plotLeft,
            translateY: center[1] + plotTop,
            scaleX: 1e-3,
            scaleY: 1e-3
          };
          group2.attr(attribs);
          if (markerGroup) {
            markerGroup.attr(attribs);
          }
        } else {
          attribs = {
            translateX: plotLeft,
            translateY: plotTop,
            scaleX: 1,
            scaleY: 1
          };
          group2.animate(attribs, animation);
          if (markerGroup) {
            markerGroup.animate(attribs, animation);
          }
        }
      }
    }
  } else {
    proceed.call(this, init2);
  }
}
function wrapSplineSeriesGetPointSpline(proceed, segment, point, i) {
  let ret, connectors;
  if (this.chart.polar) {
    if (!i) {
      ret = ["M", point.plotX, point.plotY];
    } else {
      connectors = getConnectors(segment, i, true, this.connectEnds);
      const rightContX = connectors.prevPointCont && connectors.prevPointCont.rightContX;
      const rightContY = connectors.prevPointCont && connectors.prevPointCont.rightContY;
      ret = [
        "C",
        isNumber$o(rightContX) ? rightContX : connectors.plotX,
        isNumber$o(rightContY) ? rightContY : connectors.plotY,
        isNumber$o(connectors.leftContX) ? connectors.leftContX : connectors.plotX,
        isNumber$o(connectors.leftContY) ? connectors.leftContY : connectors.plotY,
        connectors.plotX,
        connectors.plotY
      ];
    }
  } else {
    ret = proceed.call(this, segment, point, i);
  }
  return ret;
}
function wrapPointPos(proceed, chartCoordinates, plotY = this.plotY) {
  if (!this.destroyed) {
    const { plotX, series } = this, { chart } = series;
    if (chart.polar && isNumber$o(plotX) && isNumber$o(plotY)) {
      return [
        plotX + (chartCoordinates ? chart.plotLeft : 0),
        plotY + (chartCoordinates ? chart.plotTop : 0)
      ];
    }
    return proceed.call(this, chartCoordinates, plotY);
  }
}
class PolarAdditions {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AxisClass, ChartClass, PointerClass, SeriesClass, TickClass, PointClass, AreaSplineRangeSeriesClass, ColumnSeriesClass, LineSeriesClass, SplineSeriesClass) {
    Pane.compose(ChartClass, PointerClass);
    RadialAxis$1.compose(AxisClass, TickClass);
    if (pushUnique$c(composed$c, "Polar")) {
      const chartProto = ChartClass.prototype, pointProto2 = PointClass.prototype, pointerProto = PointerClass.prototype, seriesProto2 = SeriesClass.prototype;
      addEvent$v(ChartClass, "afterDrawChartBox", onChartAfterDrawChartBox);
      addEvent$v(ChartClass, "createAxes", onChartCreateAxes);
      addEvent$v(ChartClass, "init", onChartAfterInit);
      wrap$a(chartProto, "get", wrapChartGet);
      wrap$a(pointerProto, "getCoordinates", wrapPointerGetCoordinates);
      wrap$a(pointerProto, "pinch", wrapPointerPinch);
      addEvent$v(PointerClass, "getSelectionMarkerAttrs", onPointerGetSelectionMarkerAttrs);
      addEvent$v(PointerClass, "getSelectionBox", onPointerGetSelectionBox);
      addEvent$v(SeriesClass, "afterInit", onSeriesAfterInit);
      addEvent$v(
        SeriesClass,
        "afterTranslate",
        onSeriesAfterTranslate,
        { order: 2 }
        // Run after translation of ||-coords
      );
      addEvent$v(SeriesClass, "afterColumnTranslate", onAfterColumnTranslate, { order: 4 });
      wrap$a(seriesProto2, "animate", wrapSeriesAnimate);
      wrap$a(pointProto2, "pos", wrapPointPos);
      if (ColumnSeriesClass) {
        const columnProto2 = ColumnSeriesClass.prototype;
        wrap$a(columnProto2, "alignDataLabel", wrapColumnSeriesAlignDataLabel);
        wrap$a(columnProto2, "animate", wrapSeriesAnimate);
      }
      if (LineSeriesClass) {
        const lineProto2 = LineSeriesClass.prototype;
        wrap$a(lineProto2, "getGraphPath", wrapLineSeriesGetGraphPath);
      }
      if (SplineSeriesClass) {
        const splineProto2 = SplineSeriesClass.prototype;
        wrap$a(splineProto2, "getPointSpline", wrapSplineSeriesGetPointSpline);
        if (AreaSplineRangeSeriesClass) {
          const areaSplineRangeProto = AreaSplineRangeSeriesClass.prototype;
          areaSplineRangeProto.getPointSpline = splineProto2.getPointSpline;
        }
      }
    }
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(series) {
    this.series = series;
  }
  /* *
   *
   *  Functions
   *
   * */
  arc(low2, high2, start2, end) {
    const series = this.series, center = series.xAxis.center, len = series.yAxis.len, paneInnerR = center[3] / 2;
    let r = len - high2 + paneInnerR, innerR = len - pick$G(low2, len) + paneInnerR;
    if (series.yAxis.reversed) {
      if (r < 0) {
        r = paneInnerR;
      }
      if (innerR < 0) {
        innerR = paneInnerR;
      }
    }
    return {
      x: center[0],
      y: center[1],
      r,
      innerR,
      start: start2,
      end
    };
  }
  /**
   * Translate a point's plotX and plotY from the internal angle and radius
   * measures to true plotX, plotY coordinates
   * @private
   */
  toXY(point) {
    const series = this.series, chart = series.chart, xAxis2 = series.xAxis, yAxis2 = series.yAxis, plotX = point.plotX, inverted = chart.inverted, pointY = point.y;
    let plotY = point.plotY, radius = inverted ? plotX : yAxis2.len - plotY, clientX;
    if (inverted && series && !series.isRadialBar) {
      point.plotY = plotY = isNumber$o(pointY) ? yAxis2.translate(pointY) : 0;
    }
    point.rectPlotX = plotX;
    point.rectPlotY = plotY;
    if (yAxis2.center) {
      radius += yAxis2.center[3] / 2;
    }
    if (isNumber$o(plotY)) {
      const xy = inverted ? yAxis2.postTranslate(plotY, radius) : xAxis2.postTranslate(plotX, radius);
      point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
      point.plotY = point.polarPlotY = xy.y - chart.plotTop;
    }
    if (series.kdByAngle) {
      clientX = (plotX / Math.PI * 180 + xAxis2.pane.options.startAngle) % 360;
      if (clientX < 0) {
        clientX += 360;
      }
      point.clientX = clientX;
    } else {
      point.clientX = point.plotX;
    }
  }
}
const { composed: composed$b } = Highcharts;
const { addEvent: addEvent$u, objectEach: objectEach$8, pushUnique: pushUnique$b } = Utilities;
var WaterfallAxis;
(function(WaterfallAxis2) {
  function compose2(AxisClass, ChartClass) {
    if (pushUnique$b(composed$b, "Axis.Waterfall")) {
      addEvent$u(AxisClass, "init", onAxisInit2);
      addEvent$u(AxisClass, "afterBuildStacks", onAxisAfterBuildStacks);
      addEvent$u(AxisClass, "afterRender", onAxisAfterRender2);
      addEvent$u(ChartClass, "beforeRedraw", onChartBeforeRedraw2);
    }
  }
  WaterfallAxis2.compose = compose2;
  function onAxisAfterBuildStacks() {
    const axis = this, stacks = axis.waterfall.stacks;
    if (stacks) {
      stacks.changed = false;
      delete stacks.alreadyChanged;
    }
  }
  function onAxisAfterRender2() {
    const axis = this, stackLabelOptions = axis.options.stackLabels;
    if (stackLabelOptions?.enabled && axis.waterfall.stacks) {
      axis.waterfall.renderStackTotals();
    }
  }
  function onAxisInit2() {
    const axis = this;
    if (!axis.waterfall) {
      axis.waterfall = new Composition(axis);
    }
  }
  function onChartBeforeRedraw2() {
    const axes = this.axes, series = this.series;
    for (const serie of series) {
      if (serie.options.stacking) {
        for (const axis of axes) {
          if (!axis.isXAxis) {
            axis.waterfall.stacks.changed = true;
          }
        }
        break;
      }
    }
  }
  class Composition {
    /* *
     *
     *  Constructors
     *
     * */
    constructor(axis) {
      this.axis = axis;
      this.stacks = {
        changed: false
      };
    }
    /* *
     *
     *  Functions
     *
     * */
    /**
     * Calls StackItem.prototype.render function that creates and renders
     * stack total label for each waterfall stack item.
     *
     * @private
     * @function Highcharts.Axis#renderWaterfallStackTotals
     */
    renderStackTotals() {
      const yAxis2 = this.axis, waterfallStacks = yAxis2.waterfall.stacks, stackTotalGroup = yAxis2.stacking?.stackTotalGroup, dummyStackItem = new StackItem(yAxis2, yAxis2.options.stackLabels || {}, false, 0, void 0);
      this.dummyStackItem = dummyStackItem;
      if (stackTotalGroup) {
        objectEach$8(waterfallStacks, (type) => {
          objectEach$8(type, (stackItem, key2) => {
            dummyStackItem.total = stackItem.stackTotal;
            dummyStackItem.x = +key2;
            if (stackItem.label) {
              dummyStackItem.label = stackItem.label;
            }
            StackItem.prototype.render.call(dummyStackItem, stackTotalGroup);
            stackItem.label = dummyStackItem.label;
            delete dummyStackItem.label;
          });
        });
      }
      dummyStackItem.total = null;
    }
  }
  WaterfallAxis2.Composition = Composition;
})(WaterfallAxis || (WaterfallAxis = {}));
const WaterfallAxis$1 = WaterfallAxis;
const { isNumber: isNumber$n } = Utilities;
class WaterfallPoint extends ColumnSeries$f.prototype.pointClass {
  /* *
   *
   *  Functions
   *
   * */
  getClassName() {
    let className = Point$3.prototype.getClassName.call(this);
    if (this.isSum) {
      className += " highcharts-sum";
    } else if (this.isIntermediateSum) {
      className += " highcharts-intermediate-sum";
    }
    return className;
  }
  // Pass the null test in ColumnSeries.translate.
  isValid() {
    return isNumber$n(this.y) || this.isSum || Boolean(this.isIntermediateSum);
  }
}
const WaterfallSeriesDefaults = {
  /**
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @apioption plotOptions.waterfall.color
   */
  /**
   * The color used specifically for positive point columns. When not
   * specified, the general series color is used.
   *
   * In styled mode, the waterfall colors can be set with the
   * `.highcharts-point-negative`, `.highcharts-sum` and
   * `.highcharts-intermediate-sum` classes.
   *
   * @sample {highcharts} highcharts/demo/waterfall/
   *         Waterfall
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highcharts
   * @apioption plotOptions.waterfall.upColor
   */
  dataLabels: {
    inside: true
  },
  /**
   * The width of the line connecting waterfall columns.
   *
   * @product highcharts
   */
  lineWidth: 1,
  /**
   * The color of the line that connects columns in a waterfall series.
   *
   * In styled mode, the stroke can be set with the `.highcharts-graph`
   * class.
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since   3.0
   * @product highcharts
   */
  lineColor: "#333333",
  /**
   * A name for the dash style to use for the line connecting the columns
   * of the waterfall series. Possible values: Dash, DashDot, Dot,
   * LongDash, LongDashDot, LongDashDotDot, ShortDash, ShortDashDot,
   * ShortDashDotDot, ShortDot, Solid
   *
   * In styled mode, the stroke dash-array can be set with the
   * `.highcharts-graph` class.
   *
   * @type    {Highcharts.DashStyleValue}
   * @since   3.0
   * @product highcharts
   */
  dashStyle: "Dot",
  /**
   * The color of the border of each waterfall column.
   *
   * In styled mode, the border stroke can be set with the
   * `.highcharts-point` class.
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since   3.0
   * @product highcharts
   */
  borderColor: "#333333",
  states: {
    hover: {
      lineWidthPlus: 0
      // #3126
    }
  }
};
const { column: ColumnSeries$7, line: LineSeries$2 } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$t, arrayMax: arrayMax$2, arrayMin: arrayMin$1, correctFloat: correctFloat$3, crisp: crisp$4, extend: extend$z, isNumber: isNumber$m, merge: merge$C, objectEach: objectEach$7, pick: pick$F } = Utilities;
function ownProp(obj, key2) {
  return Object.hasOwnProperty.call(obj, key2);
}
class WaterfallSeries extends ColumnSeries$7 {
  /* *
   *
   *  Functions
   *
   * */
  // After generating points, set y-values for all sums.
  generatePoints() {
    ColumnSeries$7.prototype.generatePoints.apply(this);
    const processedYData = this.getColumn("y", true);
    for (let i = 0, len = this.points.length; i < len; i++) {
      const point = this.points[i], y = processedYData[i];
      if (isNumber$m(y) && (point.isIntermediateSum || point.isSum)) {
        point.y = correctFloat$3(y);
      }
    }
  }
  // Call default processData then override yData to reflect waterfall's
  // extremes on yAxis
  processData(force) {
    const series = this, options2 = series.options, yData = series.getColumn("y"), points = options2.data, dataLength = yData.length, threshold = options2.threshold || 0;
    let point, subSum, sum2, dataMin, dataMax, y;
    sum2 = subSum = dataMin = dataMax = 0;
    for (let i = 0; i < dataLength; i++) {
      y = yData[i];
      point = points?.[i] || {};
      if (y === "sum" || point.isSum) {
        yData[i] = correctFloat$3(sum2);
      } else if (y === "intermediateSum" || point.isIntermediateSum) {
        yData[i] = correctFloat$3(subSum);
        subSum = 0;
      } else {
        sum2 += y;
        subSum += y;
      }
      dataMin = Math.min(sum2, dataMin);
      dataMax = Math.max(sum2, dataMax);
    }
    super.processData.call(this, force);
    if (!options2.stacking) {
      series.dataMin = dataMin + threshold;
      series.dataMax = dataMax;
    }
    return;
  }
  // Return y value or string if point is sum
  toYData(pt) {
    if (pt.isSum) {
      return "sum";
    }
    if (pt.isIntermediateSum) {
      return "intermediateSum";
    }
    return pt.y;
  }
  // Postprocess mapping between options and SVG attributes
  pointAttribs(point, state) {
    const upColor = this.options.upColor;
    if (upColor && !point.options.color && isNumber$m(point.y)) {
      point.color = point.y > 0 ? upColor : void 0;
    }
    const attr2 = ColumnSeries$7.prototype.pointAttribs.call(this, point, state);
    delete attr2.dashstyle;
    return attr2;
  }
  // Return an empty path initially, because we need to know the stroke-width
  // in order to set the final path.
  getGraphPath() {
    return [["M", 0, 0]];
  }
  // Draw columns' connector lines
  getCrispPath() {
    const data = this.data.filter((d) => isNumber$m(d.y)), yAxis2 = this.yAxis, length = data.length, graphLineWidth = this.graph?.strokeWidth() || 0, reversedXAxis = this.xAxis.reversed, reversedYAxis = this.yAxis.reversed, stacking = this.options.stacking, path = [];
    for (let i = 1; i < length; i++) {
      if (!// Skip lines that would pass over the null point (#18636)
      (this.options.connectNulls || isNumber$m(this.data[data[i].index - 1].y))) {
        continue;
      }
      const box = data[i].box, prevPoint = data[i - 1], prevY = prevPoint.y || 0, prevBox = data[i - 1].box;
      if (!box || !prevBox) {
        continue;
      }
      const prevStack = yAxis2.waterfall.stacks[this.stackKey], isPos = prevY > 0 ? -prevBox.height : 0;
      if (prevStack && prevBox && box) {
        const prevStackX = prevStack[i - 1];
        let yPos;
        if (stacking) {
          const connectorThreshold = prevStackX.connectorThreshold;
          yPos = crisp$4(yAxis2.translate(connectorThreshold, false, true, false, true) + (reversedYAxis ? isPos : 0), graphLineWidth);
        } else {
          yPos = crisp$4(prevBox.y + (prevPoint.minPointLengthOffset || 0), graphLineWidth);
        }
        path.push([
          "M",
          (prevBox.x || 0) + (reversedXAxis ? 0 : prevBox.width || 0),
          yPos
        ], [
          "L",
          (box.x || 0) + (reversedXAxis ? box.width || 0 : 0),
          yPos
        ]);
      }
      if (prevBox && path.length && (!stacking && prevY < 0 && !reversedYAxis || prevY > 0 && reversedYAxis)) {
        const nextLast = path[path.length - 2];
        if (nextLast && typeof nextLast[2] === "number") {
          nextLast[2] += prevBox.height || 0;
        }
        const last = path[path.length - 1];
        if (last && typeof last[2] === "number") {
          last[2] += prevBox.height || 0;
        }
      }
    }
    return path;
  }
  // The graph is initially drawn with an empty definition, then updated with
  // crisp rendering.
  drawGraph() {
    LineSeries$2.prototype.drawGraph.call(this);
    if (this.graph) {
      this.graph.attr({
        d: this.getCrispPath()
      });
    }
  }
  // Waterfall has stacking along the x-values too.
  setStackedPoints(axis) {
    const series = this, options2 = series.options, waterfallStacks = axis.waterfall?.stacks, seriesThreshold = options2.threshold || 0, stackKey = series.stackKey, xData = series.getColumn("x"), yData = series.getColumn("y"), xLength = xData.length;
    let stackThreshold = seriesThreshold, interSum = stackThreshold, actualStackX, totalYVal = 0, actualSum = 0, prevSum = 0, statesLen, posTotal, negTotal, xPoint, yVal, x, alreadyChanged, changed;
    const calculateStackState = (firstS, nextS, sInx, sOff) => {
      if (actualStackX) {
        if (!statesLen) {
          actualStackX.stackState[0] = firstS;
          statesLen = actualStackX.stackState.length;
        } else {
          for (sInx; sInx < statesLen; sInx++) {
            actualStackX.stackState[sInx] += sOff;
          }
        }
        actualStackX.stackState.push(actualStackX.stackState[statesLen - 1] + nextS);
      }
    };
    if (axis.stacking && waterfallStacks) {
      if (series.reserveSpace()) {
        changed = waterfallStacks.changed;
        alreadyChanged = waterfallStacks.alreadyChanged;
        if (alreadyChanged && alreadyChanged.indexOf(stackKey) < 0) {
          changed = true;
        }
        if (!waterfallStacks[stackKey]) {
          waterfallStacks[stackKey] = {};
        }
        const actualStack = waterfallStacks[stackKey];
        if (actualStack) {
          for (let i = 0; i < xLength; i++) {
            x = xData[i];
            if (!actualStack[x] || changed) {
              actualStack[x] = {
                negTotal: 0,
                posTotal: 0,
                stackTotal: 0,
                threshold: 0,
                stateIndex: 0,
                stackState: [],
                label: changed && actualStack[x] ? actualStack[x].label : void 0
              };
            }
            actualStackX = actualStack[x];
            yVal = yData[i];
            if (yVal >= 0) {
              actualStackX.posTotal += yVal;
            } else {
              actualStackX.negTotal += yVal;
            }
            xPoint = options2.data[i];
            posTotal = actualStackX.absolutePos = actualStackX.posTotal;
            negTotal = actualStackX.absoluteNeg = actualStackX.negTotal;
            actualStackX.stackTotal = posTotal + negTotal;
            statesLen = actualStackX.stackState.length;
            if (xPoint?.isIntermediateSum) {
              calculateStackState(prevSum, actualSum, 0, prevSum);
              prevSum = actualSum;
              actualSum = seriesThreshold;
              stackThreshold ^= interSum;
              interSum ^= stackThreshold;
              stackThreshold ^= interSum;
            } else if (xPoint?.isSum) {
              calculateStackState(seriesThreshold, totalYVal, statesLen, 0);
              stackThreshold = seriesThreshold;
            } else {
              calculateStackState(stackThreshold, yVal, 0, totalYVal);
              if (xPoint) {
                totalYVal += yVal;
                actualSum += yVal;
              }
            }
            actualStackX.stateIndex++;
            actualStackX.threshold = stackThreshold;
            stackThreshold += actualStackX.stackTotal;
          }
        }
        waterfallStacks.changed = false;
        if (!waterfallStacks.alreadyChanged) {
          waterfallStacks.alreadyChanged = [];
        }
        waterfallStacks.alreadyChanged.push(stackKey);
      }
    }
  }
  // Extremes for a non-stacked series are recorded in processData.
  // In case of stacking, use Series.stackedYData to calculate extremes.
  getExtremes() {
    const stacking = this.options.stacking;
    let yAxis2, waterfallStacks, stackedYNeg, stackedYPos;
    if (stacking) {
      yAxis2 = this.yAxis;
      waterfallStacks = yAxis2.waterfall.stacks;
      stackedYNeg = this.stackedYNeg = [];
      stackedYPos = this.stackedYPos = [];
      if (stacking === "overlap") {
        objectEach$7(waterfallStacks[this.stackKey], function(stackX) {
          stackedYNeg.push(arrayMin$1(stackX.stackState));
          stackedYPos.push(arrayMax$2(stackX.stackState));
        });
      } else {
        objectEach$7(waterfallStacks[this.stackKey], function(stackX) {
          stackedYNeg.push(stackX.negTotal + stackX.threshold);
          stackedYPos.push(stackX.posTotal + stackX.threshold);
        });
      }
      return {
        dataMin: arrayMin$1(stackedYNeg),
        dataMax: arrayMax$2(stackedYPos)
      };
    }
    return {
      dataMin: this.dataMin,
      dataMax: this.dataMax
    };
  }
}
WaterfallSeries.defaultOptions = merge$C(ColumnSeries$7.defaultOptions, WaterfallSeriesDefaults);
WaterfallSeries.compose = WaterfallAxis$1.compose;
extend$z(WaterfallSeries.prototype, {
  pointValKey: "y",
  // Property needed to prevent lines between the columns from disappearing
  // when negativeColor is used.
  showLine: true,
  pointClass: WaterfallPoint
});
addEvent$t(WaterfallSeries, "afterColumnTranslate", function() {
  const series = this, { options: options2, points, yAxis: yAxis2 } = series, minPointLength = pick$F(options2.minPointLength, 5), halfMinPointLength = minPointLength / 2, threshold = options2.threshold || 0, stacking = options2.stacking, actualStack = yAxis2.waterfall.stacks[series.stackKey], processedYData = series.getColumn("y", true);
  let previousIntermediate = threshold, previousY = threshold, y, total, yPos, hPos;
  for (let i = 0; i < points.length; i++) {
    const point = points[i], yValue = processedYData[i], shapeArgs = point.shapeArgs, box = extend$z({
      x: 0,
      y: 0,
      width: 0,
      height: 0
    }, shapeArgs || {});
    point.box = box;
    const range2 = [0, yValue], pointY = point.y || 0;
    if (stacking) {
      if (actualStack) {
        const actualStackX = actualStack[i];
        if (stacking === "overlap") {
          total = actualStackX.stackState[actualStackX.stateIndex--];
          y = pointY >= 0 ? total : total - pointY;
          if (ownProp(actualStackX, "absolutePos")) {
            delete actualStackX.absolutePos;
          }
          if (ownProp(actualStackX, "absoluteNeg")) {
            delete actualStackX.absoluteNeg;
          }
        } else {
          if (pointY >= 0) {
            total = actualStackX.threshold + actualStackX.posTotal;
            actualStackX.posTotal -= pointY;
            y = total;
          } else {
            total = actualStackX.threshold + actualStackX.negTotal;
            actualStackX.negTotal -= pointY;
            y = total - pointY;
          }
          if (!actualStackX.posTotal) {
            if (isNumber$m(actualStackX.absolutePos) && ownProp(actualStackX, "absolutePos")) {
              actualStackX.posTotal = actualStackX.absolutePos;
              delete actualStackX.absolutePos;
            }
          }
          if (!actualStackX.negTotal) {
            if (isNumber$m(actualStackX.absoluteNeg) && ownProp(actualStackX, "absoluteNeg")) {
              actualStackX.negTotal = actualStackX.absoluteNeg;
              delete actualStackX.absoluteNeg;
            }
          }
        }
        if (!point.isSum) {
          actualStackX.connectorThreshold = actualStackX.threshold + actualStackX.stackTotal;
        }
        if (yAxis2.reversed) {
          yPos = pointY >= 0 ? y - pointY : y + pointY;
          hPos = y;
        } else {
          yPos = y;
          hPos = y - pointY;
        }
        point.below = yPos <= threshold;
        box.y = yAxis2.translate(yPos, false, true, false, true);
        box.height = Math.abs(box.y - yAxis2.translate(hPos, false, true, false, true));
        const dummyStackItem = yAxis2.waterfall.dummyStackItem;
        if (dummyStackItem) {
          dummyStackItem.x = i;
          dummyStackItem.label = actualStack[i].label;
          dummyStackItem.setOffset(series.pointXOffset || 0, series.barW || 0, series.stackedYNeg[i], series.stackedYPos[i], void 0, this.xAxis);
        }
      }
    } else {
      y = Math.max(previousY, previousY + pointY) + range2[0];
      box.y = yAxis2.translate(y, false, true, false, true);
      if (point.isSum) {
        box.y = yAxis2.translate(range2[1], false, true, false, true);
        box.height = Math.min(yAxis2.translate(range2[0], false, true, false, true), yAxis2.len) - box.y;
        point.below = range2[1] <= threshold;
      } else if (point.isIntermediateSum) {
        if (pointY >= 0) {
          yPos = range2[1] + previousIntermediate;
          hPos = previousIntermediate;
        } else {
          yPos = previousIntermediate;
          hPos = range2[1] + previousIntermediate;
        }
        if (yAxis2.reversed) {
          yPos ^= hPos;
          hPos ^= yPos;
          yPos ^= hPos;
        }
        box.y = yAxis2.translate(yPos, false, true, false, true);
        box.height = Math.abs(box.y - Math.min(yAxis2.translate(hPos, false, true, false, true), yAxis2.len));
        previousIntermediate += range2[1];
        point.below = yPos <= threshold;
      } else {
        box.height = yValue > 0 ? yAxis2.translate(previousY, false, true, false, true) - box.y : yAxis2.translate(previousY, false, true, false, true) - yAxis2.translate(previousY - yValue, false, true, false, true);
        previousY += yValue;
        point.below = previousY < threshold;
      }
      if (box.height < 0) {
        box.y += box.height;
        box.height *= -1;
      }
    }
    point.plotY = box.y;
    point.yBottom = box.y + box.height;
    if (box.height <= minPointLength && !point.isNull) {
      box.height = minPointLength;
      box.y -= halfMinPointLength;
      point.yBottom = box.y + box.height;
      point.plotY = box.y;
      if (pointY < 0) {
        point.minPointLengthOffset = -halfMinPointLength;
      } else {
        point.minPointLengthOffset = halfMinPointLength;
      }
    } else {
      if (point.isNull) {
        box.width = 0;
      }
      point.minPointLengthOffset = 0;
    }
    const tooltipY = point.plotY + (point.negative ? box.height : 0);
    if (point.below) {
      point.plotY += box.height;
    }
    if (point.tooltipPos) {
      if (series.chart.inverted) {
        point.tooltipPos[0] = yAxis2.len - tooltipY;
      } else {
        point.tooltipPos[1] = tooltipY;
      }
    }
    point.isInside = this.isPointInside(point);
    const crispBottom = crisp$4(point.yBottom, series.borderWidth);
    box.y = crisp$4(box.y, series.borderWidth);
    box.height = crispBottom - box.y;
    merge$C(true, point.shapeArgs, box);
  }
}, { order: 2 });
SeriesRegistry$1.registerSeriesType("waterfall", WaterfallSeries);
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/highcharts-more
 * @requires highcharts
 *
 * (c) 2009-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$d = Highcharts;
G$d.RadialAxis = RadialAxis$1;
BubbleSeries$1.compose(G$d.Axis, G$d.Chart, G$d.Legend);
PackedBubbleSeries.compose(G$d.Axis, G$d.Chart, G$d.Legend);
Pane.compose(G$d.Chart, G$d.Pointer);
PolarAdditions.compose(G$d.Axis, G$d.Chart, G$d.Pointer, G$d.Series, G$d.Tick, G$d.Point, SeriesRegistry$1.seriesTypes.areasplinerange, SeriesRegistry$1.seriesTypes.column, SeriesRegistry$1.seriesTypes.line, SeriesRegistry$1.seriesTypes.spline);
WaterfallSeries.compose(G$d.Axis, G$d.Chart);
const { deg2rad: deg2rad$4 } = Highcharts;
const { pick: pick$E } = Utilities;
function rotate3D(x, y, z, angles) {
  return {
    x: angles.cosB * x - angles.sinB * z,
    y: -angles.sinA * angles.sinB * x + angles.cosA * y - angles.cosB * angles.sinA * z,
    z: angles.cosA * angles.sinB * x + angles.sinA * y + angles.cosA * angles.cosB * z
  };
}
function perspective$6(points, chart, insidePlotArea, useInvertedPersp) {
  const options3d = chart.options.chart.options3d, inverted = pick$E(useInvertedPersp, insidePlotArea ? chart.inverted : false), origin = {
    x: chart.plotWidth / 2,
    y: chart.plotHeight / 2,
    z: options3d.depth / 2,
    vd: pick$E(options3d.depth, 1) * pick$E(options3d.viewDistance, 0)
  }, scale2 = chart.scale3d || 1, beta = deg2rad$4 * options3d.beta * (inverted ? -1 : 1), alpha = deg2rad$4 * options3d.alpha * (inverted ? -1 : 1), angles = {
    cosA: Math.cos(alpha),
    cosB: Math.cos(-beta),
    sinA: Math.sin(alpha),
    sinB: Math.sin(-beta)
  };
  if (!insidePlotArea) {
    origin.x += chart.plotLeft;
    origin.y += chart.plotTop;
  }
  return points.map(function(point) {
    const rotated = rotate3D((inverted ? point.y : point.x) - origin.x, (inverted ? point.x : point.y) - origin.y, (point.z || 0) - origin.z, angles), coordinate = perspective3D$1(rotated, origin, origin.vd);
    coordinate.x = coordinate.x * scale2 + origin.x;
    coordinate.y = coordinate.y * scale2 + origin.y;
    coordinate.z = rotated.z * scale2 + origin.z;
    return {
      x: inverted ? coordinate.y : coordinate.x,
      y: inverted ? coordinate.x : coordinate.y,
      z: coordinate.z
    };
  });
}
function perspective3D$1(coordinate, origin, distance) {
  const projection = distance > 0 && distance < Number.POSITIVE_INFINITY ? distance / (coordinate.z + origin.z + distance) : 1;
  return {
    x: coordinate.x * projection,
    y: coordinate.y * projection
  };
}
function pointCameraDistance$1(coordinates2, chart) {
  const options3d = chart.options.chart.options3d, cameraPosition = {
    x: chart.plotWidth / 2,
    y: chart.plotHeight / 2,
    z: pick$E(options3d.depth, 1) * pick$E(options3d.viewDistance, 0) + options3d.depth
  }, distance = Math.sqrt(Math.pow(cameraPosition.x - pick$E(coordinates2.plotX, coordinates2.x), 2) + Math.pow(cameraPosition.y - pick$E(coordinates2.plotY, coordinates2.y), 2) + Math.pow(cameraPosition.z - pick$E(coordinates2.plotZ, coordinates2.z), 2));
  return distance;
}
function shapeArea$2(vertexes) {
  let area = 0, i, j;
  for (i = 0; i < vertexes.length; i++) {
    j = (i + 1) % vertexes.length;
    area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
  }
  return area / 2;
}
function shapeArea3D$1(vertexes, chart, insidePlotArea) {
  return shapeArea$2(perspective$6(vertexes, chart, insidePlotArea));
}
const Math3D = {
  perspective: perspective$6,
  perspective3D: perspective3D$1,
  pointCameraDistance: pointCameraDistance$1,
  shapeArea: shapeArea$2,
  shapeArea3D: shapeArea3D$1
};
const { parse: color$7 } = Color;
const { defaultOptions: genericDefaultOptions } = DefaultOptions;
const { perspective: perspective$5, shapeArea3D } = Math3D;
const { addEvent: addEvent$s, isArray: isArray$8, merge: merge$B, pick: pick$D, wrap: wrap$9 } = Utilities;
var Chart3D;
(function(Chart3D2) {
  Chart3D2.defaultOptions = {
    chart: {
      /**
       * Options to render charts in 3 dimensions. This feature requires
       * `highcharts-3d.js`, found in the download package or online at
       * [code.highcharts.com/highcharts-3d.js](https://code.highcharts.com/highcharts-3d.js).
       *
       * @since    4.0
       * @product  highcharts
       * @requires highcharts-3d
       */
      options3d: {
        /**
         * Whether to render the chart using the 3D functionality.
         *
         * @since   4.0
         * @product highcharts
         */
        enabled: false,
        /**
         * One of the two rotation angles for the chart.
         *
         * @since   4.0
         * @product highcharts
         */
        alpha: 0,
        /**
         * One of the two rotation angles for the chart.
         *
         * @since   4.0
         * @product highcharts
         */
        beta: 0,
        /**
         * The total depth of the chart.
         *
         * @since   4.0
         * @product highcharts
         */
        depth: 100,
        /**
         * Whether the 3d box should automatically adjust to the chart
         * plot area.
         *
         * @since   4.2.4
         * @product highcharts
         */
        fitToPlot: true,
        /**
         * Defines the distance the viewer is standing in front of the
         * chart, this setting is important to calculate the perspective
         * effect in column and scatter charts. It is not used for 3D
         * pie charts.
         *
         * @since   4.0
         * @product highcharts
         */
        viewDistance: 25,
        /**
         * Set it to `"auto"` to automatically move the labels to the
         * best edge.
         *
         * @type    {"auto"|null}
         * @since   5.0.12
         * @product highcharts
         */
        axisLabelPosition: null,
        /**
         * Provides the option to draw a frame around the charts by
         * defining a bottom, front and back panel.
         *
         * @since    4.0
         * @product  highcharts
         * @requires highcharts-3d
         */
        frame: {
          /**
           * Whether the frames are visible.
           */
          visible: "default",
          /**
           * General pixel thickness for the frame faces.
           */
          size: 1,
          /**
           * The bottom of the frame around a 3D chart.
           *
           * @since    4.0
           * @product  highcharts
           * @requires highcharts-3d
           */
          /**
           * The color of the panel.
           *
           * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
           * @default   transparent
           * @since     4.0
           * @product   highcharts
           * @apioption chart.options3d.frame.bottom.color
           */
          /**
           * The thickness of the panel.
           *
           * @type      {number}
           * @default   1
           * @since     4.0
           * @product   highcharts
           * @apioption chart.options3d.frame.bottom.size
           */
          /**
           * Whether to display the frame. Possible values are `true`,
           * `false`, `"auto"` to display only the frames behind the
           * data, and `"default"` to display faces behind the data
           * based on the axis layout, ignoring the point of view.
           *
           * @sample {highcharts} highcharts/3d/scatter-frame/
           *         Auto frames
           *
           * @type      {boolean|"default"|"auto"}
           * @default   default
           * @since     5.0.12
           * @product   highcharts
           * @apioption chart.options3d.frame.bottom.visible
           */
          /**
           * The bottom of the frame around a 3D chart.
           */
          bottom: {},
          /**
           * The top of the frame around a 3D chart.
           *
           * @extends chart.options3d.frame.bottom
           */
          top: {},
          /**
           * The left side of the frame around a 3D chart.
           *
           * @extends chart.options3d.frame.bottom
           */
          left: {},
          /**
           * The right of the frame around a 3D chart.
           *
           * @extends chart.options3d.frame.bottom
           */
          right: {},
          /**
           * The back side of the frame around a 3D chart.
           *
           * @extends chart.options3d.frame.bottom
           */
          back: {},
          /**
           * The front of the frame around a 3D chart.
           *
           * @extends chart.options3d.frame.bottom
           */
          front: {}
        }
      }
    }
  };
  function compose2(ChartClass, FxClass) {
    const chartProto = ChartClass.prototype;
    const fxProto = FxClass.prototype;
    chartProto.is3d = function() {
      return !!this.options.chart.options3d?.enabled;
    };
    chartProto.propsRequireDirtyBox.push("chart.options3d");
    chartProto.propsRequireUpdateSeries.push("chart.options3d");
    fxProto.matrixSetter = function() {
      let interpolated;
      if (this.pos < 1 && (isArray$8(this.start) || isArray$8(this.end))) {
        const start2 = this.start || [1, 0, 0, 1, 0, 0], end = this.end || [1, 0, 0, 1, 0, 0];
        interpolated = [];
        for (let i = 0; i < 6; i++) {
          interpolated.push(this.pos * end[i] + (1 - this.pos) * start2[i]);
        }
      } else {
        interpolated = this.end;
      }
      this.elem.attr(this.prop, interpolated, null, true);
    };
    merge$B(true, genericDefaultOptions, Chart3D2.defaultOptions);
    addEvent$s(ChartClass, "init", onInit2);
    addEvent$s(ChartClass, "addSeries", onAddSeries);
    addEvent$s(ChartClass, "afterDrawChartBox", onAfterDrawChartBox);
    addEvent$s(ChartClass, "afterGetContainer", onAfterGetContainer2);
    addEvent$s(ChartClass, "afterInit", onAfterInit2);
    addEvent$s(ChartClass, "afterSetChartSize", onAfterSetChartSize);
    addEvent$s(ChartClass, "beforeRedraw", onBeforeRedraw);
    addEvent$s(ChartClass, "beforeRender", onBeforeRender2);
    wrap$9(chartProto, "isInsidePlot", wrapIsInsidePlot);
    wrap$9(chartProto, "renderSeries", wrapRenderSeries);
    wrap$9(chartProto, "setClassName", wrapSetClassName);
  }
  Chart3D2.compose = compose2;
  function onAddSeries(e) {
    if (this.is3d()) {
      if (e.options.type === "scatter") {
        e.options.type = "scatter3d";
      }
    }
  }
  function onAfterDrawChartBox() {
    if (this.chart3d && this.is3d()) {
      const chart = this, renderer = chart.renderer, options3d = chart.options.chart.options3d, frame = chart.chart3d.get3dFrame(), xm = chart.plotLeft, xp = chart.plotLeft + chart.plotWidth, ym = chart.plotTop, yp = chart.plotTop + chart.plotHeight, zm = 0, zp = options3d.depth, xmm = xm - (frame.left.visible ? frame.left.size : 0), xpp = xp + (frame.right.visible ? frame.right.size : 0), ymm = ym - (frame.top.visible ? frame.top.size : 0), ypp = yp + (frame.bottom.visible ? frame.bottom.size : 0), zmm = zm - (frame.front.visible ? frame.front.size : 0), zpp = zp + (frame.back.visible ? frame.back.size : 0), verb = chart.hasRendered ? "animate" : "attr";
      chart.chart3d.frame3d = frame;
      if (!chart.frameShapes) {
        chart.frameShapes = {
          bottom: renderer.polyhedron().add(),
          top: renderer.polyhedron().add(),
          left: renderer.polyhedron().add(),
          right: renderer.polyhedron().add(),
          back: renderer.polyhedron().add(),
          front: renderer.polyhedron().add()
        };
      }
      chart.frameShapes.bottom[verb]({
        "class": "highcharts-3d-frame highcharts-3d-frame-bottom",
        zIndex: frame.bottom.frontFacing ? -1e3 : 1e3,
        faces: [
          {
            fill: color$7(frame.bottom.color).brighten(0.1).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xmm,
              y: ypp,
              z: zpp
            }],
            enabled: frame.bottom.visible
          },
          {
            fill: color$7(frame.bottom.color).brighten(0.1).get(),
            vertexes: [{
              x: xm,
              y: yp,
              z: zp
            }, {
              x: xp,
              y: yp,
              z: zp
            }, {
              x: xp,
              y: yp,
              z: zm
            }, {
              x: xm,
              y: yp,
              z: zm
            }],
            enabled: frame.bottom.visible
          },
          {
            fill: color$7(frame.bottom.color).brighten(-0.1).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xm,
              y: yp,
              z: zp
            }, {
              x: xm,
              y: yp,
              z: zm
            }],
            enabled: frame.bottom.visible && !frame.left.visible
          },
          {
            fill: color$7(frame.bottom.color).brighten(-0.1).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xp,
              y: yp,
              z: zm
            }, {
              x: xp,
              y: yp,
              z: zp
            }],
            enabled: frame.bottom.visible && !frame.right.visible
          },
          {
            fill: color$7(frame.bottom.color).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xm,
              y: yp,
              z: zm
            }, {
              x: xp,
              y: yp,
              z: zm
            }],
            enabled: frame.bottom.visible && !frame.front.visible
          },
          {
            fill: color$7(frame.bottom.color).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xp,
              y: yp,
              z: zp
            }, {
              x: xm,
              y: yp,
              z: zp
            }],
            enabled: frame.bottom.visible && !frame.back.visible
          }
        ]
      });
      chart.frameShapes.top[verb]({
        "class": "highcharts-3d-frame highcharts-3d-frame-top",
        zIndex: frame.top.frontFacing ? -1e3 : 1e3,
        faces: [
          {
            fill: color$7(frame.top.color).brighten(0.1).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }],
            enabled: frame.top.visible
          },
          {
            fill: color$7(frame.top.color).brighten(0.1).get(),
            vertexes: [{
              x: xm,
              y: ym,
              z: zm
            }, {
              x: xp,
              y: ym,
              z: zm
            }, {
              x: xp,
              y: ym,
              z: zp
            }, {
              x: xm,
              y: ym,
              z: zp
            }],
            enabled: frame.top.visible
          },
          {
            fill: color$7(frame.top.color).brighten(-0.1).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xm,
              y: ym,
              z: zm
            }, {
              x: xm,
              y: ym,
              z: zp
            }],
            enabled: frame.top.visible && !frame.left.visible
          },
          {
            fill: color$7(frame.top.color).brighten(-0.1).get(),
            vertexes: [{
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xp,
              y: ym,
              z: zp
            }, {
              x: xp,
              y: ym,
              z: zm
            }],
            enabled: frame.top.visible && !frame.right.visible
          },
          {
            fill: color$7(frame.top.color).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xp,
              y: ym,
              z: zm
            }, {
              x: xm,
              y: ym,
              z: zm
            }],
            enabled: frame.top.visible && !frame.front.visible
          },
          {
            fill: color$7(frame.top.color).get(),
            vertexes: [{
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xm,
              y: ym,
              z: zp
            }, {
              x: xp,
              y: ym,
              z: zp
            }],
            enabled: frame.top.visible && !frame.back.visible
          }
        ]
      });
      chart.frameShapes.left[verb]({
        "class": "highcharts-3d-frame highcharts-3d-frame-left",
        zIndex: frame.left.frontFacing ? -1e3 : 1e3,
        faces: [
          {
            fill: color$7(frame.left.color).brighten(0.1).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xm,
              y: yp,
              z: zm
            }, {
              x: xm,
              y: yp,
              z: zp
            }, {
              x: xmm,
              y: ypp,
              z: zpp
            }],
            enabled: frame.left.visible && !frame.bottom.visible
          },
          {
            fill: color$7(frame.left.color).brighten(0.1).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xm,
              y: ym,
              z: zp
            }, {
              x: xm,
              y: ym,
              z: zm
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }],
            enabled: frame.left.visible && !frame.top.visible
          },
          {
            fill: color$7(frame.left.color).brighten(-0.1).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xmm,
              y: ypp,
              z: zmm
            }],
            enabled: frame.left.visible
          },
          {
            fill: color$7(frame.left.color).brighten(-0.1).get(),
            vertexes: [{
              x: xm,
              y: ym,
              z: zp
            }, {
              x: xm,
              y: yp,
              z: zp
            }, {
              x: xm,
              y: yp,
              z: zm
            }, {
              x: xm,
              y: ym,
              z: zm
            }],
            enabled: frame.left.visible
          },
          {
            fill: color$7(frame.left.color).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xm,
              y: ym,
              z: zm
            }, {
              x: xm,
              y: yp,
              z: zm
            }],
            enabled: frame.left.visible && !frame.front.visible
          },
          {
            fill: color$7(frame.left.color).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xm,
              y: yp,
              z: zp
            }, {
              x: xm,
              y: ym,
              z: zp
            }],
            enabled: frame.left.visible && !frame.back.visible
          }
        ]
      });
      chart.frameShapes.right[verb]({
        "class": "highcharts-3d-frame highcharts-3d-frame-right",
        zIndex: frame.right.frontFacing ? -1e3 : 1e3,
        faces: [
          {
            fill: color$7(frame.right.color).brighten(0.1).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xp,
              y: yp,
              z: zp
            }, {
              x: xp,
              y: yp,
              z: zm
            }, {
              x: xpp,
              y: ypp,
              z: zmm
            }],
            enabled: frame.right.visible && !frame.bottom.visible
          },
          {
            fill: color$7(frame.right.color).brighten(0.1).get(),
            vertexes: [{
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xp,
              y: ym,
              z: zm
            }, {
              x: xp,
              y: ym,
              z: zp
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }],
            enabled: frame.right.visible && !frame.top.visible
          },
          {
            fill: color$7(frame.right.color).brighten(-0.1).get(),
            vertexes: [{
              x: xp,
              y: ym,
              z: zm
            }, {
              x: xp,
              y: yp,
              z: zm
            }, {
              x: xp,
              y: yp,
              z: zp
            }, {
              x: xp,
              y: ym,
              z: zp
            }],
            enabled: frame.right.visible
          },
          {
            fill: color$7(frame.right.color).brighten(-0.1).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xpp,
              y: ypp,
              z: zpp
            }],
            enabled: frame.right.visible
          },
          {
            fill: color$7(frame.right.color).get(),
            vertexes: [{
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xp,
              y: yp,
              z: zm
            }, {
              x: xp,
              y: ym,
              z: zm
            }],
            enabled: frame.right.visible && !frame.front.visible
          },
          {
            fill: color$7(frame.right.color).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xp,
              y: ym,
              z: zp
            }, {
              x: xp,
              y: yp,
              z: zp
            }],
            enabled: frame.right.visible && !frame.back.visible
          }
        ]
      });
      chart.frameShapes.back[verb]({
        "class": "highcharts-3d-frame highcharts-3d-frame-back",
        zIndex: frame.back.frontFacing ? -1e3 : 1e3,
        faces: [
          {
            fill: color$7(frame.back.color).brighten(0.1).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xm,
              y: yp,
              z: zp
            }, {
              x: xp,
              y: yp,
              z: zp
            }],
            enabled: frame.back.visible && !frame.bottom.visible
          },
          {
            fill: color$7(frame.back.color).brighten(0.1).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xp,
              y: ym,
              z: zp
            }, {
              x: xm,
              y: ym,
              z: zp
            }],
            enabled: frame.back.visible && !frame.top.visible
          },
          {
            fill: color$7(frame.back.color).brighten(-0.1).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xmm,
              y: ymm,
              z: zpp
            }, {
              x: xm,
              y: ym,
              z: zp
            }, {
              x: xm,
              y: yp,
              z: zp
            }],
            enabled: frame.back.visible && !frame.left.visible
          },
          {
            fill: color$7(frame.back.color).brighten(-0.1).get(),
            vertexes: [{
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xp,
              y: yp,
              z: zp
            }, {
              x: xp,
              y: ym,
              z: zp
            }],
            enabled: frame.back.visible && !frame.right.visible
          },
          {
            fill: color$7(frame.back.color).get(),
            vertexes: [{
              x: xm,
              y: ym,
              z: zp
            }, {
              x: xp,
              y: ym,
              z: zp
            }, {
              x: xp,
              y: yp,
              z: zp
            }, {
              x: xm,
              y: yp,
              z: zp
            }],
            enabled: frame.back.visible
          },
          {
            fill: color$7(frame.back.color).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zpp
            }, {
              x: xpp,
              y: ypp,
              z: zpp
            }, {
              x: xpp,
              y: ymm,
              z: zpp
            }, {
              x: xmm,
              y: ymm,
              z: zpp
            }],
            enabled: frame.back.visible
          }
        ]
      });
      chart.frameShapes.front[verb]({
        "class": "highcharts-3d-frame highcharts-3d-frame-front",
        zIndex: frame.front.frontFacing ? -1e3 : 1e3,
        faces: [
          {
            fill: color$7(frame.front.color).brighten(0.1).get(),
            vertexes: [{
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xp,
              y: yp,
              z: zm
            }, {
              x: xm,
              y: yp,
              z: zm
            }],
            enabled: frame.front.visible && !frame.bottom.visible
          },
          {
            fill: color$7(frame.front.color).brighten(0.1).get(),
            vertexes: [{
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xm,
              y: ym,
              z: zm
            }, {
              x: xp,
              y: ym,
              z: zm
            }],
            enabled: frame.front.visible && !frame.top.visible
          },
          {
            fill: color$7(frame.front.color).brighten(-0.1).get(),
            vertexes: [{
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xm,
              y: yp,
              z: zm
            }, {
              x: xm,
              y: ym,
              z: zm
            }],
            enabled: frame.front.visible && !frame.left.visible
          },
          {
            fill: color$7(frame.front.color).brighten(-0.1).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xpp,
              y: ymm,
              z: zmm
            }, {
              x: xp,
              y: ym,
              z: zm
            }, {
              x: xp,
              y: yp,
              z: zm
            }],
            enabled: frame.front.visible && !frame.right.visible
          },
          {
            fill: color$7(frame.front.color).get(),
            vertexes: [{
              x: xp,
              y: ym,
              z: zm
            }, {
              x: xm,
              y: ym,
              z: zm
            }, {
              x: xm,
              y: yp,
              z: zm
            }, {
              x: xp,
              y: yp,
              z: zm
            }],
            enabled: frame.front.visible
          },
          {
            fill: color$7(frame.front.color).get(),
            vertexes: [{
              x: xpp,
              y: ypp,
              z: zmm
            }, {
              x: xmm,
              y: ypp,
              z: zmm
            }, {
              x: xmm,
              y: ymm,
              z: zmm
            }, {
              x: xpp,
              y: ymm,
              z: zmm
            }],
            enabled: frame.front.visible
          }
        ]
      });
    }
  }
  function onAfterGetContainer2() {
    if (this.styledMode) {
      [{
        name: "darker",
        slope: 0.6
      }, {
        name: "brighter",
        slope: 1.4
      }].forEach(function(cfg) {
        this.renderer.definition({
          tagName: "filter",
          attributes: {
            id: "highcharts-" + cfg.name
          },
          children: [{
            tagName: "feComponentTransfer",
            children: [{
              tagName: "feFuncR",
              attributes: {
                type: "linear",
                slope: cfg.slope
              }
            }, {
              tagName: "feFuncG",
              attributes: {
                type: "linear",
                slope: cfg.slope
              }
            }, {
              tagName: "feFuncB",
              attributes: {
                type: "linear",
                slope: cfg.slope
              }
            }]
          }]
        });
      }, this);
    }
  }
  function onAfterInit2() {
    const options2 = this.options;
    if (this.is3d()) {
      (options2.series || []).forEach(function(s) {
        const type = s.type || options2.chart.type || options2.chart.defaultSeriesType;
        if (type === "scatter") {
          s.type = "scatter3d";
        }
      });
    }
  }
  function onAfterSetChartSize() {
    const chart = this, options3d = chart.options.chart.options3d;
    if (chart.chart3d && chart.is3d()) {
      if (options3d) {
        options3d.alpha = options3d.alpha % 360 + (options3d.alpha >= 0 ? 0 : 360);
        options3d.beta = options3d.beta % 360 + (options3d.beta >= 0 ? 0 : 360);
      }
      const inverted = chart.inverted, clipBox = chart.clipBox, margin = chart.margin, x = inverted ? "y" : "x", y = inverted ? "x" : "y", w = inverted ? "height" : "width", h = inverted ? "width" : "height";
      clipBox[x] = -(margin[3] || 0);
      clipBox[y] = -(margin[0] || 0);
      clipBox[w] = chart.chartWidth + (margin[3] || 0) + (margin[1] || 0);
      clipBox[h] = chart.chartHeight + (margin[0] || 0) + (margin[2] || 0);
      chart.scale3d = 1;
      if (options3d.fitToPlot === true) {
        chart.scale3d = chart.chart3d.getScale(options3d.depth);
      }
      chart.chart3d.frame3d = chart.chart3d.get3dFrame();
    }
  }
  function onBeforeRedraw() {
    if (this.is3d()) {
      this.isDirtyBox = true;
    }
  }
  function onBeforeRender2() {
    if (this.chart3d && this.is3d()) {
      this.chart3d.frame3d = this.chart3d.get3dFrame();
    }
  }
  function onInit2() {
    if (!this.chart3d) {
      this.chart3d = new Additions(this);
    }
  }
  function wrapIsInsidePlot(proceed) {
    return this.is3d() || proceed.apply(this, [].slice.call(arguments, 1));
  }
  function wrapRenderSeries(proceed) {
    let series, i = this.series.length;
    if (this.is3d()) {
      while (i--) {
        series = this.series[i];
        series.translate();
        series.render();
      }
    } else {
      proceed.call(this);
    }
  }
  function wrapSetClassName(proceed) {
    proceed.apply(this, [].slice.call(arguments, 1));
    if (this.is3d()) {
      this.container.className += " highcharts-3d-chart";
    }
  }
  class Additions {
    /* *
     *
     *  Constructors
     *
     * */
    constructor(chart) {
      this.chart = chart;
    }
    /* *
     *
     *  Functions
     *
     * */
    get3dFrame() {
      const chart = this.chart, options3d = chart.options.chart.options3d, frameOptions = options3d.frame, xm = chart.plotLeft, xp = chart.plotLeft + chart.plotWidth, ym = chart.plotTop, yp = chart.plotTop + chart.plotHeight, zm = 0, zp = options3d.depth, faceOrientation = function(vertexes) {
        const area = shapeArea3D(vertexes, chart);
        if (area > 0.5) {
          return 1;
        }
        if (area < -0.5) {
          return -1;
        }
        return 0;
      }, bottomOrientation = faceOrientation([
        { x: xm, y: yp, z: zp },
        { x: xp, y: yp, z: zp },
        { x: xp, y: yp, z: zm },
        { x: xm, y: yp, z: zm }
      ]), topOrientation = faceOrientation([
        { x: xm, y: ym, z: zm },
        { x: xp, y: ym, z: zm },
        { x: xp, y: ym, z: zp },
        { x: xm, y: ym, z: zp }
      ]), leftOrientation = faceOrientation([
        { x: xm, y: ym, z: zm },
        { x: xm, y: ym, z: zp },
        { x: xm, y: yp, z: zp },
        { x: xm, y: yp, z: zm }
      ]), rightOrientation = faceOrientation([
        { x: xp, y: ym, z: zp },
        { x: xp, y: ym, z: zm },
        { x: xp, y: yp, z: zm },
        { x: xp, y: yp, z: zp }
      ]), frontOrientation = faceOrientation([
        { x: xm, y: yp, z: zm },
        { x: xp, y: yp, z: zm },
        { x: xp, y: ym, z: zm },
        { x: xm, y: ym, z: zm }
      ]), backOrientation = faceOrientation([
        { x: xm, y: ym, z: zp },
        { x: xp, y: ym, z: zp },
        { x: xp, y: yp, z: zp },
        { x: xm, y: yp, z: zp }
      ]), defaultShowFront = false, defaultShowBack = true;
      let defaultShowBottom = false, defaultShowTop = false, defaultShowLeft = false, defaultShowRight = false;
      [].concat(chart.xAxis, chart.yAxis, chart.zAxis).forEach(function(axis) {
        if (axis) {
          if (axis.horiz) {
            if (axis.opposite) {
              defaultShowTop = true;
            } else {
              defaultShowBottom = true;
            }
          } else {
            if (axis.opposite) {
              defaultShowRight = true;
            } else {
              defaultShowLeft = true;
            }
          }
        }
      });
      const getFaceOptions = function(sources, faceOrientation2, defaultVisible) {
        const faceAttrs = ["size", "color", "visible"], options2 = {};
        for (let i = 0; i < faceAttrs.length; i++) {
          const attr2 = faceAttrs[i];
          for (let j = 0; j < sources.length; j++) {
            if (typeof sources[j] === "object") {
              const val = sources[j][attr2];
              if (typeof val !== "undefined" && val !== null) {
                options2[attr2] = val;
                break;
              }
            }
          }
        }
        let isVisible = defaultVisible;
        if (options2.visible === true || options2.visible === false) {
          isVisible = options2.visible;
        } else if (options2.visible === "auto") {
          isVisible = faceOrientation2 > 0;
        }
        return {
          size: pick$D(options2.size, 1),
          color: pick$D(options2.color, "none"),
          frontFacing: faceOrientation2 > 0,
          visible: isVisible
        };
      };
      const ret = {
        axes: {},
        // FIXME: Previously, left/right, top/bottom and front/back
        // pairs shared size and color.
        // For compatibility and consistency sake, when one face have
        // size/color/visibility set, the opposite face will default to
        // the same values. Also, left/right used to be called 'side',
        // so that's also added as a fallback.
        bottom: getFaceOptions([frameOptions.bottom, frameOptions.top, frameOptions], bottomOrientation, defaultShowBottom),
        top: getFaceOptions([frameOptions.top, frameOptions.bottom, frameOptions], topOrientation, defaultShowTop),
        left: getFaceOptions([
          frameOptions.left,
          frameOptions.right,
          frameOptions.side,
          frameOptions
        ], leftOrientation, defaultShowLeft),
        right: getFaceOptions([
          frameOptions.right,
          frameOptions.left,
          frameOptions.side,
          frameOptions
        ], rightOrientation, defaultShowRight),
        back: getFaceOptions([frameOptions.back, frameOptions.front, frameOptions], backOrientation, defaultShowBack),
        front: getFaceOptions([frameOptions.front, frameOptions.back, frameOptions], frontOrientation, defaultShowFront)
      };
      if (options3d.axisLabelPosition === "auto") {
        const isValidEdge = function(face1, face2) {
          return face1.visible !== face2.visible || face1.visible && face2.visible && face1.frontFacing !== face2.frontFacing;
        };
        const yEdges = [];
        if (isValidEdge(ret.left, ret.front)) {
          yEdges.push({
            y: (ym + yp) / 2,
            x: xm,
            z: zm,
            xDir: { x: 1, y: 0, z: 0 }
          });
        }
        if (isValidEdge(ret.left, ret.back)) {
          yEdges.push({
            y: (ym + yp) / 2,
            x: xm,
            z: zp,
            xDir: { x: 0, y: 0, z: -1 }
          });
        }
        if (isValidEdge(ret.right, ret.front)) {
          yEdges.push({
            y: (ym + yp) / 2,
            x: xp,
            z: zm,
            xDir: { x: 0, y: 0, z: 1 }
          });
        }
        if (isValidEdge(ret.right, ret.back)) {
          yEdges.push({
            y: (ym + yp) / 2,
            x: xp,
            z: zp,
            xDir: { x: -1, y: 0, z: 0 }
          });
        }
        const xBottomEdges = [];
        if (isValidEdge(ret.bottom, ret.front)) {
          xBottomEdges.push({
            x: (xm + xp) / 2,
            y: yp,
            z: zm,
            xDir: { x: 1, y: 0, z: 0 }
          });
        }
        if (isValidEdge(ret.bottom, ret.back)) {
          xBottomEdges.push({
            x: (xm + xp) / 2,
            y: yp,
            z: zp,
            xDir: { x: -1, y: 0, z: 0 }
          });
        }
        const xTopEdges = [];
        if (isValidEdge(ret.top, ret.front)) {
          xTopEdges.push({
            x: (xm + xp) / 2,
            y: ym,
            z: zm,
            xDir: { x: 1, y: 0, z: 0 }
          });
        }
        if (isValidEdge(ret.top, ret.back)) {
          xTopEdges.push({
            x: (xm + xp) / 2,
            y: ym,
            z: zp,
            xDir: { x: -1, y: 0, z: 0 }
          });
        }
        const zBottomEdges = [];
        if (isValidEdge(ret.bottom, ret.left)) {
          zBottomEdges.push({
            z: (zm + zp) / 2,
            y: yp,
            x: xm,
            xDir: { x: 0, y: 0, z: -1 }
          });
        }
        if (isValidEdge(ret.bottom, ret.right)) {
          zBottomEdges.push({
            z: (zm + zp) / 2,
            y: yp,
            x: xp,
            xDir: { x: 0, y: 0, z: 1 }
          });
        }
        const zTopEdges = [];
        if (isValidEdge(ret.top, ret.left)) {
          zTopEdges.push({
            z: (zm + zp) / 2,
            y: ym,
            x: xm,
            xDir: { x: 0, y: 0, z: -1 }
          });
        }
        if (isValidEdge(ret.top, ret.right)) {
          zTopEdges.push({
            z: (zm + zp) / 2,
            y: ym,
            x: xp,
            xDir: { x: 0, y: 0, z: 1 }
          });
        }
        const pickEdge = function(edges, axis, mult) {
          if (edges.length === 0) {
            return null;
          }
          if (edges.length === 1) {
            return edges[0];
          }
          const projections2 = perspective$5(edges, chart, false);
          let best = 0;
          for (let i = 1; i < projections2.length; i++) {
            if (mult * projections2[i][axis] > mult * projections2[best][axis]) {
              best = i;
            } else if (mult * projections2[i][axis] === mult * projections2[best][axis] && projections2[i].z < projections2[best].z) {
              best = i;
            }
          }
          return edges[best];
        };
        ret.axes = {
          y: {
            "left": pickEdge(yEdges, "x", -1),
            "right": pickEdge(yEdges, "x", 1)
          },
          x: {
            "top": pickEdge(xTopEdges, "y", -1),
            "bottom": pickEdge(xBottomEdges, "y", 1)
          },
          z: {
            "top": pickEdge(zTopEdges, "y", -1),
            "bottom": pickEdge(zBottomEdges, "y", 1)
          }
        };
      } else {
        ret.axes = {
          y: {
            "left": {
              x: xm,
              z: zm,
              xDir: { x: 1, y: 0, z: 0 }
            },
            "right": {
              x: xp,
              z: zm,
              xDir: { x: 0, y: 0, z: 1 }
            }
          },
          x: {
            "top": {
              y: ym,
              z: zm,
              xDir: { x: 1, y: 0, z: 0 }
            },
            "bottom": {
              y: yp,
              z: zm,
              xDir: { x: 1, y: 0, z: 0 }
            }
          },
          z: {
            "top": {
              x: defaultShowLeft ? xp : xm,
              y: ym,
              xDir: defaultShowLeft ? { x: 0, y: 0, z: 1 } : { x: 0, y: 0, z: -1 }
            },
            "bottom": {
              x: defaultShowLeft ? xp : xm,
              y: yp,
              xDir: defaultShowLeft ? { x: 0, y: 0, z: 1 } : { x: 0, y: 0, z: -1 }
            }
          }
        };
      }
      return ret;
    }
    /**
     * Calculate scale of the 3D view. That is required to fit chart's 3D
     * projection into the actual plotting area. Reported as #4933.
     *
     * **Note:**
     * This function should ideally take the plot values instead of a chart
     * object, but since the chart object is needed for perspective it is
     * not practical. Possible to make both getScale and perspective more
     * logical and also immutable.
     *
     * @private
     * @function getScale
     *
     * @param {number} depth
     * The depth of the chart
     *
     * @return {number}
     * The scale to fit the 3D chart into the plotting area.
     *
     * @requires highcharts-3d
     */
    getScale(depth) {
      const chart = this.chart, plotLeft = chart.plotLeft, plotRight = chart.plotWidth + plotLeft, plotTop = chart.plotTop, plotBottom = chart.plotHeight + plotTop, originX = plotLeft + chart.plotWidth / 2, originY = plotTop + chart.plotHeight / 2, bbox3d = {
        minX: Number.MAX_VALUE,
        maxX: -Number.MAX_VALUE,
        minY: Number.MAX_VALUE,
        maxY: -Number.MAX_VALUE
      };
      let corners, scale2 = 1;
      corners = [{
        x: plotLeft,
        y: plotTop,
        z: 0
      }, {
        x: plotLeft,
        y: plotTop,
        z: depth
      }];
      [0, 1].forEach(function(i) {
        corners.push({
          x: plotRight,
          y: corners[i].y,
          z: corners[i].z
        });
      });
      [0, 1, 2, 3].forEach(function(i) {
        corners.push({
          x: corners[i].x,
          y: plotBottom,
          z: corners[i].z
        });
      });
      corners = perspective$5(corners, chart, false);
      corners.forEach(function(corner) {
        bbox3d.minX = Math.min(bbox3d.minX, corner.x);
        bbox3d.maxX = Math.max(bbox3d.maxX, corner.x);
        bbox3d.minY = Math.min(bbox3d.minY, corner.y);
        bbox3d.maxY = Math.max(bbox3d.maxY, corner.y);
      });
      if (plotLeft > bbox3d.minX) {
        scale2 = Math.min(scale2, 1 - Math.abs((plotLeft + originX) / (bbox3d.minX + originX)) % 1);
      }
      if (plotRight < bbox3d.maxX) {
        scale2 = Math.min(scale2, (plotRight - originX) / (bbox3d.maxX - originX));
      }
      if (plotTop > bbox3d.minY) {
        if (bbox3d.minY < 0) {
          scale2 = Math.min(scale2, (plotTop + originY) / (-bbox3d.minY + plotTop + originY));
        } else {
          scale2 = Math.min(scale2, 1 - (plotTop + originY) / (bbox3d.minY + originY) % 1);
        }
      }
      if (plotBottom < bbox3d.maxY) {
        scale2 = Math.min(scale2, Math.abs((plotBottom - originY) / (bbox3d.maxY - originY)));
      }
      return scale2;
    }
  }
  Chart3D2.Additions = Additions;
})(Chart3D || (Chart3D = {}));
const Chart3D$1 = Chart3D;
const { composed: composed$a } = Highcharts;
const { perspective: perspective$4 } = Math3D;
const { line: { prototype: lineProto } } = SeriesRegistry$1.seriesTypes;
const { pushUnique: pushUnique$a, wrap: wrap$8 } = Utilities;
function compose$b(AreaSeriesClass) {
  if (pushUnique$a(composed$a, "Area3DSeries")) {
    wrap$8(AreaSeriesClass.prototype, "getGraphPath", wrapAreaSeriesGetGraphPath);
  }
}
function wrapAreaSeriesGetGraphPath(proceed) {
  const series = this, svgPath = proceed.apply(series, [].slice.call(arguments, 1));
  if (!series.chart.is3d()) {
    return svgPath;
  }
  const getGraphPath = lineProto.getGraphPath, options2 = series.options, translatedThreshold = Math.round(
    // #10909
    series.yAxis.getThreshold(options2.threshold)
  );
  let bottomPoints = [];
  if (series.rawPointsX) {
    for (let i = 0; i < series.points.length; i++) {
      bottomPoints.push({
        x: series.rawPointsX[i],
        y: options2.stacking ? series.points[i].yBottom : translatedThreshold,
        z: series.zPadding
      });
    }
  }
  const options3d = series.chart.options.chart.options3d;
  bottomPoints = perspective$4(bottomPoints, series.chart, true).map((point) => ({ plotX: point.x, plotY: point.y, plotZ: point.z }));
  if (series.group && options3d && options3d.depth && options3d.beta) {
    if (series.markerGroup) {
      series.markerGroup.add(series.group);
      series.markerGroup.attr({
        translateX: 0,
        translateY: 0
      });
    }
    series.group.attr({
      zIndex: Math.max(1, options3d.beta > 270 || options3d.beta < 90 ? options3d.depth - Math.round(series.zPadding || 0) : Math.round(series.zPadding || 0))
    });
  }
  bottomPoints.reversed = true;
  const bottomPath = getGraphPath.call(series, bottomPoints, true, true);
  if (bottomPath[0] && bottomPath[0][0] === "M") {
    bottomPath[0] = ["L", bottomPath[0][1], bottomPath[0][2]];
  }
  if (series.areaPath) {
    const areaPath = series.areaPath.splice(0, series.areaPath.length / 2).concat(bottomPath);
    areaPath.xMap = series.areaPath.xMap;
    series.areaPath = areaPath;
  }
  series.graphPath = svgPath;
  return svgPath;
}
const Area3DSeries = {
  compose: compose$b
};
const Axis3DDefaults = {
  labels: {
    /**
     * Defines how the labels are be repositioned according to the 3D
     * chart orientation.
     *
     * - `'offset'`: Maintain a fixed horizontal/vertical distance from
     *   the tick marks, despite the chart orientation. This is the
     *   backwards compatible behavior, and causes skewing of X and Z
     *   axes.
     *
     * - `'chart'`: Preserve 3D position relative to the chart. This
     *   looks nice, but hard to read if the text isn't forward-facing.
     *
     * - `'flap'`: Rotated text along the axis to compensate for the
     *   chart orientation. This tries to maintain text as legible as
     *   possible on all orientations.
     *
     * - `'ortho'`: Rotated text along the axis direction so that the
     *   labels are orthogonal to the axis. This is very similar to
     *   `'flap'`, but prevents skewing the labels (X and Y scaling are
     *   still present).
     *
     * @sample highcharts/3d/skewed-labels/
     *         Skewed labels
     *
     * @since      5.0.15
     * @validvalue ['offset', 'chart', 'flap', 'ortho']
     * @product    highcharts
     * @requires   highcharts-3d
     */
    position3d: "offset",
    /**
     * If enabled, the axis labels will skewed to follow the
     * perspective.
     *
     * This will fix overlapping labels and titles, but texts become
     * less legible due to the distortion.
     *
     * The final appearance depends heavily on `labels.position3d`.
     *
     * @sample highcharts/3d/skewed-labels/
     *         Skewed labels
     *
     * @since    5.0.15
     * @product  highcharts
     * @requires highcharts-3d
     */
    skew3d: false
  },
  title: {
    /**
     * Defines how the title is repositioned according to the 3D chart
     * orientation.
     *
     * - `'offset'`: Maintain a fixed horizontal/vertical distance from
     *   the tick marks, despite the chart orientation. This is the
     *   backwards compatible behavior, and causes skewing of X and Z
     *   axes.
     *
     * - `'chart'`: Preserve 3D position relative to the chart. This
     *   looks nice, but hard to read if the text isn't forward-facing.
     *
     * - `'flap'`: Rotated text along the axis to compensate for the
     *   chart orientation. This tries to maintain text as legible as
     *   possible on all orientations.
     *
     * - `'ortho'`: Rotated text along the axis direction so that the
     *   labels are orthogonal to the axis. This is very similar to
     *   `'flap'`, but prevents skewing the labels (X and Y scaling are
     *   still present).
     *
     * - `undefined`: Will use the config from `labels.position3d`
     *
     * @sample highcharts/3d/skewed-labels/
     *         Skewed labels
     *
     * @type     {"offset"|"chart"|"flap"|"ortho"|null}
     * @since    5.0.15
     * @product  highcharts
     * @requires highcharts-3d
     */
    position3d: null,
    /**
     * If enabled, the axis title will skewed to follow the perspective.
     *
     * This will fix overlapping labels and titles, but texts become
     * less legible due to the distortion.
     *
     * The final appearance depends heavily on `title.position3d`.
     *
     * A `null` value will use the config from `labels.skew3d`.
     *
     * @sample highcharts/3d/skewed-labels/
     *         Skewed labels
     *
     * @type     {boolean|null}
     * @since    5.0.15
     * @product  highcharts
     * @requires highcharts-3d
     */
    skew3d: null
  }
};
const { composed: composed$9 } = Highcharts;
const { addEvent: addEvent$r, extend: extend$y, pushUnique: pushUnique$9, wrap: wrap$7 } = Utilities;
function compose$a(TickClass) {
  if (pushUnique$9(composed$9, "Axis.Tick3D")) {
    addEvent$r(TickClass, "afterGetLabelPosition", onTickAfterGetLabelPosition$1);
    wrap$7(TickClass.prototype, "getMarkPath", wrapTickGetMarkPath);
  }
}
function onTickAfterGetLabelPosition$1(e) {
  const axis3D = this.axis.axis3D;
  if (axis3D) {
    extend$y(e.pos, axis3D.fix3dPosition(e.pos));
  }
}
function wrapTickGetMarkPath(proceed) {
  const axis3D = this.axis.axis3D, path = proceed.apply(this, [].slice.call(arguments, 1));
  if (axis3D) {
    const start2 = path[0];
    const end = path[1];
    if (start2[0] === "M" && end[0] === "L") {
      const pArr = [
        axis3D.fix3dPosition({ x: start2[1], y: start2[2], z: 0 }),
        axis3D.fix3dPosition({ x: end[1], y: end[2], z: 0 })
      ];
      return this.axis.chart.renderer.toLineSegments(pArr);
    }
  }
  return path;
}
const Tick3DAdditions = {
  compose: compose$a
};
const { defaultOptions: defaultOptions$6 } = DefaultOptions;
const { deg2rad: deg2rad$3 } = Highcharts;
const { perspective: perspective$3, perspective3D, shapeArea: shapeArea$1 } = Math3D;
const { addEvent: addEvent$q, merge: merge$A, pick: pick$C, wrap: wrap$6 } = Utilities;
function onAxisAfterSetOptions$2() {
  const axis = this, chart = axis.chart, options2 = axis.options;
  if (chart.is3d?.() && axis.coll !== "colorAxis") {
    options2.tickWidth = pick$C(options2.tickWidth, 0);
    options2.gridLineWidth = pick$C(options2.gridLineWidth, 1);
  }
}
function onAxisDrawCrosshair(e) {
  const axis = this;
  if (axis.chart.is3d() && axis.coll !== "colorAxis") {
    if (e.point) {
      e.point.crosshairPos = axis.isXAxis ? e.point.axisXpos : axis.len - e.point.axisYpos;
    }
  }
}
function onAxisInit() {
  const axis = this;
  if (!axis.axis3D) {
    axis.axis3D = new Axis3DAdditions(axis);
  }
}
function wrapAxisGetLinePath(proceed) {
  const axis = this;
  if (!axis.chart.is3d() || axis.coll === "colorAxis") {
    return proceed.apply(axis, [].slice.call(arguments, 1));
  }
  return [];
}
function wrapAxisGetPlotBandPath(proceed) {
  if (!this.chart.is3d() || this.coll === "colorAxis") {
    return proceed.apply(this, [].slice.call(arguments, 1));
  }
  const args = arguments, from = args[1], to = args[2], path = [], fromPath = this.getPlotLinePath({ value: from }), toPath = this.getPlotLinePath({ value: to });
  if (fromPath && toPath) {
    for (let i = 0; i < fromPath.length; i += 2) {
      const fromStartSeg = fromPath[i], fromEndSeg = fromPath[i + 1], toStartSeg = toPath[i], toEndSeg = toPath[i + 1];
      if (fromStartSeg[0] === "M" && fromEndSeg[0] === "L" && toStartSeg[0] === "M" && toEndSeg[0] === "L") {
        path.push(
          fromStartSeg,
          fromEndSeg,
          toEndSeg,
          // `lineTo` instead of `moveTo`
          ["L", toStartSeg[1], toStartSeg[2]],
          ["Z"]
        );
      }
    }
  }
  return path;
}
function wrapAxisGetPlotLinePath(proceed) {
  const axis = this, axis3D = axis.axis3D, chart = axis.chart, path = proceed.apply(axis, [].slice.call(arguments, 1));
  if (axis.coll === "colorAxis" || !chart.chart3d || !chart.is3d()) {
    return path;
  }
  if (path === null) {
    return path;
  }
  const options3d = chart.options.chart.options3d, d = axis.isZAxis ? chart.plotWidth : options3d.depth, frame = chart.chart3d.frame3d, startSegment = path[0], endSegment = path[1];
  let pArr, pathSegments = [];
  if (startSegment[0] === "M" && endSegment[0] === "L") {
    pArr = [
      axis3D.swapZ({ x: startSegment[1], y: startSegment[2], z: 0 }),
      axis3D.swapZ({ x: startSegment[1], y: startSegment[2], z: d }),
      axis3D.swapZ({ x: endSegment[1], y: endSegment[2], z: 0 }),
      axis3D.swapZ({ x: endSegment[1], y: endSegment[2], z: d })
    ];
    if (!this.horiz) {
      if (frame.front.visible) {
        pathSegments.push(pArr[0], pArr[2]);
      }
      if (frame.back.visible) {
        pathSegments.push(pArr[1], pArr[3]);
      }
      if (frame.left.visible) {
        pathSegments.push(pArr[0], pArr[1]);
      }
      if (frame.right.visible) {
        pathSegments.push(pArr[2], pArr[3]);
      }
    } else if (this.isZAxis) {
      if (frame.left.visible) {
        pathSegments.push(pArr[0], pArr[2]);
      }
      if (frame.right.visible) {
        pathSegments.push(pArr[1], pArr[3]);
      }
      if (frame.top.visible) {
        pathSegments.push(pArr[0], pArr[1]);
      }
      if (frame.bottom.visible) {
        pathSegments.push(pArr[2], pArr[3]);
      }
    } else {
      if (frame.front.visible) {
        pathSegments.push(pArr[0], pArr[2]);
      }
      if (frame.back.visible) {
        pathSegments.push(pArr[1], pArr[3]);
      }
      if (frame.top.visible) {
        pathSegments.push(pArr[0], pArr[1]);
      }
      if (frame.bottom.visible) {
        pathSegments.push(pArr[2], pArr[3]);
      }
    }
    pathSegments = perspective$3(pathSegments, this.chart, false);
  }
  return chart.renderer.toLineSegments(pathSegments);
}
function wrapAxisGetSlotWidth(proceed, tick) {
  const axis = this, { chart, gridGroup, tickPositions, ticks } = axis;
  if (axis.categories && chart.frameShapes && chart.is3d() && gridGroup && tick && tick.label) {
    const firstGridLine = gridGroup.element.childNodes[0].getBBox(), frame3DLeft = chart.frameShapes.left.getBBox(), options3d = chart.options.chart.options3d, origin = {
      x: chart.plotWidth / 2,
      y: chart.plotHeight / 2,
      z: options3d.depth / 2,
      vd: pick$C(options3d.depth, 1) * pick$C(options3d.viewDistance, 0)
    }, index = tickPositions.indexOf(tick.pos), prevTick = ticks[tickPositions[index - 1]], nextTick = ticks[tickPositions[index + 1]];
    let labelPos, prevLabelPos, nextLabelPos;
    if (prevTick?.label?.xy) {
      prevLabelPos = perspective3D({
        x: prevTick.label.xy.x,
        y: prevTick.label.xy.y,
        z: null
      }, origin, origin.vd);
    }
    if (nextTick?.label?.xy) {
      nextLabelPos = perspective3D({
        x: nextTick.label.xy.x,
        y: nextTick.label.xy.y,
        z: null
      }, origin, origin.vd);
    }
    labelPos = {
      x: tick.label.xy.x,
      y: tick.label.xy.y,
      z: null
    };
    labelPos = perspective3D(labelPos, origin, origin.vd);
    return Math.abs(prevLabelPos ? labelPos.x - prevLabelPos.x : nextLabelPos ? nextLabelPos.x - labelPos.x : firstGridLine.x - frame3DLeft.x);
  }
  return proceed.apply(axis, [].slice.call(arguments, 1));
}
function wrapAxisGetTitlePosition(proceed) {
  const pos = proceed.apply(this, [].slice.call(arguments, 1));
  return this.axis3D ? this.axis3D.fix3dPosition(pos, true) : pos;
}
class Axis3DAdditions {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Extends axis class with 3D support.
   * @private
   */
  static compose(AxisClass, TickClass) {
    Tick3DAdditions.compose(TickClass);
    if (!AxisClass.keepProps.includes("axis3D")) {
      merge$A(true, defaultOptions$6.xAxis, Axis3DDefaults);
      AxisClass.keepProps.push("axis3D");
      addEvent$q(AxisClass, "init", onAxisInit);
      addEvent$q(AxisClass, "afterSetOptions", onAxisAfterSetOptions$2);
      addEvent$q(AxisClass, "drawCrosshair", onAxisDrawCrosshair);
      const axisProto = AxisClass.prototype;
      wrap$6(axisProto, "getLinePath", wrapAxisGetLinePath);
      wrap$6(axisProto, "getPlotBandPath", wrapAxisGetPlotBandPath);
      wrap$6(axisProto, "getPlotLinePath", wrapAxisGetPlotLinePath);
      wrap$6(axisProto, "getSlotWidth", wrapAxisGetSlotWidth);
      wrap$6(axisProto, "getTitlePosition", wrapAxisGetTitlePosition);
    }
  }
  /* *
   *
   *  Constructors
   *
   * */
  /**
   * @private
   */
  constructor(axis) {
    this.axis = axis;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   * @param {Highcharts.Axis} axis
   * Related axis.
   * @param {Highcharts.Position3DObject} pos
   * Position to fix.
   * @param {boolean} [isTitle]
   * Whether this is a title position.
   * @return {Highcharts.Position3DObject}
   * Fixed position.
   */
  fix3dPosition(pos, isTitle) {
    const axis3D = this;
    const axis = axis3D.axis;
    const chart = axis.chart;
    if (axis.coll === "colorAxis" || !chart.chart3d || !chart.is3d()) {
      return pos;
    }
    const alpha = deg2rad$3 * chart.options.chart.options3d.alpha, beta = deg2rad$3 * chart.options.chart.options3d.beta, positionMode = pick$C(isTitle && axis.options.title.position3d, axis.options.labels.position3d), skew = pick$C(isTitle && axis.options.title.skew3d, axis.options.labels.skew3d), frame = chart.chart3d.frame3d, plotLeft = chart.plotLeft, plotRight = chart.plotWidth + plotLeft, plotTop = chart.plotTop, plotBottom = chart.plotHeight + plotTop;
    let offsetX = 0, offsetY = 0, vecX, vecY = { x: 0, y: 1, z: 0 }, reverseFlap = false;
    pos = axis.axis3D.swapZ({ x: pos.x, y: pos.y, z: 0 });
    if (axis.isZAxis) {
      if (axis.opposite) {
        if (frame.axes.z.top === null) {
          return {};
        }
        offsetY = pos.y - plotTop;
        pos.x = frame.axes.z.top.x;
        pos.y = frame.axes.z.top.y;
        vecX = frame.axes.z.top.xDir;
        reverseFlap = !frame.top.frontFacing;
      } else {
        if (frame.axes.z.bottom === null) {
          return {};
        }
        offsetY = pos.y - plotBottom;
        pos.x = frame.axes.z.bottom.x;
        pos.y = frame.axes.z.bottom.y;
        vecX = frame.axes.z.bottom.xDir;
        reverseFlap = !frame.bottom.frontFacing;
      }
    } else if (axis.horiz) {
      if (axis.opposite) {
        if (frame.axes.x.top === null) {
          return {};
        }
        offsetY = pos.y - plotTop;
        pos.y = frame.axes.x.top.y;
        pos.z = frame.axes.x.top.z;
        vecX = frame.axes.x.top.xDir;
        reverseFlap = !frame.top.frontFacing;
      } else {
        if (frame.axes.x.bottom === null) {
          return {};
        }
        offsetY = pos.y - plotBottom;
        pos.y = frame.axes.x.bottom.y;
        pos.z = frame.axes.x.bottom.z;
        vecX = frame.axes.x.bottom.xDir;
        reverseFlap = !frame.bottom.frontFacing;
      }
    } else {
      if (axis.opposite) {
        if (frame.axes.y.right === null) {
          return {};
        }
        offsetX = pos.x - plotRight;
        pos.x = frame.axes.y.right.x;
        pos.z = frame.axes.y.right.z;
        vecX = frame.axes.y.right.xDir;
        vecX = { x: vecX.z, y: vecX.y, z: -vecX.x };
      } else {
        if (frame.axes.y.left === null) {
          return {};
        }
        offsetX = pos.x - plotLeft;
        pos.x = frame.axes.y.left.x;
        pos.z = frame.axes.y.left.z;
        vecX = frame.axes.y.left.xDir;
      }
    }
    if (positionMode === "chart") ;
    else if (positionMode === "flap") {
      if (!axis.horiz) {
        vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
      } else {
        let sin2 = Math.sin(alpha);
        const cos2 = Math.cos(alpha);
        if (axis.opposite) {
          sin2 = -sin2;
        }
        if (reverseFlap) {
          sin2 = -sin2;
        }
        vecY = { x: vecX.z * sin2, y: cos2, z: -vecX.x * sin2 };
      }
    } else if (positionMode === "ortho") {
      if (!axis.horiz) {
        vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
      } else {
        const sina = Math.sin(alpha);
        const cosa = Math.cos(alpha);
        const sinb = Math.sin(beta);
        const cosb = Math.cos(beta);
        const vecZ = { x: sinb * cosa, y: -sina, z: -cosa * cosb };
        vecY = {
          x: vecX.y * vecZ.z - vecX.z * vecZ.y,
          y: vecX.z * vecZ.x - vecX.x * vecZ.z,
          z: vecX.x * vecZ.y - vecX.y * vecZ.x
        };
        let scale2 = 1 / Math.sqrt(vecY.x * vecY.x + vecY.y * vecY.y + vecY.z * vecY.z);
        if (reverseFlap) {
          scale2 = -scale2;
        }
        vecY = {
          x: scale2 * vecY.x,
          y: scale2 * vecY.y,
          z: scale2 * vecY.z
        };
      }
    } else {
      if (!axis.horiz) {
        vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
      } else {
        vecY = {
          x: Math.sin(beta) * Math.sin(alpha),
          y: Math.cos(alpha),
          z: -Math.cos(beta) * Math.sin(alpha)
        };
      }
    }
    pos.x += offsetX * vecX.x + offsetY * vecY.x;
    pos.y += offsetX * vecX.y + offsetY * vecY.y;
    pos.z += offsetX * vecX.z + offsetY * vecY.z;
    const projected = perspective$3([pos], axis.chart)[0];
    if (skew) {
      const isMirrored = shapeArea$1(perspective$3([
        pos,
        { x: pos.x + vecX.x, y: pos.y + vecX.y, z: pos.z + vecX.z },
        { x: pos.x + vecY.x, y: pos.y + vecY.y, z: pos.z + vecY.z }
      ], axis.chart)) < 0;
      if (isMirrored) {
        vecX = { x: -vecX.x, y: -vecX.y, z: -vecX.z };
      }
      const pointsProjected = perspective$3([
        { x: pos.x, y: pos.y, z: pos.z },
        { x: pos.x + vecX.x, y: pos.y + vecX.y, z: pos.z + vecX.z },
        { x: pos.x + vecY.x, y: pos.y + vecY.y, z: pos.z + vecY.z }
      ], axis.chart);
      projected.matrix = [
        pointsProjected[1].x - pointsProjected[0].x,
        pointsProjected[1].y - pointsProjected[0].y,
        pointsProjected[2].x - pointsProjected[0].x,
        pointsProjected[2].y - pointsProjected[0].y,
        projected.x,
        projected.y
      ];
      projected.matrix[4] -= projected.x * projected.matrix[0] + projected.y * projected.matrix[2];
      projected.matrix[5] -= projected.x * projected.matrix[1] + projected.y * projected.matrix[3];
    }
    return projected;
  }
  /**
   * @private
   */
  swapZ(p, insidePlotArea) {
    const axis = this.axis;
    if (axis.isZAxis) {
      const plotLeft = insidePlotArea ? 0 : axis.chart.plotLeft;
      return {
        x: plotLeft + p.z,
        y: p.y,
        z: p.x - plotLeft
      };
    }
    return p;
  }
}
const { composed: composed$8 } = Highcharts;
const { perspective: perspective$2 } = Math3D;
const { addEvent: addEvent$p, extend: extend$x, isNumber: isNumber$l, merge: merge$z, pick: pick$B, pushUnique: pushUnique$8 } = Utilities;
class Series3D extends Series$9 {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(SeriesClass) {
    if (pushUnique$8(composed$8, "Core.Series3D")) {
      addEvent$p(SeriesClass, "afterTranslate", function() {
        if (this.chart.is3d()) {
          this.translate3dPoints();
        }
      });
      extend$x(SeriesClass.prototype, {
        translate3dPoints: Series3D.prototype.translate3dPoints
      });
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Translate the plotX, plotY properties and add plotZ.
   * @private
   */
  translate3dPoints() {
    const series = this, seriesOptions = series.options, chart = series.chart, zAxis = pick$B(series.zAxis, chart.options.zAxis[0]), rawPoints = [], rawPointsX = [], stack = seriesOptions.stacking ? isNumber$l(seriesOptions.stack) ? seriesOptions.stack : 0 : series.index || 0;
    let projectedPoint, zValue;
    series.zPadding = stack * (seriesOptions.depth || 0 + (seriesOptions.groupZPadding || 1));
    series.data.forEach((rawPoint) => {
      if (zAxis?.translate) {
        zValue = zAxis.logarithmic && zAxis.val2lin ? zAxis.val2lin(rawPoint.z) : rawPoint.z;
        rawPoint.plotZ = zAxis.translate(zValue);
        rawPoint.isInside = rawPoint.isInside ? zValue >= zAxis.min && zValue <= zAxis.max : false;
      } else {
        rawPoint.plotZ = series.zPadding;
      }
      rawPoint.axisXpos = rawPoint.plotX;
      rawPoint.axisYpos = rawPoint.plotY;
      rawPoint.axisZpos = rawPoint.plotZ;
      rawPoints.push({
        x: rawPoint.plotX,
        y: rawPoint.plotY,
        z: rawPoint.plotZ
      });
      rawPointsX.push(rawPoint.plotX || 0);
    });
    series.rawPointsX = rawPointsX;
    const projectedPoints = perspective$2(rawPoints, chart, true);
    series.data.forEach((rawPoint, i) => {
      projectedPoint = projectedPoints[i];
      rawPoint.plotX = projectedPoint.x;
      rawPoint.plotY = projectedPoint.y;
      rawPoint.plotZ = projectedPoint.z;
    });
  }
}
Series3D.defaultOptions = merge$z(Series$9.defaultOptions);
const { parse: color$6 } = Color;
const { Element: SVGElement } = RendererRegistry$1.getRendererType().prototype;
const { defined: defined$m, pick: pick$A } = Utilities;
class SVGElement3D extends SVGElement {
  constructor() {
    super(...arguments);
    this.parts = ["front", "top", "side"];
    this.pathType = "cuboid";
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * The init is used by base - renderer.Element
   * @private
   */
  initArgs(args) {
    const elem3d = this, renderer = elem3d.renderer, paths = renderer[elem3d.pathType + "Path"](args), zIndexes = paths.zIndexes;
    for (const part of elem3d.parts) {
      const attribs = {
        "class": "highcharts-3d-" + part,
        zIndex: zIndexes[part] || 0
      };
      if (renderer.styledMode) {
        if (part === "top") {
          attribs.filter = "url(#highcharts-brighter)";
        } else if (part === "side") {
          attribs.filter = "url(#highcharts-darker)";
        }
      }
      elem3d[part] = renderer.path(paths[part]).attr(attribs).add(elem3d);
    }
    elem3d.attr({
      "stroke-linejoin": "round",
      zIndex: zIndexes.group
    });
    elem3d.forcedSides = paths.forcedSides;
  }
  /**
   * Single property setter that applies options to each part
   * @private
   */
  singleSetterForParts(prop, val, values, verb, duration, complete) {
    const elem3d = this, newAttr = {}, optionsToApply = [null, null, verb || "attr", duration, complete], hasZIndexes = values?.zIndexes;
    if (!values) {
      newAttr[prop] = val;
      optionsToApply[0] = newAttr;
    } else {
      if (hasZIndexes?.group) {
        elem3d.attr({
          zIndex: hasZIndexes.group
        });
      }
      for (const part of Object.keys(values)) {
        newAttr[part] = {};
        newAttr[part][prop] = values[part];
        if (hasZIndexes) {
          newAttr[part].zIndex = values.zIndexes[part] || 0;
        }
      }
      optionsToApply[1] = newAttr;
    }
    return this.processParts.apply(elem3d, optionsToApply);
  }
  /**
   * Calls function for each part. Used for attr, animate and destroy.
   * @private
   */
  processParts(props, partsProps, verb, duration, complete) {
    const elem3d = this;
    for (const part of elem3d.parts) {
      if (partsProps) {
        props = pick$A(partsProps[part], false);
      }
      if (props !== false) {
        elem3d[part][verb](props, duration, complete);
      }
    }
    return elem3d;
  }
  /**
   * Destroy all parts
   * @private
   */
  destroy() {
    this.processParts(null, null, "destroy");
    return super.destroy();
  }
  // Following functions are SVGElement3DCuboid (= base)
  attr(args, val, complete, continueAnimation) {
    if (typeof args === "string" && typeof val !== "undefined") {
      const key2 = args;
      args = {};
      args[key2] = val;
    }
    if (args.shapeArgs || defined$m(args.x)) {
      return this.singleSetterForParts("d", null, this.renderer[this.pathType + "Path"](args.shapeArgs || args));
    }
    return super.attr(args, void 0, complete, continueAnimation);
  }
  animate(args, duration, complete) {
    if (defined$m(args.x) && defined$m(args.y)) {
      const paths = this.renderer[this.pathType + "Path"](args), forcedSides = paths.forcedSides;
      this.singleSetterForParts("d", null, paths, "animate", duration, complete);
      this.attr({
        zIndex: paths.zIndexes.group
      });
      if (forcedSides !== this.forcedSides) {
        this.forcedSides = forcedSides;
        if (!this.renderer.styledMode) {
          this.fillSetter(this.fill);
        }
      }
    } else {
      super.animate(args, duration, complete);
    }
    return this;
  }
  fillSetter(fill) {
    const elem3d = this;
    elem3d.forcedSides = elem3d.forcedSides || [];
    elem3d.singleSetterForParts("fill", null, {
      front: fill,
      // Do not change color if side was forced to render.
      top: color$6(fill).brighten(elem3d.forcedSides.indexOf("top") >= 0 ? 0 : 0.1).get(),
      side: color$6(fill).brighten(elem3d.forcedSides.indexOf("side") >= 0 ? 0 : -0.1).get()
    });
    elem3d.color = elem3d.fill = fill;
    return elem3d;
  }
}
SVGElement3D.types = {
  base: SVGElement3D,
  cuboid: SVGElement3D
};
const { animObject: animObject$3 } = animationExports;
const { parse: color$5 } = Color;
const { charts, deg2rad: deg2rad$2 } = Highcharts;
const { perspective: perspective$1, shapeArea } = Math3D;
const { defined: defined$l, extend: extend$w, merge: merge$y, pick: pick$z } = Utilities;
const cos = Math.cos, sin = Math.sin, PI = Math.PI, dFactor = 4 * (Math.sqrt(2) - 1) / 3 / (PI / 2);
function curveTo(cx, cy, rx, ry, start2, end, dx, dy) {
  const arcAngle = end - start2;
  let result = [];
  if (end > start2 && end - start2 > Math.PI / 2 + 1e-4) {
    result = result.concat(curveTo(cx, cy, rx, ry, start2, start2 + Math.PI / 2, dx, dy));
    result = result.concat(curveTo(cx, cy, rx, ry, start2 + Math.PI / 2, end, dx, dy));
    return result;
  }
  if (end < start2 && start2 - end > Math.PI / 2 + 1e-4) {
    result = result.concat(curveTo(cx, cy, rx, ry, start2, start2 - Math.PI / 2, dx, dy));
    result = result.concat(curveTo(cx, cy, rx, ry, start2 - Math.PI / 2, end, dx, dy));
    return result;
  }
  return [[
    "C",
    cx + rx * Math.cos(start2) - rx * dFactor * arcAngle * Math.sin(start2) + dx,
    cy + ry * Math.sin(start2) + ry * dFactor * arcAngle * Math.cos(start2) + dy,
    cx + rx * Math.cos(end) + rx * dFactor * arcAngle * Math.sin(end) + dx,
    cy + ry * Math.sin(end) - ry * dFactor * arcAngle * Math.cos(end) + dy,
    cx + rx * Math.cos(end) + dx,
    cy + ry * Math.sin(end) + dy
  ]];
}
var SVGRenderer3D;
(function(SVGRenderer3D2) {
  function compose2(SVGRendererClass) {
    const rendererProto = SVGRendererClass.prototype;
    if (!rendererProto.element3d) {
      extend$w(rendererProto, {
        Element3D: SVGElement3D,
        arc3d,
        arc3dPath,
        cuboid,
        cuboidPath,
        element3d,
        face3d,
        polyhedron,
        toLinePath,
        toLineSegments
      });
    }
  }
  SVGRenderer3D2.compose = compose2;
  function toLinePath(points, closed) {
    const result = [];
    for (const point of points) {
      result.push(["L", point.x, point.y]);
    }
    if (points.length) {
      result[0][0] = "M";
      if (closed) {
        result.push(["Z"]);
      }
    }
    return result;
  }
  function toLineSegments(points) {
    const result = [];
    let m = true;
    for (const point of points) {
      result.push(m ? ["M", point.x, point.y] : ["L", point.x, point.y]);
      m = !m;
    }
    return result;
  }
  function face3d(args) {
    const renderer = this, elementProto = renderer.Element.prototype, ret = renderer.createElement("path");
    ret.vertexes = [];
    ret.insidePlotArea = false;
    ret.enabled = true;
    ret.attr = function(hash2) {
      if (typeof hash2 === "object" && (defined$l(hash2.enabled) || defined$l(hash2.vertexes) || defined$l(hash2.insidePlotArea))) {
        this.enabled = pick$z(hash2.enabled, this.enabled);
        this.vertexes = pick$z(hash2.vertexes, this.vertexes);
        this.insidePlotArea = pick$z(hash2.insidePlotArea, this.insidePlotArea);
        delete hash2.enabled;
        delete hash2.vertexes;
        delete hash2.insidePlotArea;
        const chart = charts[renderer.chartIndex], vertexes2d = perspective$1(this.vertexes, chart, this.insidePlotArea), path = renderer.toLinePath(vertexes2d, true), area = shapeArea(vertexes2d);
        hash2.d = path;
        hash2.visibility = this.enabled && area > 0 ? "inherit" : "hidden";
      }
      return elementProto.attr.apply(this, arguments);
    };
    ret.animate = function(params2) {
      if (typeof params2 === "object" && (defined$l(params2.enabled) || defined$l(params2.vertexes) || defined$l(params2.insidePlotArea))) {
        this.enabled = pick$z(params2.enabled, this.enabled);
        this.vertexes = pick$z(params2.vertexes, this.vertexes);
        this.insidePlotArea = pick$z(params2.insidePlotArea, this.insidePlotArea);
        delete params2.enabled;
        delete params2.vertexes;
        delete params2.insidePlotArea;
        const chart = charts[renderer.chartIndex], vertexes2d = perspective$1(this.vertexes, chart, this.insidePlotArea), path = renderer.toLinePath(vertexes2d, true), area = shapeArea(vertexes2d), visibility = this.enabled && area > 0 ? "visible" : "hidden";
        params2.d = path;
        this.attr("visibility", visibility);
      }
      return elementProto.animate.apply(this, arguments);
    };
    return ret.attr(args);
  }
  function polyhedron(args) {
    const renderer = this, elementProto = renderer.Element.prototype, result = renderer.g(), destroy = result.destroy;
    if (!this.styledMode) {
      result.attr({
        "stroke-linejoin": "round"
      });
    }
    result.faces = [];
    result.destroy = function() {
      for (let i = 0; i < result.faces.length; i++) {
        result.faces[i].destroy();
      }
      return destroy.call(this);
    };
    result.attr = function(hash2, val, complete, continueAnimation) {
      if (typeof hash2 === "object" && defined$l(hash2.faces)) {
        while (result.faces.length > hash2.faces.length) {
          result.faces.pop().destroy();
        }
        while (result.faces.length < hash2.faces.length) {
          result.faces.push(renderer.face3d().add(result));
        }
        for (let i = 0; i < hash2.faces.length; i++) {
          if (renderer.styledMode) {
            delete hash2.faces[i].fill;
          }
          result.faces[i].attr(hash2.faces[i], null, complete, continueAnimation);
        }
        delete hash2.faces;
      }
      return elementProto.attr.apply(this, arguments);
    };
    result.animate = function(params2, duration, complete) {
      if (params2?.faces) {
        while (result.faces.length > params2.faces.length) {
          result.faces.pop().destroy();
        }
        while (result.faces.length < params2.faces.length) {
          result.faces.push(renderer.face3d().add(result));
        }
        for (let i = 0; i < params2.faces.length; i++) {
          result.faces[i].animate(params2.faces[i], duration, complete);
        }
        delete params2.faces;
      }
      return elementProto.animate.apply(this, arguments);
    };
    return result.attr(args);
  }
  function element3d(type, shapeArgs) {
    const elem3d = new SVGElement3D.types[type](this, "g");
    elem3d.initArgs(shapeArgs);
    return elem3d;
  }
  function cuboid(shapeArgs) {
    return this.element3d("cuboid", shapeArgs);
  }
  function cuboidPath(shapeArgs) {
    const x = shapeArgs.x || 0, y = shapeArgs.y || 0, z = shapeArgs.z || 0, h = shapeArgs.height || 0, w = shapeArgs.width || 0, d = shapeArgs.depth || 0, chart = charts[this.chartIndex], options3d = chart.options.chart.options3d, alpha = options3d.alpha, incrementX = 1e6, incrementY = 10, incrementZ = 100, forcedSides = [];
    let shape, zIndex = 0, pArr = [{
      x,
      y,
      z
    }, {
      x: x + w,
      y,
      z
    }, {
      x: x + w,
      y: y + h,
      z
    }, {
      x,
      y: y + h,
      z
    }, {
      x,
      y: y + h,
      z: z + d
    }, {
      x: x + w,
      y: y + h,
      z: z + d
    }, {
      x: x + w,
      y,
      z: z + d
    }, {
      x,
      y,
      z: z + d
    }];
    pArr = perspective$1(pArr, chart, shapeArgs.insidePlotArea);
    const mapSidePath = (i) => {
      if (h === 0 && i > 1 && i < 6) {
        return {
          x: pArr[i].x,
          // When height is 0 instead of cuboid we render plane
          // so it is needed to add fake 10 height to imitate
          // cuboid for side calculation
          y: pArr[i].y + 10,
          z: pArr[i].z
        };
      }
      if (pArr[0].x === pArr[7].x && i >= 4) {
        return {
          x: pArr[i].x + 10,
          // When height is 0 instead of cuboid we render plane
          // so it is needed to add fake 10 height to imitate
          // cuboid for side calculation
          y: pArr[i].y,
          z: pArr[i].z
        };
      }
      if (d === 0 && i < 2 || i > 5) {
        return {
          x: pArr[i].x,
          // When height is 0 instead of cuboid we render plane
          // so it is needed to add fake 10 height to imitate
          // cuboid for side calculation
          y: pArr[i].y,
          z: pArr[i].z + 10
        };
      }
      return pArr[i];
    }, mapPath = (i) => pArr[i], pickShape = (verticesIndex1, verticesIndex2, side) => {
      const face1 = verticesIndex1.map(mapPath), face2 = verticesIndex2.map(mapPath), dummyFace1 = verticesIndex1.map(mapSidePath), dummyFace2 = verticesIndex2.map(mapSidePath);
      let ret = [[], -1];
      if (shapeArea(face1) < 0) {
        ret = [face1, 0];
      } else if (shapeArea(face2) < 0) {
        ret = [face2, 1];
      } else if (side) {
        forcedSides.push(side);
        if (shapeArea(dummyFace1) < 0) {
          ret = [face1, 0];
        } else if (shapeArea(dummyFace2) < 0) {
          ret = [face2, 1];
        } else {
          ret = [face1, 0];
        }
      }
      return ret;
    };
    const front = [3, 2, 1, 0], back = [7, 6, 5, 4];
    shape = pickShape(front, back, "front");
    const path1 = shape[0], isFront = shape[1];
    const top = [1, 6, 7, 0], bottom = [4, 5, 2, 3];
    shape = pickShape(top, bottom, "top");
    const path2 = shape[0], isTop = shape[1];
    const right = [1, 2, 5, 6], left = [0, 7, 4, 3];
    shape = pickShape(right, left, "side");
    const path3 = shape[0], isRight = shape[1];
    if (isRight === 1) {
      zIndex += incrementX * (chart.plotWidth - x);
    } else if (!isRight) {
      zIndex += incrementX * x;
    }
    zIndex += incrementY * (!isTop || // Numbers checked empirically
    (alpha >= 0 && alpha <= 180 || alpha < 360 && alpha > 357.5) ? chart.plotHeight - y : 10 + y);
    if (isFront === 1) {
      zIndex += incrementZ * z;
    } else if (!isFront) {
      zIndex += incrementZ * (1e3 - z);
    }
    return {
      front: this.toLinePath(path1, true),
      top: this.toLinePath(path2, true),
      side: this.toLinePath(path3, true),
      zIndexes: {
        group: Math.round(zIndex)
      },
      forcedSides,
      // Additional info about zIndexes
      isFront,
      isTop
    };
  }
  function arc3d(attribs) {
    const renderer = this, wrapper = renderer.g(), elementProto = renderer.Element.prototype, customAttribs = [
      "alpha",
      "beta",
      "x",
      "y",
      "r",
      "innerR",
      "start",
      "end",
      "depth"
    ];
    function extractCustom(params2) {
      const ca = {};
      params2 = merge$y(params2);
      let key2;
      for (key2 in params2) {
        if (customAttribs.indexOf(key2) !== -1) {
          ca[key2] = params2[key2];
          delete params2[key2];
        }
      }
      return Object.keys(ca).length ? [ca, params2] : false;
    }
    attribs = merge$y(attribs);
    attribs.alpha = (attribs.alpha || 0) * deg2rad$2;
    attribs.beta = (attribs.beta || 0) * deg2rad$2;
    wrapper.top = renderer.path();
    wrapper.side1 = renderer.path();
    wrapper.side2 = renderer.path();
    wrapper.inn = renderer.path();
    wrapper.out = renderer.path();
    wrapper.onAdd = function() {
      const parent = wrapper.parentGroup, className = wrapper.attr("class");
      wrapper.top.add(wrapper);
      for (const face of ["out", "inn", "side1", "side2"]) {
        wrapper[face].attr({
          "class": className + " highcharts-3d-side"
        }).add(parent);
      }
    };
    for (const fn of ["addClass", "removeClass"]) {
      wrapper[fn] = function() {
        const args = arguments;
        for (const face of ["top", "out", "inn", "side1", "side2"]) {
          wrapper[face][fn].apply(wrapper[face], args);
        }
      };
    }
    wrapper.setPaths = function(attribs2) {
      const paths = wrapper.renderer.arc3dPath(attribs2), zIndex = paths.zTop * 100;
      wrapper.attribs = attribs2;
      wrapper.top.attr({ d: paths.top, zIndex: paths.zTop });
      wrapper.inn.attr({ d: paths.inn, zIndex: paths.zInn });
      wrapper.out.attr({ d: paths.out, zIndex: paths.zOut });
      wrapper.side1.attr({ d: paths.side1, zIndex: paths.zSide1 });
      wrapper.side2.attr({ d: paths.side2, zIndex: paths.zSide2 });
      wrapper.zIndex = zIndex;
      wrapper.attr({ zIndex });
      if (attribs2.center) {
        wrapper.top.setRadialReference(attribs2.center);
        delete attribs2.center;
      }
    };
    wrapper.setPaths(attribs);
    wrapper.fillSetter = function(value) {
      const darker = color$5(value).brighten(-0.1).get();
      this.fill = value;
      this.side1.attr({ fill: darker });
      this.side2.attr({ fill: darker });
      this.inn.attr({ fill: darker });
      this.out.attr({ fill: darker });
      this.top.attr({ fill: value });
      return this;
    };
    for (const setter of ["opacity", "translateX", "translateY", "visibility"]) {
      wrapper[setter + "Setter"] = function(value, key2) {
        wrapper[key2] = value;
        for (const el of ["out", "inn", "side1", "side2", "top"]) {
          wrapper[el].attr(key2, value);
        }
      };
    }
    wrapper.attr = function(params2) {
      if (typeof params2 === "object") {
        const paramArr = extractCustom(params2);
        if (paramArr) {
          const ca = paramArr[0];
          arguments[0] = paramArr[1];
          if (ca.alpha !== void 0) {
            ca.alpha *= deg2rad$2;
          }
          if (ca.beta !== void 0) {
            ca.beta *= deg2rad$2;
          }
          extend$w(wrapper.attribs, ca);
          if (wrapper.attribs) {
            wrapper.setPaths(wrapper.attribs);
          }
        }
      }
      return elementProto.attr.apply(wrapper, arguments);
    };
    wrapper.animate = function(params2, animation, complete) {
      const from = this.attribs, randomProp = "data-" + Math.random().toString(26).substring(2, 9);
      delete params2.center;
      delete params2.z;
      const anim = animObject$3(pick$z(animation, this.renderer.globalAnimation));
      if (anim.duration) {
        const paramArr = extractCustom(params2);
        wrapper[randomProp] = 0;
        params2[randomProp] = 1;
        wrapper[randomProp + "Setter"] = Highcharts.noop;
        if (paramArr) {
          const to = paramArr[0], interpolate = (key2, pos) => from[key2] + (pick$z(to[key2], from[key2]) - from[key2]) * pos;
          anim.step = function(a, fx) {
            if (fx.prop === randomProp) {
              fx.elem.setPaths(merge$y(from, {
                x: interpolate("x", fx.pos),
                y: interpolate("y", fx.pos),
                r: interpolate("r", fx.pos),
                innerR: interpolate("innerR", fx.pos),
                start: interpolate("start", fx.pos),
                end: interpolate("end", fx.pos),
                depth: interpolate("depth", fx.pos)
              }));
            }
          };
        }
        animation = anim;
      }
      return elementProto.animate.call(this, params2, animation, complete);
    };
    wrapper.destroy = function() {
      this.top.destroy();
      this.out.destroy();
      this.inn.destroy();
      this.side1.destroy();
      this.side2.destroy();
      return elementProto.destroy.call(this);
    };
    wrapper.hide = function() {
      this.top.hide();
      this.out.hide();
      this.inn.hide();
      this.side1.hide();
      this.side2.hide();
    };
    wrapper.show = function(inherit) {
      this.top.show(inherit);
      this.out.show(inherit);
      this.inn.show(inherit);
      this.side1.show(inherit);
      this.side2.show(inherit);
    };
    return wrapper;
  }
  function arc3dPath(shapeArgs) {
    const cx = shapeArgs.x || 0, cy = shapeArgs.y || 0, start2 = shapeArgs.start || 0, end = (shapeArgs.end || 0) - 1e-5, r = shapeArgs.r || 0, ir = shapeArgs.innerR || 0, d = shapeArgs.depth || 0, alpha = shapeArgs.alpha || 0, beta = shapeArgs.beta || 0;
    const cs = Math.cos(start2), ss = Math.sin(start2), ce = Math.cos(end), se = Math.sin(end), rx = r * Math.cos(beta), ry = r * Math.cos(alpha), irx = ir * Math.cos(beta), iry = ir * Math.cos(alpha), dx = d * Math.sin(beta), dy = d * Math.sin(alpha);
    let top = [
      ["M", cx + rx * cs, cy + ry * ss]
    ];
    top = top.concat(curveTo(cx, cy, rx, ry, start2, end, 0, 0));
    top.push([
      "L",
      cx + irx * ce,
      cy + iry * se
    ]);
    top = top.concat(curveTo(cx, cy, irx, iry, end, start2, 0, 0));
    top.push(["Z"]);
    const b = beta > 0 ? Math.PI / 2 : 0, a = alpha > 0 ? 0 : Math.PI / 2;
    const start22 = start2 > -b ? start2 : end > -b ? -b : start2, end2 = end < PI - a ? end : start2 < PI - a ? PI - a : end, midEnd = 2 * PI - a;
    let out = [
      ["M", cx + rx * cos(start22), cy + ry * sin(start22)]
    ];
    out = out.concat(curveTo(cx, cy, rx, ry, start22, end2, 0, 0));
    if (end > midEnd && start2 < midEnd) {
      out.push([
        "L",
        cx + rx * cos(end2) + dx,
        cy + ry * sin(end2) + dy
      ]);
      out = out.concat(curveTo(cx, cy, rx, ry, end2, midEnd, dx, dy));
      out.push([
        "L",
        cx + rx * cos(midEnd),
        cy + ry * sin(midEnd)
      ]);
      out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end, 0, 0));
      out.push([
        "L",
        cx + rx * cos(end) + dx,
        cy + ry * sin(end) + dy
      ]);
      out = out.concat(curveTo(cx, cy, rx, ry, end, midEnd, dx, dy));
      out.push([
        "L",
        cx + rx * cos(midEnd),
        cy + ry * sin(midEnd)
      ]);
      out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end2, 0, 0));
    } else if (end > PI - a && start2 < PI - a) {
      out.push([
        "L",
        cx + rx * Math.cos(end2) + dx,
        cy + ry * Math.sin(end2) + dy
      ]);
      out = out.concat(curveTo(cx, cy, rx, ry, end2, end, dx, dy));
      out.push([
        "L",
        cx + rx * Math.cos(end),
        cy + ry * Math.sin(end)
      ]);
      out = out.concat(curveTo(cx, cy, rx, ry, end, end2, 0, 0));
    }
    out.push([
      "L",
      cx + rx * Math.cos(end2) + dx,
      cy + ry * Math.sin(end2) + dy
    ]);
    out = out.concat(curveTo(cx, cy, rx, ry, end2, start22, dx, dy));
    out.push(["Z"]);
    let inn = [
      ["M", cx + irx * cs, cy + iry * ss]
    ];
    inn = inn.concat(curveTo(cx, cy, irx, iry, start2, end, 0, 0));
    inn.push([
      "L",
      cx + irx * Math.cos(end) + dx,
      cy + iry * Math.sin(end) + dy
    ]);
    inn = inn.concat(curveTo(cx, cy, irx, iry, end, start2, dx, dy));
    inn.push(["Z"]);
    const side1 = [
      ["M", cx + rx * cs, cy + ry * ss],
      ["L", cx + rx * cs + dx, cy + ry * ss + dy],
      ["L", cx + irx * cs + dx, cy + iry * ss + dy],
      ["L", cx + irx * cs, cy + iry * ss],
      ["Z"]
    ];
    const side2 = [
      ["M", cx + rx * ce, cy + ry * se],
      ["L", cx + rx * ce + dx, cy + ry * se + dy],
      ["L", cx + irx * ce + dx, cy + iry * se + dy],
      ["L", cx + irx * ce, cy + iry * se],
      ["Z"]
    ];
    const angleCorr = Math.atan2(dy, -dx);
    let angleEnd = Math.abs(end + angleCorr), angleStart = Math.abs(start2 + angleCorr), angleMid = Math.abs((start2 + end) / 2 + angleCorr);
    function toZeroPIRange(angle) {
      angle = angle % (2 * Math.PI);
      if (angle > Math.PI) {
        angle = 2 * Math.PI - angle;
      }
      return angle;
    }
    angleEnd = toZeroPIRange(angleEnd);
    angleStart = toZeroPIRange(angleStart);
    angleMid = toZeroPIRange(angleMid);
    const incPrecision = 1e5, a12 = angleMid * incPrecision, a22 = angleStart * incPrecision, a3 = angleEnd * incPrecision;
    return {
      top,
      // Max angle is PI, so this is always higher
      zTop: Math.PI * incPrecision + 1,
      out,
      zOut: Math.max(a12, a22, a3),
      inn,
      zInn: Math.max(a12, a22, a3),
      side1,
      // To keep below zOut and zInn in case of same values
      zSide1: a3 * 0.99,
      side2,
      zSide2: a22 * 0.99
    };
  }
})(SVGRenderer3D || (SVGRenderer3D = {}));
const SVGRenderer3D$1 = SVGRenderer3D;
const { defaultOptions: defaultOptions$5 } = DefaultOptions;
const { addEvent: addEvent$o, merge: merge$x, pick: pick$y, splat: splat$8 } = Utilities;
function chartAddZAxis(options2) {
  return new ZAxis(this, options2);
}
function onChartAfterCreateAxes() {
  const zAxisOptions = this.options.zAxis = splat$8(this.options.zAxis || {});
  if (!this.is3d()) {
    return;
  }
  this.zAxis = [];
  zAxisOptions.forEach((axisOptions) => {
    this.addZAxis(axisOptions).setScale();
  });
}
class ZAxis extends Axis {
  constructor() {
    super(...arguments);
    this.isZAxis = true;
  }
  static compose(ChartClass) {
    const chartProto = ChartClass.prototype;
    if (!chartProto.addZAxis) {
      defaultOptions$5.zAxis = merge$x(defaultOptions$5.xAxis, {
        offset: 0,
        lineWidth: 0
      });
      chartProto.addZAxis = chartAddZAxis;
      chartProto.collectionsWithInit.zAxis = [chartProto.addZAxis];
      chartProto.collectionsWithUpdate.push("zAxis");
      addEvent$o(ChartClass, "afterCreateAxes", onChartAfterCreateAxes);
    }
  }
  /* *
   *
   *  Constructor
   *
   * */
  init(chart, userOptions) {
    this.isZAxis = true;
    super.init(chart, userOptions, "zAxis");
  }
  /* *
   *
   *  Functions
   *
   * */
  getSeriesExtremes() {
    this.hasVisibleSeries = false;
    this.dataMin = this.dataMax = this.ignoreMinPadding = this.ignoreMaxPadding = void 0;
    if (this.stacking) {
      this.stacking.buildStacks();
    }
    this.series.forEach((series) => {
      if (series.reserveSpace()) {
        let threshold = series.options.threshold;
        this.hasVisibleSeries = true;
        if (this.positiveValuesOnly && threshold <= 0) {
          threshold = void 0;
        }
        const zData = series.getColumn("z");
        if (zData.length) {
          this.dataMin = Math.min(pick$y(this.dataMin, zData[0]), Math.min.apply(null, zData));
          this.dataMax = Math.max(pick$y(this.dataMax, zData[0]), Math.max.apply(null, zData));
        }
      }
    });
  }
  /**
   * @private
   */
  setAxisSize() {
    const chart = this.chart;
    super.setAxisSize();
    this.width = this.len = chart.options.chart.options3d?.depth || 0;
    this.right = chart.chartWidth - this.width - this.left;
  }
}
const { composed: composed$7 } = Highcharts;
const { perspective } = Math3D;
const { addEvent: addEvent$n, extend: extend$v, pick: pick$x, pushUnique: pushUnique$7, wrap: wrap$5 } = Utilities;
function columnSeriesTranslate3dShapes() {
  const series = this, chart = series.chart, seriesOptions = series.options, depth = seriesOptions.depth, stack = seriesOptions.stacking ? seriesOptions.stack || 0 : series.index;
  let z = stack * (depth + (seriesOptions.groupZPadding || 1)), borderCrisp = series.borderWidth % 2 ? 0.5 : 0, point2dPos;
  if (chart.inverted && !series.yAxis.reversed) {
    borderCrisp *= -1;
  }
  if (seriesOptions.grouping !== false) {
    z = 0;
  }
  z += seriesOptions.groupZPadding || 1;
  for (const point of series.points) {
    point.outside3dPlot = null;
    if (point.y !== null) {
      const shapeArgs = extend$v({ x: 0, y: 0, width: 0, height: 0 }, point.shapeArgs || {}), dimensions = [["x", "width"], ["y", "height"]], tooltipPos = point.tooltipPos;
      let borderlessBase;
      for (const d of dimensions) {
        borderlessBase = shapeArgs[d[0]] - borderCrisp;
        if (borderlessBase < 0) {
          shapeArgs[d[1]] += shapeArgs[d[0]] + borderCrisp;
          shapeArgs[d[0]] = -borderCrisp;
          borderlessBase = 0;
        }
        if (borderlessBase + shapeArgs[d[1]] > series[d[0] + "Axis"].len && // Do not change height/width of column if 0 (#6708)
        shapeArgs[d[1]] !== 0) {
          shapeArgs[d[1]] = series[d[0] + "Axis"].len - shapeArgs[d[0]];
        }
        if (
          // Do not remove columns with zero height/width.
          shapeArgs[d[1]] !== 0 && (shapeArgs[d[0]] >= series[d[0] + "Axis"].len || shapeArgs[d[0]] + shapeArgs[d[1]] <= borderCrisp)
        ) {
          for (const key2 in shapeArgs) {
            shapeArgs[key2] = key2 === "y" ? -9999 : 0;
          }
          point.outside3dPlot = true;
        }
      }
      if (point.shapeType === "roundedRect") {
        point.shapeType = "cuboid";
      }
      point.shapeArgs = extend$v(shapeArgs, {
        z,
        depth,
        insidePlotArea: true
      });
      point2dPos = {
        x: shapeArgs.x + shapeArgs.width / 2,
        y: shapeArgs.y,
        z: z + depth / 2
        // The center of column in Z dimension
      };
      if (chart.inverted) {
        point2dPos.x = shapeArgs.height;
        point2dPos.y = point.clientX || 0;
      }
      point.axisXpos = point2dPos.x;
      point.axisYpos = point2dPos.y;
      point.axisZpos = point2dPos.z;
      point.plot3d = perspective([point2dPos], chart, true, false)[0];
      if (tooltipPos) {
        const translatedTTPos = perspective([{
          x: tooltipPos[0],
          y: tooltipPos[1],
          z: z + depth / 2
          // The center of column in Z dimension
        }], chart, true, false)[0];
        point.tooltipPos = [translatedTTPos.x, translatedTTPos.y];
      }
    }
  }
  series.z = z;
}
function compose$9(SeriesClass, StackItemClass) {
  if (pushUnique$7(composed$7, "Column3D")) {
    const seriesProto2 = SeriesClass.prototype, stackItemProto = StackItemClass.prototype, { column: ColumnSeriesClass, columnRange: ColumnRangeSeriesClass } = SeriesClass.types;
    wrap$5(seriesProto2, "alignDataLabel", wrapSeriesAlignDataLabel);
    wrap$5(seriesProto2, "justifyDataLabel", wrapSeriesJustifyDataLabel);
    wrap$5(stackItemProto, "getStackBox", wrapStackItemGetStackBox);
    if (ColumnSeriesClass) {
      const columnSeriesProto = ColumnSeriesClass.prototype, columnPointProto = columnSeriesProto.pointClass.prototype;
      columnSeriesProto.translate3dPoints = () => void 0;
      columnSeriesProto.translate3dShapes = columnSeriesTranslate3dShapes;
      addEvent$n(columnSeriesProto, "afterInit", onColumnSeriesAfterInit);
      wrap$5(columnPointProto, "hasNewShapeType", wrapColumnPointHasNewShapeType);
      wrap$5(columnSeriesProto, "animate", wrapColumnSeriesAnimate);
      wrap$5(columnSeriesProto, "plotGroup", wrapColumnSeriesPlotGroup);
      wrap$5(columnSeriesProto, "pointAttribs", wrapColumnSeriesPointAttribs);
      wrap$5(columnSeriesProto, "setState", wrapColumnSeriesSetState);
      wrap$5(columnSeriesProto, "setVisible", wrapColumnSeriesSetVisible);
      wrap$5(columnSeriesProto, "translate", wrapColumnSeriesTranslate);
    }
    if (ColumnRangeSeriesClass) {
      const columnRangeSeriesProto = ColumnRangeSeriesClass.prototype, columnRangePointProto = columnRangeSeriesProto.pointClass.prototype;
      wrap$5(columnRangePointProto, "hasNewShapeType", wrapColumnPointHasNewShapeType);
      wrap$5(columnRangeSeriesProto, "plotGroup", wrapColumnSeriesPlotGroup);
      wrap$5(columnRangeSeriesProto, "pointAttribs", wrapColumnSeriesPointAttribs);
      wrap$5(columnRangeSeriesProto, "setState", wrapColumnSeriesSetState);
      wrap$5(columnRangeSeriesProto, "setVisible", wrapColumnSeriesSetVisible);
    }
  }
}
function retrieveStacks(chart, stacking) {
  const series = chart.series, stacks = { totalStacks: 0 };
  let stackNumber, i = 1;
  series.forEach(function(s) {
    stackNumber = pick$x(s.options.stack, stacking ? 0 : series.length - 1 - s.index);
    if (!stacks[stackNumber]) {
      stacks[stackNumber] = { series: [s], position: i };
      i++;
    } else {
      stacks[stackNumber].series.push(s);
    }
  });
  stacks.totalStacks = i + 1;
  return stacks;
}
function onColumnSeriesAfterInit() {
  if (this.chart.is3d()) {
    const series = this, seriesOptions = series.options, grouping = seriesOptions.grouping, stacking = seriesOptions.stacking, reversedStacks = series.yAxis.options.reversedStacks;
    let z = 0;
    if (!(typeof grouping !== "undefined" && !grouping)) {
      const stacks = retrieveStacks(this.chart, stacking), stack = seriesOptions.stack || 0;
      let i;
      for (i = 0; i < stacks[stack].series.length; i++) {
        if (stacks[stack].series[i] === this) {
          break;
        }
      }
      z = 10 * (stacks.totalStacks - stacks[stack].position) + (reversedStacks ? i : -i);
      if (!this.xAxis.reversed) {
        z = stacks.totalStacks * 10 - z;
      }
    }
    seriesOptions.depth = seriesOptions.depth || 25;
    series.z = series.z || 0;
    seriesOptions.zIndex = z;
  }
}
function wrapColumnPointHasNewShapeType(proceed, ...args) {
  return this.series.chart.is3d() ? this.graphic && this.graphic.element.nodeName !== "g" : proceed.apply(this, args);
}
function wrapColumnSeriesAnimate(proceed) {
  if (!this.chart.is3d()) {
    proceed.apply(this, [].slice.call(arguments, 1));
  } else {
    const args = arguments, init2 = args[1], yAxis2 = this.yAxis, series = this, reversed = this.yAxis.reversed;
    if (init2) {
      for (const point of series.points) {
        if (point.y !== null) {
          point.height = point.shapeArgs.height;
          point.shapey = point.shapeArgs.y;
          point.shapeArgs.height = 1;
          if (!reversed) {
            if (point.stackY) {
              point.shapeArgs.y = point.plotY + yAxis2.translate(point.stackY);
            } else {
              point.shapeArgs.y = point.plotY + (point.negative ? -point.height : point.height);
            }
          }
        }
      }
    } else {
      for (const point of series.points) {
        if (point.y !== null) {
          point.shapeArgs.height = point.height;
          point.shapeArgs.y = point.shapey;
          if (point.graphic) {
            point.graphic[point.outside3dPlot ? "attr" : "animate"](point.shapeArgs, series.options.animation);
          }
        }
      }
      this.drawDataLabels();
    }
  }
}
function wrapColumnSeriesPlotGroup(proceed, prop, _name, _visibility, _zIndex, parent) {
  if (prop !== "dataLabelsGroup" && prop !== "markerGroup") {
    if (this.chart.is3d()) {
      if (this[prop]) {
        delete this[prop];
      }
      if (parent) {
        if (!this.chart.columnGroup) {
          this.chart.columnGroup = this.chart.renderer.g("columnGroup").add(parent);
        }
        this[prop] = this.chart.columnGroup;
        this.chart.columnGroup.attr(this.getPlotBox());
        this[prop].survive = true;
        if (prop === "group") {
          arguments[3] = "visible";
        }
      }
    }
  }
  return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
}
function wrapColumnSeriesPointAttribs(proceed) {
  const attr2 = proceed.apply(this, [].slice.call(arguments, 1));
  if (this.chart.is3d && this.chart.is3d()) {
    attr2.stroke = this.options.edgeColor || attr2.fill;
    attr2["stroke-width"] = pick$x(this.options.edgeWidth, 1);
  }
  return attr2;
}
function wrapColumnSeriesSetState(proceed, state, inherit) {
  const is3d = this.chart.is3d && this.chart.is3d();
  if (is3d) {
    this.options.inactiveOtherPoints = true;
  }
  proceed.call(this, state, inherit);
  if (is3d) {
    this.options.inactiveOtherPoints = false;
  }
}
function wrapColumnSeriesSetVisible(proceed, vis) {
  const series = this;
  if (series.chart.is3d()) {
    for (const point of series.points) {
      point.visible = point.options.visible = vis = typeof vis === "undefined" ? !pick$x(series.visible, point.visible) : vis;
      series.options.data[series.data.indexOf(point)] = point.options;
      if (point.graphic) {
        point.graphic.attr({
          visibility: vis ? "visible" : "hidden"
        });
      }
    }
  }
  proceed.apply(this, Array.prototype.slice.call(arguments, 1));
}
function wrapColumnSeriesTranslate(proceed) {
  proceed.apply(this, [].slice.call(arguments, 1));
  if (this.chart.is3d()) {
    this.translate3dShapes();
  }
}
function wrapSeriesAlignDataLabel(proceed, point, _dataLabel, options2, alignTo) {
  const chart = this.chart;
  options2.outside3dPlot = point.outside3dPlot;
  if (chart.is3d() && this.is("column")) {
    const series = this, seriesOptions = series.options, inside = pick$x(options2.inside, !!series.options.stacking), options3d = chart.options.chart.options3d, xOffset = point.pointWidth / 2 || 0;
    let dLPosition = {
      x: alignTo.x + xOffset,
      y: alignTo.y,
      z: series.z + seriesOptions.depth / 2
    };
    if (chart.inverted) {
      if (inside) {
        alignTo.width = 0;
        dLPosition.x += point.shapeArgs.height / 2;
      }
      if (options3d.alpha >= 90 && options3d.alpha <= 270) {
        dLPosition.y += point.shapeArgs.width;
      }
    }
    dLPosition = perspective([dLPosition], chart, true, false)[0];
    alignTo.x = dLPosition.x - xOffset;
    alignTo.y = point.outside3dPlot ? -9e9 : dLPosition.y;
  }
  proceed.apply(this, [].slice.call(arguments, 1));
}
function wrapSeriesJustifyDataLabel(proceed) {
  return !arguments[2].outside3dPlot ? proceed.apply(this, [].slice.call(arguments, 1)) : false;
}
function wrapStackItemGetStackBox(proceed, stackBoxProps) {
  const stackBox = proceed.apply(this, [].slice.call(arguments, 1));
  const stackItem = this, chart = this.axis.chart, { width: xWidth } = stackBoxProps;
  if (chart.is3d() && stackItem.base) {
    const baseSeriesInd = +stackItem.base.split(",")[0];
    const columnSeries = chart.series[baseSeriesInd];
    const options3d = chart.options.chart.options3d;
    if (columnSeries && columnSeries.type === "column") {
      let dLPosition = {
        x: stackBox.x + (chart.inverted ? stackBox.height : xWidth / 2),
        y: stackBox.y,
        z: columnSeries.options.depth / 2
      };
      if (chart.inverted) {
        stackBox.width = 0;
        if (options3d.alpha >= 90 && options3d.alpha <= 270) {
          dLPosition.y += xWidth;
        }
      }
      dLPosition = perspective([dLPosition], chart, true, false)[0];
      stackBox.x = dLPosition.x - xWidth / 2;
      stackBox.y = dLPosition.y;
    }
  }
  return stackBox;
}
const Column3DComposition = {
  compose: compose$9
};
const { pie: { prototype: { pointClass: PiePoint$2 } } } = SeriesRegistry$1.seriesTypes;
class Pie3DPoint extends PiePoint$2 {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  haloPath() {
    return this.series?.chart.is3d() ? [] : super.haloPath.apply(this, arguments);
  }
}
const { composed: composed$6, deg2rad: deg2rad$1 } = Highcharts;
const { pie: PieSeries$2 } = SeriesRegistry$1.seriesTypes;
const { extend: extend$u, pick: pick$w, pushUnique: pushUnique$6 } = Utilities;
class Pie3DSeries extends PieSeries$2 {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(SeriesClass) {
    if (pushUnique$6(composed$6, "Pie3D")) {
      SeriesClass.types.pie = Pie3DSeries;
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  addPoint() {
    super.addPoint.apply(this, arguments);
    if (this.chart.is3d()) {
      this.update(this.userOptions, true);
    }
  }
  /**
   * @private
   */
  animate(init2) {
    if (!this.chart.is3d()) {
      super.animate.apply(this, arguments);
    } else {
      const center = this.center, group2 = this.group, markerGroup = this.markerGroup;
      let animation = this.options.animation, attribs;
      if (animation === true) {
        animation = {};
      }
      if (init2) {
        group2.oldtranslateX = pick$w(group2.oldtranslateX, group2.translateX);
        group2.oldtranslateY = pick$w(group2.oldtranslateY, group2.translateY);
        attribs = {
          translateX: center[0],
          translateY: center[1],
          scaleX: 1e-3,
          // #1499
          scaleY: 1e-3
        };
        group2.attr(attribs);
        if (markerGroup) {
          markerGroup.attrSetters = group2.attrSetters;
          markerGroup.attr(attribs);
        }
      } else {
        attribs = {
          translateX: group2.oldtranslateX,
          translateY: group2.oldtranslateY,
          scaleX: 1,
          scaleY: 1
        };
        group2.animate(attribs, animation);
        if (markerGroup) {
          markerGroup.animate(attribs, animation);
        }
      }
    }
  }
  /**
   * @private
   */
  getDataLabelPosition(point, distance) {
    const labelPosition = super.getDataLabelPosition(point, distance);
    if (this.chart.is3d()) {
      const options3d = this.chart.options.chart.options3d, shapeArgs = point.shapeArgs, r = shapeArgs.r, a12 = (shapeArgs.alpha || options3d?.alpha) * deg2rad$1, b12 = (shapeArgs.beta || options3d?.beta) * deg2rad$1, a22 = (shapeArgs.start + shapeArgs.end) / 2, connectorPosition = labelPosition.connectorPosition, yOffset = -r * (1 - Math.cos(a12)) * Math.sin(a22), xOffset = r * (Math.cos(b12) - 1) * Math.cos(a22);
      for (const coordinates2 of [
        labelPosition?.natural,
        connectorPosition.breakAt,
        connectorPosition.touchingSliceAt
      ]) {
        coordinates2.x += xOffset;
        coordinates2.y += yOffset;
      }
    }
    return labelPosition;
  }
  /**
   * @private
   */
  pointAttribs(point) {
    const attr2 = super.pointAttribs.apply(this, arguments), options2 = this.options;
    if (this.chart.is3d() && !this.chart.styledMode) {
      attr2.stroke = options2.edgeColor || point.color || this.color;
      attr2["stroke-width"] = pick$w(options2.edgeWidth, 1);
    }
    return attr2;
  }
  /**
   * @private
   */
  translate() {
    super.translate.apply(this, arguments);
    if (!this.chart.is3d()) {
      return;
    }
    const series = this, seriesOptions = series.options, depth = seriesOptions.depth || 0, options3d = series.chart.options.chart.options3d, alpha = options3d.alpha, beta = options3d.beta;
    let z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : series._i * depth;
    z += depth / 2;
    if (seriesOptions.grouping !== false) {
      z = 0;
    }
    for (const point of series.points) {
      const shapeArgs = point.shapeArgs;
      point.shapeType = "arc3d";
      shapeArgs.z = z;
      shapeArgs.depth = depth * 0.75;
      shapeArgs.alpha = alpha;
      shapeArgs.beta = beta;
      shapeArgs.center = series.center;
      const angle = (shapeArgs.end + shapeArgs.start) / 2;
      point.slicedTranslation = {
        translateX: Math.round(Math.cos(angle) * seriesOptions.slicedOffset * Math.cos(alpha * deg2rad$1)),
        translateY: Math.round(Math.sin(angle) * seriesOptions.slicedOffset * Math.cos(alpha * deg2rad$1))
      };
    }
  }
  /**
   * @private
   */
  drawTracker() {
    super.drawTracker.apply(this, arguments);
    if (!this.chart.is3d()) {
      return;
    }
    for (const point of this.points) {
      if (point.graphic) {
        for (const face of ["out", "inn", "side1", "side2"]) {
          if (point.graphic) {
            point.graphic[face].element.point = point;
          }
        }
      }
    }
  }
}
extend$u(Pie3DSeries.prototype, {
  pointClass: Pie3DPoint
});
const { pointClass: ScatterPoint$2 } = ScatterSeries$4.prototype;
const { defined: defined$k } = Utilities;
class Scatter3DPoint extends ScatterPoint$2 {
  /* *
   *
   *  Functions
   *
   * */
  applyOptions() {
    super.applyOptions.apply(this, arguments);
    if (!defined$k(this.z)) {
      this.z = 0;
    }
    return this;
  }
}
const Scatter3DSeriesDefaults = {
  tooltip: {
    pointFormat: "x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>z: <b>{point.z}</b><br/>"
  }
};
const { pointCameraDistance } = Math3D;
const { extend: extend$t, merge: merge$w } = Utilities;
class Scatter3DSeries extends ScatterSeries$4 {
  /* *
   *
   *  Functions
   *
   * */
  pointAttribs(point) {
    const attribs = super.pointAttribs.apply(this, arguments);
    if (this.chart.is3d() && point) {
      attribs.zIndex = pointCameraDistance(point, this.chart);
    }
    return attribs;
  }
}
Scatter3DSeries.defaultOptions = merge$w(ScatterSeries$4.defaultOptions, Scatter3DSeriesDefaults);
extend$t(Scatter3DSeries.prototype, {
  axisTypes: ["xAxis", "yAxis", "zAxis"],
  // Require direct touch rather than using the k-d-tree, because the
  // k-d-tree currently doesn't take the xyz coordinate system into
  // account (#4552)
  directTouch: true,
  parallelArrays: ["x", "y", "z"],
  pointArrayMap: ["x", "y", "z"],
  pointClass: Scatter3DPoint
});
SeriesRegistry$1.registerSeriesType("scatter3d", Scatter3DSeries);
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/highcharts-3d
 * @requires highcharts
 *
 * 3D features for Highcharts JS
 *
 * License: www.highcharts.com/license
 */
const G$c = Highcharts;
Area3DSeries.compose(G$c.Series.types.area);
Axis3DAdditions.compose(G$c.Axis, G$c.Tick);
Chart3D$1.compose(G$c.Chart, G$c.Fx);
Column3DComposition.compose(G$c.Series, StackItem);
Pie3DSeries.compose(G$c.Series);
Series3D.compose(G$c.Series);
SVGRenderer3D$1.compose(RendererRegistry$1.getRendererType());
ZAxis.compose(G$c.Chart);
const { win: win$1 } = Highcharts;
const { discardElement: discardElement$1, objectEach: objectEach$6 } = Utilities;
function ajax$1(settings) {
  const headers = {
    json: "application/json",
    xml: "application/xml",
    text: "text/plain",
    octet: "application/octet-stream"
  }, r = new XMLHttpRequest();
  function handleError(xhr2, err) {
    if (settings.error) {
      settings.error(xhr2, err);
    }
  }
  if (!settings.url) {
    return false;
  }
  r.open((settings.type || "get").toUpperCase(), settings.url, true);
  if (!settings.headers?.["Content-Type"]) {
    r.setRequestHeader("Content-Type", headers[settings.dataType || "json"] || headers.text);
  }
  objectEach$6(settings.headers, function(val, key2) {
    r.setRequestHeader(key2, val);
  });
  if (settings.responseType) {
    r.responseType = settings.responseType;
  }
  r.onreadystatechange = function() {
    let res;
    if (r.readyState === 4) {
      if (r.status === 200) {
        if (settings.responseType !== "blob") {
          res = r.responseText;
          if (settings.dataType === "json") {
            try {
              res = JSON.parse(res);
            } catch (e) {
              if (e instanceof Error) {
                return handleError(r, e);
              }
            }
          }
        }
        return settings.success?.(res, r);
      }
      handleError(r, r.responseText);
    }
  };
  if (settings.data && typeof settings.data !== "string") {
    settings.data = JSON.stringify(settings.data);
  }
  r.send(settings.data);
}
function getJSON(url, success) {
  HttpUtilities.ajax({
    url,
    success,
    dataType: "json",
    headers: {
      // Override the Content-Type to avoid preflight problems with CORS
      // in the Highcharts demos
      "Content-Type": "text/plain"
    }
  });
}
function post(url, data, fetchOptions) {
  const formData = new win$1.FormData();
  objectEach$6(data, function(val, name) {
    formData.append(name, val);
  });
  formData.append("b64", "true");
  const { filename, type } = data;
  return win$1.fetch(url, {
    method: "POST",
    body: formData,
    ...fetchOptions
  }).then((res) => {
    if (res.ok) {
      res.text().then((text) => {
        const link = document.createElement("a");
        link.href = `data:${type};base64,${text}`;
        link.download = filename;
        link.click();
        discardElement$1(link);
      });
    }
  });
}
const HttpUtilities = {
  ajax: ajax$1,
  getJSON,
  post
};
const { getOptions } = DefaultOptions;
const { doc: doc$3 } = Highcharts;
const { ajax } = HttpUtilities;
const { seriesTypes } = SeriesRegistry$1;
const { addEvent: addEvent$m, defined: defined$j, extend: extend$s, fireEvent: fireEvent$a, isNumber: isNumber$k, merge: merge$v, objectEach: objectEach$5, pick: pick$v, splat: splat$7 } = Utilities;
function getFreeIndexes(numberOfColumns, seriesBuilders) {
  const freeIndexes = [], freeIndexValues = [];
  let s, i, referencedIndexes;
  for (i = 0; i < numberOfColumns; i = i + 1) {
    freeIndexes.push(true);
  }
  for (s = 0; s < seriesBuilders.length; s = s + 1) {
    referencedIndexes = seriesBuilders[s].getReferencedColumnIndexes();
    for (i = 0; i < referencedIndexes.length; i = i + 1) {
      freeIndexes[referencedIndexes[i]] = false;
    }
  }
  for (i = 0; i < freeIndexes.length; i = i + 1) {
    if (freeIndexes[i]) {
      freeIndexValues.push(i);
    }
  }
  return freeIndexValues;
}
function hasURLOption(options2) {
  return Boolean(options2 && (options2.rowsURL || options2.csvURL || options2.columnsURL));
}
class Data {
  /* *
   *
   *  Static Properties
   *
   * */
  /**
   * Creates a data object to parse data for a chart.
   *
   * @function Highcharts.data
   */
  static data(dataOptions, chartOptions = {}, chart) {
    return new Data(dataOptions, chartOptions, chart);
  }
  /**
   * Reorganize rows into columns.
   *
   * @function Highcharts.Data.rowsToColumns
   */
  static rowsToColumns(rows) {
    let row, rowsLength, col, colsLength, columns;
    if (rows) {
      columns = [];
      rowsLength = rows.length;
      for (row = 0; row < rowsLength; row++) {
        colsLength = rows[row].length;
        for (col = 0; col < colsLength; col++) {
          if (!columns[col]) {
            columns[col] = [];
          }
          columns[col][row] = rows[row][col];
        }
      }
    }
    return columns;
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(dataOptions, chartOptions = {}, chart) {
    this.rowsToColumns = Data.rowsToColumns;
    this.dateFormats = {
      "YYYY/mm/dd": {
        regex: /^(\d{4})[\-\/\.](\d{1,2})[\-\/\.](\d{1,2})$/,
        parser: function(match2) {
          return match2 ? Date.UTC(+match2[1], +match2[2] - 1, +match2[3]) : NaN;
        }
      },
      "dd/mm/YYYY": {
        regex: /^(\d{1,2})[\-\/\.](\d{1,2})[\-\/\.](\d{4})$/,
        parser: function(match2) {
          return match2 ? Date.UTC(+match2[3], +match2[2] - 1, +match2[1]) : NaN;
        },
        alternative: "mm/dd/YYYY"
        // Different format with the same regex
      },
      "mm/dd/YYYY": {
        regex: /^(\d{1,2})[\-\/\.](\d{1,2})[\-\/\.](\d{4})$/,
        parser: function(match2) {
          return match2 ? Date.UTC(+match2[3], +match2[1] - 1, +match2[2]) : NaN;
        }
      },
      "dd/mm/YY": {
        regex: /^(\d{1,2})[\-\/\.](\d{1,2})[\-\/\.](\d{2})$/,
        parser: function(match2) {
          if (!match2) {
            return NaN;
          }
          const d = /* @__PURE__ */ new Date();
          let year = +match2[3];
          if (year > d.getFullYear() - 2e3) {
            year += 1900;
          } else {
            year += 2e3;
          }
          return Date.UTC(year, +match2[2] - 1, +match2[1]);
        },
        alternative: "mm/dd/YY"
        // Different format with the same regex
      },
      "mm/dd/YY": {
        regex: /^(\d{1,2})[\-\/\.](\d{1,2})[\-\/\.](\d{2})$/,
        parser: function(match2) {
          return match2 ? Date.UTC(+match2[3] + 2e3, +match2[1] - 1, +match2[2]) : NaN;
        }
      }
    };
    this.chart = chart;
    this.chartOptions = chartOptions;
    this.options = dataOptions;
    this.rawColumns = [];
    this.init(dataOptions, chartOptions, chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the Data object with the given options
   *
   * @private
   * @function Highcharts.Data#init
   */
  init(dataOptions, chartOptions, chart) {
    let decimalPoint = dataOptions.decimalPoint, hasData;
    if (chartOptions) {
      this.chartOptions = chartOptions;
    }
    if (chart) {
      this.chart = chart;
    }
    if (decimalPoint !== "." && decimalPoint !== ",") {
      decimalPoint = void 0;
    }
    this.options = dataOptions;
    this.columns = dataOptions.columns || this.rowsToColumns(dataOptions.rows) || [];
    this.firstRowAsNames = pick$v(dataOptions.firstRowAsNames, this.firstRowAsNames, true);
    this.decimalRegex = decimalPoint && new RegExp("^(-?[0-9]+)" + decimalPoint + "([0-9]+)$");
    if (this.liveDataTimeout !== void 0) {
      clearTimeout(this.liveDataTimeout);
    }
    this.rawColumns = [];
    if (this.columns.length) {
      this.dataFound();
      hasData = !hasURLOption(dataOptions);
    }
    if (!hasData) {
      hasData = this.fetchLiveData();
    }
    if (!hasData) {
      hasData = Boolean(this.parseCSV().length);
    }
    if (!hasData) {
      hasData = Boolean(this.parseTable().length);
    }
    if (!hasData) {
      hasData = this.parseGoogleSpreadsheet();
    }
    if (!hasData && dataOptions.afterComplete) {
      dataOptions.afterComplete(this);
    }
  }
  /**
   * Get the column distribution. For example, a line series takes a single
   * column for Y values. A range series takes two columns for low and high
   * values respectively, and an OHLC series takes four columns.
   *
   * @function Highcharts.Data#getColumnDistribution
   */
  getColumnDistribution() {
    const chartOptions = this.chartOptions, options2 = this.options, xColumns = [], getValueCount = function(type = "line") {
      return (seriesTypes[type].prototype.pointArrayMap || [0]).length;
    }, getPointArrayMap = function(type = "line") {
      return seriesTypes[type].prototype.pointArrayMap;
    }, globalType = chartOptions?.chart?.type, individualCounts = [], seriesBuilders = [], seriesMapping = options2?.seriesMapping || chartOptions?.series?.map(function() {
      return { x: 0 };
    }) || [];
    let seriesIndex = 0;
    (chartOptions?.series || []).forEach((series) => {
      individualCounts.push(getValueCount(series.type || globalType));
    });
    seriesMapping.forEach((mapping) => {
      xColumns.push(mapping.x || 0);
    });
    if (xColumns.length === 0) {
      xColumns.push(0);
    }
    seriesMapping.forEach((mapping) => {
      const builder = new SeriesBuilder(), numberOfValueColumnsNeeded = individualCounts[seriesIndex] || getValueCount(globalType), seriesArr = chartOptions?.series ?? [], series = seriesArr[seriesIndex] ?? {}, defaultPointArrayMap = getPointArrayMap(series.type || globalType), pointArrayMap = defaultPointArrayMap ?? ["y"];
      if (
        // User-defined x.mapping
        defined$j(mapping.x) || // All non cartesian don't need 'x'
        series.isCartesian || // Except pie series:
        !defaultPointArrayMap
      ) {
        builder.addColumnReader(mapping.x, "x");
      }
      objectEach$5(mapping, function(val, name) {
        if (name !== "x") {
          builder.addColumnReader(val, name);
        }
      });
      for (let i = 0; i < numberOfValueColumnsNeeded; i++) {
        if (!builder.hasReader(pointArrayMap[i])) {
          builder.addColumnReader(void 0, pointArrayMap[i]);
        }
      }
      seriesBuilders.push(builder);
      seriesIndex++;
    });
    let globalPointArrayMap = getPointArrayMap(globalType);
    if (typeof globalPointArrayMap === "undefined") {
      globalPointArrayMap = ["y"];
    }
    this.valueCount = {
      global: getValueCount(globalType),
      xColumns,
      individual: individualCounts,
      seriesBuilders,
      globalPointArrayMap
    };
  }
  /**
   * When the data is parsed into columns, either by CSV, table, GS or direct
   * input, continue with other operations.
   *
   * @private
   * @function Highcharts.Data#dataFound
   */
  dataFound() {
    if (this.options.switchRowsAndColumns) {
      this.columns = this.rowsToColumns(this.columns);
    }
    this.getColumnDistribution();
    this.parseTypes();
    if (this.parsed() !== false) {
      this.complete();
    }
  }
  /**
   * Parse a CSV input string
   *
   * @function Highcharts.Data#parseCSV
   */
  parseCSV(inOptions) {
    const self2 = this, columns = this.columns = [], options2 = inOptions || this.options, startColumn = options2.startColumn || 0, endColumn = options2.endColumn || Number.MAX_VALUE, dataTypes = [], potDelimiters = {
      ",": 0,
      ";": 0,
      "	": 0
    };
    let csv = options2.csv, startRow = options2.startRow || 0, endRow = options2.endRow || Number.MAX_VALUE, itemDelimiter, lines, rowIt = 0;
    function parseRow(columnStr, rowNumber, noAdd, callbacks) {
      let i = 0, c = "", cl = "", cn = "", token = "", actualColumn = 0, column2 = 0;
      function read(j) {
        c = columnStr[j];
        cl = columnStr[j - 1];
        cn = columnStr[j + 1];
      }
      function pushType(type) {
        if (dataTypes.length < column2 + 1) {
          dataTypes.push([type]);
        }
        if (dataTypes[column2][dataTypes[column2].length - 1] !== type) {
          dataTypes[column2].push(type);
        }
      }
      function push() {
        if (startColumn > actualColumn || actualColumn > endColumn) {
          ++actualColumn;
          token = "";
          return;
        }
        if (!options2.columnTypes) {
          if (!isNaN(parseFloat(token)) && isFinite(token)) {
            token = parseFloat(token);
            pushType("number");
          } else if (!isNaN(Date.parse(token))) {
            token = token.replace(/\//g, "-");
            pushType("date");
          } else {
            pushType("string");
          }
        }
        if (columns.length < column2 + 1) {
          columns.push([]);
        }
        {
          columns[column2][rowNumber] = token;
        }
        token = "";
        ++column2;
        ++actualColumn;
      }
      if (!columnStr.trim().length) {
        return;
      }
      if (columnStr.trim()[0] === "#") {
        return;
      }
      for (; i < columnStr.length; i++) {
        read(i);
        if (c === '"') {
          read(++i);
          while (i < columnStr.length) {
            if (c === '"' && cl !== '"' && cn !== '"') {
              break;
            }
            if (c !== '"' || c === '"' && cl !== '"') {
              token += c;
            }
            read(++i);
          }
        } else if (c === itemDelimiter) {
          push();
        } else {
          token += c;
        }
      }
      push();
    }
    function guessDelimiter(lines2) {
      let points = 0, commas = 0, guessed = false;
      lines2.some(function(columnStr, i) {
        let inStr = false, c, cn, cl, token = "";
        if (i > 13) {
          return true;
        }
        for (let j = 0; j < columnStr.length; j++) {
          c = columnStr[j];
          cn = columnStr[j + 1];
          cl = columnStr[j - 1];
          if (c === "#") {
            return;
          }
          if (c === '"') {
            if (inStr) {
              if (cl !== '"' && cn !== '"') {
                while (cn === " " && j < columnStr.length) {
                  cn = columnStr[++j];
                }
                if (typeof potDelimiters[cn] !== "undefined") {
                  potDelimiters[cn]++;
                }
                inStr = false;
              }
            } else {
              inStr = true;
            }
          } else if (typeof potDelimiters[c] !== "undefined") {
            token = token.trim();
            if (!isNaN(Date.parse(token))) {
              potDelimiters[c]++;
            } else if (isNaN(token) || !isFinite(token)) {
              potDelimiters[c]++;
            }
            token = "";
          } else {
            token += c;
          }
          if (c === ",") {
            commas++;
          }
          if (c === ".") {
            points++;
          }
        }
      });
      if (potDelimiters[";"] > potDelimiters[","]) {
        guessed = ";";
      } else if (potDelimiters[","] > potDelimiters[";"]) {
        guessed = ",";
      } else {
        guessed = ",";
      }
      if (!options2.decimalPoint) {
        if (points > commas) {
          options2.decimalPoint = ".";
        } else {
          options2.decimalPoint = ",";
        }
        self2.decimalRegex = new RegExp("^(-?[0-9]+)" + options2.decimalPoint + "([0-9]+)$");
      }
      return guessed;
    }
    function deduceDateFormat(data, limit) {
      const format2 = "YYYY/mm/dd", stable = [], max2 = [];
      let thing, guessedFormat = [], calculatedFormat, i = 0, madeDeduction = false, j;
      if (!limit || limit > data.length) {
        limit = data.length;
      }
      for (; i < limit; i++) {
        if (typeof data[i] !== "undefined" && data[i]?.length) {
          thing = data[i].trim().replace(/\//g, " ").replace(/\-/g, " ").replace(/\./g, " ").split(" ");
          guessedFormat = [
            "",
            "",
            ""
          ];
          for (j = 0; j < thing.length; j++) {
            if (j < guessedFormat.length) {
              thing[j] = parseInt(thing[j], 10);
              if (thing[j]) {
                max2[j] = !max2[j] || max2[j] < thing[j] ? thing[j] : max2[j];
                if (typeof stable[j] !== "undefined") {
                  if (stable[j] !== thing[j]) {
                    stable[j] = false;
                  }
                } else {
                  stable[j] = thing[j];
                }
                if (thing[j] > 31) {
                  if (thing[j] < 100) {
                    guessedFormat[j] = "YY";
                  } else {
                    guessedFormat[j] = "YYYY";
                  }
                } else if (thing[j] > 12 && thing[j] <= 31) {
                  guessedFormat[j] = "dd";
                  madeDeduction = true;
                } else if (!guessedFormat[j].length) {
                  guessedFormat[j] = "mm";
                }
              }
            }
          }
        }
      }
      if (madeDeduction) {
        for (j = 0; j < stable.length; j++) {
          if (stable[j] !== false) {
            if (max2[j] > 12 && guessedFormat[j] !== "YY" && guessedFormat[j] !== "YYYY") {
              guessedFormat[j] = "YY";
            }
          } else if (max2[j] > 12 && guessedFormat[j] === "mm") {
            guessedFormat[j] = "dd";
          }
        }
        if (guessedFormat.length === 3 && guessedFormat[1] === "dd" && guessedFormat[2] === "dd") {
          guessedFormat[2] = "YY";
        }
        calculatedFormat = guessedFormat.join("/");
        if (!(options2.dateFormats || self2.dateFormats)[calculatedFormat]) {
          fireEvent$a(self2, "deduceDateFailed");
          return format2;
        }
        return calculatedFormat;
      }
      return format2;
    }
    if (csv && options2.beforeParse) {
      csv = options2.beforeParse.call(this, csv);
    }
    if (csv) {
      lines = csv.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split(options2.lineDelimiter || "\n");
      if (!startRow || startRow < 0) {
        startRow = 0;
      }
      if (!endRow || endRow >= lines.length) {
        endRow = lines.length - 1;
      }
      if (options2.itemDelimiter) {
        itemDelimiter = options2.itemDelimiter;
      } else {
        itemDelimiter = guessDelimiter(lines);
      }
      let offset2 = 0;
      for (rowIt = startRow; rowIt <= endRow; rowIt++) {
        if (lines[rowIt][0] === "#") {
          offset2++;
        } else {
          parseRow(lines[rowIt], rowIt - startRow - offset2);
        }
      }
      if ((!options2.columnTypes || options2.columnTypes.length === 0) && dataTypes.length && dataTypes[0].length && dataTypes[0][1] === "date" && !options2.dateFormat) {
        options2.dateFormat = deduceDateFormat(columns[0]);
      }
      this.dataFound();
    }
    return columns;
  }
  /**
   * Parse a HTML table
   *
   * @function Highcharts.Data#parseTable
   */
  parseTable() {
    const options2 = this.options, columns = this.columns || [], startRow = options2.startRow || 0, endRow = options2.endRow || Number.MAX_VALUE, startColumn = options2.startColumn || 0, endColumn = options2.endColumn || Number.MAX_VALUE;
    if (options2.table) {
      let table = options2.table;
      if (typeof table === "string") {
        table = doc$3.getElementById(table);
      }
      [].forEach.call(table.getElementsByTagName("tr"), (tr, rowNo) => {
        if (rowNo >= startRow && rowNo <= endRow) {
          [].forEach.call(tr.children, (item, colNo) => {
            const row = columns[colNo - startColumn];
            let i = 1;
            if ((item.tagName === "TD" || item.tagName === "TH") && colNo >= startColumn && colNo <= endColumn) {
              if (!columns[colNo - startColumn]) {
                columns[colNo - startColumn] = [];
              }
              columns[colNo - startColumn][rowNo - startRow] = item.innerHTML;
              while (rowNo - startRow >= i && row[rowNo - startRow - i] === void 0) {
                row[rowNo - startRow - i] = null;
                i++;
              }
            }
          });
        }
      });
      this.dataFound();
    }
    return columns;
  }
  /**
   * Fetch or refetch live data
   *
   * @function Highcharts.Data#fetchLiveData
   *
   * @return {boolean}
   *         The URLs that were tried can be found in the options
   */
  fetchLiveData() {
    const data = this, chart = this.chart, options2 = this.options, maxRetries = 3, pollingEnabled = options2.enablePolling, originalOptions = merge$v(options2);
    let currentRetries = 0, updateIntervalMs = (options2.dataRefreshRate || 2) * 1e3;
    if (!hasURLOption(options2)) {
      return false;
    }
    if (updateIntervalMs < 1e3) {
      updateIntervalMs = 1e3;
    }
    delete options2.csvURL;
    delete options2.rowsURL;
    delete options2.columnsURL;
    function performFetch(initialFetch) {
      function request(url, done, tp) {
        if (!url || !/^(http|\/|\.\/|\.\.\/)/.test(url)) {
          if (url && options2.error) {
            options2.error("Invalid URL");
          }
          return false;
        }
        if (initialFetch) {
          clearTimeout(data.liveDataTimeout);
          chart.liveDataURL = url;
        }
        function poll() {
          if (pollingEnabled && chart.liveDataURL === url) {
            data.liveDataTimeout = setTimeout(performFetch, updateIntervalMs);
          }
        }
        ajax({
          url,
          dataType: tp || "json",
          success: function(res) {
            if (chart?.series) {
              done(res);
            }
            poll();
          },
          error: function(xhr2, text) {
            if (++currentRetries < maxRetries) {
              poll();
            }
            return options2.error?.(text, xhr2);
          }
        });
        return true;
      }
      if (!request(originalOptions.csvURL, function(res) {
        chart.update({
          data: {
            csv: res
          }
        });
      }, "text")) {
        if (!request(originalOptions.rowsURL, function(res) {
          chart.update({
            data: {
              rows: res
            }
          });
        })) {
          request(originalOptions.columnsURL, function(res) {
            chart.update({
              data: {
                columns: res
              }
            });
          });
        }
      }
    }
    performFetch(true);
    return hasURLOption(options2);
  }
  /**
   * Parse a Google spreadsheet.
   *
   * @function Highcharts.Data#parseGoogleSpreadsheet
   *
   * @return {boolean}
   *         Always returns false, because it is an intermediate fetch.
   */
  parseGoogleSpreadsheet() {
    const data = this, options2 = this.options, googleSpreadsheetKey = options2.googleSpreadsheetKey, chart = this.chart, refreshRate = Math.max((options2.dataRefreshRate || 2) * 1e3, 4e3);
    const getRange = () => {
      if (options2.googleSpreadsheetRange) {
        return options2.googleSpreadsheetRange;
      }
      const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      const start2 = (alphabet.charAt(options2.startColumn || 0) || "A") + ((options2.startRow || 0) + 1);
      let end = alphabet.charAt(pick$v(options2.endColumn, -1)) || "ZZ";
      if (defined$j(options2.endRow)) {
        end += options2.endRow + 1;
      }
      return `${start2}:${end}`;
    };
    function fetchSheet(fn) {
      const url = [
        "https://sheets.googleapis.com/v4/spreadsheets",
        googleSpreadsheetKey,
        "values",
        getRange(),
        "?alt=json&majorDimension=COLUMNS&valueRenderOption=UNFORMATTED_VALUE&dateTimeRenderOption=FORMATTED_STRING&key=" + options2.googleAPIKey
      ].join("/");
      ajax({
        url,
        dataType: "json",
        success: function(json) {
          fn(json);
          if (options2.enablePolling) {
            data.liveDataTimeout = setTimeout(function() {
              fetchSheet(fn);
            }, refreshRate);
          }
        },
        error: function(xhr2, text) {
          return options2.error?.(text, xhr2);
        }
      });
    }
    if (googleSpreadsheetKey) {
      delete options2.googleSpreadsheetKey;
      fetchSheet(function(json) {
        const columns = json.values;
        if (!columns || columns.length === 0) {
          return false;
        }
        const rowCount = columns.reduce((rowCount2, column2) => Math.max(rowCount2, column2.length), 0);
        columns.forEach((column2) => {
          for (let i = 0; i < rowCount; i++) {
            if (typeof column2[i] === "undefined") {
              column2[i] = null;
            }
          }
        });
        if (chart?.series) {
          chart.update({
            data: {
              columns
            }
          });
        } else {
          data.columns = columns;
          data.dataFound();
        }
      });
    }
    return false;
  }
  /**
   * Trim a string from whitespaces.
   *
   * @function Highcharts.Data#trim
   *
   * @param {string} str
   *        String to trim
   *
   * @param {boolean} [inside=false]
   *        Remove all spaces between numbers.
   *
   * @return {string}
   *         Trimed string
   */
  trim(str, inside) {
    if (typeof str === "string") {
      str = str.replace(/^\s+|\s+$/g, "");
      if (inside && /[\d\s]+/.test(str)) {
        str = str.replace(/\s/g, "");
      }
      if (this.decimalRegex) {
        str = str.replace(this.decimalRegex, "$1.$2");
      }
    }
    return str;
  }
  /**
   * Parse numeric cells in to number types and date types in to true dates.
   *
   * @function Highcharts.Data#parseTypes
   */
  parseTypes() {
    const columns = this.columns || [];
    let col = columns.length;
    while (col--) {
      this.parseColumn(columns[col], col);
    }
  }
  /**
   * Parse a single column. Set properties like .isDatetime and .isNumeric.
   *
   * @function Highcharts.Data#parseColumn
   *
   * @param {Array<Highcharts.DataValueType>} column
   *        Column to parse
   *
   * @param {number} col
   *        Column index
   */
  parseColumn(column2, col) {
    const rawColumns = this.rawColumns, columns = this.columns = this.columns || [], firstRowAsNames = this.firstRowAsNames, isXColumn = this.valueCount?.xColumns.indexOf(col) !== -1, backup = [], chartOptions = this.chartOptions, columnTypes = this.options.columnTypes || [], columnType = columnTypes[col], forceCategory = isXColumn && (chartOptions?.xAxis && splat$7(chartOptions.xAxis)[0].type === "category") || columnType === "string", columnHasName = defined$j(column2.name);
    let row = column2.length, val, floatVal, trimVal, trimInsideVal, dateVal, diff, descending2;
    if (!rawColumns[col]) {
      rawColumns[col] = [];
    }
    while (row--) {
      val = backup[row] || column2[row];
      trimVal = this.trim(val);
      trimInsideVal = this.trim(val, true);
      floatVal = parseFloat(trimInsideVal);
      if (typeof rawColumns[col][row] === "undefined") {
        rawColumns[col][row] = trimVal;
      }
      if (forceCategory || row === 0 && firstRowAsNames && !columnHasName) {
        column2[row] = "" + trimVal;
      } else if (+trimInsideVal === floatVal) {
        column2[row] = floatVal;
        if (floatVal > 365 * 24 * 3600 * 1e3 && columnType !== "float") {
          column2.isDatetime = true;
        } else {
          column2.isNumeric = true;
        }
        if (typeof column2[row + 1] !== "undefined") {
          descending2 = floatVal > column2[row + 1];
        }
      } else {
        if (trimVal?.length) {
          dateVal = this.parseDate(val);
        }
        if (isXColumn && isNumber$k(dateVal) && columnType !== "float") {
          backup[row] = val;
          column2[row] = dateVal;
          column2.isDatetime = true;
          if (typeof column2[row + 1] !== "undefined") {
            diff = dateVal > column2[row + 1];
            if (diff !== descending2 && typeof descending2 !== "undefined") {
              if (this.alternativeFormat) {
                this.dateFormat = this.alternativeFormat;
                row = column2.length;
                this.alternativeFormat = this.dateFormats[this.dateFormat].alternative;
              } else {
                column2.unsorted = true;
              }
            }
            descending2 = diff;
          }
        } else {
          column2[row] = trimVal === "" ? null : trimVal;
          if (row !== 0 && (column2.isDatetime || column2.isNumeric)) {
            column2.mixed = true;
          }
        }
      }
    }
    if (isXColumn && column2.mixed) {
      columns[col] = rawColumns[col];
    }
    if (isXColumn && descending2 && this.options.sort) {
      for (col = 0; col < columns.length; col++) {
        columns[col].reverse();
        if (firstRowAsNames) {
          const poppedColumn = columns[col].pop();
          if (poppedColumn) {
            columns[col].unshift(poppedColumn);
          }
        }
      }
    }
  }
  /**
   * Parse a date and return it as a number. Overridable through
   * `options.parseDate`.
   *
   * @function Highcharts.Data#parseDate
   */
  parseDate(val) {
    const parseDate2 = this.options.parseDate;
    let ret, key2, format2, dateFormat2 = this.options.dateFormat || this.dateFormat, match2;
    if (parseDate2) {
      ret = parseDate2(val);
    } else if (typeof val === "string") {
      if (!dateFormat2) {
        for (key2 in this.dateFormats) {
          format2 = this.dateFormats[key2];
          match2 = val.match(format2.regex);
          if (match2) {
            this.dateFormat = dateFormat2 = key2;
            this.alternativeFormat = format2.alternative;
            ret = format2.parser(match2);
            break;
          }
        }
      } else {
        format2 = this.dateFormats[dateFormat2];
        if (!format2) {
          format2 = this.dateFormats["YYYY/mm/dd"];
        }
        match2 = val.match(format2.regex);
        if (match2) {
          ret = format2.parser(match2);
        }
      }
      if (!match2) {
        if (val.match(/:.+(GMT|UTC|[Z+\-])/)) {
          val = val.replace(/\s*(?:GMT|UTC)?([+\-])(\d\d)(\d\d)$/, "$1$2:$3").replace(/(?:\s+|GMT|UTC)([+\-])/, "$1").replace(/(\d)\s*(?:GMT|UTC|Z)$/, "$1+00:00");
        }
        match2 = Date.parse(val);
        if (typeof match2 === "object" && match2 !== null && match2.getTime) {
          ret = match2.getTime() - match2.getTimezoneOffset() * 6e4;
        } else if (isNumber$k(match2)) {
          ret = match2 - new Date(match2).getTimezoneOffset() * 6e4;
        }
      }
    }
    return ret;
  }
  /**
   * Get the parsed data in a form that we can apply directly to the
   * `series.data` config. Array positions can be mapped using the
   * `series.keys` option.
   *
   * @example
   * const data = Highcharts.data({
   *   csv: document.getElementById('data').innerHTML
   * }).getData();
   *
   * @function Highcharts.Data#getData
   *
   * @return {Array<Array<DataValueType>>|undefined} Data rows
   */
  getData() {
    if (this.columns) {
      return this.rowsToColumns(this.columns)?.slice(1);
    }
  }
  /**
   * A hook for working directly on the parsed columns
   *
   * @function Highcharts.Data#parsed
   */
  parsed() {
    if (this.options.parsed) {
      return this.options.parsed.call(this, this.columns);
    }
  }
  /**
   * If a complete callback function is provided in the options, interpret the
   * columns into a Highcharts options object.
   *
   * The function requires that the context has the `valueCount` property set.
   *
   * @function Highcharts.Data#complete
   */
  complete() {
    const columns = this.columns = this.columns || [], options2 = this.options, allSeriesBuilders = [];
    let type = "linear", series, data, i, j, r, seriesIndex, chartOptions, builder, freeIndexes, typeCol, index;
    columns.length;
    if (options2.complete || options2.afterComplete) {
      if (this.firstRowAsNames) {
        for (i = 0; i < columns.length; i++) {
          const curCol = columns[i];
          if (!defined$j(curCol.name)) {
            curCol.name = pick$v(curCol.shift(), "").toString();
          }
        }
      }
      series = [];
      freeIndexes = getFreeIndexes(columns?.length || 0, this.valueCount.seriesBuilders);
      for (seriesIndex = 0; seriesIndex < this.valueCount.seriesBuilders.length; seriesIndex++) {
        builder = this.valueCount.seriesBuilders[seriesIndex];
        if (builder.populateColumns(freeIndexes)) {
          allSeriesBuilders.push(builder);
        }
      }
      while (freeIndexes.length > 0) {
        builder = new SeriesBuilder();
        builder.addColumnReader(0, "x");
        index = freeIndexes.indexOf(0);
        if (index !== -1) {
          freeIndexes.splice(index, 1);
        }
        for (i = 0; i < this.valueCount.global; i++) {
          builder.addColumnReader(void 0, this.valueCount.globalPointArrayMap[i]);
        }
        if (builder.populateColumns(freeIndexes)) {
          allSeriesBuilders.push(builder);
        }
      }
      if (allSeriesBuilders.length > 0 && allSeriesBuilders[0].readers.length > 0) {
        typeCol = columns?.[allSeriesBuilders[0].readers[0].columnIndex ?? -1];
        if (typeof typeCol !== "undefined") {
          if (typeCol.isDatetime) {
            type = "datetime";
          } else if (!typeCol.isNumeric) {
            type = "category";
          }
        }
      }
      if (type === "category") {
        for (seriesIndex = 0; seriesIndex < allSeriesBuilders.length; seriesIndex++) {
          builder = allSeriesBuilders[seriesIndex];
          for (r = 0; r < builder.readers.length; r++) {
            if (builder.readers[r].configName === "x") {
              builder.readers[r].configName = "name";
            }
          }
        }
      }
      for (seriesIndex = 0; seriesIndex < allSeriesBuilders.length; seriesIndex++) {
        builder = allSeriesBuilders[seriesIndex];
        data = [];
        for (j = 0; j < columns[0].length; j++) {
          data[j] = builder.read(columns, j);
        }
        series[seriesIndex] = {
          data,
          pointStart: data[0] && (builder.pointIsArray ? data[0]?.[0] : data[0]?.x) || void 0
        };
        if (builder.name) {
          series[seriesIndex].name = builder.name;
        }
        if (type === "category") {
          series[seriesIndex].turboThreshold = 0;
          series[seriesIndex].pointStart = 0;
        }
      }
      chartOptions = { series };
      if (type === "linear" && (!this.xAxisOptions || this.xAxisOptions.type === type)) {
        type = this.xAxisOptions = void 0;
      } else {
        this.xAxisOptions = { type };
        if (type === "category") {
          this.xAxisOptions.uniqueNames = false;
        }
      }
      if (!this.chart) {
        merge$v(true, chartOptions, { xAxis: this.xAxisOptions || {} });
      }
      options2.complete?.(chartOptions);
      options2.afterComplete?.(this, chartOptions);
    }
  }
  /**
   * Sets properties directly on the xAxis object.
   *
   * @private
   */
  xAxisUpdateHandler(axis) {
    const options2 = this.xAxisOptions;
    if (!options2) {
      return;
    }
    if (!axis.options.type && options2.type) {
      axis.type = options2.type;
    }
    if (!axis.options.uniqueNames && options2.uniqueNames === false) {
      axis.uniqueNames = options2.uniqueNames;
    }
  }
  /**
   * Updates the chart with new data options.
   *
   * @function Highcharts.Data#update
   *
   * @param {Highcharts.DataOptions} options
   *        The new data options.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart after the new options are set.
   */
  update(options2, redraw) {
    const chart = this.chart, chartOptions = chart.options;
    if (options2) {
      options2.afterComplete = function(dataInstance, dataOptions) {
        if (!dataOptions) {
          return;
        }
        const xAxis2 = chart.xAxis[0], xAxisOptions = dataInstance.xAxisOptions;
        if (xAxisOptions && xAxis2 && (xAxis2.type !== xAxisOptions.type && !xAxis2.options.type || xAxis2.uniqueNames && xAxisOptions.uniqueNames === false && xAxis2.options.uniqueNames === void 0)) {
          xAxis2.update({}, false);
        } else {
          (dataOptions?.series || []).forEach(function(seriesOptions) {
            delete seriesOptions.pointStart;
          });
        }
        chart.update(dataOptions, redraw, true);
      };
      merge$v(true, chartOptions.data, options2);
      if (chartOptions.data?.googleSpreadsheetKey && !options2.columns) {
        delete chartOptions.data.columns;
      }
      this.init(chartOptions.data || {}, chartOptions);
    }
  }
}
addEvent$m(Axis, "afterSetOptions", function() {
  if (this.isXAxis && // Init or update
  (!this.chart.xAxis.length || this.chart.xAxis[0] === this)) {
    this.chart.data?.xAxisUpdateHandler(this);
  }
});
addEvent$m(Chart$1, "init", function(e) {
  const chart = this, callback = e.args[1], defaultDataOptions = getOptions().data;
  let userOptions = e.args[0] || {};
  if ((defaultDataOptions || userOptions && userOptions.data) && !chart.hasDataDef) {
    chart.hasDataDef = true;
    const dataOptions = merge$v(defaultDataOptions, userOptions.data);
    chart.data = new Data(extend$s(dataOptions, {
      afterComplete: function(dataInstance, dataOptions2) {
        let i, series;
        if (Object.hasOwnProperty.call(userOptions, "series")) {
          if (typeof userOptions.series === "object") {
            i = Math.max(userOptions.series.length, dataOptions2?.series?.length ?? 0);
            while (i--) {
              series = userOptions.series[i] || {};
              userOptions.series[i] = merge$v(series, dataOptions2?.series?.[i] ?? {});
            }
          } else {
            delete userOptions.series;
          }
        }
        userOptions = merge$v(dataOptions2, userOptions);
        chart.data = dataInstance;
        chart.init(userOptions, callback);
      }
    }), userOptions, chart);
    e.preventDefault();
  }
});
class SeriesBuilder {
  constructor() {
    this.readers = [];
    this.pointIsArray = true;
  }
  /**
   * Populates readers with column indexes. A reader can be added without
   * a specific index and for those readers the index is taken sequentially
   * from the free columns (this is handled by the ColumnCursor instance).
   *
   * @function SeriesBuilder#populateColumns
   */
  populateColumns(freeIndexes) {
    const builder = this;
    let enoughColumns = true;
    builder.readers.forEach((reader) => {
      if (typeof reader.columnIndex === "undefined") {
        reader.columnIndex = freeIndexes.shift();
      }
    });
    builder.readers.forEach((reader) => {
      if (typeof reader.columnIndex === "undefined") {
        enoughColumns = false;
      }
    });
    return enoughColumns;
  }
  /**
   * Reads a row from the dataset and returns a point or array depending
   * on the names of the readers.
   *
   * @function SeriesBuilder#read<T>
   */
  read(columns, rowIndex) {
    const builder = this, pointIsArray = builder.pointIsArray, point = pointIsArray ? [] : {};
    builder.readers.forEach((reader) => {
      const value = columns[reader.columnIndex][rowIndex];
      if (pointIsArray) {
        point.push(value);
      } else {
        if (reader.configName.indexOf(".") > 0) {
          Point$3.prototype.setNestedProperty(point, value, reader.configName);
        } else {
          point[reader.configName] = value;
        }
      }
    });
    if (typeof this.name === "undefined" && builder.readers.length >= 2) {
      const columnIndexes = [];
      builder.readers.forEach(function(reader) {
        if (reader.configName === "x" || reader.configName === "name" || reader.configName === "y") {
          if (typeof reader.columnIndex !== "undefined") {
            columnIndexes.push(reader.columnIndex);
          }
        }
      });
      if (columnIndexes.length >= 2) {
        columnIndexes.shift();
        columnIndexes.sort(function(a, b) {
          return a - b;
        });
      }
      this.name = columns[pick$v(columnIndexes.shift(), 0)].name;
    }
    return point;
  }
  /**
   * Creates and adds ColumnReader from the given columnIndex and configName.
   * ColumnIndex can be undefined and in that case the reader will be given
   * an index when columns are populated.
   *
   * @function SeriesBuilder#addColumnReader
   */
  addColumnReader(columnIndex, configName) {
    this.readers.push({
      columnIndex,
      configName
    });
    if (!(configName === "x" || configName === "y" || typeof configName === "undefined")) {
      this.pointIsArray = false;
    }
  }
  /**
   * Returns an array of column indexes that the builder will use when
   * reading data.
   *
   * @function SeriesBuilder#getReferencedColumnIndexes
   */
  getReferencedColumnIndexes() {
    const referencedColumnIndexes = [];
    let i, columnReader;
    for (i = 0; i < this.readers.length; i = i + 1) {
      columnReader = this.readers[i];
      if (typeof columnReader.columnIndex !== "undefined") {
        referencedColumnIndexes.push(columnReader.columnIndex);
      }
    }
    return referencedColumnIndexes;
  }
  /**
   * Returns true if the builder has a reader for the given configName.
   *
   * @function SeriesBuilder#hasReader
   */
  hasReader(configName) {
    let i, columnReader;
    for (i = 0; i < this.readers.length; i = i + 1) {
      columnReader = this.readers[i];
      if (columnReader.configName === configName) {
        return true;
      }
    }
  }
}
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/data
 * @requires highcharts
 *
 * Data module
 *
 * (c) 2012-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$b = Highcharts;
G$b.Data = G$b.Data || Data;
G$b.HttpUtilities = G$b.HttpUtilities || HttpUtilities;
G$b.ajax = G$b.HttpUtilities.ajax;
G$b.data = G$b.Data.data;
G$b.getJSON = G$b.HttpUtilities.getJSON;
G$b.post = G$b.HttpUtilities.post;
const lang$2 = {
  /**
   * @since   10.0.0
   * @product highcharts highmaps
   *
   * @private
   */
  mainBreadcrumb: "Main"
};
const options = {
  /**
   * A collection of attributes for the buttons. The object takes SVG
   * attributes like `fill`, `stroke`, `stroke-width`, as well as `style`,
   * a collection of CSS properties for the text.
   *
   * The object can also be extended with states, so you can set
   * presentational options for `hover`, `select` or `disabled` button
   * states.
   *
   * @sample {highcharts} highcharts/breadcrumbs/single-button
   *         Themed, single button
   *
   * @type    {Highcharts.SVGAttributes}
   * @since   10.0.0
   * @product highcharts
   */
  buttonTheme: {
    /** @ignore */
    fill: "none",
    /** @ignore */
    height: 18,
    /** @ignore */
    padding: 2,
    /** @ignore */
    "stroke-width": 0,
    /** @ignore */
    zIndex: 7,
    /** @ignore */
    states: {
      select: {
        fill: "none"
      }
    },
    style: {
      color: "#334eff"
      /* Palette.highlightColor80 */
    }
  },
  /**
   * The default padding for each button and separator in each direction.
   *
   * @type  {number}
   * @since 10.0.0
   */
  buttonSpacing: 5,
  /**
   * Fires when clicking on the breadcrumbs button. Two arguments are
   * passed to the function. First breadcrumb button as an SVG element.
   * Second is the breadcrumbs class, containing reference to the chart,
   * series etc.
   *
   * ```js
   * click: function(button, breadcrumbs) {
   *   console.log(button);
   * }
   * ```
   *
   * Return false to stop default buttons click action.
   *
   * @type      {Highcharts.BreadcrumbsClickCallbackFunction}
   * @since     10.0.0
   * @apioption navigation.breadcrumbs.events.click
   */
  /**
   * When the breadcrumbs are floating, the plot area will not move to
   * make space for it. By default, the chart will not make space for the
   * buttons. This property won't work when positioned in the middle.
   *
   * @sample highcharts/breadcrumbs/single-button
   *         Floating button
   *
   * @type  {boolean}
   * @since 10.0.0
   */
  floating: false,
  /**
   * A format string for the breadcrumbs button. Variables are enclosed by
   * curly brackets. Available values are passed in the declared point
   * options.
   *
   * @type      {string|undefined}
   * @since 10.0.0
   * @default   undefined
   * @sample {highcharts} highcharts/breadcrumbs/format Display custom
   *          values in breadcrumb button.
   */
  format: void 0,
  /**
   * Callback function to format the breadcrumb text from scratch.
   *
   * @type      {Highcharts.BreadcrumbsFormatterCallbackFunction}
   * @since     10.0.0
   * @default   undefined
   * @apioption navigation.breadcrumbs.formatter
   */
  /**
   * What box to align the button to. Can be either `plotBox` or
   * `spacingBox`.
   *
   * @type    {Highcharts.ButtonRelativeToValue}
   * @default plotBox
   * @since   10.0.0
   * @product highcharts highmaps
   */
  relativeTo: "plotBox",
  /**
   * Whether to reverse the order of buttons. This is common in Arabic
   * and Hebrew.
   *
   * @sample {highcharts} highcharts/breadcrumbs/rtl
   *         Breadcrumbs in RTL
   *
   * @type  {boolean}
   * @since 10.2.0
   */
  rtl: false,
  /**
   * Positioning for the button row. The breadcrumbs buttons will be
   * aligned properly for the default chart layout (title,  subtitle,
   * legend, range selector) for the custom chart layout set the position
   * properties.
   *
   * @sample  {highcharts} highcharts/breadcrumbs/single-button
   *          Single, right aligned button
   *
   * @type    {Highcharts.BreadcrumbsAlignOptions}
   * @since   10.0.0
   * @product highcharts highmaps
   */
  position: {
    /**
     * Horizontal alignment of the breadcrumbs buttons.
     *
     * @type {Highcharts.AlignValue}
     */
    align: "left",
    /**
     * Vertical alignment of the breadcrumbs buttons.
     *
     * @type {Highcharts.VerticalAlignValue}
     */
    verticalAlign: "top",
    /**
     * The X offset of the breadcrumbs button group.
     *
     * @type {number}
     */
    x: 0,
    /**
     * The Y offset of the breadcrumbs button group. When `undefined`,
     * and `floating` is `false`, the `y` position is adapted so that
     * the breadcrumbs are rendered outside the target area.
     *
     * @type {number|undefined}
     */
    y: void 0
  },
  /**
   * Options object for Breadcrumbs separator.
   *
   * @since 10.0.0
   */
  separator: {
    /**
     * @type    {string}
     * @since   10.0.0
     * @product highcharts
     */
    text: "/",
    /**
     * CSS styles for the breadcrumbs separator.
     *
     * In styled mode, the breadcrumbs separators are styled by the
     * `.highcharts-separator` rule with its different states.
     *  @type  {Highcharts.CSSObject}
     *  @since 10.0.0
     */
    style: {
      color: "#666666",
      fontSize: "0.8em"
    }
  },
  /**
   * Show full path or only a single button.
   *
   * @sample {highcharts} highcharts/breadcrumbs/single-button
   *         Single, styled button
   *
   * @type  {boolean}
   * @since 10.0.0
   */
  showFullPath: true,
  /**
   * CSS styles for all breadcrumbs.
   *
   * In styled mode, the breadcrumbs buttons are styled by the
   * `.highcharts-breadcrumbs-buttons .highcharts-button` rule with its
   * different states.
   *
   * @type  {Highcharts.SVGAttributes}
   * @since 10.0.0
   */
  style: {},
  /**
   * Whether to use HTML to render the breadcrumbs items texts.
   *
   * @type  {boolean}
   * @since 10.0.0
   */
  useHTML: false,
  /**
   * The z index of the breadcrumbs group.
   *
   * @type  {number}
   * @since 10.0.0
   */
  zIndex: 7
};
const BreadcrumbsDefaults = {
  lang: lang$2,
  options
};
const { format: format$1 } = Templating;
const { composed: composed$5 } = Highcharts;
const { addEvent: addEvent$l, defined: defined$i, extend: extend$r, fireEvent: fireEvent$9, isString: isString$3, merge: merge$u, objectEach: objectEach$4, pick: pick$u, pushUnique: pushUnique$5 } = Utilities;
function onChartAfterShowResetZoom() {
  const chart = this;
  if (chart.breadcrumbs) {
    const bbox = chart.resetZoomButton && chart.resetZoomButton.getBBox(), breadcrumbsOptions = chart.breadcrumbs.options;
    if (bbox && breadcrumbsOptions.position.align === "right" && breadcrumbsOptions.relativeTo === "plotBox") {
      chart.breadcrumbs.alignBreadcrumbsGroup(-bbox.width - breadcrumbsOptions.buttonSpacing);
    }
  }
}
function onChartDestroy() {
  if (this.breadcrumbs) {
    this.breadcrumbs.destroy();
    this.breadcrumbs = void 0;
  }
}
function onChartGetMargins() {
  const breadcrumbs = this.breadcrumbs;
  if (breadcrumbs && !breadcrumbs.options.floating && breadcrumbs.level) {
    const breadcrumbsOptions = breadcrumbs.options, buttonTheme = breadcrumbsOptions.buttonTheme, breadcrumbsHeight = (buttonTheme.height || 0) + 2 * (buttonTheme.padding || 0) + breadcrumbsOptions.buttonSpacing, verticalAlign = breadcrumbsOptions.position.verticalAlign;
    if (verticalAlign === "bottom") {
      this.marginBottom = (this.marginBottom || 0) + breadcrumbsHeight;
      breadcrumbs.yOffset = breadcrumbsHeight;
    } else if (verticalAlign !== "middle") {
      this.plotTop += breadcrumbsHeight;
      breadcrumbs.yOffset = -breadcrumbsHeight;
    } else {
      breadcrumbs.yOffset = void 0;
    }
  }
}
function onChartRedraw() {
  this.breadcrumbs && this.breadcrumbs.redraw();
}
function onChartSelection(event) {
  if (event.resetSelection === true && this.breadcrumbs) {
    this.breadcrumbs.alignBreadcrumbsGroup();
  }
}
class Breadcrumbs {
  /* *
   *
   *  Functions
   *
   * */
  static compose(ChartClass, highchartsDefaultOptions) {
    if (pushUnique$5(composed$5, "Breadcrumbs")) {
      addEvent$l(ChartClass, "destroy", onChartDestroy);
      addEvent$l(ChartClass, "afterShowResetZoom", onChartAfterShowResetZoom);
      addEvent$l(ChartClass, "getMargins", onChartGetMargins);
      addEvent$l(ChartClass, "redraw", onChartRedraw);
      addEvent$l(ChartClass, "selection", onChartSelection);
      extend$r(highchartsDefaultOptions.lang, BreadcrumbsDefaults.lang);
    }
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart, userOptions) {
    this.elementList = {};
    this.isDirty = true;
    this.level = 0;
    this.list = [];
    const chartOptions = merge$u(chart.options.drilldown && chart.options.drilldown.drillUpButton, Breadcrumbs.defaultOptions, chart.options.navigation && chart.options.navigation.breadcrumbs, userOptions);
    this.chart = chart;
    this.options = chartOptions || {};
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Update Breadcrumbs properties, like level and list.
   *
   * @function Highcharts.Breadcrumbs#updateProperties
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  updateProperties(list) {
    this.setList(list);
    this.setLevel();
    this.isDirty = true;
  }
  /**
   * Set breadcrumbs list.
   * @function Highcharts.Breadcrumbs#setList
   *
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   * @param {Highcharts.BreadcrumbsOptions} list
   *        Breadcrumbs list.
   */
  setList(list) {
    this.list = list;
  }
  /**
   * Calculate level on which chart currently is.
   *
   * @function Highcharts.Breadcrumbs#setLevel
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  setLevel() {
    this.level = this.list.length && this.list.length - 1;
  }
  /**
   * Get Breadcrumbs level
   *
   * @function Highcharts.Breadcrumbs#getLevel
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  getLevel() {
    return this.level;
  }
  /**
   * Default button text formatter.
   *
   * @function Highcharts.Breadcrumbs#getButtonText
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   * @param {Highcharts.Breadcrumbs} breadcrumb
   *        Breadcrumb.
   * @return {string}
   *         Formatted text.
   */
  getButtonText(breadcrumb) {
    const breadcrumbs = this, chart = breadcrumbs.chart, breadcrumbsOptions = breadcrumbs.options, lang2 = chart.options.lang, textFormat = pick$u(breadcrumbsOptions.format, breadcrumbsOptions.showFullPath ? "{level.name}" : "← {level.name}"), defaultText = lang2 && pick$u(lang2.drillUpText, lang2.mainBreadcrumb);
    let returnText = breadcrumbsOptions.formatter && breadcrumbsOptions.formatter(breadcrumb) || format$1(textFormat, { level: breadcrumb.levelOptions }, chart) || "";
    if ((isString$3(returnText) && !returnText.length || returnText === "← ") && defined$i(defaultText)) {
      returnText = !breadcrumbsOptions.showFullPath ? "← " + defaultText : defaultText;
    }
    return returnText;
  }
  /**
   * Redraw.
   *
   * @function Highcharts.Breadcrumbs#redraw
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  redraw() {
    if (this.isDirty) {
      this.render();
    }
    if (this.group) {
      this.group.align();
    }
    this.isDirty = false;
  }
  /**
   * Create a group, then draw breadcrumbs together with the separators.
   *
   * @function Highcharts.Breadcrumbs#render
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  render() {
    const breadcrumbs = this, chart = breadcrumbs.chart, breadcrumbsOptions = breadcrumbs.options;
    if (!breadcrumbs.group && breadcrumbsOptions) {
      breadcrumbs.group = chart.renderer.g("breadcrumbs-group").addClass("highcharts-no-tooltip highcharts-breadcrumbs").attr({
        zIndex: breadcrumbsOptions.zIndex
      }).add();
    }
    if (breadcrumbsOptions.showFullPath) {
      this.renderFullPathButtons();
    } else {
      this.renderSingleButton();
    }
    this.alignBreadcrumbsGroup();
  }
  /**
   * Draw breadcrumbs together with the separators.
   *
   * @function Highcharts.Breadcrumbs#renderFullPathButtons
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  renderFullPathButtons() {
    this.destroySingleButton();
    this.resetElementListState();
    this.updateListElements();
    this.destroyListElements();
  }
  /**
   * Render Single button - when showFullPath is not used. The button is
   * similar to the old drillUpButton
   *
   * @function Highcharts.Breadcrumbs#renderSingleButton
   * @param {Highcharts.Breadcrumbs} this Breadcrumbs class.
   */
  renderSingleButton() {
    const breadcrumbs = this, chart = breadcrumbs.chart, list = breadcrumbs.list, breadcrumbsOptions = breadcrumbs.options, buttonSpacing = breadcrumbsOptions.buttonSpacing;
    this.destroyListElements();
    const posX = breadcrumbs.group ? breadcrumbs.group.getBBox().width : buttonSpacing, posY = buttonSpacing;
    const previousBreadcrumb = list[list.length - 2];
    if (!chart.drillUpButton && this.level > 0) {
      chart.drillUpButton = breadcrumbs.renderButton(previousBreadcrumb, posX, posY);
    } else if (chart.drillUpButton) {
      if (this.level > 0) {
        this.updateSingleButton();
      } else {
        this.destroySingleButton();
      }
    }
  }
  /**
   * Update group position based on align and it's width.
   *
   * @function Highcharts.Breadcrumbs#renderSingleButton
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  alignBreadcrumbsGroup(xOffset) {
    const breadcrumbs = this;
    if (breadcrumbs.group) {
      const breadcrumbsOptions = breadcrumbs.options, buttonTheme = breadcrumbsOptions.buttonTheme, positionOptions = breadcrumbsOptions.position, alignTo = breadcrumbsOptions.relativeTo === "chart" || breadcrumbsOptions.relativeTo === "spacingBox" ? void 0 : "plotBox", bBox = breadcrumbs.group.getBBox(), additionalSpace = 2 * (buttonTheme.padding || 0) + breadcrumbsOptions.buttonSpacing;
      positionOptions.width = bBox.width + additionalSpace;
      positionOptions.height = bBox.height + additionalSpace;
      const newPositions = merge$u(positionOptions);
      if (xOffset) {
        newPositions.x += xOffset;
      }
      if (breadcrumbs.options.rtl) {
        newPositions.x += positionOptions.width;
      }
      newPositions.y = pick$u(newPositions.y, this.yOffset, 0);
      breadcrumbs.group.align(newPositions, true, alignTo);
    }
  }
  /**
   * Render a button.
   *
   * @function Highcharts.Breadcrumbs#renderButton
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   * @param {Highcharts.Breadcrumbs} breadcrumb
   *        Current breadcrumb
   * @param {Highcharts.Breadcrumbs} posX
   *        Initial horizontal position
   * @param {Highcharts.Breadcrumbs} posY
   *        Initial vertical position
   * @return {SVGElement|void}
   *        Returns the SVG button
   */
  renderButton(breadcrumb, posX, posY) {
    const breadcrumbs = this, chart = this.chart, breadcrumbsOptions = breadcrumbs.options, buttonTheme = merge$u(breadcrumbsOptions.buttonTheme);
    const button = chart.renderer.button(breadcrumbs.getButtonText(breadcrumb), posX, posY, function(e) {
      const buttonEvents = breadcrumbsOptions.events && breadcrumbsOptions.events.click;
      let callDefaultEvent;
      if (buttonEvents) {
        callDefaultEvent = buttonEvents.call(breadcrumbs, e, breadcrumb);
      }
      if (callDefaultEvent !== false) {
        if (!breadcrumbsOptions.showFullPath) {
          e.newLevel = breadcrumbs.level - 1;
        } else {
          e.newLevel = breadcrumb.level;
        }
        fireEvent$9(breadcrumbs, "up", e);
      }
    }, buttonTheme).addClass("highcharts-breadcrumbs-button").add(breadcrumbs.group);
    if (!chart.styledMode) {
      button.attr(breadcrumbsOptions.style);
    }
    return button;
  }
  /**
   * Render a separator.
   *
   * @function Highcharts.Breadcrumbs#renderSeparator
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   * @param {Highcharts.Breadcrumbs} posX
   *        Initial horizontal position
   * @param {Highcharts.Breadcrumbs} posY
   *        Initial vertical position
   * @return {Highcharts.SVGElement}
   *        Returns the SVG button
   */
  renderSeparator(posX, posY) {
    const breadcrumbs = this, chart = this.chart, breadcrumbsOptions = breadcrumbs.options, separatorOptions = breadcrumbsOptions.separator;
    const separator = chart.renderer.label(separatorOptions.text, posX, posY, void 0, void 0, void 0, false).addClass("highcharts-breadcrumbs-separator").add(breadcrumbs.group);
    if (!chart.styledMode) {
      separator.css(separatorOptions.style);
    }
    return separator;
  }
  /**
   * Update.
   * @function Highcharts.Breadcrumbs#update
   *
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   * @param {Highcharts.BreadcrumbsOptions} options
   *        Breadcrumbs class.
   * @param {boolean} redraw
   *        Redraw flag
   */
  update(options2) {
    merge$u(true, this.options, options2);
    this.destroy();
    this.isDirty = true;
  }
  /**
   * Update button text when the showFullPath set to false.
   * @function Highcharts.Breadcrumbs#updateSingleButton
   *
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  updateSingleButton() {
    const chart = this.chart, currentBreadcrumb = this.list[this.level - 1];
    if (chart.drillUpButton) {
      chart.drillUpButton.attr({
        text: this.getButtonText(currentBreadcrumb)
      });
    }
  }
  /**
   * Destroy the chosen breadcrumbs group
   *
   * @function Highcharts.Breadcrumbs#destroy
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  destroy() {
    this.destroySingleButton();
    this.destroyListElements(true);
    if (this.group) {
      this.group.destroy();
    }
    this.group = void 0;
  }
  /**
   * Destroy the elements' buttons and separators.
   *
   * @function Highcharts.Breadcrumbs#destroyListElements
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  destroyListElements(force) {
    const elementList = this.elementList;
    objectEach$4(elementList, (element, level) => {
      if (force || !elementList[level].updated) {
        element = elementList[level];
        element.button && element.button.destroy();
        element.separator && element.separator.destroy();
        delete element.button;
        delete element.separator;
        delete elementList[level];
      }
    });
    if (force) {
      this.elementList = {};
    }
  }
  /**
   * Destroy the single button if exists.
   *
   * @function Highcharts.Breadcrumbs#destroySingleButton
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  destroySingleButton() {
    if (this.chart.drillUpButton) {
      this.chart.drillUpButton.destroy();
      this.chart.drillUpButton = void 0;
    }
  }
  /**
   * Reset state for all buttons in elementList.
   *
   * @function Highcharts.Breadcrumbs#resetElementListState
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  resetElementListState() {
    objectEach$4(this.elementList, (element) => {
      element.updated = false;
    });
  }
  /**
   * Update rendered elements inside the elementList.
   *
   * @function Highcharts.Breadcrumbs#updateListElements
   *
   * @param {Highcharts.Breadcrumbs} this
   *        Breadcrumbs class.
   */
  updateListElements() {
    const breadcrumbs = this, elementList = breadcrumbs.elementList, buttonSpacing = breadcrumbs.options.buttonSpacing, posY = buttonSpacing, list = breadcrumbs.list, rtl = breadcrumbs.options.rtl, rtlFactor = rtl ? -1 : 1, updateXPosition = function(element, spacing) {
      return rtlFactor * element.getBBox().width + rtlFactor * spacing;
    }, adjustToRTL = function(element, posX2, posY2) {
      element.translate(posX2 - element.getBBox().width, posY2);
    };
    let posX = breadcrumbs.group ? updateXPosition(breadcrumbs.group, buttonSpacing) : buttonSpacing, currentBreadcrumb, breadcrumb;
    for (let i = 0, iEnd = list.length; i < iEnd; ++i) {
      const isLast = i === iEnd - 1;
      let button, separator;
      breadcrumb = list[i];
      if (elementList[breadcrumb.level]) {
        currentBreadcrumb = elementList[breadcrumb.level];
        button = currentBreadcrumb.button;
        if (!currentBreadcrumb.separator && !isLast) {
          posX += rtlFactor * buttonSpacing;
          currentBreadcrumb.separator = breadcrumbs.renderSeparator(posX, posY);
          if (rtl) {
            adjustToRTL(currentBreadcrumb.separator, posX, posY);
          }
          posX += updateXPosition(currentBreadcrumb.separator, buttonSpacing);
        } else if (currentBreadcrumb.separator && isLast) {
          currentBreadcrumb.separator.destroy();
          delete currentBreadcrumb.separator;
        }
        elementList[breadcrumb.level].updated = true;
      } else {
        button = breadcrumbs.renderButton(breadcrumb, posX, posY);
        if (rtl) {
          adjustToRTL(button, posX, posY);
        }
        posX += updateXPosition(button, buttonSpacing);
        if (!isLast) {
          separator = breadcrumbs.renderSeparator(posX, posY);
          if (rtl) {
            adjustToRTL(separator, posX, posY);
          }
          posX += updateXPosition(separator, buttonSpacing);
        }
        elementList[breadcrumb.level] = {
          button,
          separator,
          updated: true
        };
      }
      if (button) {
        button.setState(isLast ? 2 : 0);
      }
    }
  }
}
Breadcrumbs.defaultOptions = BreadcrumbsDefaults.options;
const DrilldownDefaults = {
  /**
   * When this option is false, clicking a single point will drill down
   * all points in the same category, equivalent to clicking the X axis
   * label.
   *
   * @sample {highcharts} highcharts/drilldown/allowpointdrilldown-false/
   *         Don't allow point drilldown
   *
   * @type      {boolean}
   * @default   true
   * @since     4.1.7
   * @product   highcharts
   * @apioption drilldown.allowPointDrilldown
   */
  /**
   * Options for the breadcrumbs, the navigation at the top leading the way
   * up through the drilldown levels.
   *
   * @since 10.0.0
   * @product   highcharts highmaps
   * @extends   navigation.breadcrumbs
   * @optionparent drilldown.breadcrumbs
   */
  /**
   * An array of series configurations for the drill down. Each series
   * configuration uses the same syntax as the [series](#series) option set.
   * These drilldown series are hidden by default. The drilldown series is
   * linked to the parent series' point by its `id`.
   *
   * @type      {Array<Highcharts.SeriesOptionsType>}
   * @since     3.0.8
   * @product   highcharts highmaps
   * @apioption drilldown.series
   */
  /**
   * Additional styles to apply to the X axis label for a point that
   * has drilldown data. By default it is underlined and blue to invite
   * to interaction.
   *
   * In styled mode, active label styles can be set with the
   * `.highcharts-drilldown-axis-label` class.
   *
   * @sample {highcharts} highcharts/drilldown/labels/
   *         Label styles
   *
   * @type    {Highcharts.CSSObject}
   * @default { "cursor": "pointer", "color": "#003399", "fontWeight": "bold", "textDecoration": "underline" }
   * @since   3.0.8
   * @product highcharts highmaps
   */
  activeAxisLabelStyle: {
    /** @ignore-option */
    cursor: "pointer",
    /** @ignore-option */
    color: "#0022ff",
    /** @ignore-option */
    fontWeight: "bold",
    /** @ignore-option */
    textDecoration: "underline"
  },
  /**
   * Additional styles to apply to the data label of a point that has
   * drilldown data. By default it is underlined and blue to invite to
   * interaction.
   *
   * In styled mode, active data label styles can be applied with the
   * `.highcharts-drilldown-data-label` class.
   *
   * @sample {highcharts} highcharts/drilldown/labels/
   *         Label styles
   *
   * @type    {Highcharts.CSSObject}
   * @default { "cursor": "pointer", "color": "#003399", "fontWeight": "bold", "textDecoration": "underline" }
   * @since   3.0.8
   * @product highcharts highmaps
   */
  activeDataLabelStyle: {
    cursor: "pointer",
    color: "#0022ff",
    fontWeight: "bold",
    textDecoration: "underline"
  },
  /**
   * Set the animation for all drilldown animations. Animation of a drilldown
   * occurs when drilling between a column point and a column series,
   * or a pie slice and a full pie series. Drilldown can still be used
   * between series and points of different types, but animation will
   * not occur.
   *
   * The animation can either be set as a boolean or a configuration
   * object. If `true`, it will use the 'swing' jQuery easing and a duration
   * of 500 ms. If used as a configuration object, the following properties
   * are supported:
   *
   * - `duration`: The duration of the animation in milliseconds.
   *
   * - `easing`: A string reference to an easing function set on the `Math`
   *   object. See
   *   [the easing demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-animation-easing/).
   *
   * @type    {boolean|Highcharts.AnimationOptionsObject}
   * @since   3.0.8
   * @product highcharts highmaps
   */
  animation: {
    /** @ignore-option */
    duration: 500
  },
  /**
   * Drill up button is deprecated since Highcharts v9.3.2. Use
   * [drilldown.breadcrumbs](#drilldown.breadcrumbs) instead.
   *
   * Options for the drill up button that appears when drilling down on a
   * series. The text for the button is defined in
   * [lang.drillUpText](#lang.drillUpText).
   *
   * @sample highcharts/breadcrumbs/single-button
   *         Breadcrumbs set up like a legacy button
   * @sample {highcharts} highcharts/drilldown/drillupbutton/ Drill up button
   * @sample {highmaps} highcharts/drilldown/drillupbutton/ Drill up button
   *
   * @since   3.0.8
   * @product highcharts highmaps
   *
   * @deprecated 9.3.2
   */
  drillUpButton: {
    /**
     * What box to align the button to. Can be either `plotBox` or
     * `spacingBox`.
     *
     * @type       {Highcharts.ButtonRelativeToValue}
     * @default    plotBox
     * @since      3.0.8
     * @product    highcharts highmaps
     * @apioption  drilldown.drillUpButton.relativeTo
     */
    /**
     * A collection of attributes for the button. The object takes SVG
     * attributes like `fill`, `stroke`, `stroke-width` or `r`, the border
     * radius. The theme also supports `style`, a collection of CSS
     * properties for the text. Equivalent attributes for the hover state
     * are given in `theme.states.hover`.
     *
     * In styled mode, drill-up button styles can be applied with the
     * `.highcharts-drillup-button` class.
     *
     * @sample {highcharts} highcharts/drilldown/drillupbutton/
     *         Button theming
     * @sample {highmaps} highcharts/drilldown/drillupbutton/
     *         Button theming
     *
     * @type      {Object}
     * @since     3.0.8
     * @product   highcharts highmaps
     * @apioption drilldown.drillUpButton.theme
     */
    /**
     * Positioning options for the button within the `relativeTo` box.
     * Available properties are `x`, `y`, `align` and `verticalAlign`.
     *
     * @type    {Highcharts.AlignObject}
     * @since   3.0.8
     * @product highcharts highmaps
     */
    position: {
      /**
       * Vertical alignment of the button.
       *
       * @type      {Highcharts.VerticalAlignValue}
       * @default   top
       * @product   highcharts highmaps
       * @apioption drilldown.drillUpButton.position.verticalAlign
       */
      /**
       * Horizontal alignment.
       *
       * @type {Highcharts.AlignValue}
       */
      align: "right",
      /**
       * The X offset of the button.
       */
      x: -10,
      /**
       * The Y offset of the button.
       */
      y: 10
    }
  },
  /**
   * Enable or disable zooming into a region of clicked map point you want to
   * drill into. If mapZooming is set to false the drilldown/drillup
   * animations only fade in/fade out without zooming to a specific map point.
   *
   * @sample    maps/demo/map-drilldown-preloaded/
   *            Map drilldown without async maps loading
   *
   * @type      {boolean}
   * @default   true
   * @since 11.0.0
   * @product   highmaps
   * @apioption drilldown.mapZooming
   */
  mapZooming: true
};
const { animObject: animObject$2 } = animationExports;
const { addEvent: addEvent$k, extend: extend$q, fireEvent: fireEvent$8, merge: merge$t, pick: pick$t, syncTimeout: syncTimeout$1 } = Utilities;
function applyCursorCSS(element, cursor, addClass2, styledMode) {
  element[addClass2 ? "addClass" : "removeClass"]("highcharts-drilldown-point");
  if (!styledMode) {
    element.css({ cursor });
  }
}
function columnAnimateDrilldown(init2) {
  const series = this, chart = series.chart, drilldownLevels = chart.drilldownLevels, animationOptions = animObject$2((chart.options.drilldown || {}).animation), xAxis2 = this.xAxis, styledMode = chart.styledMode;
  if (!init2) {
    let animateFrom;
    (drilldownLevels || []).forEach((level) => {
      if (series.options._ddSeriesId === level.lowerSeriesOptions._ddSeriesId) {
        animateFrom = level.shapeArgs;
        if (!styledMode && animateFrom) {
          animateFrom.fill = level.color;
        }
      }
    });
    animateFrom.x += pick$t(xAxis2.oldPos, xAxis2.pos) - xAxis2.pos;
    series.points.forEach((point) => {
      const animateTo = point.shapeArgs;
      if (!styledMode) {
        animateTo.fill = point.color;
      }
      if (point.graphic) {
        point.graphic.attr(animateFrom).animate(extend$q(point.shapeArgs, { fill: point.color || series.color }), animationOptions);
      }
    });
    if (chart.drilldown) {
      chart.drilldown.fadeInGroup(this.dataLabelsGroup);
    }
    delete this.animate;
  }
}
function columnAnimateDrillupFrom(level) {
  const series = this, animationOptions = animObject$2((series.chart.options.drilldown || {}).animation);
  (series.trackerGroups || []).forEach((key2) => {
    if (series[key2]) {
      series[key2].on("mouseover");
    }
  });
  let group2 = series.group;
  const removeGroup = group2 !== series.chart.columnGroup;
  if (removeGroup) {
    delete series.group;
  }
  (this.points || this.data).forEach((point) => {
    const graphic = point.graphic, animateTo = level.shapeArgs;
    if (graphic && animateTo) {
      const complete = () => {
        graphic.destroy();
        if (group2 && removeGroup) {
          group2 = group2.destroy();
        }
      };
      delete point.graphic;
      if (!series.chart.styledMode) {
        animateTo.fill = level.color;
      }
      if (animationOptions.duration) {
        graphic.animate(animateTo, merge$t(animationOptions, { complete }));
      } else {
        graphic.attr(animateTo);
        complete();
      }
    }
  });
}
function columnAnimateDrillupTo(init2) {
  const series = this, level = series.drilldownLevel;
  if (!init2) {
    series.points.forEach((point) => {
      const dataLabel = point.dataLabel;
      if (point.graphic) {
        point.graphic.hide();
      }
      if (dataLabel) {
        dataLabel.hidden = dataLabel.attr("visibility") === "hidden";
        if (!dataLabel.hidden) {
          dataLabel.hide();
          dataLabel.connector?.hide();
        }
      }
    });
    syncTimeout$1(() => {
      if (series.points) {
        let pointsWithNodes = [];
        series.data.forEach((el) => {
          pointsWithNodes.push(el);
        });
        if (series.nodes) {
          pointsWithNodes = pointsWithNodes.concat(series.nodes);
        }
        pointsWithNodes.forEach((point, i) => {
          const verb = i === (level && level.pointIndex) ? "show" : "fadeIn", inherit = verb === "show" ? true : void 0, dataLabel = point.dataLabel;
          if (point.graphic && // #3407
          point.visible) {
            point.graphic[verb](inherit);
          }
          if (dataLabel && !dataLabel.hidden) {
            dataLabel.fadeIn();
            dataLabel.connector?.fadeIn();
          }
        });
      }
    }, Math.max(series.chart.options.drilldown.animation.duration - 50, 0));
    delete this.animate;
  }
}
function compose$8(SeriesClass, seriesTypes2) {
  const PointClass = SeriesClass.prototype.pointClass, pointProto2 = PointClass.prototype;
  if (!pointProto2.doDrilldown) {
    const { column: ColumnSeriesClass, map: MapSeriesClass, pie: PieSeriesClass } = seriesTypes2;
    addEvent$k(PointClass, "afterInit", onPointAfterInit);
    addEvent$k(PointClass, "afterSetState", onPointAfterSetState);
    addEvent$k(PointClass, "update", onPointUpdate);
    pointProto2.doDrilldown = pointDoDrilldown;
    pointProto2.runDrilldown = pointRunDrilldown;
    addEvent$k(SeriesClass, "afterDrawDataLabels", onSeriesAfterDrawDataLabels);
    addEvent$k(SeriesClass, "afterDrawTracker", onSeriesAfterDrawTracker);
    if (ColumnSeriesClass) {
      const columnProto2 = ColumnSeriesClass.prototype;
      columnProto2.animateDrilldown = columnAnimateDrilldown;
      columnProto2.animateDrillupFrom = columnAnimateDrillupFrom;
      columnProto2.animateDrillupTo = columnAnimateDrillupTo;
    }
    if (MapSeriesClass) {
      const mapProto = MapSeriesClass.prototype;
      mapProto.animateDrilldown = mapAnimateDrilldown;
      mapProto.animateDrillupFrom = mapAnimateDrillupFrom;
      mapProto.animateDrillupTo = mapAnimateDrillupTo;
    }
    if (PieSeriesClass) {
      const pieProto = PieSeriesClass.prototype;
      pieProto.animateDrilldown = pieAnimateDrilldown;
      pieProto.animateDrillupFrom = columnAnimateDrillupFrom;
      pieProto.animateDrillupTo = columnAnimateDrillupTo;
    }
  }
}
function mapAnimateDrilldown(init2) {
  const series = this, chart = series.chart, group2 = series.group;
  if (chart && group2 && series.options && chart.options.drilldown && chart.options.drilldown.animation) {
    if (init2 && chart.mapView) {
      group2.attr({
        opacity: 0.01
      });
      chart.mapView.allowTransformAnimation = false;
      series.options.inactiveOtherPoints = true;
      series.options.enableMouseTracking = false;
    } else {
      group2.animate({
        opacity: 1
      }, chart.options.drilldown.animation, () => {
        if (series.options) {
          series.options.inactiveOtherPoints = false;
          series.options.enableMouseTracking = pick$t(series.userOptions && series.userOptions.enableMouseTracking, true);
        }
      });
      if (chart.drilldown) {
        chart.drilldown.fadeInGroup(this.dataLabelsGroup);
      }
    }
  }
}
function mapAnimateDrillupFrom() {
  const series = this, chart = series.chart;
  if (chart && chart.mapView) {
    chart.mapView.allowTransformAnimation = false;
  }
  if (series.options) {
    series.options.inactiveOtherPoints = true;
  }
}
function mapAnimateDrillupTo(init2) {
  const series = this, chart = series.chart, group2 = series.group;
  if (chart && group2) {
    if (init2) {
      group2.attr({
        opacity: 0.01
      });
      if (series.options) {
        series.options.inactiveOtherPoints = true;
      }
    } else {
      group2.animate({ opacity: 1 }, (chart.options.drilldown || {}).animation);
      if (chart.drilldown) {
        chart.drilldown.fadeInGroup(series.dataLabelsGroup);
      }
    }
  }
}
function onPointAfterInit() {
  const point = this;
  if (point.drilldown && !point.unbindDrilldownClick) {
    point.unbindDrilldownClick = addEvent$k(point, "click", onPointClick);
  }
  return point;
}
function onPointAfterSetState() {
  const point = this, series = point.series, styledMode = series.chart.styledMode;
  if (point.drilldown && series.halo && point.state === "hover") {
    applyCursorCSS(series.halo, "pointer", true, styledMode);
  } else if (series.halo) {
    applyCursorCSS(series.halo, "auto", false, styledMode);
  }
}
function onPointClick(e) {
  const point = this, series = point.series;
  if (series.xAxis && (series.chart.options.drilldown || {}).allowPointDrilldown === false) {
    series.xAxis.drilldownCategory(point.x, e);
  } else {
    point.runDrilldown(void 0, void 0, e);
  }
}
function onPointUpdate(e) {
  const point = this, options2 = e.options || {};
  if (options2.drilldown && !point.unbindDrilldownClick) {
    point.unbindDrilldownClick = addEvent$k(point, "click", onPointClick);
  } else if (!options2.drilldown && options2.drilldown !== void 0 && point.unbindDrilldownClick) {
    point.unbindDrilldownClick = point.unbindDrilldownClick();
  }
}
function onSeriesAfterDrawDataLabels() {
  const series = this, chart = series.chart, css2 = chart.options.drilldown.activeDataLabelStyle, renderer = chart.renderer, styledMode = chart.styledMode;
  for (const point of series.points) {
    const dataLabelsOptions = point.options.dataLabels, pointCSS = pick$t(point.dlOptions, dataLabelsOptions && dataLabelsOptions.style, {});
    if (point.drilldown && point.dataLabel) {
      if (css2.color === "contrast" && !styledMode) {
        pointCSS.color = renderer.getContrast(point.color || series.color);
      }
      if (dataLabelsOptions && dataLabelsOptions.color) {
        pointCSS.color = dataLabelsOptions.color;
      }
      point.dataLabel.addClass("highcharts-drilldown-data-label");
      if (!styledMode) {
        point.dataLabel.css(css2).css(pointCSS);
      }
    }
  }
}
function onSeriesAfterDrawTracker() {
  const series = this, styledMode = series.chart.styledMode;
  for (const point of series.points) {
    if (point.drilldown && point.graphic) {
      applyCursorCSS(point.graphic, "pointer", true, styledMode);
    }
  }
}
function pieAnimateDrilldown(init2) {
  const series = this, chart = series.chart, points = series.points, level = chart.drilldownLevels[chart.drilldownLevels.length - 1], animationOptions = chart.options.drilldown.animation;
  if (series.is("item")) {
    animationOptions.duration = 0;
  }
  if (series.center) {
    const animateFrom = level.shapeArgs, start2 = animateFrom.start, angle = animateFrom.end - start2, startAngle = angle / series.points.length, styledMode = chart.styledMode;
    if (!init2) {
      let animateTo, point;
      for (let i = 0, iEnd = points.length; i < iEnd; ++i) {
        point = points[i];
        animateTo = point.shapeArgs;
        if (!styledMode) {
          animateFrom.fill = level.color;
          animateTo.fill = point.color;
        }
        if (point.graphic) {
          point.graphic.attr(merge$t(animateFrom, {
            start: start2 + i * startAngle,
            end: start2 + (i + 1) * startAngle
          }))[animationOptions ? "animate" : "attr"](animateTo, animationOptions);
        }
      }
      if (chart.drilldown) {
        chart.drilldown.fadeInGroup(series.dataLabelsGroup);
      }
      delete series.animate;
    }
  }
}
function pointDoDrilldown() {
  this.runDrilldown();
}
function pointRunDrilldown(holdRedraw, category, originalEvent) {
  const point = this, series = point.series, chart = series.chart, drilldown = chart.options.drilldown || {};
  let i = (drilldown.series || []).length, seriesOptions;
  if (!chart.ddDupes) {
    chart.ddDupes = [];
  }
  chart.colorCounter = chart.symbolCounter = 0;
  while (i-- && !seriesOptions) {
    if (drilldown.series && drilldown.series[i].id === point.drilldown && point.drilldown && chart.ddDupes.indexOf(point.drilldown) === -1) {
      seriesOptions = drilldown.series[i];
      chart.ddDupes.push(point.drilldown);
    }
  }
  fireEvent$8(chart, "drilldown", {
    point,
    seriesOptions,
    category,
    originalEvent,
    points: typeof category !== "undefined" && series.xAxis.getDDPoints(category).slice(0)
  }, (e) => {
    const chart2 = e.point.series && e.point.series.chart, seriesOptions2 = e.seriesOptions;
    if (chart2 && seriesOptions2) {
      if (holdRedraw) {
        chart2.addSingleSeriesAsDrilldown(e.point, seriesOptions2);
      } else {
        chart2.addSeriesAsDrilldown(e.point, seriesOptions2);
      }
    }
  });
}
const DrilldownSeries = {
  compose: compose$8
};
const { animObject: animObject$1 } = animationExports;
const { noop: noop$3 } = Highcharts;
const { addEvent: addEvent$j, defined: defined$h, diffObjects, extend: extend$p, fireEvent: fireEvent$7, merge: merge$s, objectEach: objectEach$3, pick: pick$s, removeEvent: removeEvent$3, syncTimeout } = Utilities;
let ddSeriesId = 1;
function axisDrilldownCategory(x, originalEvent) {
  this.getDDPoints(x).forEach(function(point) {
    if (point && point.series && point.series.visible && point.runDrilldown) {
      point.runDrilldown(true, x, originalEvent);
    }
  });
  this.chart.applyDrilldown();
}
function axisGetDDPoints(x) {
  return this.ddPoints && this.ddPoints[x] || [];
}
function createBreadcrumbsList(chart) {
  const list = [], drilldownLevels = chart.drilldownLevels;
  if (drilldownLevels && drilldownLevels.length) {
    if (!list[0]) {
      list.push({
        level: 0,
        levelOptions: drilldownLevels[0].seriesOptions
      });
    }
    drilldownLevels.forEach(function(level) {
      const lastBreadcrumb = list[list.length - 1];
      if (level.levelNumber + 1 > lastBreadcrumb.level) {
        list.push({
          level: level.levelNumber + 1,
          levelOptions: merge$s({
            name: level.lowerSeries.name
          }, level.pointOptions)
        });
      }
    });
  }
  return list;
}
class ChartAdditions {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.chart = chart;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Add a series to the chart as drilldown from a specific point in the
   * parent series. This method is used for async drilldown, when clicking a
   * point in a series should result in loading and displaying a more
   * high-resolution series. When not async, the setup is simpler using the
   * [drilldown.series](https://api.highcharts.com/highcharts/drilldown.series)
   * options structure.
   *
   * @sample highcharts/drilldown/async/
   *         Async drilldown
   *
   * @function Highcharts.Chart#addSeriesAsDrilldown
   *
   * @param {Highcharts.Point} point
   * The point from which the drilldown will start.
   *
   * @param {Highcharts.SeriesOptionsType} options
   * The series options for the new, detailed series.
   */
  addSeriesAsDrilldown(point, options2) {
    const chart = this.chart || this;
    fireEvent$7(this, "addSeriesAsDrilldown", { seriesOptions: options2 });
    if (chart.mapView) {
      point.series.isDrilling = true;
      chart.series.forEach((series) => {
        series.options.inactiveOtherPoints = true;
        series.dataLabelsGroup?.destroy();
        delete series.dataLabelsGroup;
      });
      if (chart.options.drilldown && !chart.mapView.projection.hasGeoProjection && DrilldownDefaults) {
        const userDrilldown = diffObjects(chart.options.drilldown, DrilldownDefaults);
        if (!defined$h(userDrilldown.mapZooming)) {
          chart.options.drilldown.mapZooming = false;
        }
      }
      if (chart.options.drilldown && chart.options.drilldown.animation && chart.options.drilldown.mapZooming) {
        chart.mapView.allowTransformAnimation = true;
        const animOptions = animObject$1(chart.options.drilldown.animation);
        if (typeof animOptions !== "boolean") {
          const userComplete = animOptions.complete, drilldownComplete = function(obj) {
            if (obj && obj.applyDrilldown && chart.mapView) {
              chart.addSingleSeriesAsDrilldown(point, options2);
              chart.applyDrilldown();
              chart.mapView.allowTransformAnimation = false;
            }
          };
          animOptions.complete = function() {
            if (userComplete) {
              userComplete.apply(this, arguments);
            }
            drilldownComplete.apply(this, arguments);
          };
        }
        point.zoomTo(animOptions);
      } else {
        chart.addSingleSeriesAsDrilldown(point, options2);
        chart.applyDrilldown();
      }
    } else {
      chart.addSingleSeriesAsDrilldown(point, options2);
      chart.applyDrilldown();
    }
  }
  /** @private */
  addSingleSeriesAsDrilldown(point, ddOptions) {
    const chart = this.chart || this, oldSeries = point.series, xAxis2 = oldSeries.xAxis, yAxis2 = oldSeries.yAxis, colorProp = chart.styledMode ? { colorIndex: pick$s(point.colorIndex, oldSeries.colorIndex) } : { color: point.color || oldSeries.color }, levelNumber = oldSeries.options._levelNumber || 0;
    if (!chart.drilldownLevels) {
      chart.drilldownLevels = [];
    }
    ddOptions = extend$p(extend$p({
      _ddSeriesId: ddSeriesId++
    }, colorProp), ddOptions);
    let levelSeries = [], levelSeriesOptions = [], last;
    last = chart.drilldownLevels[chart.drilldownLevels.length - 1];
    if (last && last.levelNumber !== levelNumber) {
      last = void 0;
    }
    oldSeries.chart.series.forEach((series) => {
      if (series.xAxis === xAxis2) {
        series.options._ddSeriesId = series.options._ddSeriesId || ddSeriesId++;
        series.options.colorIndex = series.colorIndex;
        series.options._levelNumber = series.options._levelNumber || levelNumber;
        if (last) {
          levelSeries = last.levelSeries;
          levelSeriesOptions = last.levelSeriesOptions;
        } else {
          levelSeries.push(series);
          series.purgedOptions = merge$s({
            _ddSeriesId: series.options._ddSeriesId,
            _levelNumber: series.options._levelNumber,
            selected: series.options.selected
          }, series.userOptions);
          levelSeriesOptions.push(series.purgedOptions);
        }
      }
    });
    const level = extend$p({
      levelNumber,
      seriesOptions: oldSeries.options,
      seriesPurgedOptions: oldSeries.purgedOptions,
      levelSeriesOptions,
      levelSeries,
      shapeArgs: point.shapeArgs,
      // No graphic in line series with markers disabled
      bBox: point.graphic ? point.graphic.getBBox() : {},
      color: point.isNull ? "rgba(0,0,0,0)" : colorProp.color,
      lowerSeriesOptions: ddOptions,
      pointOptions: point.options,
      pointIndex: point.index,
      oldExtremes: {
        xMin: xAxis2 && xAxis2.userMin,
        xMax: xAxis2 && xAxis2.userMax,
        yMin: yAxis2 && yAxis2.userMin,
        yMax: yAxis2 && yAxis2.userMax
      },
      resetZoomButton: last && last.levelNumber === levelNumber ? void 0 : chart.resetZoomButton
    }, colorProp);
    chart.drilldownLevels.push(level);
    if (xAxis2 && xAxis2.names) {
      xAxis2.names.length = 0;
    }
    const newSeries = level.lowerSeries = chart.addSeries(ddOptions, false);
    newSeries.options._levelNumber = levelNumber + 1;
    if (xAxis2) {
      xAxis2.oldPos = xAxis2.pos;
      xAxis2.userMin = xAxis2.userMax = null;
      yAxis2.userMin = yAxis2.userMax = null;
    }
    newSeries.isDrilling = true;
    if (oldSeries.type === newSeries.type) {
      newSeries.animate = newSeries.animateDrilldown || noop$3;
      newSeries.options.animation = true;
    }
  }
  applyDrilldown() {
    const chart = this.chart || this, drilldownLevels = chart.drilldownLevels;
    let levelToRemove;
    if (drilldownLevels && drilldownLevels.length > 0) {
      levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
      chart.hasCartesianSeries = drilldownLevels.some(
        (level) => level.lowerSeries.isCartesian
        // #19725
      );
      (chart.drilldownLevels || []).forEach((level) => {
        if (chart.mapView && chart.options.drilldown && chart.options.drilldown.mapZooming) {
          chart.redraw();
          level.lowerSeries.isDrilling = false;
          chart.mapView.fitToBounds(level.lowerSeries.bounds);
          level.lowerSeries.isDrilling = true;
        }
        if (level.levelNumber === levelToRemove) {
          level.levelSeries.forEach((series) => {
            if (!chart.mapView) {
              if (series.options && series.options._levelNumber === levelToRemove) {
                series.remove(false);
              }
            } else if (series.options && series.options._levelNumber === levelToRemove && series.group) {
              let animOptions = {};
              if (chart.options.drilldown) {
                animOptions = chart.options.drilldown.animation;
              }
              series.group.animate({
                opacity: 0
              }, animOptions, () => {
                series.remove(false);
                if (!level.levelSeries.filter((el) => Object.keys(el).length).length) {
                  if (chart.resetZoomButton) {
                    chart.resetZoomButton.hide();
                    delete chart.resetZoomButton;
                  }
                  chart.pointer?.reset();
                  fireEvent$7(chart, "afterDrilldown");
                  if (chart.mapView) {
                    chart.series.forEach((series2) => {
                      series2.isDirtyData = true;
                      series2.isDrilling = false;
                    });
                    chart.mapView.fitToBounds(void 0, void 0);
                    chart.mapView.allowTransformAnimation = true;
                  }
                  fireEvent$7(chart, "afterApplyDrilldown");
                }
              });
            }
          });
        }
      });
    }
    if (!chart.mapView) {
      if (chart.resetZoomButton) {
        chart.resetZoomButton.hide();
        delete chart.resetZoomButton;
      }
      chart.pointer?.reset();
      fireEvent$7(chart, "afterDrilldown");
      if (!chart.hasCartesianSeries) {
        chart.axes.forEach((axis) => {
          axis.destroy(true);
          axis.init(chart, merge$s(axis.userOptions, axis.options));
        });
      }
      chart.redraw();
      fireEvent$7(chart, "afterApplyDrilldown");
    }
  }
  /**
   * When the chart is drilled down to a child series, calling
   * `chart.drillUp()` will drill up to the parent series.
   *
   * @requires  modules/drilldown
   *
   * @function Highcharts.Chart#drillUp
   *
   * @sample {highcharts} highcharts/drilldown/programmatic
   *         Programmatic drilldown
   */
  drillUp(isMultipleDrillUp) {
    const chart = this.chart || this;
    if (!chart.drilldownLevels || chart.drilldownLevels.length === 0) {
      return;
    }
    fireEvent$7(chart, "beforeDrillUp");
    const drilldownLevels = chart.drilldownLevels, levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber, chartSeries = chart.series, drilldownLevelsNumber = chart.drilldownLevels.length, addSeries = (seriesOptions, oldSeries) => {
      let addedSeries;
      chartSeries.forEach((series) => {
        if (series.options._ddSeriesId === seriesOptions._ddSeriesId) {
          addedSeries = series;
        }
      });
      addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
      if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
        addedSeries.animate = addedSeries.animateDrillupTo;
      }
      if (seriesOptions === level.seriesPurgedOptions) {
        return addedSeries;
      }
    }, removeSeries = (oldSeries) => {
      oldSeries.remove(false);
      chart.series.forEach((series) => {
        if (series.colorAxis) {
          series.isDirtyData = true;
        }
        series.options.inactiveOtherPoints = false;
      });
      chart.redraw();
    };
    let i = drilldownLevels.length, seriesI, level, oldExtremes;
    chart.symbolCounter = chart.colorCounter = 0;
    while (i--) {
      let oldSeries, newSeries;
      level = drilldownLevels[i];
      if (level.levelNumber === levelNumber) {
        drilldownLevels.pop();
        oldSeries = level.lowerSeries;
        if (!oldSeries.chart) {
          seriesI = chartSeries.length;
          while (seriesI--) {
            if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id && chartSeries[seriesI].options._levelNumber === levelNumber + 1) {
              oldSeries = chartSeries[seriesI];
              break;
            }
          }
        }
        oldSeries.dataTable.setColumn("x", []);
        if (oldSeries.xAxis && oldSeries.xAxis.names && (drilldownLevelsNumber === 0 || i === drilldownLevelsNumber - 1)) {
          oldSeries.xAxis.names.length = 0;
        }
        level.levelSeriesOptions.forEach((el) => {
          const addedSeries = addSeries(el, oldSeries);
          if (addedSeries) {
            newSeries = addedSeries;
          }
        });
        fireEvent$7(chart, "drillup", {
          seriesOptions: level.seriesPurgedOptions || level.seriesOptions
        });
        if (newSeries) {
          if (newSeries.type === oldSeries.type) {
            newSeries.drilldownLevel = level;
            newSeries.options.animation = chart.options.drilldown.animation;
            if (oldSeries.animateDrillupFrom && oldSeries.chart) {
              oldSeries.animateDrillupFrom(level);
            }
          }
          newSeries.options._levelNumber = levelNumber;
        }
        const seriesToRemove = oldSeries;
        if (!chart.mapView) {
          seriesToRemove.remove(false);
        }
        if (newSeries && newSeries.xAxis) {
          oldExtremes = level.oldExtremes;
          newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
          newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
        }
        if (level.resetZoomButton) {
          chart.resetZoomButton = level.resetZoomButton;
        }
        if (!chart.mapView) {
          fireEvent$7(chart, "afterDrillUp");
        } else {
          const shouldAnimate = level.levelNumber === levelNumber && isMultipleDrillUp, zoomingDrill = chart.options.drilldown && chart.options.drilldown.animation && chart.options.drilldown.mapZooming;
          if (shouldAnimate) {
            oldSeries.remove(false);
          } else {
            if (oldSeries.dataLabelsGroup) {
              oldSeries.dataLabelsGroup.destroy();
              delete oldSeries.dataLabelsGroup;
            }
            if (chart.mapView && newSeries) {
              if (zoomingDrill) {
                oldSeries.isDrilling = true;
                newSeries.isDrilling = true;
                chart.redraw(false);
                chart.mapView.fitToBounds(oldSeries.bounds, void 0, true, false);
              }
              chart.mapView.allowTransformAnimation = true;
              fireEvent$7(chart, "afterDrillUp", {
                seriesOptions: newSeries ? newSeries.userOptions : void 0
              });
              if (zoomingDrill) {
                chart.mapView.setView(void 0, pick$s(chart.mapView.minZoom, 1), true, {
                  complete: function() {
                    if (Object.prototype.hasOwnProperty.call(this, "complete")) {
                      removeSeries(oldSeries);
                    }
                  }
                });
                newSeries._hasTracking = false;
              } else {
                chart.mapView.allowTransformAnimation = false;
                if (oldSeries.group) {
                  oldSeries.group.animate({
                    opacity: 0
                  }, chart.options.drilldown.animation, () => {
                    removeSeries(oldSeries);
                    if (chart.mapView) {
                      chart.mapView.allowTransformAnimation = true;
                    }
                  });
                } else {
                  removeSeries(oldSeries);
                  chart.mapView.allowTransformAnimation = true;
                }
              }
              newSeries.isDrilling = false;
            }
          }
        }
      }
    }
    if (!chart.mapView && !isMultipleDrillUp) {
      chart.redraw();
    }
    if (chart.ddDupes) {
      chart.ddDupes.length = 0;
    }
    fireEvent$7(chart, "drillupall");
  }
  /**
   * A function to fade in a group. First, the element is being hidden, then,
   * using `opactiy`, is faded in. Used for example by `dataLabelsGroup` where
   * simple SVGElement.fadeIn() is not enough, because of other features (e.g.
   * InactiveState) using `opacity` to fadeIn/fadeOut.
   *
   * @requires modules/drilldown
   *
   * @private
   * @param {SVGElement} [group]
   *        The SVG element to be faded in.
   */
  fadeInGroup(group2) {
    const chart = this.chart, animationOptions = animObject$1(chart.options.drilldown.animation);
    if (group2) {
      group2.hide();
      syncTimeout(() => {
        if (group2 && group2.added) {
          group2.fadeIn();
        }
      }, Math.max(animationOptions.duration - 50, 0));
    }
  }
  /**
   * Update function to be called internally from Chart.update (#7600, #12855)
   * @private
   */
  update(options2, redraw) {
    const chart = this.chart;
    merge$s(true, chart.options.drilldown, options2);
    if (pick$s(redraw, true)) {
      chart.redraw();
    }
  }
}
var Drilldown;
(function(Drilldown2) {
  function compose2(AxisClass, ChartClass, highchartsDefaultOptions, SeriesClass, seriesTypes2, SVGRendererClass, TickClass) {
    DrilldownSeries.compose(SeriesClass, seriesTypes2);
    const DrilldownChart = ChartClass, chartProto = DrilldownChart.prototype;
    if (!chartProto.drillUp) {
      const SVGElementClass = SVGRendererClass.prototype.Element, addonProto = ChartAdditions.prototype, axisProto = AxisClass.prototype, elementProto = SVGElementClass.prototype, tickProto = TickClass.prototype;
      axisProto.drilldownCategory = axisDrilldownCategory;
      axisProto.getDDPoints = axisGetDDPoints;
      Breadcrumbs.compose(ChartClass, highchartsDefaultOptions);
      addEvent$j(Breadcrumbs, "up", onBreadcrumbsUp);
      chartProto.addSeriesAsDrilldown = addonProto.addSeriesAsDrilldown;
      chartProto.addSingleSeriesAsDrilldown = addonProto.addSingleSeriesAsDrilldown;
      chartProto.applyDrilldown = addonProto.applyDrilldown;
      chartProto.drillUp = addonProto.drillUp;
      addEvent$j(DrilldownChart, "afterDrilldown", onChartAfterDrilldown);
      addEvent$j(DrilldownChart, "afterDrillUp", onChartAfterDrillUp);
      addEvent$j(DrilldownChart, "afterInit", onChartAfterInit2);
      addEvent$j(DrilldownChart, "drillup", onChartDrillup);
      addEvent$j(DrilldownChart, "drillupall", onChartDrillupall);
      addEvent$j(DrilldownChart, "render", onChartRender2);
      addEvent$j(DrilldownChart, "update", onChartUpdate2);
      highchartsDefaultOptions.drilldown = DrilldownDefaults;
      elementProto.fadeIn = svgElementFadeIn;
      tickProto.drillable = tickDrillable;
    }
  }
  Drilldown2.compose = compose2;
  function onBreadcrumbsUp(e) {
    const chart = this.chart, drillUpsNumber = this.getLevel() - e.newLevel;
    let isMultipleDrillUp = drillUpsNumber > 1;
    for (let i = 0; i < drillUpsNumber; i++) {
      if (i === drillUpsNumber - 1) {
        isMultipleDrillUp = false;
      }
      chart.drillUp(isMultipleDrillUp);
    }
  }
  function onChartAfterDrilldown() {
    const chart = this, drilldownOptions = chart.options.drilldown, breadcrumbsOptions = drilldownOptions && drilldownOptions.breadcrumbs;
    if (!chart.breadcrumbs) {
      chart.breadcrumbs = new Breadcrumbs(chart, breadcrumbsOptions);
    }
    chart.breadcrumbs.updateProperties(createBreadcrumbsList(chart));
  }
  function onChartAfterDrillUp() {
    const chart = this;
    if (chart.breadcrumbs) {
      chart.breadcrumbs.updateProperties(createBreadcrumbsList(chart));
    }
  }
  function onChartAfterInit2() {
    this.drilldown = new ChartAdditions(this);
  }
  function onChartDrillup() {
    const chart = this;
    if (chart.resetZoomButton) {
      chart.resetZoomButton = chart.resetZoomButton.destroy();
    }
  }
  function onChartDrillupall() {
    const chart = this;
    if (chart.resetZoomButton) {
      chart.showResetZoom();
    }
  }
  function onChartRender2() {
    (this.xAxis || []).forEach((axis) => {
      axis.ddPoints = {};
      axis.series.forEach((series) => {
        const xData = series.getColumn("x"), points = series.points;
        for (let i = 0, iEnd = xData.length, p; i < iEnd; i++) {
          p = series.options.data[i];
          if (typeof p !== "number") {
            p = series.pointClass.prototype.optionsToObject.call({ series }, p);
            if (p.drilldown) {
              if (!axis.ddPoints[xData[i]]) {
                axis.ddPoints[xData[i]] = [];
              }
              const index = i - (series.cropStart || 0);
              axis.ddPoints[xData[i]].push(points && index >= 0 && index < points.length ? points[index] : true);
            }
          }
        }
      });
      objectEach$3(axis.ticks, (tick) => tick.drillable());
    });
  }
  function onChartUpdate2(e) {
    const breadcrumbs = this.breadcrumbs, breadcrumbOptions = e.options.drilldown && e.options.drilldown.breadcrumbs;
    if (breadcrumbs && breadcrumbOptions) {
      breadcrumbs.update(breadcrumbOptions);
    }
  }
  function svgElementFadeIn(animation) {
    const elem = this;
    elem.attr({
      opacity: 0.1,
      visibility: "inherit"
    }).animate({
      opacity: pick$s(elem.newOpacity, 1)
      // `newOpacity` used in maps
    }, animation || {
      duration: 250
    });
  }
  function tickDrillable() {
    const pos = this.pos, label = this.label, axis = this.axis, isDrillable = axis.coll === "xAxis" && axis.getDDPoints, ddPointsX = isDrillable && axis.getDDPoints(pos), styledMode = axis.chart.styledMode;
    if (isDrillable) {
      if (label && ddPointsX && ddPointsX.length) {
        label.drillable = true;
        if (!label.basicStyles && !styledMode) {
          label.basicStyles = merge$s(label.styles);
        }
        label.addClass("highcharts-drilldown-axis-label");
        if (label.removeOnDrillableClick) {
          removeEvent$3(label.element, "click");
        }
        label.removeOnDrillableClick = addEvent$j(label.element, "click", function(e) {
          e.preventDefault();
          axis.drilldownCategory(pos, e);
        });
        if (!styledMode && axis.chart.options.drilldown) {
          label.css(axis.chart.options.drilldown.activeAxisLabelStyle || {});
        }
      } else if (label && label.drillable && label.removeOnDrillableClick) {
        if (!styledMode) {
          label.styles = {};
          label.element.removeAttribute("style");
          label.css(label.basicStyles);
        }
        label.removeOnDrillableClick();
        label.removeClass("highcharts-drilldown-axis-label");
      }
    }
  }
})(Drilldown || (Drilldown = {}));
const Drilldown$1 = Drilldown;
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/drilldown
 * @requires highcharts
 *
 * Highcharts Drilldown module
 *
 * Author: Torstein Honsi
 * License: www.highcharts.com/license
 *
 */
const G$a = Highcharts;
G$a.Breadcrumbs = G$a.Breadcrumbs || Breadcrumbs;
Drilldown$1.compose(G$a.Axis, G$a.Chart, G$a.defaultOptions, G$a.Series, G$a.seriesTypes, G$a.SVGRenderer, G$a.Tick);
const { isTouchDevice } = Highcharts;
const exporting = {
  /**
   * Experimental setting to allow HTML inside the chart (added through
   * the `useHTML` options), directly in the exported image. This allows
   * you to preserve complicated HTML structures like tables or bi-directional
   * text in exported charts.
   *
   * Disclaimer: The HTML is rendered in a `foreignObject` tag in the
   * generated SVG. The official export server is based on PhantomJS,
   * which supports this, but other SVG clients, like Batik, does not
   * support it. This also applies to downloaded SVG that you want to
   * open in a desktop client.
   *
   * @type      {boolean}
   * @default   false
   * @since     4.1.8
   * @apioption exporting.allowHTML
   */
  /**
   * Allows the end user to sort the data table by clicking on column headers.
   *
   * @since 10.3.3
   * @apioption exporting.allowTableSorting
   */
  allowTableSorting: true,
  /**
   * Allow exporting a chart retaining any user-applied CSS.
   *
   * Note that this is is default behavior in [styledMode](#chart.styledMode).
   *
   * @see [styledMode](#chart.styledMode)
   *
   * @sample {highcharts} highcharts/exporting/apply-stylesheets/
   *
   * @type      {boolean}
   * @default   false
   * @since 12.0.0
   * @apioption exporting.applyStyleSheets
   */
  /**
   * Additional chart options to be merged into the chart before exporting to
   * an image format. This does not apply to printing the chart via the export
   * menu.
   *
   * For example, a common use case is to add data labels to improve
   * readability of the exported chart, or to add a printer-friendly color
   * scheme to exported PDFs.
   *
   * @sample {highcharts} highcharts/exporting/chartoptions-data-labels/
   *         Added data labels
   * @sample {highstock} highcharts/exporting/chartoptions-data-labels/
   *         Added data labels
   *
   * @type      {Highcharts.Options}
   * @apioption exporting.chartOptions
   */
  /**
   * Whether to enable the exporting module. Disabling the module will
   * hide the context button, but API methods will still be available.
   *
   * @sample {highcharts} highcharts/exporting/enabled-false/
   *         Exporting module is loaded but disabled
   * @sample {highstock} highcharts/exporting/enabled-false/
   *         Exporting module is loaded but disabled
   *
   * @type      {boolean}
   * @default   true
   * @since     2.0
   * @apioption exporting.enabled
   */
  /**
   * Function to call if the offline-exporting module fails to export
   * a chart on the client side, and [fallbackToExportServer](
   * #exporting.fallbackToExportServer) is disabled. If left undefined, an
   * exception is thrown instead. Receives two parameters, the exporting
   * options, and the error from the module.
   *
   * @see [fallbackToExportServer](#exporting.fallbackToExportServer)
   *
   * @type      {Highcharts.ExportingErrorCallbackFunction}
   * @since     5.0.0
   * @requires  modules/exporting
   * @requires  modules/offline-exporting
   * @apioption exporting.error
   */
  /**
   * Whether or not to fall back to the export server if the offline-exporting
   * module is unable to export the chart on the client side. This happens for
   * certain browsers, and certain features (e.g.
   * [allowHTML](#exporting.allowHTML)), depending on the image type exporting
   * to. For very complex charts, it is possible that export can fail in
   * browsers that don't support Blob objects, due to data URL length limits.
   * It is recommended to define the [exporting.error](#exporting.error)
   * handler if disabling fallback, in order to notify users in case export
   * fails.
   *
   * @type      {boolean}
   * @default   true
   * @since     4.1.8
   * @requires  modules/exporting
   * @requires  modules/offline-exporting
   * @apioption exporting.fallbackToExportServer
   */
  /**
   * The filename, without extension, to use for the exported chart.
   *
   * @sample {highcharts} highcharts/exporting/filename/
   *         Custom file name
   * @sample {highstock} highcharts/exporting/filename/
   *         Custom file name
   *
   * @type      {string}
   * @default   chart
   * @since     2.0
   * @apioption exporting.filename
   */
  /**
   * Highcharts v11.2.0 and older. An object containing additional key value
   * data for the POST form that sends the SVG to the export server. For
   * example, a `target` can be set to make sure the generated image is
   * received in another frame, or a custom `enctype` or `encoding` can be
   * set.
   *
   * With Highcharts v11.3.0, the `fetch` API replaced the old HTML form. To
   * modify the request, now use [fetchOptions](#exporting.fetchOptions)
   * instead.
   *
   * @deprecated
   * @type      {Highcharts.HTMLAttributes}
   * @since     3.0.8
   * @apioption exporting.formAttributes
   */
  /**
   * Options for the fetch request used when sending the SVG to the export
   * server.
   *
   * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
   * for more information
   *
   * @type {Object}
   * @since 11.3.0
   * @apioption exporting.fetchOptions
   */
  /**
   * Path where Highcharts will look for export module dependencies to
   * load on demand if they don't already exist on `window`. Should currently
   * point to location of [CanVG](https://github.com/canvg/canvg) library,
   * [jsPDF](https://github.com/parallax/jsPDF) and
   * [svg2pdf.js](https://github.com/yWorks/svg2pdf.js), required for client
   * side export in certain browsers.
   *
   * @type      {string}
   * @default   https://code.highcharts.com/{version}/lib
   * @since     5.0.0
   * @apioption exporting.libURL
   */
  /**
   * Analogous to [sourceWidth](#exporting.sourceWidth).
   *
   * @type      {number}
   * @since     3.0
   * @apioption exporting.sourceHeight
   */
  /**
   * The width of the original chart when exported, unless an explicit
   * [chart.width](#chart.width) is set, or a pixel width is set on the
   * container. The width exported raster image is then multiplied by
   * [scale](#exporting.scale).
   *
   * @sample {highcharts} highcharts/exporting/sourcewidth/
   *         Source size demo
   * @sample {highstock} highcharts/exporting/sourcewidth/
   *         Source size demo
   * @sample {highmaps} maps/exporting/sourcewidth/
   *         Source size demo
   *
   * @type      {number}
   * @since     3.0
   * @apioption exporting.sourceWidth
   */
  /**
   * The pixel width of charts exported to PNG or JPG. As of Highcharts
   * 3.0, the default pixel width is a function of the [chart.width](
   * #chart.width) or [exporting.sourceWidth](#exporting.sourceWidth) and the
   * [exporting.scale](#exporting.scale).
   *
   * @sample {highcharts} highcharts/exporting/width/
   *         Export to 200px wide images
   * @sample {highstock} highcharts/exporting/width/
   *         Export to 200px wide images
   *
   * @type      {number}
   * @since     2.0
   * @apioption exporting.width
   */
  /**
   * Default MIME type for exporting if `chart.exportChart()` is called
   * without specifying a `type` option. Possible values are `image/png`,
   *  `image/jpeg`, `application/pdf` and `image/svg+xml`.
   *
   * @type  {Highcharts.ExportingMimeTypeValue}
   * @since 2.0
   */
  type: "image/png",
  /**
   * The URL for the server module converting the SVG string to an image
   * format. By default this points to Highchart's free web service.
   *
   * @since 2.0
   */
  url: `https://export-svg.highcharts.com?v=${Highcharts.version}`,
  /**
   * Settings for a custom font for the exported PDF, when using the
   * `offline-exporting` module. This is used for languages containing
   * non-ASCII characters, like Chinese, Russian, Japanese etc.
   *
   * As described in the [jsPDF
   * docs](https://github.com/parallax/jsPDF#use-of-unicode-characters--utf-8),
   * the 14 standard fonts in PDF are limited to the ASCII-codepage.
   * Therefore, in order to support other text in the exported PDF, one or
   * more TTF font files have to be passed on to the exporting module.
   *
   * See more in [the
   * docs](https://www.highcharts.com/docs/export-module/client-side-export).
   *
   * @sample {highcharts} highcharts/exporting/offline-download-pdffont/
   *         Download PDF in a language containing non-Latin characters.
   *
   * @since 10.0.0
   * @requires modules/offline-exporting
   */
  pdfFont: {
    /**
     * The TTF font file for normal `font-style`. If font variations like
     * `bold` or `italic` are not defined, the `normal` font will be used
     * for those too.
     *
     * @type string|undefined
     */
    normal: void 0,
    /**
     * The TTF font file for bold text.
     *
     * @type string|undefined
     */
    bold: void 0,
    /**
     * The TTF font file for bold and italic text.
     *
     * @type string|undefined
     */
    bolditalic: void 0,
    /**
     * The TTF font file for italic text.
     *
     * @type string|undefined
     */
    italic: void 0
  },
  /**
   * When printing the chart from the menu item in the burger menu, if
   * the on-screen chart exceeds this width, it is resized. After printing
   * or cancelled, it is restored. The default width makes the chart
   * fit into typical paper format. Note that this does not affect the
   * chart when printing the web page as a whole.
   *
   * @since 4.2.5
   */
  printMaxWidth: 780,
  /**
   * Defines the scale or zoom factor for the exported image compared
   * to the on-screen display. While for instance a 600px wide chart
   * may look good on a website, it will look bad in print. The default
   * scale of 2 makes this chart export to a 1200px PNG or JPG.
   *
   * @see [chart.width](#chart.width)
   * @see [exporting.sourceWidth](#exporting.sourceWidth)
   *
   * @sample {highcharts} highcharts/exporting/scale/
   *         Scale demonstrated
   * @sample {highstock} highcharts/exporting/scale/
   *         Scale demonstrated
   * @sample {highmaps} maps/exporting/scale/
   *         Scale demonstrated
   *
   * @since 3.0
   */
  scale: 2,
  /**
   * Options for the export related buttons, print and export. In addition
   * to the default buttons listed here, custom buttons can be added.
   * See [navigation.buttonOptions](#navigation.buttonOptions) for general
   * options.
   *
   * @type     {Highcharts.Dictionary<*>}
   * @requires modules/exporting
   */
  buttons: {
    /**
     * Options for the export button.
     *
     * In styled mode, export button styles can be applied with the
     * `.highcharts-contextbutton` class.
     *
     * @declare  Highcharts.ExportingButtonsOptionsObject
     * @extends  navigation.buttonOptions
     * @requires modules/exporting
     */
    contextButton: {
      /**
       * A click handler callback to use on the button directly instead of
       * the popup menu.
       *
       * @sample highcharts/exporting/buttons-contextbutton-onclick/
       *         Skip the menu and export the chart directly
       *
       * @type      {Function}
       * @since     2.0
       * @apioption exporting.buttons.contextButton.onclick
       */
      /**
       * See [navigation.buttonOptions.symbolFill](
       * #navigation.buttonOptions.symbolFill).
       *
       * @type      {Highcharts.ColorString}
       * @default   #666666
       * @since     2.0
       * @apioption exporting.buttons.contextButton.symbolFill
       */
      /**
       * The horizontal position of the button relative to the `align`
       * option.
       *
       * @type      {number}
       * @default   -10
       * @since     2.0
       * @apioption exporting.buttons.contextButton.x
       */
      /**
       * The class name of the context button.
       */
      className: "highcharts-contextbutton",
      /**
       * The class name of the menu appearing from the button.
       */
      menuClassName: "highcharts-contextmenu",
      /**
       * The symbol for the button. Points to a definition function in
       * the `Highcharts.Renderer.symbols` collection. The default
       * `menu` function is part of the exporting module. Possible
       * values are "circle", "square", "diamond", "triangle",
       * "triangle-down", "menu", "menuball" or custom shape.
       *
       * @sample highcharts/exporting/buttons-contextbutton-symbol/
       *         Use a circle for symbol
       * @sample highcharts/exporting/buttons-contextbutton-symbol-custom/
       *         Custom shape as symbol
       *
       * @type  {Highcharts.SymbolKeyValue|"menu"|"menuball"|string}
       * @since 2.0
       */
      symbol: "menu",
      /**
       * The key to a [lang](#lang) option setting that is used for the
       * button's title tooltip. When the key is `contextButtonTitle`, it
       * refers to [lang.contextButtonTitle](#lang.contextButtonTitle)
       * that defaults to "Chart context menu".
       *
       * @since 6.1.4
       */
      titleKey: "contextButtonTitle",
      /**
       * A collection of strings pointing to config options for the menu
       * items. The config options are defined in the
       * `menuItemDefinitions` option.
       *
       * By default, there is the "View in full screen" and "Print" menu
       * items, plus one menu item for each of the available export types.
       *
       * @sample {highcharts} highcharts/exporting/menuitemdefinitions/
       *         Menu item definitions
       * @sample {highstock} highcharts/exporting/menuitemdefinitions/
       *         Menu item definitions
       * @sample {highmaps} highcharts/exporting/menuitemdefinitions/
       *         Menu item definitions
       *
       * @type    {Array<string>}
       * @default ["viewFullscreen", "printChart", "separator", "downloadPNG", "downloadJPEG", "downloadSVG"]
       * @since   2.0
       */
      menuItems: [
        "viewFullscreen",
        "printChart",
        "separator",
        "downloadPNG",
        "downloadJPEG",
        "downloadSVG"
      ]
    }
  },
  /**
   * An object consisting of definitions for the menu items in the context
   * menu. Each key value pair has a `key` that is referenced in the
   * [menuItems](#exporting.buttons.contextButton.menuItems) setting,
   * and a `value`, which is an object with the following properties:
   *
   * - **onclick:** The click handler for the menu item
   *
   * - **text:** The text for the menu item
   *
   * - **textKey:** If internationalization is required, the key to a language
   *   string
   *
   * Custom text for the "exitFullScreen" can be set only in lang options
   * (it is not a separate button).
   *
   * @sample {highcharts} highcharts/exporting/menuitemdefinitions/
   *         Menu item definitions
   * @sample {highstock} highcharts/exporting/menuitemdefinitions/
   *         Menu item definitions
   * @sample {highmaps} highcharts/exporting/menuitemdefinitions/
   *         Menu item definitions
   *
   *
   * @type    {Highcharts.Dictionary<Highcharts.ExportingMenuObject>}
   * @default {"viewFullscreen": {}, "printChart": {}, "separator": {}, "downloadPNG": {}, "downloadJPEG": {}, "downloadPDF": {}, "downloadSVG": {}}
   * @since   5.0.13
   */
  menuItemDefinitions: {
    /**
     * @ignore
     */
    viewFullscreen: {
      textKey: "viewFullscreen",
      onclick: function() {
        if (this.fullscreen) {
          this.fullscreen.toggle();
        }
      }
    },
    /**
     * @ignore
     */
    printChart: {
      textKey: "printChart",
      onclick: function() {
        this.print();
      }
    },
    /**
     * @ignore
     */
    separator: {
      separator: true
    },
    /**
     * @ignore
     */
    downloadPNG: {
      textKey: "downloadPNG",
      onclick: function() {
        this.exportChart();
      }
    },
    /**
     * @ignore
     */
    downloadJPEG: {
      textKey: "downloadJPEG",
      onclick: function() {
        this.exportChart({
          type: "image/jpeg"
        });
      }
    },
    /**
     * @ignore
     */
    downloadPDF: {
      textKey: "downloadPDF",
      onclick: function() {
        this.exportChart({
          type: "application/pdf"
        });
      }
    },
    /**
     * @ignore
     */
    downloadSVG: {
      textKey: "downloadSVG",
      onclick: function() {
        this.exportChart({
          type: "image/svg+xml"
        });
      }
    }
  }
};
const lang$1 = {
  /**
   * Exporting module only. The text for the menu item to view the chart
   * in full screen.
   *
   * @since 8.0.1
   */
  viewFullscreen: "View in full screen",
  /**
   * Exporting module only. The text for the menu item to exit the chart
   * from full screen.
   *
   * @since 8.0.1
   */
  exitFullscreen: "Exit from full screen",
  /**
   * Exporting module only. The text for the menu item to print the chart.
   *
   * @since    3.0.1
   * @requires modules/exporting
   */
  printChart: "Print chart",
  /**
   * Exporting module only. The text for the PNG download menu item.
   *
   * @since    2.0
   * @requires modules/exporting
   */
  downloadPNG: "Download PNG image",
  /**
   * Exporting module only. The text for the JPEG download menu item.
   *
   * @since    2.0
   * @requires modules/exporting
   */
  downloadJPEG: "Download JPEG image",
  /**
   * Exporting module only. The text for the PDF download menu item.
   *
   * @since    2.0
   * @requires modules/exporting
   */
  downloadPDF: "Download PDF document",
  /**
   * Exporting module only. The text for the SVG download menu item.
   *
   * @since    2.0
   * @requires modules/exporting
   */
  downloadSVG: "Download SVG vector image",
  /**
   * Exporting module menu. The tooltip title for the context menu holding
   * print and export menu items.
   *
   * @since    3.0
   * @requires modules/exporting
   */
  contextButtonTitle: "Chart context menu"
};
const navigation = {
  /**
   * A collection of options for buttons appearing in the exporting
   * module.
   *
   * In styled mode, the buttons are styled with the
   * `.highcharts-contextbutton` and `.highcharts-button-symbol` classes.
   *
   * @requires modules/exporting
   */
  buttonOptions: {
    /**
     * Whether to enable buttons.
     *
     * @sample highcharts/navigation/buttonoptions-enabled/
     *         Exporting module loaded but buttons disabled
     *
     * @type      {boolean}
     * @default   true
     * @since     2.0
     * @apioption navigation.buttonOptions.enabled
     */
    /**
     * The pixel size of the symbol on the button.
     *
     * @sample highcharts/navigation/buttonoptions-height/
     *         Bigger buttons
     *
     * @since 2.0
     */
    symbolSize: 14,
    /**
     * The x position of the center of the symbol inside the button.
     *
     * @sample highcharts/navigation/buttonoptions-height/
     *         Bigger buttons
     *
     * @since 2.0
     */
    symbolX: 14.5,
    /**
     * The y position of the center of the symbol inside the button.
     *
     * @sample highcharts/navigation/buttonoptions-height/
     *         Bigger buttons
     *
     * @since 2.0
     */
    symbolY: 13.5,
    /**
     * Alignment for the buttons.
     *
     * @sample highcharts/navigation/buttonoptions-align/
     *         Center aligned
     *
     * @type  {Highcharts.AlignValue}
     * @since 2.0
     */
    align: "right",
    /**
     * The pixel spacing between buttons, and between the context button and
     * the title.
     *
     * @sample highcharts/title/widthadjust
     *         Adjust the spacing when using text button
     * @since 2.0
     */
    buttonSpacing: 5,
    /**
     * Pixel height of the buttons.
     *
     * @sample highcharts/navigation/buttonoptions-height/
     *         Bigger buttons
     *
     * @since 2.0
     */
    height: 28,
    /**
     * A text string to add to the individual button.
     *
     * @sample highcharts/exporting/buttons-text/
     *         Full text button
     * @sample highcharts/exporting/buttons-text-usehtml/
     *         Icon using CSS font in text
     * @sample highcharts/exporting/buttons-text-symbol/
     *         Combined symbol and text
     *
     * @type      {string}
     * @default   null
     * @since     3.0
     * @apioption navigation.buttonOptions.text
     */
    /**
     * Whether to use HTML for rendering the button. HTML allows for things
     * like inline CSS or image-based icons.
     *
     * @sample highcharts/exporting/buttons-text-usehtml/
     *         Icon using CSS font in text
     *
     * @type      boolean
     * @default   false
     * @since 10.3.0
     * @apioption navigation.buttonOptions.useHTML
     */
    /**
     * The vertical offset of the button's position relative to its
     * `verticalAlign`. By default adjusted for the chart title alignment.
     *
     * @sample highcharts/navigation/buttonoptions-verticalalign/
     *         Buttons at lower right
     *
     * @since     2.0
     * @apioption navigation.buttonOptions.y
     */
    y: -5,
    /**
     * The vertical alignment of the buttons. Can be one of `"top"`,
     * `"middle"` or `"bottom"`.
     *
     * @sample highcharts/navigation/buttonoptions-verticalalign/
     *         Buttons at lower right
     *
     * @type  {Highcharts.VerticalAlignValue}
     * @since 2.0
     */
    verticalAlign: "top",
    /**
     * The pixel width of the button.
     *
     * @sample highcharts/navigation/buttonoptions-height/
     *         Bigger buttons
     *
     * @since 2.0
     */
    width: 28,
    /**
     * Fill color for the symbol within the button.
     *
     * @sample highcharts/navigation/buttonoptions-symbolfill/
     *         Blue symbol stroke for one of the buttons
     *
     * @type  {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since 2.0
     */
    symbolFill: "#666666",
    /**
     * The color of the symbol's stroke or line.
     *
     * @sample highcharts/navigation/buttonoptions-symbolstroke/
     *         Blue symbol stroke
     *
     * @type  {Highcharts.ColorString}
     * @since 2.0
     */
    symbolStroke: "#666666",
    /**
     * The pixel stroke width of the symbol on the button.
     *
     * @sample highcharts/navigation/buttonoptions-height/
     *         Bigger buttons
     *
     * @since 2.0
     */
    symbolStrokeWidth: 3,
    /**
     * A configuration object for the button theme. The object accepts
     * SVG properties like `stroke-width`, `stroke` and `fill`.
     * Tri-state button styles are supported by the `states.hover` and
     * `states.select` objects.
     *
     * @sample highcharts/navigation/buttonoptions-theme/
     *         Theming the buttons
     *
     * @requires modules/exporting
     *
     * @since 3.0
     */
    theme: {
      /**
       * The default fill exists only to capture hover events.
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       */
      fill: "#ffffff",
      /**
       * Padding for the button.
       */
      padding: 5,
      /**
       * Default stroke for the buttons.
       *
       * @type      {Highcharts.ColorString}
       */
      stroke: "none",
      /**
       * Default stroke linecap for the buttons.
       */
      "stroke-linecap": "round"
    }
  },
  /**
   * CSS styles for the popup menu appearing by default when the export
   * icon is clicked. This menu is rendered in HTML.
   *
   * @see In styled mode, the menu is styled with the `.highcharts-menu`
   *      class.
   *
   * @sample highcharts/navigation/menustyle/
   *         Light gray menu background
   *
   * @type    {Highcharts.CSSObject}
   * @default {"background": "#ffffff", "borderRadius": "3px", "padding": "0.5em"}
   * @since   2.0
   */
  menuStyle: {
    /** @ignore-option */
    border: "none",
    /** @ignore-option */
    borderRadius: "3px",
    /** @ignore-option */
    background: "#ffffff",
    /** @ignore-option */
    padding: "0.5em"
  },
  /**
   * CSS styles for the individual items within the popup menu appearing
   * by default when the export icon is clicked. The menu items are
   * rendered in HTML. Font size defaults to `11px` on desktop and `14px`
   * on touch devices.
   *
   * @see In styled mode, the menu items are styled with the
   *      `.highcharts-menu-item` class.
   *
   * @sample {highcharts} highcharts/navigation/menuitemstyle/
   *         Add a grey stripe to the left
   *
   * @type    {Highcharts.CSSObject}
   * @default {"padding": "0.5em", "color": "#333333", "background": "none", "borderRadius": "3px", "fontSize": "0.8em", "transition": "background 250ms, color 250ms"}
   * @since   2.0
   */
  menuItemStyle: {
    /** @ignore-option */
    background: "none",
    /** @ignore-option */
    borderRadius: "3px",
    /** @ignore-option */
    color: "#333333",
    /** @ignore-option */
    padding: "0.5em",
    /** @ignore-option */
    fontSize: isTouchDevice ? "0.9em" : "0.8em",
    /** @ignore-option */
    transition: "background 250ms, color 250ms"
  },
  /**
   * CSS styles for the hover state of the individual items within the
   * popup menu appearing by default when the export icon is clicked. The
   * menu items are rendered in HTML.
   *
   * @see In styled mode, the menu items are styled with the
   *      `.highcharts-menu-item` class.
   *
   * @sample highcharts/navigation/menuitemhoverstyle/
   *         Bold text on hover
   *
   * @type    {Highcharts.CSSObject}
   * @default {"background": "#f2f2f2" }
   * @since   2.0
   */
  menuItemHoverStyle: {
    /** @ignore-option */
    background: "#f2f2f2"
    /* Palette.neutralColor5 */
  }
};
const ExportingDefaults = {
  exporting,
  lang: lang$1,
  navigation
};
var ExportingSymbols;
(function(ExportingSymbols2) {
  const modifiedClasses = [];
  function compose2(SVGRendererClass) {
    if (modifiedClasses.indexOf(SVGRendererClass) === -1) {
      modifiedClasses.push(SVGRendererClass);
      const symbols2 = SVGRendererClass.prototype.symbols;
      symbols2.menu = menu;
      symbols2.menuball = menuball.bind(symbols2);
    }
  }
  ExportingSymbols2.compose = compose2;
  function menu(x, y, width, height) {
    const arr = [
      ["M", x, y + 2.5],
      ["L", x + width, y + 2.5],
      ["M", x, y + height / 2 + 0.5],
      ["L", x + width, y + height / 2 + 0.5],
      ["M", x, y + height - 1.5],
      ["L", x + width, y + height - 1.5]
    ];
    return arr;
  }
  function menuball(x, y, width, height) {
    const h = height / 3 - 2;
    let path = [];
    path = path.concat(this.circle(width - h, y, h, h), this.circle(width - h, y + h + 4, h, h), this.circle(width - h, y + 2 * (h + 4), h, h));
    return path;
  }
})(ExportingSymbols || (ExportingSymbols = {}));
const ExportingSymbols$1 = ExportingSymbols;
const { composed: composed$4 } = Highcharts;
const { addEvent: addEvent$i, fireEvent: fireEvent$6, pushUnique: pushUnique$4 } = Utilities;
function onChartBeforeRender() {
  this.fullscreen = new Fullscreen(this);
}
class Fullscreen {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * Prepares the chart class to support fullscreen.
   *
   * @param {typeof_Highcharts.Chart} ChartClass
   * The chart class to decorate with fullscreen support.
   */
  static compose(ChartClass) {
    if (pushUnique$4(composed$4, "Fullscreen")) {
      addEvent$i(ChartClass, "beforeRender", onChartBeforeRender);
    }
  }
  /* *
   *
   *  Constructors
   *
   * */
  constructor(chart) {
    this.chart = chart;
    this.isOpen = false;
    const container = chart.renderTo;
    if (!this.browserProps) {
      if (typeof container.requestFullscreen === "function") {
        this.browserProps = {
          fullscreenChange: "fullscreenchange",
          requestFullscreen: "requestFullscreen",
          exitFullscreen: "exitFullscreen"
        };
      } else if (container.mozRequestFullScreen) {
        this.browserProps = {
          fullscreenChange: "mozfullscreenchange",
          requestFullscreen: "mozRequestFullScreen",
          exitFullscreen: "mozCancelFullScreen"
        };
      } else if (container.webkitRequestFullScreen) {
        this.browserProps = {
          fullscreenChange: "webkitfullscreenchange",
          requestFullscreen: "webkitRequestFullScreen",
          exitFullscreen: "webkitExitFullscreen"
        };
      } else if (container.msRequestFullscreen) {
        this.browserProps = {
          fullscreenChange: "MSFullscreenChange",
          requestFullscreen: "msRequestFullscreen",
          exitFullscreen: "msExitFullscreen"
        };
      }
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Stops displaying the chart in fullscreen mode.
   * Exporting module required.
   *
   * @since       8.0.1
   *
   * @function    Highcharts.Fullscreen#close
   * @return      {void}
   * @requires    modules/full-screen
   */
  close() {
    const fullscreen = this, chart = fullscreen.chart, optionsChart = chart.options.chart;
    fireEvent$6(chart, "fullscreenClose", null, function() {
      if (fullscreen.isOpen && fullscreen.browserProps && chart.container.ownerDocument instanceof Document) {
        chart.container.ownerDocument[fullscreen.browserProps.exitFullscreen]();
      }
      if (fullscreen.unbindFullscreenEvent) {
        fullscreen.unbindFullscreenEvent = fullscreen.unbindFullscreenEvent();
      }
      chart.setSize(fullscreen.origWidth, fullscreen.origHeight, false);
      fullscreen.origWidth = void 0;
      fullscreen.origHeight = void 0;
      optionsChart.width = fullscreen.origWidthOption;
      optionsChart.height = fullscreen.origHeightOption;
      fullscreen.origWidthOption = void 0;
      fullscreen.origHeightOption = void 0;
      fullscreen.isOpen = false;
      fullscreen.setButtonText();
    });
  }
  /**
   * Displays the chart in fullscreen mode.
   * When fired customly by user before exporting context button is created,
   * button's text will not be replaced - it's on the user side.
   * Exporting module required.
   *
   * @since       8.0.1
   *
   * @function Highcharts.Fullscreen#open
   * @return      {void}
   * @requires    modules/full-screen
   */
  open() {
    const fullscreen = this, chart = fullscreen.chart, optionsChart = chart.options.chart;
    fireEvent$6(chart, "fullscreenOpen", null, function() {
      if (optionsChart) {
        fullscreen.origWidthOption = optionsChart.width;
        fullscreen.origHeightOption = optionsChart.height;
      }
      fullscreen.origWidth = chart.chartWidth;
      fullscreen.origHeight = chart.chartHeight;
      if (fullscreen.browserProps) {
        const unbindChange = addEvent$i(
          chart.container.ownerDocument,
          // Chart's document
          fullscreen.browserProps.fullscreenChange,
          function() {
            if (fullscreen.isOpen) {
              fullscreen.isOpen = false;
              fullscreen.close();
            } else {
              chart.setSize(null, null, false);
              fullscreen.isOpen = true;
              fullscreen.setButtonText();
            }
          }
        );
        const unbindDestroy = addEvent$i(chart, "destroy", unbindChange);
        fullscreen.unbindFullscreenEvent = () => {
          unbindChange();
          unbindDestroy();
        };
        const promise = chart.renderTo[fullscreen.browserProps.requestFullscreen]();
        if (promise) {
          promise["catch"](function() {
            alert(
              // eslint-disable-line no-alert
              "Full screen is not supported inside a frame."
            );
          });
        }
      }
    });
  }
  /**
   * Replaces the exporting context button's text when toogling the
   * fullscreen mode.
   *
   * @private
   *
   * @since 8.0.1
   *
   * @requires modules/full-screen
   */
  setButtonText() {
    const chart = this.chart, exportDivElements = chart.exportDivElements, exportingOptions = chart.options.exporting, menuItems = exportingOptions && exportingOptions.buttons && exportingOptions.buttons.contextButton.menuItems, lang2 = chart.options.lang;
    if (exportingOptions && exportingOptions.menuItemDefinitions && lang2 && lang2.exitFullscreen && lang2.viewFullscreen && menuItems && exportDivElements) {
      const exportDivElement = exportDivElements[menuItems.indexOf("viewFullscreen")];
      if (exportDivElement) {
        AST.setElementHTML(exportDivElement, !this.isOpen ? exportingOptions.menuItemDefinitions.viewFullscreen.text || lang2.viewFullscreen : lang2.exitFullscreen);
      }
    }
  }
  /**
   * Toggles displaying the chart in fullscreen mode.
   * By default, when the exporting module is enabled, a context button with
   * a drop down menu in the upper right corner accesses this function.
   * Exporting module required.
   *
   * @since 8.0.1
   *
   * @sample      highcharts/members/chart-togglefullscreen/
   *              Toggle fullscreen mode from a HTML button
   *
   * @function Highcharts.Fullscreen#toggle
   * @requires    modules/full-screen
   */
  toggle() {
    const fullscreen = this;
    if (!fullscreen.isOpen) {
      fullscreen.open();
    } else {
      fullscreen.close();
    }
  }
}
const { defaultOptions: defaultOptions$4 } = DefaultOptions;
const { doc: doc$2, SVG_NS, win } = Highcharts;
const { addEvent: addEvent$h, css: css$1, createElement, discardElement, extend: extend$o, find: find$5, fireEvent: fireEvent$5, isObject: isObject$8, merge: merge$r, objectEach: objectEach$2, pick: pick$r, removeEvent: removeEvent$2, splat: splat$6, uniqueKey } = Utilities;
var Exporting;
(function(Exporting2) {
  const inlineDenylist = [
    /-/,
    // In Firefox, both hyphened and camelCased names are listed
    /^(clipPath|cssText|d|height|width)$/,
    // Full words
    /^font$/,
    // More specific props are set
    /[lL]ogical(Width|Height)$/,
    /^parentRule$/,
    /^(cssRules|ownerRules)$/,
    // #19516 read-only properties
    /perspective/,
    /TapHighlightColor/,
    /^transition/,
    /^length$/,
    // #7700
    /^\d+$/
    // #17538
  ];
  const inlineToAttributes = [
    "fill",
    "stroke",
    "strokeLinecap",
    "strokeLinejoin",
    "strokeWidth",
    "textAnchor",
    "x",
    "y"
  ];
  Exporting2.inlineAllowlist = [];
  const unstyledElements = [
    "clipPath",
    "defs",
    "desc"
  ];
  let printingChart;
  function addButton(options2) {
    const chart = this, renderer = chart.renderer, btnOptions = merge$r(chart.options.navigation.buttonOptions, options2), onclick = btnOptions.onclick, menuItems = btnOptions.menuItems, symbolSize = btnOptions.symbolSize || 12;
    let symbol;
    if (!chart.btnCount) {
      chart.btnCount = 0;
    }
    if (!chart.exportDivElements) {
      chart.exportDivElements = [];
      chart.exportSVGElements = [];
    }
    if (btnOptions.enabled === false || !btnOptions.theme) {
      return;
    }
    const theme2 = chart.styledMode ? {} : btnOptions.theme;
    let callback;
    if (onclick) {
      callback = function(e) {
        if (e) {
          e.stopPropagation();
        }
        onclick.call(chart, e);
      };
    } else if (menuItems) {
      callback = function(e) {
        if (e) {
          e.stopPropagation();
        }
        chart.contextMenu(button.menuClassName, menuItems, button.translateX || 0, button.translateY || 0, button.width || 0, button.height || 0, button);
        button.setState(2);
      };
    }
    if (btnOptions.text && btnOptions.symbol) {
      theme2.paddingLeft = pick$r(theme2.paddingLeft, 30);
    } else if (!btnOptions.text) {
      extend$o(theme2, {
        width: btnOptions.width,
        height: btnOptions.height,
        padding: 0
      });
    }
    const button = renderer.button(btnOptions.text, 0, 0, callback, theme2, void 0, void 0, void 0, void 0, btnOptions.useHTML).addClass(options2.className).attr({
      title: pick$r(chart.options.lang[btnOptions._titleKey || btnOptions.titleKey], "")
    });
    button.menuClassName = options2.menuClassName || "highcharts-menu-" + chart.btnCount++;
    if (btnOptions.symbol) {
      symbol = renderer.symbol(
        btnOptions.symbol,
        Math.round((btnOptions.symbolX || 0) - symbolSize / 2),
        Math.round((btnOptions.symbolY || 0) - symbolSize / 2),
        symbolSize,
        symbolSize,
        {
          width: symbolSize,
          height: symbolSize
        }
      ).addClass("highcharts-button-symbol").attr({
        zIndex: 1
      }).add(button);
      if (!chart.styledMode) {
        symbol.attr({
          stroke: btnOptions.symbolStroke,
          fill: btnOptions.symbolFill,
          "stroke-width": btnOptions.symbolStrokeWidth || 1
        });
      }
    }
    button.add(chart.exportingGroup).align(extend$o(btnOptions, {
      width: button.width,
      x: pick$r(btnOptions.x, chart.buttonOffset)
      // #1654
    }), true, "spacingBox");
    chart.buttonOffset += ((button.width || 0) + btnOptions.buttonSpacing) * (btnOptions.align === "right" ? -1 : 1);
    chart.exportSVGElements.push(button, symbol);
  }
  function afterPrint() {
    const chart = this;
    if (!chart.printReverseInfo) {
      return void 0;
    }
    const { childNodes, origDisplay, resetParams } = chart.printReverseInfo;
    chart.moveContainers(chart.renderTo);
    [].forEach.call(childNodes, function(node, i) {
      if (node.nodeType === 1) {
        node.style.display = origDisplay[i] || "";
      }
    });
    chart.isPrinting = false;
    if (resetParams) {
      chart.setSize.apply(chart, resetParams);
    }
    delete chart.printReverseInfo;
    printingChart = void 0;
    fireEvent$5(chart, "afterPrint");
  }
  function beforePrint() {
    const chart = this, body = doc$2.body, printMaxWidth = chart.options.exporting.printMaxWidth, printReverseInfo = {
      childNodes: body.childNodes,
      origDisplay: [],
      resetParams: void 0
    };
    chart.isPrinting = true;
    chart.pointer?.reset(void 0, 0);
    fireEvent$5(chart, "beforePrint");
    const handleMaxWidth = printMaxWidth && chart.chartWidth > printMaxWidth;
    if (handleMaxWidth) {
      printReverseInfo.resetParams = [
        chart.options.chart.width,
        void 0,
        false
      ];
      chart.setSize(printMaxWidth, void 0, false);
    }
    [].forEach.call(printReverseInfo.childNodes, function(node, i) {
      if (node.nodeType === 1) {
        printReverseInfo.origDisplay[i] = node.style.display;
        node.style.display = "none";
      }
    });
    chart.moveContainers(body);
    chart.printReverseInfo = printReverseInfo;
  }
  function chartCallback2(chart) {
    const composition = chart;
    composition.renderExporting();
    addEvent$h(chart, "redraw", composition.renderExporting);
    addEvent$h(chart, "destroy", composition.destroyExport);
  }
  function compose2(ChartClass, SVGRendererClass) {
    ExportingSymbols$1.compose(SVGRendererClass);
    Fullscreen.compose(ChartClass);
    const chartProto = ChartClass.prototype;
    if (!chartProto.exportChart) {
      chartProto.afterPrint = afterPrint;
      chartProto.exportChart = exportChart;
      chartProto.inlineStyles = inlineStyles;
      chartProto.print = print;
      chartProto.sanitizeSVG = sanitizeSVG;
      chartProto.getChartHTML = getChartHTML;
      chartProto.getSVG = getSVG;
      chartProto.getSVGForExport = getSVGForExport;
      chartProto.getFilename = getFilename;
      chartProto.moveContainers = moveContainers;
      chartProto.beforePrint = beforePrint;
      chartProto.contextMenu = contextMenu;
      chartProto.addButton = addButton;
      chartProto.destroyExport = destroyExport;
      chartProto.renderExporting = renderExporting;
      chartProto.resolveCSSVariables = resolveCSSVariables;
      chartProto.callbacks.push(chartCallback2);
      addEvent$h(ChartClass, "init", onChartInit);
      addEvent$h(ChartClass, "layOutTitle", onChartLayOutTitle);
      if (Highcharts.isSafari) {
        win.matchMedia("print").addListener(function(mqlEvent) {
          if (!printingChart) {
            return void 0;
          }
          if (mqlEvent.matches) {
            printingChart.beforePrint();
          } else {
            printingChart.afterPrint();
          }
        });
      }
      defaultOptions$4.exporting = merge$r(ExportingDefaults.exporting, defaultOptions$4.exporting);
      defaultOptions$4.lang = merge$r(ExportingDefaults.lang, defaultOptions$4.lang);
      defaultOptions$4.navigation = merge$r(ExportingDefaults.navigation, defaultOptions$4.navigation);
    }
  }
  Exporting2.compose = compose2;
  function contextMenu(className, items, x, y, width, height, button) {
    const chart = this, navOptions = chart.options.navigation, chartWidth = chart.chartWidth, chartHeight = chart.chartHeight, cacheName = "cache-" + className, menuPadding = Math.max(width, height);
    let innerMenu, menu = chart[cacheName];
    if (!menu) {
      chart.exportContextMenu = chart[cacheName] = menu = createElement("div", {
        className
      }, {
        position: "absolute",
        zIndex: 1e3,
        padding: menuPadding + "px",
        pointerEvents: "auto",
        ...chart.renderer.style
      }, chart.scrollablePlotArea?.fixedDiv || chart.container);
      innerMenu = createElement("ul", { className: "highcharts-menu" }, chart.styledMode ? {} : {
        listStyle: "none",
        margin: 0,
        padding: 0
      }, menu);
      if (!chart.styledMode) {
        css$1(innerMenu, extend$o({
          MozBoxShadow: "3px 3px 10px #888",
          WebkitBoxShadow: "3px 3px 10px #888",
          boxShadow: "3px 3px 10px #888"
        }, navOptions.menuStyle));
      }
      menu.hideMenu = function() {
        css$1(menu, { display: "none" });
        if (button) {
          button.setState(0);
        }
        chart.openMenu = false;
        css$1(chart.renderTo, { overflow: "hidden" });
        css$1(chart.container, { overflow: "hidden" });
        Utilities.clearTimeout(menu.hideTimer);
        fireEvent$5(chart, "exportMenuHidden");
      };
      chart.exportEvents.push(
        addEvent$h(menu, "mouseleave", function() {
          menu.hideTimer = win.setTimeout(menu.hideMenu, 500);
        }),
        addEvent$h(menu, "mouseenter", function() {
          Utilities.clearTimeout(menu.hideTimer);
        }),
        // Hide it on clicking or touching outside the menu (#2258,
        // #2335, #2407)
        addEvent$h(doc$2, "mouseup", function(e) {
          if (!chart.pointer?.inClass(e.target, className)) {
            menu.hideMenu();
          }
        }),
        addEvent$h(menu, "click", function() {
          if (chart.openMenu) {
            menu.hideMenu();
          }
        })
      );
      items.forEach(function(item) {
        if (typeof item === "string") {
          item = chart.options.exporting.menuItemDefinitions[item];
        }
        if (isObject$8(item, true)) {
          let element;
          if (item.separator) {
            element = createElement("hr", void 0, void 0, innerMenu);
          } else {
            if (item.textKey === "viewData" && chart.isDataTableVisible) {
              item.textKey = "hideData";
            }
            element = createElement("li", {
              className: "highcharts-menu-item",
              onclick: function(e) {
                if (e) {
                  e.stopPropagation();
                }
                menu.hideMenu();
                if (typeof item !== "string" && item.onclick) {
                  item.onclick.apply(chart, arguments);
                }
              }
            }, void 0, innerMenu);
            AST.setElementHTML(element, item.text || chart.options.lang[item.textKey]);
            if (!chart.styledMode) {
              element.onmouseover = function() {
                css$1(this, navOptions.menuItemHoverStyle);
              };
              element.onmouseout = function() {
                css$1(this, navOptions.menuItemStyle);
              };
              css$1(element, extend$o({
                cursor: "pointer"
              }, navOptions.menuItemStyle || {}));
            }
          }
          chart.exportDivElements.push(element);
        }
      });
      chart.exportDivElements.push(innerMenu, menu);
      chart.exportMenuWidth = menu.offsetWidth;
      chart.exportMenuHeight = menu.offsetHeight;
    }
    const menuStyle = { display: "block" };
    if (x + (chart.exportMenuWidth || 0) > chartWidth) {
      menuStyle.right = chartWidth - x - width - menuPadding + "px";
    } else {
      menuStyle.left = x - menuPadding + "px";
    }
    if (y + height + (chart.exportMenuHeight || 0) > chartHeight && button.alignOptions?.verticalAlign !== "top") {
      menuStyle.bottom = chartHeight - y - menuPadding + "px";
    } else {
      menuStyle.top = y + height - menuPadding + "px";
    }
    css$1(menu, menuStyle);
    css$1(chart.renderTo, { overflow: "" });
    css$1(chart.container, { overflow: "" });
    chart.openMenu = true;
    fireEvent$5(chart, "exportMenuShown");
  }
  function destroyExport(e) {
    const chart = e ? e.target : this, exportSVGElements = chart.exportSVGElements, exportDivElements = chart.exportDivElements, exportEvents = chart.exportEvents;
    let cacheName;
    if (exportSVGElements) {
      exportSVGElements.forEach((elem, i) => {
        if (elem) {
          elem.onclick = elem.ontouchstart = null;
          cacheName = "cache-" + elem.menuClassName;
          if (chart[cacheName]) {
            delete chart[cacheName];
          }
          exportSVGElements[i] = elem.destroy();
        }
      });
      exportSVGElements.length = 0;
    }
    if (chart.exportingGroup) {
      chart.exportingGroup.destroy();
      delete chart.exportingGroup;
    }
    if (exportDivElements) {
      exportDivElements.forEach(function(elem, i) {
        if (elem) {
          Utilities.clearTimeout(elem.hideTimer);
          removeEvent$2(elem, "mouseleave");
          exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
          discardElement(elem);
        }
      });
      exportDivElements.length = 0;
    }
    if (exportEvents) {
      exportEvents.forEach(function(unbind) {
        unbind();
      });
      exportEvents.length = 0;
    }
  }
  function exportChart(exportingOptions, chartOptions) {
    const svg2 = this.getSVGForExport(exportingOptions, chartOptions);
    exportingOptions = merge$r(this.options.exporting, exportingOptions);
    HttpUtilities.post(exportingOptions.url, {
      filename: exportingOptions.filename ? exportingOptions.filename.replace(/\//g, "-") : this.getFilename(),
      type: exportingOptions.type,
      width: exportingOptions.width,
      scale: exportingOptions.scale,
      svg: svg2
    }, exportingOptions.fetchOptions);
  }
  function getChartHTML(applyStyleSheets) {
    if (applyStyleSheets) {
      this.inlineStyles();
    }
    this.resolveCSSVariables();
    return this.container.innerHTML;
  }
  function getFilename() {
    const s = this.userOptions.title && this.userOptions.title.text;
    let filename = this.options.exporting.filename;
    if (filename) {
      return filename.replace(/\//g, "-");
    }
    if (typeof s === "string") {
      filename = s.toLowerCase().replace(/<\/?[^>]+(>|$)/g, "").replace(/[\s_]+/g, "-").replace(/[^a-z\d\-]/g, "").replace(/^[\-]+/g, "").replace(/[\-]+/g, "-").substr(0, 24).replace(/[\-]+$/g, "");
    }
    if (!filename || filename.length < 5) {
      filename = "chart";
    }
    return filename;
  }
  function getSVG(chartOptions) {
    const chart = this;
    let svg2, seriesOptions, options2 = merge$r(chart.options, chartOptions);
    options2.plotOptions = merge$r(chart.userOptions.plotOptions, chartOptions && chartOptions.plotOptions);
    options2.time = merge$r(chart.userOptions.time, chartOptions && chartOptions.time);
    const sandbox = createElement("div", null, {
      position: "absolute",
      top: "-9999em",
      width: chart.chartWidth + "px",
      height: chart.chartHeight + "px"
    }, doc$2.body);
    const cssWidth = chart.renderTo.style.width, cssHeight = chart.renderTo.style.height, sourceWidth = options2.exporting.sourceWidth || options2.chart.width || /px$/.test(cssWidth) && parseInt(cssWidth, 10) || (options2.isGantt ? 800 : 600), sourceHeight = options2.exporting.sourceHeight || options2.chart.height || /px$/.test(cssHeight) && parseInt(cssHeight, 10) || 400;
    extend$o(options2.chart, {
      animation: false,
      renderTo: sandbox,
      forExport: true,
      renderer: "SVGRenderer",
      width: sourceWidth,
      height: sourceHeight
    });
    options2.exporting.enabled = false;
    delete options2.data;
    options2.series = [];
    chart.series.forEach(function(serie) {
      seriesOptions = merge$r(serie.userOptions, {
        animation: false,
        // Turn off animation
        enableMouseTracking: false,
        showCheckbox: false,
        visible: serie.visible
      });
      if (!seriesOptions.isInternal) {
        options2.series.push(seriesOptions);
      }
    });
    const colls = {};
    chart.axes.forEach(function(axis) {
      if (!axis.userOptions.internalKey) {
        axis.userOptions.internalKey = uniqueKey();
      }
      if (!axis.options.isInternal) {
        if (!colls[axis.coll]) {
          colls[axis.coll] = true;
          options2[axis.coll] = [];
        }
        options2[axis.coll].push(merge$r(axis.userOptions, {
          visible: axis.visible,
          // Force some options that could have be set directly on
          // the axis while missing in the userOptions or options.
          type: axis.type,
          uniqueNames: axis.uniqueNames
        }));
      }
    });
    options2.colorAxis = chart.userOptions.colorAxis;
    const chartCopy = new chart.constructor(options2, chart.callback);
    if (chartOptions) {
      ["xAxis", "yAxis", "series"].forEach(function(coll) {
        const collOptions = {};
        if (chartOptions[coll]) {
          collOptions[coll] = chartOptions[coll];
          chartCopy.update(collOptions);
        }
      });
    }
    chart.axes.forEach(function(axis) {
      const axisCopy = find$5(chartCopy.axes, (copy) => copy.options.internalKey === axis.userOptions.internalKey);
      if (axisCopy) {
        const extremes = axis.getExtremes(), exportOverride = splat$6(chartOptions?.[axis.coll] || {})[0], userMin = "min" in exportOverride ? exportOverride.min : extremes.userMin, userMax = "max" in exportOverride ? exportOverride.max : extremes.userMax;
        if (typeof userMin !== "undefined" && userMin !== axisCopy.min || typeof userMax !== "undefined" && userMax !== axisCopy.max) {
          axisCopy.setExtremes(userMin ?? void 0, userMax ?? void 0, true, false);
        }
      }
    });
    svg2 = chartCopy.getChartHTML(chart.styledMode || options2.exporting?.applyStyleSheets);
    fireEvent$5(this, "getSVG", { chartCopy });
    svg2 = chart.sanitizeSVG(svg2, options2);
    options2 = null;
    chartCopy.destroy();
    discardElement(sandbox);
    return svg2;
  }
  function getSVGForExport(options2, chartOptions) {
    const chartExportingOptions = this.options.exporting;
    return this.getSVG(merge$r({ chart: { borderRadius: 0 } }, chartExportingOptions.chartOptions, chartOptions, {
      exporting: {
        sourceWidth: options2 && options2.sourceWidth || chartExportingOptions.sourceWidth,
        sourceHeight: options2 && options2.sourceHeight || chartExportingOptions.sourceHeight
      }
    }));
  }
  function hyphenate(prop) {
    return prop.replace(/[A-Z]/g, function(match2) {
      return "-" + match2.toLowerCase();
    });
  }
  function inlineStyles() {
    const denylist = inlineDenylist, allowlist = Exporting2.inlineAllowlist, defaultStyles2 = {};
    let dummySVG;
    const iframe = doc$2.createElement("iframe");
    css$1(iframe, {
      width: "1px",
      height: "1px",
      visibility: "hidden"
    });
    doc$2.body.appendChild(iframe);
    const iframeDoc = iframe.contentWindow && iframe.contentWindow.document;
    if (iframeDoc) {
      iframeDoc.body.appendChild(iframeDoc.createElementNS(SVG_NS, "svg"));
    }
    function recurse(node) {
      const filteredStyles = {};
      let styles, parentStyles, dummy, denylisted, allowlisted, i;
      function filterStyles(val, prop) {
        denylisted = allowlisted = false;
        if (allowlist.length) {
          i = allowlist.length;
          while (i-- && !allowlisted) {
            allowlisted = allowlist[i].test(prop);
          }
          denylisted = !allowlisted;
        }
        if (prop === "transform" && val === "none") {
          denylisted = true;
        }
        i = denylist.length;
        while (i-- && !denylisted) {
          if (prop.length > 1e3) {
            throw new Error("Input too long");
          }
          denylisted = denylist[i].test(prop) || typeof val === "function";
        }
        if (!denylisted) {
          if ((parentStyles[prop] !== val || node.nodeName === "svg") && defaultStyles2[node.nodeName][prop] !== val) {
            if (!inlineToAttributes || inlineToAttributes.indexOf(prop) !== -1) {
              if (val) {
                node.setAttribute(hyphenate(prop), val);
              }
            } else {
              filteredStyles[prop] = val;
            }
          }
        }
      }
      if (iframeDoc && node.nodeType === 1 && unstyledElements.indexOf(node.nodeName) === -1) {
        styles = win.getComputedStyle(node, null);
        parentStyles = node.nodeName === "svg" ? {} : win.getComputedStyle(node.parentNode, null);
        if (!defaultStyles2[node.nodeName]) {
          dummySVG = iframeDoc.getElementsByTagName("svg")[0];
          dummy = iframeDoc.createElementNS(node.namespaceURI, node.nodeName);
          dummySVG.appendChild(dummy);
          const s = win.getComputedStyle(dummy, null), defaults2 = {};
          for (const key2 in s) {
            if (key2.length < 1e3 && typeof s[key2] === "string" && !/^\d+$/.test(key2)) {
              defaults2[key2] = s[key2];
            }
          }
          defaultStyles2[node.nodeName] = defaults2;
          if (node.nodeName === "text") {
            delete defaultStyles2.text.fill;
          }
          dummySVG.removeChild(dummy);
        }
        for (const p in styles) {
          if (
            // Some browsers put lots of styles on the prototype...
            Highcharts.isFirefox || Highcharts.isMS || Highcharts.isSafari || // #16902
            // ... Chrome puts them on the instance
            Object.hasOwnProperty.call(styles, p)
          ) {
            filterStyles(styles[p], p);
          }
        }
        css$1(node, filteredStyles);
        if (node.nodeName === "svg") {
          node.setAttribute("stroke-width", "1px");
        }
        if (node.nodeName === "text") {
          return;
        }
        [].forEach.call(node.children || node.childNodes, recurse);
      }
    }
    function tearDown() {
      dummySVG.parentNode.removeChild(dummySVG);
      iframe.parentNode.removeChild(iframe);
    }
    recurse(this.container.querySelector("svg"));
    tearDown();
  }
  function resolveCSSVariables() {
    const svgElements = this.container.querySelectorAll("*"), colorAttributes = ["color", "fill", "stop-color", "stroke"];
    Array.from(svgElements).forEach((element) => {
      colorAttributes.forEach((attr2) => {
        const attrValue = element.getAttribute(attr2);
        if (attrValue?.includes("var(")) {
          element.setAttribute(attr2, getComputedStyle(element).getPropertyValue(attr2));
        }
      });
    });
  }
  function moveContainers(moveTo) {
    const { scrollablePlotArea } = this;
    // When scrollablePlotArea is active (#9533)
    (scrollablePlotArea ? [
      scrollablePlotArea.fixedDiv,
      scrollablePlotArea.scrollingContainer
    ] : [this.container]).forEach(function(div) {
      moveTo.appendChild(div);
    });
  }
  function onChartInit() {
    const chart = this, update = (prop, options2, redraw) => {
      chart.isDirtyExporting = true;
      merge$r(true, chart.options[prop], options2);
      if (pick$r(redraw, true)) {
        chart.redraw();
      }
    };
    chart.exporting = {
      update: function(options2, redraw) {
        update("exporting", options2, redraw);
      }
    };
    ChartNavigationComposition$1.compose(chart).navigation.addUpdate((options2, redraw) => {
      update("navigation", options2, redraw);
    });
  }
  function onChartLayOutTitle({ alignTo, key: key2, textPxLength }) {
    const exportingOptions = this.options.exporting, { align, buttonSpacing = 0, verticalAlign, width = 0 } = merge$r(this.options.navigation?.buttonOptions, exportingOptions?.buttons?.contextButton), space = alignTo.width - textPxLength, widthAdjust = width + buttonSpacing;
    if ((exportingOptions?.enabled ?? true) && key2 === "title" && align === "right" && verticalAlign === "top") {
      if (space < 2 * widthAdjust) {
        if (space < widthAdjust) {
          alignTo.width -= widthAdjust;
        } else if (this.title?.alignValue !== "left") {
          alignTo.x -= widthAdjust - space / 2;
        }
      }
    }
  }
  function print() {
    const chart = this;
    if (chart.isPrinting) {
      return;
    }
    printingChart = chart;
    if (!Highcharts.isSafari) {
      chart.beforePrint();
    }
    setTimeout(() => {
      win.focus();
      win.print();
      if (!Highcharts.isSafari) {
        setTimeout(() => {
          chart.afterPrint();
        }, 1e3);
      }
    }, 1);
  }
  function renderExporting() {
    const chart = this, exportingOptions = chart.options.exporting, buttons = exportingOptions.buttons, isDirty = chart.isDirtyExporting || !chart.exportSVGElements;
    chart.buttonOffset = 0;
    if (chart.isDirtyExporting) {
      chart.destroyExport();
    }
    if (isDirty && exportingOptions.enabled !== false) {
      chart.exportEvents = [];
      chart.exportingGroup = chart.exportingGroup || chart.renderer.g("exporting-group").attr({
        zIndex: 3
        // #4955, // #8392
      }).add();
      objectEach$2(buttons, function(button) {
        chart.addButton(button);
      });
      chart.isDirtyExporting = false;
    }
  }
  function sanitizeSVG(svg2, options2) {
    const split = svg2.indexOf("</svg>") + 6, useForeignObject = svg2.indexOf("<foreignObject") > -1;
    let html2 = svg2.substr(split);
    svg2 = svg2.substr(0, split);
    if (useForeignObject) {
      svg2 = svg2.replace(/(<(?:img|br).*?(?=\>))>/g, "$1 />");
    } else if (html2 && options2?.exporting?.allowHTML) {
      html2 = '<foreignObject x="0" y="0" width="' + options2.chart.width + '" height="' + options2.chart.height + '"><body xmlns="http://www.w3.org/1999/xhtml">' + // Some tags needs to be closed in xhtml (#13726)
      html2.replace(/(<(?:img|br).*?(?=\>))>/g, "$1 />") + "</body></foreignObject>";
      svg2 = svg2.replace("</svg>", html2 + "</svg>");
    }
    svg2 = svg2.replace(/zIndex="[^"]+"/g, "").replace(/symbolName="[^"]+"/g, "").replace(/jQuery\d+="[^"]+"/g, "").replace(/url\(("|&quot;)(.*?)("|&quot;)\;?\)/g, "url($2)").replace(/url\([^#]+#/g, "url(#").replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ').replace(/ (NS\d+\:)?href=/g, " xlink:href=").replace(/\n+/g, " ").replace(/&nbsp;/g, " ").replace(/&shy;/g, "­");
    return svg2;
  }
})(Exporting || (Exporting = {}));
const Exporting$1 = Exporting;
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/exporting
 * @requires highcharts
 *
 * Exporting module
 *
 * (c) 2010-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$9 = Highcharts;
G$9.HttpUtilities = G$9.HttpUtilities || HttpUtilities;
G$9.ajax = G$9.HttpUtilities.ajax;
G$9.getJSON = G$9.HttpUtilities.getJSON;
G$9.post = G$9.HttpUtilities.post;
Exporting$1.compose(G$9.Chart, G$9.Renderer);
const FunnelSeriesDefaults = {
  /**
   * Initial animation is by default disabled for the funnel chart.
   */
  animation: false,
  /**
   * The corner radius of the border surrounding all points or series. A
   * number signifies pixels. A percentage string, like for example `50%`,
   * signifies a size relative to the series width.
   *
   * @sample highcharts/plotoptions/funnel-border-radius
   *         Funnel and pyramid with rounded border
   */
  borderRadius: 0,
  /**
   * The center of the series. By default, it is centered in the middle
   * of the plot area, so it fills the plot area height.
   *
   * @type    {Array<number|string>}
   * @default ["50%", "50%"]
   * @since   3.0
   */
  center: ["50%", "50%"],
  /**
   * The width of the funnel compared to the width of the plot area,
   * or the pixel width if it is a number.
   *
   * @type  {number|string}
   * @since 3.0
   */
  width: "90%",
  /**
   * The width of the neck, the lower part of the funnel. A number defines
   * pixel width, a percentage string defines a percentage of the plot
   * area width.
   *
   * @sample {highcharts} highcharts/demo/funnel/
   *         Funnel demo
   *
   * @type  {number|string}
   * @since 3.0
   */
  neckWidth: "30%",
  /**
   * The height of the funnel or pyramid. If it is a number it defines
   * the pixel height, if it is a percentage string it is the percentage
   * of the plot area height.
   *
   * @sample {highcharts} highcharts/demo/funnel/
   *         Funnel demo
   *
   * @type  {number|string}
   * @since 3.0
   */
  height: "100%",
  /**
   * The height of the neck, the lower part of the funnel. A number
   * defines pixel width, a percentage string defines a percentage of the
   * plot area height.
   *
   * @type {number|string}
   */
  neckHeight: "25%",
  /**
   * A reversed funnel has the widest area down. A reversed funnel with
   * no neck width and neck height is a pyramid.
   *
   * @since 3.0.10
   */
  reversed: false,
  /**
   * To avoid adapting the data label size in Pie.drawDataLabels.
   * @ignore-option
   */
  size: true,
  dataLabels: {
    connectorWidth: 1,
    verticalAlign: "middle"
  },
  /**
   * Options for the series states.
   */
  states: {
    /**
     * @excluding halo, marker, lineWidth, lineWidthPlus
     * @apioption plotOptions.funnel.states.hover
     */
    /**
     * Options for a selected funnel item.
     *
     * @excluding halo, marker, lineWidth, lineWidthPlus
     */
    select: {
      /**
       * A specific color for the selected point.
       *
       * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       */
      color: "#cccccc",
      /**
       * A specific border color for the selected point.
       *
       * @type {Highcharts.ColorString}
       */
      borderColor: "#000000"
      /* Palette.neutralColor100 */
    }
  }
};
const { composed: composed$3, noop: noop$2 } = Highcharts;
const { column: ColumnSeries$6, pie: PieSeries$1 } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$g, correctFloat: correctFloat$2, extend: extend$n, fireEvent: fireEvent$4, isArray: isArray$7, merge: merge$q, pick: pick$q, pushUnique: pushUnique$3, relativeLength: relativeLength$6, splat: splat$5 } = Utilities;
const baseAlignDataLabel = SeriesRegistry$1.series.prototype.alignDataLabel;
function getLength(length, relativeTo) {
  return /%$/.test(length) ? relativeTo * parseInt(length, 10) / 100 : parseInt(length, 10);
}
class FunnelSeries extends PieSeries$1 {
  /* *
   *
   *  Functions
   *
   * */
  /* eslint-disable valid-jsdoc */
  /**
   * @private
   */
  alignDataLabel(point, dataLabel, options2, alignTo, isNew) {
    const series = point.series, reversed = series.options.reversed, dlBox = point.dlBox || point.shapeArgs, { align, padding = 0, verticalAlign } = options2, inside = ((series.options || {}).dataLabels || {}).inside, centerY = series.center[1], plotY = point.plotY || 0, pointPlotY = reversed ? 2 * centerY - plotY : plotY, dataLabelHeight = dataLabel.height ?? dataLabel.getBBox().height, widthAtLabel = series.getWidthAt(pointPlotY - dlBox.height / 2 + dataLabelHeight), offset2 = verticalAlign === "middle" ? (dlBox.topWidth - dlBox.bottomWidth) / 4 : (widthAtLabel - dlBox.bottomWidth) / 2;
    let y = dlBox.y, x = dlBox.x;
    if (verticalAlign === "middle") {
      y = dlBox.y - dlBox.height / 2 + dataLabelHeight / 2;
    } else if (verticalAlign === "top") {
      y = dlBox.y - dlBox.height + dataLabelHeight + padding;
    }
    if (verticalAlign === "top" && !reversed || verticalAlign === "bottom" && reversed || verticalAlign === "middle") {
      if (align === "right") {
        x = dlBox.x - padding + offset2;
      } else if (align === "left") {
        x = dlBox.x + padding - offset2;
      }
    }
    alignTo = {
      x,
      y: reversed ? y - dlBox.height : y,
      width: dlBox.bottomWidth,
      height: dlBox.height
    };
    options2.verticalAlign = "bottom";
    if (inside) {
      options2.distance = void 0;
    }
    if (inside && point.visible) {
      baseAlignDataLabel.call(series, point, dataLabel, options2, alignTo, isNew);
    }
    if (inside) {
      if (!point.visible && point.dataLabel) {
        point.dataLabel.placed = false;
      }
      if (point.contrastColor) {
        dataLabel.css({
          color: point.contrastColor
        });
      }
    }
  }
  /**
   * Extend the data label method.
   * @private
   */
  drawDataLabels() {
    (splat$5(this.options.dataLabels || {})[0].inside ? ColumnSeries$6 : PieSeries$1).prototype.drawDataLabels.call(this);
  }
  /** @private */
  getDataLabelPosition(point, distance) {
    const y = point.plotY || 0, sign2 = point.half ? 1 : -1, x = this.getX(y, !!point.half, point);
    return {
      distance,
      // Initial position of the data label - it's utilized for finding
      // the final position for the label
      natural: {
        x: 0,
        y
      },
      computed: {
        // Used for generating connector path - initialized later in
        // drawDataLabels function x: undefined, y: undefined
      },
      // Left - funnel on the left side of the data label
      // Right - funnel on the right side of the data label
      alignment: point.half ? "right" : "left",
      connectorPosition: {
        breakAt: {
          x: x + (distance - 5) * sign2,
          y
        },
        touchingSliceAt: {
          x: x + distance * sign2,
          y
        }
      }
    };
  }
  /**
   * Overrides the pie translate method.
   * @private
   */
  translate() {
    const series = this, chart = series.chart, options2 = series.options, reversed = options2.reversed, ignoreHiddenPoint = options2.ignoreHiddenPoint, borderRadiusObject = BorderRadius.optionsToObject(options2.borderRadius), plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, center = options2.center, centerX = getLength(center[0], plotWidth), centerY = getLength(center[1], plotHeight), width = getLength(options2.width, plotWidth), height = getLength(options2.height, plotHeight), neckWidth = getLength(options2.neckWidth, plotWidth), neckHeight = getLength(options2.neckHeight, plotHeight), neckY = centerY - height / 2 + height - neckHeight, points = series.points, borderRadius = relativeLength$6(borderRadiusObject.radius, width), radiusScope = borderRadiusObject.scope, half = options2.dataLabels.position === "left" ? 1 : 0, roundingFactors = (angle) => {
      const tan = Math.tan(angle / 2), cosA = Math.cos(alpha), sinA = Math.sin(alpha);
      let r = borderRadius, t = r / tan, k = Math.tan((Math.PI - angle) / 3.2104);
      if (t > maxT) {
        t = maxT;
        r = t * tan;
      }
      k *= r;
      return {
        dx: [t * cosA, (t - k) * cosA, t - k, t],
        dy: [t * sinA, (t - k) * sinA, t - k, t].map((i) => reversed ? -i : i)
      };
    };
    let sum2 = 0, cumulative = 0, tempWidth, path, fraction, alpha, maxT, x1, y1, x2, x3, y3, x4, y5;
    series.getWidthAt = function(y) {
      const top = centerY - height / 2;
      return y > neckY || height === neckHeight ? neckWidth : neckWidth + (width - neckWidth) * (1 - (y - top) / (height - neckHeight));
    };
    series.getX = function(y, half2, point) {
      return centerX + (half2 ? -1 : 1) * (series.getWidthAt(reversed ? 2 * centerY - y : y) / 2 + (point.dataLabel?.dataLabelPosition?.distance ?? relativeLength$6(this.options.dataLabels?.distance || 0, width)));
    };
    series.center = [centerX, centerY, height];
    series.centerX = centerX;
    for (const point of points) {
      if (point.y && point.isValid() && (!ignoreHiddenPoint || point.visible !== false)) {
        sum2 += point.y;
      }
    }
    for (const point of points) {
      y5 = null;
      fraction = sum2 ? point.y / sum2 : 0;
      y1 = centerY - height / 2 + cumulative * height;
      y3 = y1 + fraction * height;
      tempWidth = series.getWidthAt(y1);
      x1 = centerX - tempWidth / 2;
      x2 = x1 + tempWidth;
      tempWidth = series.getWidthAt(y3);
      x3 = centerX - tempWidth / 2;
      x4 = x3 + tempWidth;
      if (correctFloat$2(y1) >= neckY) {
        x1 = x3 = centerX - neckWidth / 2;
        x2 = x4 = centerX + neckWidth / 2;
      } else if (y3 > neckY) {
        y5 = y3;
        tempWidth = series.getWidthAt(neckY);
        x3 = centerX - tempWidth / 2;
        x4 = x3 + tempWidth;
        y3 = neckY;
      }
      if (reversed) {
        y1 = 2 * centerY - y1;
        y3 = 2 * centerY - y3;
        if (y5 !== null) {
          y5 = 2 * centerY - y5;
        }
      }
      if (borderRadius && (radiusScope === "point" || point.index === 0 || point.index === points.length - 1 || y5 !== null)) {
        const h = Math.abs(y3 - y1), xSide = x2 - x4, lBase = x4 - x3, lSide = Math.sqrt(xSide * xSide + h * h);
        alpha = Math.atan(xSide !== 0 ? h / xSide : Infinity);
        maxT = lSide / 2;
        if (y5 !== null) {
          maxT = Math.min(maxT, Math.abs(y5 - y3) / 2);
        }
        if (lBase >= 1) {
          maxT = Math.min(maxT, lBase / 2);
        }
        let f = roundingFactors(alpha);
        if (radiusScope === "stack" && point.index !== 0) {
          path = [
            ["M", x1, y1],
            ["L", x2, y1]
          ];
        } else {
          path = [
            ["M", x1 + f.dx[0], y1 + f.dy[0]],
            [
              "C",
              x1 + f.dx[1],
              y1 + f.dy[1],
              x1 + f.dx[2],
              y1,
              x1 + f.dx[3],
              y1
            ],
            ["L", x2 - f.dx[3], y1],
            [
              "C",
              x2 - f.dx[2],
              y1,
              x2 - f.dx[1],
              y1 + f.dy[1],
              x2 - f.dx[0],
              y1 + f.dy[0]
            ]
          ];
        }
        if (y5 !== null) {
          const fr = roundingFactors(Math.PI / 2);
          f = roundingFactors(Math.PI / 2 + alpha);
          path.push(["L", x4 + f.dx[0], y3 - f.dy[0]], [
            "C",
            x4 + f.dx[1],
            y3 - f.dy[1],
            x4,
            y3 + f.dy[2],
            x4,
            y3 + f.dy[3]
          ]);
          if (radiusScope === "stack" && point.index !== points.length - 1) {
            path.push(["L", x4, y5], ["L", x3, y5]);
          } else {
            path.push(["L", x4, y5 - fr.dy[3]], [
              "C",
              x4,
              y5 - fr.dy[2],
              x4 - fr.dx[2],
              y5,
              x4 - fr.dx[3],
              y5
            ], ["L", x3 + fr.dx[3], y5], [
              "C",
              x3 + fr.dx[2],
              y5,
              x3,
              y5 - fr.dy[2],
              x3,
              y5 - fr.dy[3]
            ]);
          }
          path.push(["L", x3, y3 + f.dy[3]], [
            "C",
            x3,
            y3 + f.dy[2],
            x3 - f.dx[1],
            y3 - f.dy[1],
            x3 - f.dx[0],
            y3 - f.dy[0]
          ]);
        } else if (lBase >= 1) {
          f = roundingFactors(Math.PI - alpha);
          if (radiusScope === "stack" && point.index === 0) {
            path.push(["L", x4, y3], ["L", x3, y3]);
          } else {
            path.push(["L", x4 + f.dx[0], y3 - f.dy[0]], [
              "C",
              x4 + f.dx[1],
              y3 - f.dy[1],
              x4 - f.dx[2],
              y3,
              x4 - f.dx[3],
              y3
            ], ["L", x3 + f.dx[3], y3], [
              "C",
              x3 + f.dx[2],
              y3,
              x3 - f.dx[1],
              y3 - f.dy[1],
              x3 - f.dx[0],
              y3 - f.dy[0]
            ]);
          }
        } else {
          f = roundingFactors(Math.PI - alpha * 2);
          path.push(["L", x3 + f.dx[0], y3 - f.dy[0]], [
            "C",
            x3 + f.dx[1],
            y3 - f.dy[1],
            x3 - f.dx[1],
            y3 - f.dy[1],
            x3 - f.dx[0],
            y3 - f.dy[0]
          ]);
        }
      } else {
        path = [
          ["M", x1, y1],
          ["L", x2, y1],
          ["L", x4, y3]
        ];
        if (y5 !== null) {
          path.push(["L", x4, y5], ["L", x3, y5]);
        }
        path.push(["L", x3, y3]);
      }
      path.push(["Z"]);
      point.shapeType = "path";
      point.shapeArgs = { d: path };
      point.percentage = fraction * 100;
      point.plotX = centerX;
      point.plotY = (y1 + (y5 || y3)) / 2;
      point.tooltipPos = [
        centerX,
        point.plotY
      ];
      point.dlBox = {
        x: x3,
        y: y1,
        topWidth: x2 - x1,
        bottomWidth: x4 - x3,
        height: Math.abs(pick$q(y5, y3) - y1),
        width: NaN
      };
      point.slice = noop$2;
      point.half = half;
      if (point.isValid() && (!ignoreHiddenPoint || point.visible !== false)) {
        cumulative += fraction;
      }
    }
    fireEvent$4(series, "afterTranslate");
  }
  /**
   * Funnel items don't have angles (#2289).
   * @private
   */
  sortByAngle(points) {
    points.sort((a, b) => a.plotY - b.plotY);
  }
}
FunnelSeries.defaultOptions = merge$q(PieSeries$1.defaultOptions, FunnelSeriesDefaults);
extend$n(FunnelSeries.prototype, {
  animate: noop$2
});
(function(FunnelSeries2) {
  function compose2(ChartClass) {
    if (pushUnique$3(composed$3, "FunnelSeries")) {
      addEvent$g(ChartClass, "afterHideAllOverlappingLabels", onChartAfterHideAllOverlappingLabels);
    }
  }
  FunnelSeries2.compose = compose2;
  function onChartAfterHideAllOverlappingLabels() {
    for (const series of this.series) {
      let dataLabelsOptions = series.options && series.options.dataLabels;
      if (isArray$7(dataLabelsOptions)) {
        dataLabelsOptions = dataLabelsOptions[0];
      }
      if (series.is("pie") && series.placeDataLabels && dataLabelsOptions && !dataLabelsOptions.inside) {
        series.placeDataLabels();
      }
    }
  }
})(FunnelSeries || (FunnelSeries = {}));
SeriesRegistry$1.registerSeriesType("funnel", FunnelSeries);
const FunnelSeries$1 = FunnelSeries;
const PyramidSeriesDefaults = {
  /**
   * The pyramid neck height is zero by default, as opposed to the funnel,
   * which shares the same layout logic.
   *
   * @since 3.0.10
   */
  neckHeight: "0%",
  /**
   * The pyramid neck width is zero by default, as opposed to the funnel,
   * which shares the same layout logic.
   *
   * @since 3.0.10
   */
  neckWidth: "0%",
  /**
   * The pyramid is reversed by default, as opposed to the funnel, which
   * shares the layout engine, and is not reversed.
   *
   * @since 3.0.10
   */
  reversed: true
};
const { merge: merge$p } = Utilities;
class PyramidSeries extends FunnelSeries$1 {
}
PyramidSeries.defaultOptions = merge$p(FunnelSeries$1.defaultOptions, PyramidSeriesDefaults);
SeriesRegistry$1.registerSeriesType("pyramid", PyramidSeries);
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/funnel
 * @requires highcharts
 *
 * Highcharts funnel module
 *
 * (c) 2010-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G$8 = Highcharts;
FunnelSeries$1.compose(G$8.Chart);
const { parse: color$4 } = Color;
const { addEvent: addEvent$f, extend: extend$m, merge: merge$o, pick: pick$p, splat: splat$4 } = Utilities;
var ColorAxisComposition;
(function(ColorAxisComposition2) {
  let ColorAxisConstructor;
  function compose2(ColorAxisClass, ChartClass, FxClass, LegendClass, SeriesClass) {
    const chartProto = ChartClass.prototype, fxProto = FxClass.prototype, seriesProto2 = SeriesClass.prototype;
    if (!chartProto.collectionsWithUpdate.includes("colorAxis")) {
      ColorAxisConstructor = ColorAxisClass;
      chartProto.collectionsWithUpdate.push("colorAxis");
      chartProto.collectionsWithInit.colorAxis = [
        chartProto.addColorAxis
      ];
      addEvent$f(ChartClass, "afterCreateAxes", onChartAfterCreateAxes2);
      wrapChartCreateAxis(ChartClass);
      fxProto.fillSetter = wrapFxFillSetter;
      fxProto.strokeSetter = wrapFxStrokeSetter;
      addEvent$f(LegendClass, "afterGetAllItems", onLegendAfterGetAllItems2);
      addEvent$f(LegendClass, "afterColorizeItem", onLegendAfterColorizeItem);
      addEvent$f(LegendClass, "afterUpdate", onLegendAfterUpdate);
      extend$m(seriesProto2, {
        optionalAxis: "colorAxis",
        translateColors: seriesTranslateColors
      });
      extend$m(seriesProto2.pointClass.prototype, {
        setVisible: pointSetVisible
      });
      addEvent$f(SeriesClass, "afterTranslate", onSeriesAfterTranslate2, { order: 1 });
      addEvent$f(SeriesClass, "bindAxes", onSeriesBindAxes);
    }
  }
  ColorAxisComposition2.compose = compose2;
  function onChartAfterCreateAxes2() {
    const { userOptions } = this;
    this.colorAxis = [];
    if (userOptions.colorAxis) {
      userOptions.colorAxis = splat$4(userOptions.colorAxis);
      userOptions.colorAxis.map((axisOptions) => new ColorAxisConstructor(this, axisOptions));
    }
  }
  function onLegendAfterGetAllItems2(e) {
    const colorAxes = this.chart.colorAxis || [], destroyItem = (item) => {
      const i2 = e.allItems.indexOf(item);
      if (i2 !== -1) {
        this.destroyItem(e.allItems[i2]);
        e.allItems.splice(i2, 1);
      }
    };
    let colorAxisItems = [], options2, i;
    colorAxes.forEach(function(colorAxis) {
      options2 = colorAxis.options;
      if (options2?.showInLegend) {
        if (options2.dataClasses && options2.visible) {
          colorAxisItems = colorAxisItems.concat(colorAxis.getDataClassLegendSymbols());
        } else if (options2.visible) {
          colorAxisItems.push(colorAxis);
        }
        colorAxis.series.forEach(function(series) {
          if (!series.options.showInLegend || options2.dataClasses) {
            if (series.options.legendType === "point") {
              series.points.forEach(function(point) {
                destroyItem(point);
              });
            } else {
              destroyItem(series);
            }
          }
        });
      }
    });
    i = colorAxisItems.length;
    while (i--) {
      e.allItems.unshift(colorAxisItems[i]);
    }
  }
  function onLegendAfterColorizeItem(e) {
    if (e.visible && e.item.legendColor) {
      e.item.legendItem.symbol.attr({
        fill: e.item.legendColor
      });
    }
  }
  function onLegendAfterUpdate(e) {
    this.chart.colorAxis?.forEach((colorAxis) => {
      colorAxis.update({}, e.redraw);
    });
  }
  function onSeriesAfterTranslate2() {
    if (this.chart.colorAxis?.length || this.colorAttribs) {
      this.translateColors();
    }
  }
  function onSeriesBindAxes() {
    const axisTypes = this.axisTypes;
    if (!axisTypes) {
      this.axisTypes = ["colorAxis"];
    } else if (axisTypes.indexOf("colorAxis") === -1) {
      axisTypes.push("colorAxis");
    }
  }
  function pointSetVisible(vis) {
    const point = this, method = vis ? "show" : "hide";
    point.visible = point.options.visible = Boolean(vis);
    ["graphic", "dataLabel"].forEach(function(key2) {
      if (point[key2]) {
        point[key2][method]();
      }
    });
    this.series.buildKDTree();
  }
  ColorAxisComposition2.pointSetVisible = pointSetVisible;
  function seriesTranslateColors() {
    const series = this, points = this.getPointsCollection(), nullColor = this.options.nullColor, colorAxis = this.colorAxis, colorKey = this.colorKey;
    points.forEach((point) => {
      const value = point.getNestedProperty(colorKey), color2 = point.options.color || (point.isNull || point.value === null ? nullColor : colorAxis && typeof value !== "undefined" ? colorAxis.toColor(value, point) : point.color || series.color);
      if (color2 && point.color !== color2) {
        point.color = color2;
        if (series.options.legendType === "point" && point.legendItem && point.legendItem.label) {
          series.chart.legend.colorizeItem(point, point.visible);
        }
      }
    });
  }
  function wrapChartCreateAxis(ChartClass) {
    const superCreateAxis = ChartClass.prototype.createAxis;
    ChartClass.prototype.createAxis = function(type, options2) {
      const chart = this;
      if (type !== "colorAxis") {
        return superCreateAxis.apply(chart, arguments);
      }
      const axis = new ColorAxisConstructor(chart, merge$o(options2.axis, {
        index: chart[type].length,
        isX: false
      }));
      chart.isDirtyLegend = true;
      chart.axes.forEach((axis2) => {
        axis2.series = [];
      });
      chart.series.forEach((series) => {
        series.bindAxes();
        series.isDirtyData = true;
      });
      if (pick$p(options2.redraw, true)) {
        chart.redraw(options2.animation);
      }
      return axis;
    };
  }
  function wrapFxFillSetter() {
    this.elem.attr("fill", color$4(this.start).tweenTo(color$4(this.end), this.pos), void 0, true);
  }
  function wrapFxStrokeSetter() {
    this.elem.attr("stroke", color$4(this.start).tweenTo(color$4(this.end), this.pos), void 0, true);
  }
})(ColorAxisComposition || (ColorAxisComposition = {}));
const ColorAxisComposition$1 = ColorAxisComposition;
const colorAxisDefaults = {
  /**
   * Whether to allow decimals on the color axis.
   * @type      {boolean}
   * @default   true
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.allowDecimals
   */
  /**
   * Determines how to set each data class' color if no individual
   * color is set. The default value, `tween`, computes intermediate
   * colors between `minColor` and `maxColor`. The other possible
   * value, `category`, pulls colors from the global or chart specific
   * [colors](#colors) array.
   *
   * @sample {highmaps} maps/coloraxis/dataclasscolor/
   *         Category colors
   *
   * @type       {string}
   * @default    tween
   * @product    highcharts highstock highmaps
   * @validvalue ["tween", "category"]
   * @apioption  colorAxis.dataClassColor
   */
  /**
   * An array of data classes or ranges for the choropleth map. If
   * none given, the color axis is scalar and values are distributed
   * as a gradient between the minimum and maximum colors.
   *
   * @sample {highmaps} maps/demo/data-class-ranges/
   *         Multiple ranges
   *
   * @sample {highmaps} maps/demo/data-class-two-ranges/
   *         Two ranges
   *
   * @type      {Array<*>}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.dataClasses
   */
  /**
   * The layout of the color axis. Can be `'horizontal'` or `'vertical'`.
   * If none given, the color axis has the same layout as the legend.
   *
   * @sample highcharts/coloraxis/horizontal-layout/
   *         Horizontal color axis layout with vertical legend
   *
   * @type      {string|undefined}
   * @since     7.2.0
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.layout
   */
  /**
   * The color of each data class. If not set, the color is pulled
   * from the global or chart-specific [colors](#colors) array. In
   * styled mode, this option is ignored. Instead, use colors defined
   * in CSS.
   *
   * @sample {highmaps} maps/demo/data-class-two-ranges/
   *         Explicit colors
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.dataClasses.color
   */
  /**
   * The start of the value range that the data class represents,
   * relating to the point value.
   *
   * The range of each `dataClass` is closed in both ends, but can be
   * overridden by the next `dataClass`.
   *
   * @type      {number}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.dataClasses.from
   */
  /**
   * The name of the data class as it appears in the legend.
   * If no name is given, it is automatically created based on the
   * `from` and `to` values. For full programmatic control,
   * [legend.labelFormatter](#legend.labelFormatter) can be used.
   * In the formatter, `this.from` and `this.to` can be accessed.
   *
   * @sample {highmaps} maps/coloraxis/dataclasses-name/
   *         Named data classes
   *
   * @sample {highmaps} maps/coloraxis/dataclasses-labelformatter/
   *         Formatted data classes
   *
   * @type      {string}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.dataClasses.name
   */
  /**
   * The end of the value range that the data class represents,
   * relating to the point value.
   *
   * The range of each `dataClass` is closed in both ends, but can be
   * overridden by the next `dataClass`.
   *
   * @type      {number}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.dataClasses.to
   */
  /** @ignore-option */
  lineWidth: 0,
  /**
   * Padding of the min value relative to the length of the axis. A
   * padding of 0.05 will make a 100px axis 5px longer.
   *
   * @product highcharts highstock highmaps
   */
  minPadding: 0,
  /**
   * The maximum value of the axis in terms of map point values. If
   * `null`, the max value is automatically calculated. If the
   * `endOnTick` option is true, the max value might be rounded up.
   *
   * @sample {highmaps} maps/coloraxis/gridlines/
   *         Explicit min and max to reduce the effect of outliers
   *
   * @type      {number}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.max
   */
  /**
   * The minimum value of the axis in terms of map point values. If
   * `null`, the min value is automatically calculated. If the
   * `startOnTick` option is true, the min value might be rounded
   * down.
   *
   * @sample {highmaps} maps/coloraxis/gridlines/
   *         Explicit min and max to reduce the effect of outliers
   *
   * @type      {number}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.min
   */
  /**
   * Padding of the max value relative to the length of the axis. A
   * padding of 0.05 will make a 100px axis 5px longer.
   *
   * @product highcharts highstock highmaps
   */
  maxPadding: 0,
  /**
   * Color of the grid lines extending from the axis across the
   * gradient.
   *
   * @sample {highmaps} maps/coloraxis/gridlines/
   *         Grid lines demonstrated
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highcharts highstock highmaps
   */
  gridLineColor: "#ffffff",
  /**
   * The width of the grid lines extending from the axis across the
   * gradient of a scalar color axis.
   *
   * @sample {highmaps} maps/coloraxis/gridlines/
   *         Grid lines demonstrated
   *
   * @product highcharts highstock highmaps
   */
  gridLineWidth: 1,
  /**
   * The interval of the tick marks in axis units. When `null`, the
   * tick interval is computed to approximately follow the
   * `tickPixelInterval`.
   *
   * @type      {number}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.tickInterval
   */
  /**
   * If [tickInterval](#colorAxis.tickInterval) is `null` this option
   * sets the approximate pixel interval of the tick marks.
   *
   * @product highcharts highstock highmaps
   */
  tickPixelInterval: 72,
  /**
   * Whether to force the axis to start on a tick. Use this option
   * with the `maxPadding` option to control the axis start.
   *
   * @product highcharts highstock highmaps
   */
  startOnTick: true,
  /**
   * Whether to force the axis to end on a tick. Use this option with
   * the [maxPadding](#colorAxis.maxPadding) option to control the
   * axis end.
   *
   * @product highcharts highstock highmaps
   */
  endOnTick: true,
  /** @ignore */
  offset: 0,
  /**
   * The triangular marker on a scalar color axis that points to the
   * value of the hovered area. To disable the marker, set
   * `marker: null`.
   *
   * @sample {highmaps} maps/coloraxis/marker/
   *         Black marker
   *
   * @declare Highcharts.PointMarkerOptionsObject
   * @product highcharts highstock highmaps
   */
  marker: {
    /**
     * Animation for the marker as it moves between values. Set to
     * `false` to disable animation. Defaults to `{ duration: 50 }`.
     *
     * @type    {boolean|Partial<Highcharts.AnimationOptionsObject>}
     * @product highcharts highstock highmaps
     */
    animation: {
      /** @internal */
      duration: 50
    },
    /** @internal */
    width: 0.01,
    /**
     * The color of the marker.
     *
     * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @product highcharts highstock highmaps
     */
    color: "#999999"
    /* Palette.neutralColor40 */
  },
  /**
   * The axis labels show the number for each tick.
   *
   * For more live examples on label options, see [xAxis.labels in the
   * Highcharts API.](/highcharts#xAxis.labels)
   *
   * @extends xAxis.labels
   * @product highcharts highstock highmaps
   */
  labels: {
    distance: 8,
    /**
     * How to handle overflowing labels on horizontal color axis. If set
     * to `"allow"`, it will not be aligned at all. By default it
     * `"justify"` labels inside the chart area. If there is room to
     * move it, it will be aligned to the edge, else it will be removed.
     *
     * @validvalue ["allow", "justify"]
     * @product    highcharts highstock highmaps
     */
    overflow: "justify",
    rotation: 0
  },
  /**
   * The color to represent the minimum of the color axis. Unless
   * [dataClasses](#colorAxis.dataClasses) or
   * [stops](#colorAxis.stops) are set, the gradient starts at this
   * value.
   *
   * If dataClasses are set, the color is based on minColor and
   * maxColor unless a color is set for each data class, or the
   * [dataClassColor](#colorAxis.dataClassColor) is set.
   *
   * @sample {highmaps} maps/coloraxis/mincolor-maxcolor/
   *         Min and max colors on scalar (gradient) axis
   * @sample {highmaps} maps/coloraxis/mincolor-maxcolor-dataclasses/
   *         On data classes
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product highcharts highstock highmaps
   */
  minColor: "#e6e9ff",
  /**
   * The color to represent the maximum of the color axis. Unless
   * [dataClasses](#colorAxis.dataClasses) or
   * [stops](#colorAxis.stops) are set, the gradient ends at this
   * value.
   *
   * If dataClasses are set, the color is based on minColor and
   * maxColor unless a color is set for each data class, or the
   * [dataClassColor](#colorAxis.dataClassColor) is set.
   *
   * @sample {highmaps} maps/coloraxis/mincolor-maxcolor/
   *         Min and max colors on scalar (gradient) axis
   * @sample {highmaps} maps/coloraxis/mincolor-maxcolor-dataclasses/
   *         On data classes
   *
   * @type    {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product highcharts highstock highmaps
   */
  maxColor: "#0022ff",
  /**
   * Color stops for the gradient of a scalar color axis. Use this in
   * cases where a linear gradient between a `minColor` and `maxColor`
   * is not sufficient. The stops is an array of tuples, where the
   * first item is a float between 0 and 1 assigning the relative
   * position in the gradient, and the second item is the color.
   *
   * @sample highcharts/coloraxis/coloraxis-stops/
   *         Color axis stops
   * @sample highcharts/coloraxis/color-key-with-stops/
   *         Color axis stops with custom colorKey
   * @sample {highmaps} maps/demo/heatmap/
   *         Heatmap with three color stops
   *
   * @type      {Array<Array<number,Highcharts.ColorString>>}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.stops
   */
  /**
   * The pixel length of the main tick marks on the color axis.
   */
  tickLength: 5,
  /**
   * The type of interpolation to use for the color axis. Can be
   * `linear` or `logarithmic`.
   *
   * @sample highcharts/coloraxis/logarithmic-with-emulate-negative-values/
   *         Logarithmic color axis with extension to emulate negative
   *         values
   *
   * @type      {Highcharts.ColorAxisTypeValue}
   * @default   linear
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.type
   */
  /**
   * Whether to reverse the axis so that the highest number is closest
   * to the origin. Defaults to `false` in a horizontal legend and
   * `true` in a vertical legend, where the smallest value starts on
   * top.
   *
   * @type      {boolean}
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.reversed
   */
  /**
   * @product   highcharts highstock highmaps
   * @excluding afterBreaks, pointBreak, pointInBreak
   * @apioption colorAxis.events
   */
  /**
   * Fires when the legend item belonging to the colorAxis is clicked.
   * One parameter, `event`, is passed to the function.
   *
   * **Note:** This option is deprecated in favor of
   * [legend.events.itemClick](#legend.events.itemClick).
   *
   * @deprecated 11.4.4
   * @type       {Function}
   * @product    highcharts highstock highmaps
   * @apioption  colorAxis.events.legendItemClick
   */
  /**
   * The width of the color axis. If it's a number, it is interpreted as
   * pixels.
   *
   * If it's a percentage string, it is interpreted as percentages of the
   * total plot width.
   *
   * @sample    highcharts/coloraxis/width-and-height
   *            Percentage width and pixel height for color axis
   *
   * @type      {number|string}
   * @since     11.3.0
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.width
   */
  /**
   * The height of the color axis. If it's a number, it is interpreted as
   * pixels.
   *
   * If it's a percentage string, it is interpreted as percentages of the
   * total plot height.
   *
   * @sample    highcharts/coloraxis/width-and-height
   *            Percentage width and pixel height for color axis
   *
   * @type      {number|string}
   * @since     11.3.0
   * @product   highcharts highstock highmaps
   * @apioption colorAxis.height
   */
  /**
   * Whether to display the colorAxis in the legend.
   *
   * @sample highcharts/coloraxis/hidden-coloraxis-with-3d-chart/
   *         Hidden color axis with 3d chart
   *
   * @see [heatmap.showInLegend](#series.heatmap.showInLegend)
   *
   * @since   4.2.7
   * @product highcharts highstock highmaps
   */
  showInLegend: true
};
const { parse: color$3 } = Color;
const { merge: merge$n } = Utilities;
var ColorAxisLike;
(function(ColorAxisLike2) {
  function initDataClasses(userOptions) {
    const axis = this, chart = axis.chart, legendItem = axis.legendItem = axis.legendItem || {}, options2 = axis.options, userDataClasses = userOptions.dataClasses || [];
    let dataClass, dataClasses, colorCount = chart.options.chart.colorCount, colorCounter = 0, colors;
    axis.dataClasses = dataClasses = [];
    legendItem.labels = [];
    for (let i = 0, iEnd = userDataClasses.length; i < iEnd; ++i) {
      dataClass = userDataClasses[i];
      dataClass = merge$n(dataClass);
      dataClasses.push(dataClass);
      if (!chart.styledMode && dataClass.color) {
        continue;
      }
      if (options2.dataClassColor === "category") {
        if (!chart.styledMode) {
          colors = chart.options.colors || [];
          colorCount = colors.length;
          dataClass.color = colors[colorCounter];
        }
        dataClass.colorIndex = colorCounter;
        colorCounter++;
        if (colorCounter === colorCount) {
          colorCounter = 0;
        }
      } else {
        dataClass.color = color$3(options2.minColor).tweenTo(
          color$3(options2.maxColor),
          iEnd < 2 ? 0.5 : i / (iEnd - 1)
          // #3219
        );
      }
    }
  }
  ColorAxisLike2.initDataClasses = initDataClasses;
  function initStops() {
    const axis = this, options2 = axis.options, stops = axis.stops = options2.stops || [
      [0, options2.minColor || ""],
      [1, options2.maxColor || ""]
    ];
    for (let i = 0, iEnd = stops.length; i < iEnd; ++i) {
      stops[i].color = color$3(stops[i][1]);
    }
  }
  ColorAxisLike2.initStops = initStops;
  function normalizedValue(value) {
    const axis = this, max2 = axis.max || 0, min2 = axis.min || 0;
    if (axis.logarithmic) {
      value = axis.logarithmic.log2lin(value);
    }
    return 1 - (max2 - value) / (max2 - min2 || 1);
  }
  ColorAxisLike2.normalizedValue = normalizedValue;
  function toColor(value, point) {
    const axis = this;
    const dataClasses = axis.dataClasses;
    const stops = axis.stops;
    let pos, from, to, color2, dataClass, i;
    if (dataClasses) {
      i = dataClasses.length;
      while (i--) {
        dataClass = dataClasses[i];
        from = dataClass.from;
        to = dataClass.to;
        if ((typeof from === "undefined" || value >= from) && (typeof to === "undefined" || value <= to)) {
          color2 = dataClass.color;
          if (point) {
            point.dataClass = i;
            point.colorIndex = dataClass.colorIndex;
          }
          break;
        }
      }
    } else {
      pos = axis.normalizedValue(value);
      i = stops.length;
      while (i--) {
        if (pos > stops[i][0]) {
          break;
        }
      }
      from = stops[i] || stops[i + 1];
      to = stops[i + 1] || from;
      pos = 1 - (to[0] - pos) / (to[0] - from[0] || 1);
      color2 = from.color.tweenTo(to.color, pos);
    }
    return color2;
  }
  ColorAxisLike2.toColor = toColor;
})(ColorAxisLike || (ColorAxisLike = {}));
const ColorAxisLike$1 = ColorAxisLike;
const { defaultOptions: defaultOptions$3 } = DefaultOptions;
const { series: Series$2 } = SeriesRegistry$1;
const { defined: defined$g, extend: extend$l, fireEvent: fireEvent$3, isArray: isArray$6, isNumber: isNumber$j, merge: merge$m, pick: pick$o, relativeLength: relativeLength$5 } = Utilities;
defaultOptions$3.colorAxis = merge$m(defaultOptions$3.xAxis, colorAxisDefaults);
class ColorAxis extends Axis {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(ChartClass, FxClass, LegendClass, SeriesClass) {
    ColorAxisComposition$1.compose(ColorAxis, ChartClass, FxClass, LegendClass, SeriesClass);
  }
  /* *
   *
   *  Constructors
   *
   * */
  /**
   * @private
   */
  constructor(chart, userOptions) {
    super(chart, userOptions);
    this.coll = "colorAxis";
    this.visible = true;
    this.init(chart, userOptions);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initializes the color axis.
   *
   * @function Highcharts.ColorAxis#init
   *
   * @param {Highcharts.Chart} chart
   * The related chart of the color axis.
   *
   * @param {Highcharts.ColorAxisOptions} userOptions
   * The color axis options for initialization.
   */
  init(chart, userOptions) {
    const axis = this;
    const legend = chart.options.legend || {}, horiz = userOptions.layout ? userOptions.layout !== "vertical" : legend.layout !== "vertical";
    axis.side = userOptions.side || horiz ? 2 : 1;
    axis.reversed = userOptions.reversed || !horiz;
    axis.opposite = !horiz;
    super.init(chart, userOptions, "colorAxis");
    this.userOptions = userOptions;
    if (isArray$6(chart.userOptions.colorAxis)) {
      chart.userOptions.colorAxis[this.index] = userOptions;
    }
    if (userOptions.dataClasses) {
      axis.initDataClasses(userOptions);
    }
    axis.initStops();
    axis.horiz = horiz;
    axis.zoomEnabled = false;
  }
  /**
   * Returns true if the series has points at all.
   *
   * @function Highcharts.ColorAxis#hasData
   *
   * @return {boolean}
   * True, if the series has points, otherwise false.
   */
  hasData() {
    return !!(this.tickPositions || []).length;
  }
  /**
   * Override so that ticks are not added in data class axes (#6914)
   * @private
   */
  setTickPositions() {
    if (!this.dataClasses) {
      return super.setTickPositions();
    }
  }
  /**
   * Extend the setOptions method to process extreme colors and color stops.
   * @private
   */
  setOptions(userOptions) {
    const options2 = merge$m(
      defaultOptions$3.colorAxis,
      userOptions,
      // Forced options
      {
        showEmpty: false,
        title: null,
        visible: this.chart.options.legend.enabled && userOptions.visible !== false
      }
    );
    super.setOptions(options2);
    this.options.crosshair = this.options.marker;
  }
  /**
   * @private
   */
  setAxisSize() {
    const axis = this, chart = axis.chart, symbol = axis.legendItem?.symbol;
    let { width, height } = axis.getSize();
    if (symbol) {
      this.left = +symbol.attr("x");
      this.top = +symbol.attr("y");
      this.width = width = +symbol.attr("width");
      this.height = height = +symbol.attr("height");
      this.right = chart.chartWidth - this.left - width;
      this.bottom = chart.chartHeight - this.top - height;
      this.pos = this.horiz ? this.left : this.top;
    }
    this.len = (this.horiz ? width : height) || ColorAxis.defaultLegendLength;
  }
  /**
   * Override the getOffset method to add the whole axis groups inside the
   * legend.
   * @private
   */
  getOffset() {
    const axis = this;
    const group2 = axis.legendItem?.group;
    const sideOffset = axis.chart.axisOffset[axis.side];
    if (group2) {
      axis.axisParent = group2;
      super.getOffset();
      const legend = this.chart.legend;
      legend.allItems.forEach(function(item) {
        if (item instanceof ColorAxis) {
          item.drawLegendSymbol(legend, item);
        }
      });
      legend.render();
      this.chart.getMargins(true);
      if (!this.chart.series.some((series) => series.isDrilling)) {
        axis.isDirty = true;
      }
      if (!axis.added) {
        axis.added = true;
        axis.labelLeft = 0;
        axis.labelRight = axis.width;
      }
      axis.chart.axisOffset[axis.side] = sideOffset;
    }
  }
  /**
   * Create the color gradient.
   * @private
   */
  setLegendColor() {
    const axis = this;
    const horiz = axis.horiz;
    const reversed = axis.reversed;
    const one = reversed ? 1 : 0;
    const zero = reversed ? 0 : 1;
    const grad = horiz ? [one, 0, zero, 0] : [0, zero, 0, one];
    axis.legendColor = {
      linearGradient: {
        x1: grad[0],
        y1: grad[1],
        x2: grad[2],
        y2: grad[3]
      },
      stops: axis.stops
    };
  }
  /**
   * The color axis appears inside the legend and has its own legend symbol.
   * @private
   */
  drawLegendSymbol(legend, item) {
    const axis = this, legendItem = item.legendItem || {}, padding = legend.padding, legendOptions = legend.options, labelOptions = axis.options.labels, itemDistance = pick$o(legendOptions.itemDistance, 10), horiz = axis.horiz, { width, height } = axis.getSize(), labelPadding = pick$o(
      // @todo: This option is not documented, nor implemented when
      // vertical
      legendOptions.labelPadding,
      horiz ? 16 : 30
    );
    this.setLegendColor();
    if (!legendItem.symbol) {
      legendItem.symbol = this.chart.renderer.symbol("roundedRect").attr({
        r: legendOptions.symbolRadius ?? 3,
        zIndex: 1
      }).add(legendItem.group);
    }
    legendItem.symbol.attr({
      x: 0,
      y: (legend.baseline || 0) - 11,
      width,
      height
    });
    legendItem.labelWidth = width + padding + (horiz ? itemDistance : pick$o(labelOptions.x, labelOptions.distance) + (this.maxLabelLength || 0));
    legendItem.labelHeight = height + padding + (horiz ? labelPadding : 0);
  }
  /**
   * Fool the legend.
   * @private
   */
  setState(state) {
    this.series.forEach(function(series) {
      series.setState(state);
    });
  }
  /**
   * @private
   */
  setVisible() {
  }
  /**
   * @private
   */
  getSeriesExtremes() {
    const axis = this;
    const series = axis.series;
    let colorValArray, colorKey, calculatedExtremes, cSeries, i = series.length;
    this.dataMin = Infinity;
    this.dataMax = -Infinity;
    while (i--) {
      cSeries = series[i];
      colorKey = cSeries.colorKey = pick$o(cSeries.options.colorKey, cSeries.colorKey, cSeries.pointValKey, cSeries.zoneAxis, "y");
      calculatedExtremes = cSeries[colorKey + "Min"] && cSeries[colorKey + "Max"];
      for (const key2 of [colorKey, "value", "y"]) {
        colorValArray = cSeries.getColumn(key2);
        if (colorValArray.length) {
          break;
        }
      }
      if (calculatedExtremes) {
        cSeries.minColorValue = cSeries[colorKey + "Min"];
        cSeries.maxColorValue = cSeries[colorKey + "Max"];
      } else {
        const cExtremes = Series$2.prototype.getExtremes.call(cSeries, colorValArray);
        cSeries.minColorValue = cExtremes.dataMin;
        cSeries.maxColorValue = cExtremes.dataMax;
      }
      if (defined$g(cSeries.minColorValue) && defined$g(cSeries.maxColorValue)) {
        this.dataMin = Math.min(this.dataMin, cSeries.minColorValue);
        this.dataMax = Math.max(this.dataMax, cSeries.maxColorValue);
      }
      if (!calculatedExtremes) {
        Series$2.prototype.applyExtremes.call(cSeries);
      }
    }
  }
  /**
   * Internal function to draw a crosshair.
   *
   * @function Highcharts.ColorAxis#drawCrosshair
   *
   * @param {Highcharts.PointerEventObject} [e]
   *        The event arguments from the modified pointer event, extended with
   *        `chartX` and `chartY`
   *
   * @param {Highcharts.Point} [point]
   *        The Point object if the crosshair snaps to points.
   *
   * @emits Highcharts.ColorAxis#event:afterDrawCrosshair
   * @emits Highcharts.ColorAxis#event:drawCrosshair
   */
  drawCrosshair(e, point) {
    const axis = this, legendItem = axis.legendItem || {}, plotX = point?.plotX, plotY = point?.plotY, axisPos = axis.pos, axisLen = axis.len;
    let crossPos;
    if (point) {
      crossPos = axis.toPixels(point.getNestedProperty(point.series.colorKey));
      if (crossPos < axisPos) {
        crossPos = axisPos - 2;
      } else if (crossPos > axisPos + axisLen) {
        crossPos = axisPos + axisLen + 2;
      }
      point.plotX = crossPos;
      point.plotY = axis.len - crossPos;
      super.drawCrosshair(e, point);
      point.plotX = plotX;
      point.plotY = plotY;
      if (axis.cross && !axis.cross.addedToColorAxis && legendItem.group) {
        axis.cross.addClass("highcharts-coloraxis-marker").add(legendItem.group);
        axis.cross.addedToColorAxis = true;
        if (!axis.chart.styledMode && typeof axis.crosshair === "object") {
          axis.cross.attr({
            fill: axis.crosshair.color
          });
        }
      }
    }
  }
  /**
   * @private
   */
  getPlotLinePath(options2) {
    const axis = this, left = axis.left, pos = options2.translatedValue, top = axis.top;
    return isNumber$j(pos) ? (
      // `pos` can be 0 (#3969)
      axis.horiz ? [
        ["M", pos - 4, top - 6],
        ["L", pos + 4, top - 6],
        ["L", pos, top],
        ["Z"]
      ] : [
        ["M", left, pos],
        ["L", left - 6, pos + 6],
        ["L", left - 6, pos - 6],
        ["Z"]
      ]
    ) : super.getPlotLinePath(options2);
  }
  /**
   * Updates a color axis instance with a new set of options. The options are
   * merged with the existing options, so only new or altered options need to
   * be specified.
   *
   * @function Highcharts.ColorAxis#update
   *
   * @param {Highcharts.ColorAxisOptions} newOptions
   * The new options that will be merged in with existing options on the color
   * axis.
   *
   * @param {boolean} [redraw]
   * Whether to redraw the chart after the color axis is altered. If doing
   * more operations on the chart, it is a good idea to set redraw to `false`
   * and call {@link Highcharts.Chart#redraw} after.
   */
  update(newOptions, redraw) {
    const axis = this, chart = axis.chart, legend = chart.legend;
    this.series.forEach((series) => {
      series.isDirtyData = true;
    });
    if (newOptions.dataClasses && legend.allItems || axis.dataClasses) {
      axis.destroyItems();
    }
    super.update(newOptions, redraw);
    if (axis.legendItem?.label) {
      axis.setLegendColor();
      legend.colorizeItem(this, true);
    }
  }
  /**
   * Destroy color axis legend items.
   * @private
   */
  destroyItems() {
    const axis = this, chart = axis.chart, legendItem = axis.legendItem || {};
    if (legendItem.label) {
      chart.legend.destroyItem(axis);
    } else if (legendItem.labels) {
      for (const item of legendItem.labels) {
        chart.legend.destroyItem(item);
      }
    }
    chart.isDirtyLegend = true;
  }
  //   Removing the whole axis (#14283)
  destroy() {
    this.chart.isDirtyLegend = true;
    this.destroyItems();
    super.destroy(...[].slice.call(arguments));
  }
  /**
   * Removes the color axis and the related legend item.
   *
   * @function Highcharts.ColorAxis#remove
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart following the remove.
   */
  remove(redraw) {
    this.destroyItems();
    super.remove(redraw);
  }
  /**
   * Get the legend item symbols for data classes.
   * @private
   */
  getDataClassLegendSymbols() {
    const axis = this, chart = axis.chart, legendItems = axis.legendItem && axis.legendItem.labels || [], legendOptions = chart.options.legend, valueDecimals = pick$o(legendOptions.valueDecimals, -1), valueSuffix = pick$o(legendOptions.valueSuffix, "");
    const getPointsInDataClass = (i) => axis.series.reduce((points, s) => {
      points.push(...s.points.filter((point) => point.dataClass === i));
      return points;
    }, []);
    let name;
    if (!legendItems.length) {
      axis.dataClasses.forEach((dataClass, i) => {
        const from = dataClass.from, to = dataClass.to, { numberFormatter } = chart;
        let vis = true;
        name = "";
        if (typeof from === "undefined") {
          name = "< ";
        } else if (typeof to === "undefined") {
          name = "> ";
        }
        if (typeof from !== "undefined") {
          name += numberFormatter(from, valueDecimals) + valueSuffix;
        }
        if (typeof from !== "undefined" && typeof to !== "undefined") {
          name += " - ";
        }
        if (typeof to !== "undefined") {
          name += numberFormatter(to, valueDecimals) + valueSuffix;
        }
        legendItems.push(extend$l({
          chart,
          name,
          options: {},
          drawLegendSymbol: LegendSymbol$1.rectangle,
          visible: true,
          isDataClass: true,
          // Override setState to set either normal or inactive
          // state to all points in this data class
          setState: (state) => {
            for (const point of getPointsInDataClass(i)) {
              point.setState(state);
            }
          },
          // Override setState to show or hide all points in this
          // data class
          setVisible: function() {
            this.visible = vis = axis.visible = !vis;
            const affectedSeries = [];
            for (const point of getPointsInDataClass(i)) {
              point.setVisible(vis);
              point.hiddenInDataClass = !vis;
              if (affectedSeries.indexOf(point.series) === -1) {
                affectedSeries.push(point.series);
              }
            }
            chart.legend.colorizeItem(this, vis);
            affectedSeries.forEach((series) => {
              fireEvent$3(series, "afterDataClassLegendClick");
            });
          }
        }, dataClass));
      });
    }
    return legendItems;
  }
  /**
   * Get size of color axis symbol.
   * @private
   */
  getSize() {
    const axis = this, { chart, horiz } = axis, { height: colorAxisHeight, width: colorAxisWidth } = axis.options, { legend: legendOptions } = chart.options, width = pick$o(defined$g(colorAxisWidth) ? relativeLength$5(colorAxisWidth, chart.chartWidth) : void 0, legendOptions?.symbolWidth, horiz ? ColorAxis.defaultLegendLength : 12), height = pick$o(defined$g(colorAxisHeight) ? relativeLength$5(colorAxisHeight, chart.chartHeight) : void 0, legendOptions?.symbolHeight, horiz ? 12 : ColorAxis.defaultLegendLength);
    return {
      width,
      height
    };
  }
}
ColorAxis.defaultLegendLength = 200;
ColorAxis.keepProps = [
  "legendItem"
];
extend$l(ColorAxis.prototype, ColorAxisLike$1);
Array.prototype.push.apply(Axis.keepProps, ColorAxis.keepProps);
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/color-axis
 * @requires highcharts
 *
 * ColorAxis module
 *
 * (c) 2012-2025 Pawel Potaczek
 *
 * License: www.highcharts.com/license
 */
const G$7 = Highcharts;
G$7.ColorAxis = G$7.ColorAxis || ColorAxis;
G$7.ColorAxis.compose(G$7.Chart, G$7.Fx, G$7.Legend, G$7.Series);
const { column: { prototype: columnProto } } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$e, defined: defined$f } = Utilities;
var ColorMapComposition;
(function(ColorMapComposition2) {
  ColorMapComposition2.pointMembers = {
    dataLabelOnNull: true,
    moveToTopOnHover: true,
    isValid: pointIsValid
  };
  ColorMapComposition2.seriesMembers = {
    colorKey: "value",
    axisTypes: ["xAxis", "yAxis", "colorAxis"],
    parallelArrays: ["x", "y", "value"],
    pointArrayMap: ["value"],
    trackerGroups: ["group", "markerGroup", "dataLabelsGroup"],
    colorAttribs: seriesColorAttribs,
    pointAttribs: columnProto.pointAttribs
  };
  function compose2(SeriesClass) {
    const PointClass = SeriesClass.prototype.pointClass;
    addEvent$e(PointClass, "afterSetState", onPointAfterSetState2);
    return SeriesClass;
  }
  ColorMapComposition2.compose = compose2;
  function onPointAfterSetState2(e) {
    const point = this, series = point.series, renderer = series.chart.renderer;
    if (point.moveToTopOnHover && point.graphic) {
      if (!series.stateMarkerGraphic) {
        series.stateMarkerGraphic = new SVGElement$1(renderer, "use").css({
          pointerEvents: "none"
        }).add(point.graphic.parentGroup);
      }
      if (e?.state === "hover") {
        point.graphic.attr({
          id: this.id
        });
        series.stateMarkerGraphic.attr({
          href: `${renderer.url}#${this.id}`,
          visibility: "visible"
        });
      } else {
        series.stateMarkerGraphic.attr({
          href: ""
        });
      }
    }
  }
  function pointIsValid() {
    return this.value !== null && this.value !== Infinity && this.value !== -Infinity && // Undefined is allowed, but NaN is not (#17279)
    (this.value === void 0 || !isNaN(this.value));
  }
  function seriesColorAttribs(point) {
    const ret = {};
    if (defined$f(point.color) && (!point.state || point.state === "normal")) {
      ret[this.colorProp || "fill"] = point.color;
    }
    return ret;
  }
})(ColorMapComposition || (ColorMapComposition = {}));
const ColorMapComposition$1 = ColorMapComposition;
const { scatter: { prototype: { pointClass: ScatterPoint$1 } } } = SeriesRegistry$1.seriesTypes;
const { clamp: clamp$6, defined: defined$e, extend: extend$k, pick: pick$n } = Utilities;
class HeatmapPoint extends ScatterPoint$1 {
  /* *
   *
   *  Functions
   *
   * */
  /** @private */
  applyOptions(options2, x) {
    if (this.isNull || this.value === null) {
      delete this.color;
    }
    super.applyOptions(options2, x);
    this.formatPrefix = this.isNull || this.value === null ? "null" : "point";
    return this;
  }
  /** @private */
  getCellAttributes() {
    const point = this, series = point.series, seriesOptions = series.options, xPad = (seriesOptions.colsize || 1) / 2, yPad = (seriesOptions.rowsize || 1) / 2, xAxis2 = series.xAxis, yAxis2 = series.yAxis, markerOptions = point.options.marker || series.options.marker, pointPlacement = series.pointPlacementToXValue(), pointPadding = pick$n(point.pointPadding, seriesOptions.pointPadding, 0), cellAttr = {
      x1: clamp$6(Math.round(xAxis2.len - xAxis2.translate(point.x - xPad, false, true, false, true, -pointPlacement)), -xAxis2.len, 2 * xAxis2.len),
      x2: clamp$6(Math.round(xAxis2.len - xAxis2.translate(point.x + xPad, false, true, false, true, -pointPlacement)), -xAxis2.len, 2 * xAxis2.len),
      y1: clamp$6(Math.round(yAxis2.translate(point.y - yPad, false, true, false, true)), -yAxis2.len, 2 * yAxis2.len),
      y2: clamp$6(Math.round(yAxis2.translate(point.y + yPad, false, true, false, true)), -yAxis2.len, 2 * yAxis2.len)
    };
    const dimensions = [["width", "x"], ["height", "y"]];
    for (const dimension of dimensions) {
      const prop = dimension[0], direction = dimension[1];
      let start2 = direction + "1", end = direction + "2";
      const side = Math.abs(cellAttr[start2] - cellAttr[end]), borderWidth = markerOptions && markerOptions.lineWidth || 0, plotPos = Math.abs(cellAttr[start2] + cellAttr[end]) / 2, widthOrHeight = markerOptions && markerOptions[prop];
      if (defined$e(widthOrHeight) && widthOrHeight < side) {
        const halfCellSize = widthOrHeight / 2 + borderWidth / 2;
        cellAttr[start2] = plotPos - halfCellSize;
        cellAttr[end] = plotPos + halfCellSize;
      }
      if (pointPadding) {
        if (direction === "x" && xAxis2.reversed || direction === "y" && !yAxis2.reversed) {
          start2 = end;
          end = direction + "1";
        }
        cellAttr[start2] += pointPadding;
        cellAttr[end] -= pointPadding;
      }
    }
    return cellAttr;
  }
  /**
   * @private
   */
  haloPath(size) {
    if (!size) {
      return [];
    }
    const { x = 0, y = 0, width = 0, height = 0 } = this.shapeArgs || {};
    return [
      ["M", x - size, y - size],
      ["L", x - size, y + height + size],
      ["L", x + width + size, y + height + size],
      ["L", x + width + size, y - size],
      ["Z"]
    ];
  }
  /**
   * Color points have a value option that determines whether or not it is
   * a null point
   * @private
   */
  isValid() {
    return this.value !== Infinity && this.value !== -Infinity;
  }
}
extend$k(HeatmapPoint.prototype, {
  dataLabelOnNull: true,
  moveToTopOnHover: true,
  ttBelow: false
});
const { isNumber: isNumber$i } = Utilities;
const HeatmapSeriesDefaults = {
  /**
   * Animation is disabled by default on the heatmap series.
   */
  animation: false,
  /**
   * The border radius for each heatmap item. The border's color and
   * width can be set in marker options.
   *
   * @see [lineColor](#plotOptions.heatmap.marker.lineColor)
   * @see [lineWidth](#plotOptions.heatmap.marker.lineWidth)
   */
  borderRadius: 0,
  /**
   * The border width for each heatmap item.
   */
  borderWidth: 0,
  /**
   * Padding between the points in the heatmap.
   *
   * @type      {number}
   * @default   0
   * @since     6.0
   * @apioption plotOptions.heatmap.pointPadding
   */
  /**
   * @default   value
   * @apioption plotOptions.heatmap.colorKey
   */
  /**
   * The main color of the series. In heat maps this color is rarely used,
   * as we mostly use the color to denote the value of each point. Unless
   * options are set in the [colorAxis](#colorAxis), the default value
   * is pulled from the [options.colors](#colors) array.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     4.0
   * @product   highcharts
   * @apioption plotOptions.heatmap.color
   */
  /**
   * The column size - how many X axis units each column in the heatmap
   * should span.
   *
   * @sample {highcharts} maps/demo/heatmap/
   *         One day
   * @sample {highmaps} maps/demo/heatmap/
   *         One day
   *
   * @type      {number}
   * @default   1
   * @since     4.0
   * @product   highcharts highmaps
   * @apioption plotOptions.heatmap.colsize
   */
  /**
   * The row size - how many Y axis units each heatmap row should span.
   *
   * @sample {highcharts} maps/demo/heatmap/
   *         1 by default
   * @sample {highmaps} maps/demo/heatmap/
   *         1 by default
   *
   * @type      {number}
   * @default   1
   * @since     4.0
   * @product   highcharts highmaps
   * @apioption plotOptions.heatmap.rowsize
   */
  /**
   * Make the heatmap render its data points as an interpolated image.
   *
   * @sample highcharts/demo/heatmap-interpolation
   *   Interpolated heatmap image displaying user activity on a website
   * @sample highcharts/series-heatmap/interpolation
   *   Interpolated heatmap toggle
   *
   */
  interpolation: false,
  /**
   * The color applied to null points. In styled mode, a general CSS class
   * is applied instead.
   *
   * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   */
  nullColor: "#f7f7f7",
  dataLabels: {
    formatter: function() {
      const { numberFormatter } = this.series.chart;
      const { value } = this.point;
      return isNumber$i(value) ? numberFormatter(value, -1) : "";
    },
    inside: true,
    verticalAlign: "middle",
    crop: false,
    /**
     * @ignore-option
     */
    overflow: "allow",
    padding: 0
    // #3837
  },
  /**
   * @excluding radius, enabledThreshold
   * @since     8.1
   */
  marker: {
    /**
     * A predefined shape or symbol for the marker. When undefined, the
     * symbol is pulled from options.symbols. Other possible values are
     * `'circle'`, `'square'`,`'diamond'`, `'triangle'`,
     * `'triangle-down'`, `'rect'`, and `'ellipse'`.
     *
     * Additionally, the URL to a graphic can be given on this form:
     * `'url(graphic.png)'`. Note that for the image to be applied to
     * exported charts, its URL needs to be accessible by the export
     * server.
     *
     * Custom callbacks for symbol path generation can also be added to
     * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
     * used by its method name, as shown in the demo.
     *
     * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
     *         Predefined, graphic and custom markers
     * @sample {highstock} highcharts/plotoptions/series-marker-symbol/
     *         Predefined, graphic and custom markers
     */
    symbol: "rect",
    /** @ignore-option */
    radius: 0,
    lineColor: void 0,
    states: {
      /**
       * @excluding radius, radiusPlus
       */
      hover: {
        /**
         * Set the marker's fixed width on hover state.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-width
         *         70px fixed marker's width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.hover.width
         */
        /**
         * Set the marker's fixed height on hover state.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-width
         *         70px fixed marker's width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.hover.height
         */
        /**
         * The number of pixels to increase the width of the
         * selected point.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-widthplus
         *         20px greater width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.hover.widthPlus
         */
        /**
         * The number of pixels to increase the height of the
         * selected point.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-widthplus
        *          20px greater width and height on hover
            *
            * @type      {number|undefined}
            * @default   undefined
            * @product   highcharts highmaps
            * @apioption plotOptions.heatmap.marker.states.hover.heightPlus
            */
        /**
         * The additional line width for a hovered point.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-linewidthplus
         *         5 pixels wider lineWidth on hover
         * @sample {highmaps} maps/plotoptions/heatmap-marker-states-hover-linewidthplus
         *         5 pixels wider lineWidth on hover
         */
        lineWidthPlus: 0
      },
      /**
       * @excluding radius
       */
      select: {
        /**
         * Set the marker's fixed width on select state.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-width
         *         70px fixed marker's width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.select.width
         */
        /**
         * Set the marker's fixed height on select state.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-width
         *         70px fixed marker's width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.select.height
         */
        /**
         * The number of pixels to increase the width of the
         * selected point.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-widthplus
         *         20px greater width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.select.widthPlus
         */
        /**
         * The number of pixels to increase the height of the
         * selected point.
         *
         * @sample {highcharts} maps/plotoptions/heatmap-marker-states-hover-widthplus
         *         20px greater width and height on hover
         *
         * @type      {number|undefined}
         * @default   undefined
         * @product   highcharts highmaps
         * @apioption plotOptions.heatmap.marker.states.select.heightPlus
         */
      }
    }
  },
  clip: true,
  /** @ignore-option */
  pointRange: null,
  // Dynamically set to colsize by default
  tooltip: {
    pointFormat: "{point.x}, {point.y}: {point.value}<br/>"
  },
  states: {
    hover: {
      /** @ignore-option */
      halo: false,
      // #3406, halo is disabled on heatmaps by default
      /**
       * How much to brighten the point on interaction. Requires the
       * main color to be defined in hex or rgb(a) format.
       *
       * In styled mode, the hover brightening is by default replaced
       * with a fill-opacity set in the `.highcharts-point:hover`
       * rule.
       */
      brightness: 0.2
    }
  },
  legendSymbol: "rectangle"
};
const { doc: doc$1 } = Highcharts;
const { defined: defined$d, pick: pick$m } = Utilities;
function colorFromPoint$1(value, point) {
  const colorAxis = point.series.colorAxis;
  if (colorAxis) {
    const rgba = colorAxis.toColor(value || 0, point).split(")")[0].split("(")[1].split(",").map((s) => pick$m(parseFloat(s), parseInt(s, 10)));
    rgba[3] = pick$m(rgba[3], 1) * 255;
    if (!defined$d(value) || !point.visible) {
      rgba[3] = 0;
    }
    return rgba;
  }
  return [0, 0, 0, 0];
}
function getContext$1(series) {
  const { canvas, context } = series;
  if (canvas && context) {
    context.clearRect(0, 0, canvas.width, canvas.height);
  } else {
    series.canvas = doc$1.createElement("canvas");
    series.context = series.canvas.getContext("2d", {
      willReadFrequently: true
    }) || void 0;
    return series.context;
  }
  return context;
}
const InterpolationUtilities = {
  colorFromPoint: colorFromPoint$1,
  getContext: getContext$1
};
const { series: Series$1, seriesTypes: { column: ColumnSeries$5, scatter: ScatterSeries$1 } } = SeriesRegistry$1;
const { prototype: { symbols } } = SVGRenderer;
const { addEvent: addEvent$d, extend: extend$j, fireEvent: fireEvent$2, isNumber: isNumber$h, merge: merge$l, pick: pick$l } = Utilities;
const { colorFromPoint, getContext } = InterpolationUtilities;
class HeatmapSeries extends ScatterSeries$1 {
  constructor() {
    super(...arguments);
    this.valueMax = NaN;
    this.valueMin = NaN;
    this.isDirtyCanvas = true;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  drawPoints() {
    const series = this, seriesOptions = series.options, interpolation = seriesOptions.interpolation, seriesMarkerOptions = seriesOptions.marker || {};
    if (interpolation) {
      const { image, chart, xAxis: xAxis2, yAxis: yAxis2 } = series, { reversed: xRev = false, len: width } = xAxis2, { reversed: yRev = false, len: height } = yAxis2, dimensions = { width, height };
      if (!image || series.isDirtyData || series.isDirtyCanvas) {
        const ctx = getContext(series), { canvas, options: { colsize = 1, rowsize = 1 }, points, points: { length } } = series, pointsLen = length - 1, colorAxis = chart.colorAxis && chart.colorAxis[0];
        if (canvas && ctx && colorAxis) {
          const { min: xMin, max: xMax } = xAxis2.getExtremes(), { min: yMin, max: yMax } = yAxis2.getExtremes(), xDelta = xMax - xMin, yDelta = yMax - yMin, imgMultiple = 8, lastX = Math.round(imgMultiple * (xDelta / colsize / imgMultiple)), lastY = Math.round(imgMultiple * (yDelta / rowsize / imgMultiple)), [transformX, transformY] = [
            [lastX, lastX / xDelta, xRev, "ceil"],
            [lastY, lastY / yDelta, !yRev, "floor"]
          ].map(([last, scale2, rev, rounding]) => rev ? (v) => Math[rounding](last - scale2 * v) : (v) => Math[rounding](scale2 * v)), canvasWidth = canvas.width = lastX + 1, canvasHeight = canvas.height = lastY + 1, canvasArea = canvasWidth * canvasHeight, pixelToPointScale = pointsLen / canvasArea, pixelData = new Uint8ClampedArray(canvasArea * 4), pointInPixels = (x, y) => Math.ceil(canvasWidth * transformY(y - yMin) + transformX(x - xMin)) * 4;
          series.buildKDTree();
          for (let i = 0; i < canvasArea; i++) {
            const point = points[Math.ceil(pixelToPointScale * i)], { x, y } = point;
            pixelData.set(colorFromPoint(point.value, point), pointInPixels(x, y));
          }
          ctx.putImageData(new ImageData(pixelData, canvasWidth), 0, 0);
          if (image) {
            image.attr({
              ...dimensions,
              href: canvas.toDataURL("image/png", 1)
            });
          } else {
            series.directTouch = false;
            series.image = chart.renderer.image(canvas.toDataURL("image/png", 1)).attr(dimensions).add(series.group);
          }
        }
        series.isDirtyCanvas = false;
      } else if (image.width !== width || image.height !== height) {
        image.attr(dimensions);
      }
    } else if (seriesMarkerOptions.enabled || series._hasPointMarkers) {
      Series$1.prototype.drawPoints.call(series);
      series.points.forEach((point) => {
        if (point.graphic) {
          point.graphic[series.chart.styledMode ? "css" : "animate"](series.colorAttribs(point));
          if (point.value === null) {
            point.graphic.addClass("highcharts-null-point");
          }
        }
      });
    }
  }
  /**
   * @private
   */
  getExtremes() {
    const { dataMin, dataMax } = Series$1.prototype.getExtremes.call(this, this.getColumn("value"));
    if (isNumber$h(dataMin)) {
      this.valueMin = dataMin;
    }
    if (isNumber$h(dataMax)) {
      this.valueMax = dataMax;
    }
    return Series$1.prototype.getExtremes.call(this);
  }
  /**
   * Override to also allow null points, used when building the k-d-tree for
   * tooltips in boost mode.
   * @private
   */
  getValidPoints(points, insideOnly) {
    return Series$1.prototype.getValidPoints.call(this, points, insideOnly, true);
  }
  /**
   * Define hasData function for non-cartesian series. Returns true if the
   * series has points at all.
   * @private
   */
  hasData() {
    return !!this.dataTable.rowCount;
  }
  /**
   * Override the init method to add point ranges on both axes.
   * @private
   */
  init() {
    super.init.apply(this, arguments);
    const options2 = this.options;
    options2.pointRange = pick$l(options2.pointRange, options2.colsize || 1);
    this.yAxis.axisPointRange = options2.rowsize || 1;
    symbols.ellipse = symbols.circle;
    if (options2.marker && isNumber$h(options2.borderRadius)) {
      options2.marker.r = options2.borderRadius;
    }
  }
  /**
   * @private
   */
  markerAttribs(point, state) {
    const shapeArgs = point.shapeArgs || {};
    if (point.hasImage) {
      return {
        x: point.plotX,
        y: point.plotY
      };
    }
    if (state && state !== "normal") {
      const pointMarkerOptions = point.options.marker || {}, seriesMarkerOptions = this.options.marker || {}, seriesStateOptions = seriesMarkerOptions.states?.[state] || {}, pointStateOptions = pointMarkerOptions.states?.[state] || {};
      const width = (pointStateOptions.width || seriesStateOptions.width || shapeArgs.width || 0) + (pointStateOptions.widthPlus || seriesStateOptions.widthPlus || 0);
      const height = (pointStateOptions.height || seriesStateOptions.height || shapeArgs.height || 0) + (pointStateOptions.heightPlus || seriesStateOptions.heightPlus || 0);
      const x = (shapeArgs.x || 0) + ((shapeArgs.width || 0) - width) / 2, y = (shapeArgs.y || 0) + ((shapeArgs.height || 0) - height) / 2;
      return { x, y, width, height };
    }
    return shapeArgs;
  }
  /**
   * @private
   */
  pointAttribs(point, state) {
    const series = this, attr2 = Series$1.prototype.pointAttribs.call(series, point, state), seriesOptions = series.options || {}, plotOptions = series.chart.options.plotOptions || {}, seriesPlotOptions = plotOptions.series || {}, heatmapPlotOptions = plotOptions.heatmap || {}, borderColor = point?.options.borderColor || seriesOptions.borderColor || heatmapPlotOptions.borderColor || seriesPlotOptions.borderColor, borderWidth = point?.options.borderWidth || seriesOptions.borderWidth || heatmapPlotOptions.borderWidth || seriesPlotOptions.borderWidth || attr2["stroke-width"];
    attr2.stroke = point?.marker?.lineColor || seriesOptions.marker?.lineColor || borderColor || this.color;
    attr2["stroke-width"] = borderWidth;
    if (state && state !== "normal") {
      const stateOptions = merge$l(seriesOptions.states?.[state], seriesOptions.marker?.states?.[state], point?.options.states?.[state] || {});
      attr2.fill = stateOptions.color || Color.parse(attr2.fill).brighten(stateOptions.brightness || 0).get();
      attr2.stroke = stateOptions.lineColor || attr2.stroke;
    }
    return attr2;
  }
  /**
   * @private
   */
  translate() {
    const series = this, options2 = series.options, { borderRadius, marker } = options2, symbol = marker?.symbol || "rect", shape = symbols[symbol] ? symbol : "rect", hasRegularShape = ["circle", "square"].indexOf(shape) !== -1;
    series.generatePoints();
    for (const point of series.points) {
      const cellAttr = point.getCellAttributes();
      let x = Math.min(cellAttr.x1, cellAttr.x2), y = Math.min(cellAttr.y1, cellAttr.y2), width = Math.max(Math.abs(cellAttr.x2 - cellAttr.x1), 0), height = Math.max(Math.abs(cellAttr.y2 - cellAttr.y1), 0);
      point.hasImage = (point.marker?.symbol || symbol).indexOf("url") === 0;
      if (hasRegularShape) {
        const sizeDiff = Math.abs(width - height);
        x = Math.min(cellAttr.x1, cellAttr.x2) + (width < height ? 0 : sizeDiff / 2);
        y = Math.min(cellAttr.y1, cellAttr.y2) + (width < height ? sizeDiff / 2 : 0);
        width = height = Math.min(width, height);
      }
      if (point.hasImage) {
        point.marker = { width, height };
      }
      point.plotX = point.clientX = (cellAttr.x1 + cellAttr.x2) / 2;
      point.plotY = (cellAttr.y1 + cellAttr.y2) / 2;
      point.shapeType = "path";
      point.shapeArgs = merge$l(true, { x, y, width, height }, {
        d: symbols[shape](x, y, width, height, { r: isNumber$h(borderRadius) ? borderRadius : 0 })
      });
    }
    fireEvent$2(series, "afterTranslate");
  }
}
HeatmapSeries.defaultOptions = merge$l(ScatterSeries$1.defaultOptions, HeatmapSeriesDefaults);
addEvent$d(HeatmapSeries, "afterDataClassLegendClick", function() {
  this.isDirtyCanvas = true;
  this.drawPoints();
});
extend$j(HeatmapSeries.prototype, {
  axisTypes: ColorMapComposition$1.seriesMembers.axisTypes,
  colorKey: ColorMapComposition$1.seriesMembers.colorKey,
  directTouch: true,
  getExtremesFromAll: true,
  keysAffectYAxis: ["y"],
  parallelArrays: ColorMapComposition$1.seriesMembers.parallelArrays,
  pointArrayMap: ["y", "value"],
  pointClass: HeatmapPoint,
  specialGroup: "group",
  trackerGroups: ColorMapComposition$1.seriesMembers.trackerGroups,
  /**
   * @private
   */
  alignDataLabel: ColumnSeries$5.prototype.alignDataLabel,
  colorAttribs: ColorMapComposition$1.seriesMembers.colorAttribs,
  getSymbol: Series$1.prototype.getSymbol
});
ColorMapComposition$1.compose(HeatmapSeries);
SeriesRegistry$1.registerSeriesType("heatmap", HeatmapSeries);
const { extend: extend$i } = Utilities;
function init$A(axis) {
  extend$i(axis, ColorAxisLike$1);
}
const SolidGaugeAxis = {
  init: init$A
};
const SolidGaugeSeriesDefaults = {
  /**
   * The inner radius for points in a solid gauge. Can be given only in
   * percentage, either as a number or a string like `"50%"`.
   *
   * @sample {highcharts} highcharts/plotoptions/solidgauge-radius/
   *         Individual radius and innerRadius
   *
   * @type      {string}
   * @default   "60%"
   * @since     4.1.6
   * @product   highcharts
   * @apioption plotOptions.solidgauge.innerRadius
   */
  /**
   * Whether the strokes of the solid gauge should be `round` or `square`.
   *
   * @sample {highcharts} highcharts/demo/gauge-multiple-kpi/
   *         Rounded gauge
   *
   * @type       {string}
   * @default    round
   * @since      4.2.2
   * @product    highcharts
   * @validvalue ["square", "round"]
   * @apioption  plotOptions.solidgauge.linecap
   */
  /**
   * Allow the gauge to overshoot the end of the perimeter axis by this
   * many degrees. Say if the gauge axis goes from 0 to 60, a value of
   * 100, or 1000, will show 5 degrees beyond the end of the axis when this
   * option is set to 5.
   *
   * @type      {number}
   * @default   0
   * @since     3.0.10
   * @product   highcharts
   * @apioption plotOptions.solidgauge.overshoot
   */
  /**
   * The outer radius for points in a solid gauge. Can be given only in
   * percentage, either as a number or a string like `"100%"`.
   *
   * @sample {highcharts} highcharts/plotoptions/solidgauge-radius/
   *         Individual radius and innerRadius
   *
   * @type      {string}
   * @default   "100%"
   * @since     4.1.6
   * @product   highcharts
   * @apioption plotOptions.solidgauge.radius
   */
  /**
   * Whether to draw rounded edges on the gauge. This options adds the radius
   * of the rounding to the ends of the arc, so it extends past the actual
   * values. When `borderRadius` is set, it takes precedence over `rounded`. A
   * `borderRadius` of 50% behaves like `rounded`, except the shape is not
   * extended past its value.
   *
   * @sample {highcharts} highcharts/demo/gauge-multiple-kpi/
   *         Gauge showing multiple KPIs
   *
   * @type      {boolean}
   * @default   false
   * @since     5.0.8
   * @product   highcharts
   * @apioption plotOptions.solidgauge.rounded
   */
  /**
   * The threshold or base level for the gauge.
   *
   * @sample {highcharts} highcharts/plotoptions/solidgauge-threshold/
   *         Zero threshold with negative and positive values
   *
   * @type      {number|null}
   * @since     5.0.3
   * @product   highcharts
   * @apioption plotOptions.solidgauge.threshold
   */
  /**
   * Whether to give each point an individual color.
   */
  colorByPoint: true,
  dataLabels: {
    y: 0
  }
};
const { gauge: GaugeSeries, pie: PieSeries } = SeriesRegistry$1.seriesTypes;
const { clamp: clamp$5, extend: extend$h, isNumber: isNumber$g, merge: merge$k, pick: pick$k, pInt } = Utilities;
class SolidGaugeSeries extends GaugeSeries {
  /* *
   *
   *  Functions
   *
   * */
  // Extend the translate function to extend the Y axis with the necessary
  // decoration (#5895).
  translate() {
    const axis = this.yAxis;
    SolidGaugeAxis.init(axis);
    if (!axis.dataClasses && axis.options.dataClasses) {
      axis.initDataClasses(axis.options);
    }
    axis.initStops();
    GaugeSeries.prototype.translate.call(this);
  }
  // Draw the points where each point is one needle.
  drawPoints() {
    const series = this, yAxis2 = series.yAxis, center = yAxis2.center, options2 = series.options, renderer = series.chart.renderer, overshoot = options2.overshoot, rounded = options2.rounded && options2.borderRadius === void 0, overshootVal = isNumber$g(overshoot) ? overshoot / 180 * Math.PI : 0;
    let thresholdAngleRad;
    if (isNumber$g(options2.threshold)) {
      thresholdAngleRad = yAxis2.startAngleRad + yAxis2.translate(options2.threshold, void 0, void 0, void 0, true);
    }
    this.thresholdAngleRad = pick$k(thresholdAngleRad, yAxis2.startAngleRad);
    for (const point of series.points) {
      if (!point.isNull) {
        const radius = pInt(pick$k(
          point.options.radius,
          options2.radius,
          100
          // %
        )) * center[2] / 200, innerRadius = pInt(pick$k(
          point.options.innerRadius,
          options2.innerRadius,
          60
          // %
        )) * center[2] / 200, axisMinAngle = Math.min(yAxis2.startAngleRad, yAxis2.endAngleRad), axisMaxAngle = Math.max(yAxis2.startAngleRad, yAxis2.endAngleRad);
        let graphic = point.graphic, rotation = yAxis2.startAngleRad + yAxis2.translate(point.y, void 0, void 0, void 0, true), shapeArgs, d, toColor = yAxis2.toColor(point.y, point);
        if (toColor === "none") {
          toColor = point.color || series.color || "none";
        }
        if (toColor !== "none") {
          point.color = toColor;
        }
        rotation = clamp$5(rotation, axisMinAngle - overshootVal, axisMaxAngle + overshootVal);
        if (options2.wrap === false) {
          rotation = clamp$5(rotation, axisMinAngle, axisMaxAngle);
        }
        const angleOfRounding = rounded ? (radius - innerRadius) / 2 / radius : 0, start2 = Math.min(rotation, series.thresholdAngleRad) - angleOfRounding;
        let end = Math.max(rotation, series.thresholdAngleRad) + angleOfRounding;
        if (end - start2 > 2 * Math.PI) {
          end = start2 + 2 * Math.PI;
        }
        let borderRadius = rounded ? "50%" : 0;
        if (options2.borderRadius) {
          borderRadius = BorderRadius.optionsToObject(options2.borderRadius).radius;
        }
        point.shapeArgs = shapeArgs = {
          x: center[0],
          y: center[1],
          r: radius,
          innerR: innerRadius,
          start: start2,
          end,
          borderRadius
        };
        point.startR = radius;
        if (graphic) {
          d = shapeArgs.d;
          graphic.animate(extend$h({ fill: toColor }, shapeArgs));
          if (d) {
            shapeArgs.d = d;
          }
        } else {
          point.graphic = graphic = renderer.arc(shapeArgs).attr({
            fill: toColor,
            "sweep-flag": 0
          }).add(series.group);
        }
        if (!series.chart.styledMode) {
          if (options2.linecap !== "square") {
            graphic.attr({
              "stroke-linecap": "round",
              "stroke-linejoin": "round"
            });
          }
          graphic.attr({
            stroke: options2.borderColor || "none",
            "stroke-width": options2.borderWidth || 0
          });
        }
        if (graphic) {
          graphic.addClass(point.getClassName(), true);
        }
      }
    }
  }
  // Extend the pie slice animation by animating from start angle and up.
  animate(init2) {
    if (!init2) {
      this.startAngleRad = this.thresholdAngleRad;
      PieSeries.prototype.animate.call(this, init2);
    }
  }
}
SolidGaugeSeries.defaultOptions = merge$k(GaugeSeries.defaultOptions, SolidGaugeSeriesDefaults);
SeriesRegistry$1.registerSeriesType("solidgauge", SolidGaugeSeries);
class TreemapAlgorithmGroup {
  /* *
   *
   *  Constructor
   *
   * */
  constructor(h, w, d, p) {
    this.height = h;
    this.width = w;
    this.plot = p;
    this.direction = d;
    this.startDirection = d;
    this.total = 0;
    this.nW = 0;
    this.lW = 0;
    this.nH = 0;
    this.lH = 0;
    this.elArr = [];
    this.lP = {
      total: 0,
      lH: 0,
      nH: 0,
      lW: 0,
      nW: 0,
      nR: 0,
      lR: 0,
      aspectRatio: function(w2, h2) {
        return Math.max(w2 / h2, h2 / w2);
      }
    };
  }
  /* *
   *
   *  Functions
   *
   * */
  addElement(el) {
    this.lP.total = this.elArr[this.elArr.length - 1];
    this.total = this.total + el;
    if (this.direction === 0) {
      this.lW = this.nW;
      this.lP.lH = this.lP.total / this.lW;
      this.lP.lR = this.lP.aspectRatio(this.lW, this.lP.lH);
      this.nW = this.total / this.height;
      this.lP.nH = this.lP.total / this.nW;
      this.lP.nR = this.lP.aspectRatio(this.nW, this.lP.nH);
    } else {
      this.lH = this.nH;
      this.lP.lW = this.lP.total / this.lH;
      this.lP.lR = this.lP.aspectRatio(this.lP.lW, this.lH);
      this.nH = this.total / this.width;
      this.lP.nW = this.lP.total / this.nH;
      this.lP.nR = this.lP.aspectRatio(this.lP.nW, this.nH);
    }
    this.elArr.push(el);
  }
  reset() {
    this.nW = 0;
    this.lW = 0;
    this.elArr = [];
    this.total = 0;
  }
}
class TreemapNode {
  constructor() {
    this.childrenTotal = 0;
    this.visible = false;
  }
  /* *
   *
   *  Functions
   *
   * */
  init(id, i, children, height, level, series, parent) {
    this.id = id;
    this.i = i;
    this.children = children;
    this.height = height;
    this.level = level;
    this.series = series;
    this.parent = parent;
    return this;
  }
}
function draw(point, params2) {
  const { animatableAttribs, onComplete, css: css2, renderer } = params2;
  const animation = point.series && point.series.chart.hasRendered ? (
    // Chart-level animation on updates
    void 0
  ) : (
    // Series-level animation on new points
    point.series && point.series.options.animation
  );
  let graphic = point.graphic;
  params2.attribs = {
    ...params2.attribs,
    "class": point.getClassName()
  };
  if (point.shouldDraw()) {
    if (!graphic) {
      if (params2.shapeType === "text") {
        graphic = renderer.text();
      } else if (params2.shapeType === "image") {
        graphic = renderer.image(params2.imageUrl || "").attr(params2.shapeArgs || {});
      } else {
        graphic = renderer[params2.shapeType](params2.shapeArgs || {});
      }
      point.graphic = graphic;
      graphic.add(params2.group);
    }
    if (css2) {
      graphic.css(css2);
    }
    graphic.attr(params2.attribs).animate(animatableAttribs, params2.isNew ? false : animation, onComplete);
  } else if (graphic) {
    const destroy = () => {
      point.graphic = graphic = graphic && graphic.destroy();
      if (typeof onComplete === "function") {
        onComplete();
      }
    };
    if (Object.keys(animatableAttribs).length) {
      graphic.animate(animatableAttribs, void 0, () => destroy());
    } else {
      destroy();
    }
  }
}
const DrawPointUtilities = {
  draw
};
const { pie: { prototype: { pointClass: PiePoint$1 } }, scatter: { prototype: { pointClass: ScatterPoint } } } = SeriesRegistry$1.seriesTypes;
const { extend: extend$g, isNumber: isNumber$f, pick: pick$j } = Utilities;
class TreemapPoint extends ScatterPoint {
  constructor() {
    super(...arguments);
    this.groupedPointsAmount = 0;
    this.shapeType = "rect";
  }
  /* *
   *
   *  Functions
   *
   * */
  draw(params2) {
    DrawPointUtilities.draw(this, params2);
  }
  getClassName() {
    const series = this.series, options2 = series.options;
    let className = super.getClassName();
    if (this.node.level <= series.nodeMap[series.rootNode].level && this.node.children.length) {
      className += " highcharts-above-level";
    } else if (!this.node.isGroup && !this.node.isLeaf && !series.nodeMap[series.rootNode].isGroup && !pick$j(options2.interactByLeaf, !options2.allowTraversingTree)) {
      className += " highcharts-internal-node-interactive";
    } else if (!this.node.isGroup && !this.node.isLeaf && !series.nodeMap[series.rootNode].isGroup) {
      className += " highcharts-internal-node";
    }
    return className;
  }
  /**
   * A tree point is valid if it has han id too, assume it may be a parent
   * item.
   *
   * @private
   * @function Highcharts.Point#isValid
   */
  isValid() {
    return Boolean(this.id || isNumber$f(this.value));
  }
  setState(state) {
    super.setState.apply(this, arguments);
    if (this.graphic) {
      this.graphic.attr({
        zIndex: state === "hover" ? 1 : 0
      });
    }
  }
  shouldDraw() {
    return isNumber$f(this.plotY) && this.y !== null;
  }
}
extend$g(TreemapPoint.prototype, {
  setVisible: PiePoint$1.prototype.setVisible
});
const { isString: isString$2 } = Utilities;
const TreemapSeriesDefaults = {
  /**
   * When enabled the user can click on a point which is a parent and
   * zoom in on its children. Deprecated and replaced by
   * [allowTraversingTree](#plotOptions.treemap.allowTraversingTree).
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-allowdrilltonode/
   *         Enabled
   *
   * @deprecated
   * @type      {boolean}
   * @default   false
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.allowDrillToNode
   */
  /**
   * When enabled the user can click on a point which is a parent and
   * zoom in on its children.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-allowtraversingtree/
   *         Enabled
   * @sample {highcharts} highcharts/plotoptions/treemap-grouping-traversing/
   *         Traversing to Grouped Points node
   *
   * @since     7.0.3
   * @product   highcharts
   */
  allowTraversingTree: false,
  animationLimit: 250,
  /**
   * The border radius for each treemap item.
   */
  borderRadius: 0,
  /**
   * Options for the breadcrumbs, the navigation at the top leading the
   * way up through the traversed levels.
   *
   *
   * @since 10.0.0
   * @product   highcharts
   * @extends   navigation.breadcrumbs
   * @apioption plotOptions.treemap.breadcrumbs
   */
  /**
   * When the series contains less points than the crop threshold, all
   * points are drawn, event if the points fall outside the visible plot
   * area at the current zoom. The advantage of drawing all points
   * (including markers and columns), is that animation is performed on
   * updates. On the other hand, when the series contains more points than
   * the crop threshold, the series data is cropped to only contain points
   * that fall within the plot area. The advantage of cropping away
   * invisible points is to increase performance on large series.
   *
   * @type      {number}
   * @default   300
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.cropThreshold
   */
  /**
   * Fires on a request for change of root node for the tree, before the
   * update is made. An event object is passed to the function, containing
   * additional properties `newRootId`, `previousRootId`, `redraw` and
   * `trigger`.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-events-setrootnode/
   *         Alert update information on setRootNode event.
   *
   * @type {Function}
   * @default undefined
   * @since 7.0.3
   * @product highcharts
   * @apioption plotOptions.treemap.events.setRootNode
   */
  /**
   * This option decides if the user can interact with the parent nodes
   * or just the leaf nodes. When this option is undefined, it will be
   * true by default. However when allowTraversingTree is true, then it
   * will be false by default.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-interactbyleaf-false/
   *         False
   * @sample {highcharts} highcharts/plotoptions/treemap-interactbyleaf-true-and-allowtraversingtree/
   *         InteractByLeaf and allowTraversingTree is true
   *
   * @type      {boolean}
   * @since     4.1.2
   * @product   highcharts
   * @apioption plotOptions.treemap.interactByLeaf
   */
  /**
   * The sort index of the point inside the treemap level.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-sortindex/
   *         Sort by years
   *
   * @type      {number}
   * @since     4.1.10
   * @product   highcharts
   * @apioption plotOptions.treemap.sortIndex
   */
  /**
   * A series specific or series type specific color set to apply instead
   * of the global [colors](#colors) when
   * [colorByPoint](#plotOptions.treemap.colorByPoint) is true.
   *
   * @type      {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}
   * @since     3.0
   * @product   highcharts
   * @apioption plotOptions.treemap.colors
   */
  /**
   * Whether to display this series type or specific series item in the
   * legend.
   */
  showInLegend: false,
  /**
   * @ignore-option
   */
  marker: void 0,
  /**
   * When using automatic point colors pulled from the `options.colors`
   * collection, this option determines whether the chart should receive
   * one color per series or one color per point.
   *
   * @see [series colors](#plotOptions.treemap.colors)
   *
   * @since     2.0
   * @product   highcharts
   * @apioption plotOptions.treemap.colorByPoint
   */
  colorByPoint: false,
  /**
   * @since 4.1.0
   */
  dataLabels: {
    enabled: true,
    formatter: function() {
      const point = this && this.point ? this.point : {}, name = isString$2(point.name) ? point.name : "";
      return name;
    },
    /**
     * Whether the data label should act as a group-level header. For leaf
     * nodes, headers are not supported and the data label will be rendered
     * inside.
     *
     * @sample {highcharts} highcharts/series-treemap/headers
     *         Headers for parent nodes
     *
     * @since 12.2.0
     */
    headers: false,
    inside: true,
    padding: 2,
    verticalAlign: "middle",
    style: {
      textOverflow: "ellipsis"
    }
  },
  tooltip: {
    headerFormat: "",
    pointFormat: "<b>{point.name}</b>: {point.value}<br/>",
    /**
     * The HTML of the grouped point's nodes in the tooltip. Works only for
     * Treemap series grouping and analogously to
     * [pointFormat](#tooltip.pointFormat).
     *
     * The grouped nodes point tooltip can be also formatted using
     * `tooltip.formatter` callback function and `point.isGroupNode` flag.
     *
     * @type      {string}
     * @default   '+ {point.groupedPointsAmount} more...'
     * @apioption tooltip.clusterFormat
     */
    clusterFormat: "+ {point.groupedPointsAmount} more...<br/>"
  },
  /**
   * Whether to ignore hidden points when the layout algorithm runs.
   * If `false`, hidden points will leave open spaces.
   *
   * @since 5.0.8
   */
  ignoreHiddenPoint: true,
  /**
   * This option decides which algorithm is used for setting position
   * and dimensions of the points.
   *
   * @see [How to write your own algorithm](https://www.highcharts.com/docs/chart-and-series-types/treemap)
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-sliceanddice/
   *         SliceAndDice by default
   * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-stripes/
   *         Stripes
   * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-squarified/
   *         Squarified
   * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-strip/
   *         Strip
   *
   * @since      4.1.0
   * @validvalue ["sliceAndDice", "stripes", "squarified", "strip"]
   */
  layoutAlgorithm: "sliceAndDice",
  /**
   * Defines which direction the layout algorithm will start drawing.
   *
   * @since       4.1.0
   * @validvalue ["vertical", "horizontal"]
   */
  layoutStartingDirection: "vertical",
  /**
   * Enabling this option will make the treemap alternate the drawing
   * direction between vertical and horizontal. The next levels starting
   * direction will always be the opposite of the previous.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-alternatestartingdirection-true/
   *         Enabled
   *
   * @since 4.1.0
   */
  alternateStartingDirection: false,
  /**
   * Used together with the levels and allowTraversingTree options. When
   * set to false the first level visible to be level one, which is
   * dynamic when traversing the tree. Otherwise the level will be the
   * same as the tree structure.
   *
   * @since 4.1.0
   */
  levelIsConstant: true,
  /**
   * Options for the button appearing when traversing down in a treemap.
   *
   * Since v9.3.3 the `traverseUpButton` is replaced by `breadcrumbs`.
   *
   * @deprecated
   */
  traverseUpButton: {
    /**
     * The position of the button.
     */
    position: {
      /**
       * Vertical alignment of the button.
       *
       * @type      {Highcharts.VerticalAlignValue}
       * @default   top
       * @product   highcharts
       * @apioption plotOptions.treemap.traverseUpButton.position.verticalAlign
       */
      /**
       * Horizontal alignment of the button.
       *
       * @type {Highcharts.AlignValue}
       */
      align: "right",
      /**
       * Horizontal offset of the button.
       */
      x: -10,
      /**
       * Vertical offset of the button.
       */
      y: 10
    }
  },
  /**
   * Group padding for parent elements in terms of pixels. See also the
   * `nodeSizeBy` option that controls how the leaf nodes' size is affected by
   * the padding.
   *
   * @sample    {highcharts} highcharts/series-treemap/grouppadding/
   *            Group padding
   * @type      {number}
   * @since 12.2.0
   * @product   highcharts
   * @apioption plotOptions.treemap.groupPadding
   */
  /**
   * Set options on specific levels. Takes precedence over series options,
   * but not point options.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-levels/
   *         Styling dataLabels and borders
   * @sample {highcharts} highcharts/demo/treemap-with-levels/
   *         Different layoutAlgorithm
   *
   * @type      {Array<*>}
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels
   */
  /**
   * Experimental. How to set the size of child nodes when a header or padding
   * is present. When `leaf`, the group is expanded to make room for headers
   * and padding in order to preserve the relative sizes between leaves. When
   * `group`, the leaves are naïvely fit into the remaining area after the
   * header and padding are subtracted.
   *
   * @sample    {highcharts} highcharts/series-treemap/nodesizeby/
   *            Node sizing
   * @since 12.2.0
   * @type      {string}
   * @validvalue ["group", "leaf"]
   * @default   group
   * @apioption plotOptions.treemap.nodeSizeBy
   */
  /**
   * Can set a `borderColor` on all points which lies on the same level.
   *
   * @type      {Highcharts.ColorString}
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.borderColor
   */
  /**
   * Set the dash style of the border of all the point which lies on the
   * level. See
   * [plotOptions.scatter.dashStyle](#plotoptions.scatter.dashstyle)
   * for possible options.
   *
   * @type      {Highcharts.DashStyleValue}
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.borderDashStyle
   */
  /**
   * Can set the borderWidth on all points which lies on the same level.
   *
   * @type      {number}
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.borderWidth
   */
  /**
   * Can set a color on all points which lies on the same level.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.color
   */
  /**
   * A configuration object to define how the color of a child varies from
   * the parent's color. The variation is distributed among the children
   * of node. For example when setting brightness, the brightness change
   * will range from the parent's original brightness on the first child,
   * to the amount set in the `to` setting on the last node. This allows a
   * gradient-like color scheme that sets children out from each other
   * while highlighting the grouping on treemaps and sectors on sunburst
   * charts.
   *
   * @sample highcharts/demo/sunburst/
   *         Sunburst with color variation
   *
   * @sample highcharts/series-treegraph/color-variation
   *         Treegraph nodes with color variation
   *
   * @since     6.0.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.colorVariation
   */
  /**
   * The key of a color variation. Currently supports `brightness` only.
   *
   * @type       {string}
   * @since      6.0.0
   * @product    highcharts
   * @validvalue ["brightness"]
   * @apioption  plotOptions.treemap.levels.colorVariation.key
   */
  /**
   * The ending value of a color variation. The last sibling will receive
   * this value.
   *
   * @type      {number}
   * @since     6.0.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.colorVariation.to
   */
  /**
   * Can set the options of dataLabels on each point which lies on the
   * level.
   * [plotOptions.treemap.dataLabels](#plotOptions.treemap.dataLabels) for
   * possible values.
   *
   * @extends   plotOptions.treemap.dataLabels
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.dataLabels
   */
  /**
   * Can set the layoutAlgorithm option on a specific level.
   *
   * @type       {string}
   * @since      4.1.0
   * @product    highcharts
   * @validvalue ["sliceAndDice", "stripes", "squarified", "strip"]
   * @apioption  plotOptions.treemap.levels.layoutAlgorithm
   */
  /**
   * Can set the layoutStartingDirection option on a specific level.
   *
   * @type       {string}
   * @since      4.1.0
   * @product    highcharts
   * @validvalue ["vertical", "horizontal"]
   * @apioption  plotOptions.treemap.levels.layoutStartingDirection
   */
  /**
   * Decides which level takes effect from the options set in the levels
   * object.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-levels/
   *         Styling of both levels
   *
   * @type      {number}
   * @since     4.1.0
   * @product   highcharts
   * @apioption plotOptions.treemap.levels.level
   */
  // Presentational options
  /**
   * The color of the border surrounding each tree map item.
   *
   * @type {Highcharts.ColorString}
   */
  borderColor: "#e6e6e6",
  /**
   * The width of the border surrounding each tree map item.
   */
  borderWidth: 1,
  colorKey: "colorValue",
  /**
   * The opacity of grouped points in treemap. When a point has children, the
   * group point is covering the children, and is given this opacity. The
   * visibility of the children is determined by the opacity.
   *
   * @since 4.2.4
   */
  opacity: 0.15,
  /**
   * A wrapper object for all the series options in specific states.
   *
   * @extends plotOptions.heatmap.states
   */
  states: {
    /**
     * Options for the hovered series
     *
     * @extends   plotOptions.heatmap.states.hover
     * @excluding halo
     */
    hover: {
      /**
       * The border color for the hovered state.
       */
      borderColor: "#999999",
      /**
       * Brightness for the hovered point. Defaults to 0 if the
       * heatmap series is loaded first, otherwise 0.1.
       *
       * @type    {number}
       * @default undefined
       */
      brightness: SeriesRegistry$1.seriesTypes.heatmap ? 0 : 0.1,
      /**
       * @extends plotOptions.heatmap.states.hover.halo
       */
      halo: false,
      /**
       * The opacity of a point in treemap. When a point has children,
       * the visibility of the children is determined by the opacity.
       *
       * @since 4.2.4
       */
      opacity: 0.75,
      /**
       * The shadow option for hovered state.
       */
      shadow: false
    }
  },
  legendSymbol: "rectangle",
  /**
   * This option enables automatic traversing to the last child level upon
   * node interaction. This feature simplifies navigation by immediately
   * focusing on the deepest layer of the data structure without intermediate
   * steps.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-traverse-to-leaf/
   *         Traverse to leaf enabled
   *
   * @since   11.4.4
   *
   * @product highcharts
   */
  traverseToLeaf: false,
  /**
   * An option to optimize treemap series rendering by grouping smaller leaf
   * nodes below a certain square area threshold in pixels. If the square area
   * of a point becomes smaller than the specified threshold, determined by
   * the `pixelWidth` and/or `pixelHeight` options, then this point is moved
   * into one group point per series.
   *
   * @sample {highcharts} highcharts/plotoptions/treemap-grouping-simple
   *         Simple demo of Treemap grouping
   * @sample {highcharts} highcharts/plotoptions/treemap-grouping-multiple-parents
   *         Treemap grouping with multiple parents
   * @sample {highcharts} highcharts/plotoptions/treemap-grouping-advanced
   *         Advanced demo of Treemap grouping
   *
   * @since 12.1.0
   *
   * @excluding allowOverlap, animation, dataLabels, drillToCluster, events,
   * layoutAlgorithm, marker, states, zones
   *
   * @product highcharts
   */
  cluster: {
    /**
     * An additional, individual class name for the grouped point's graphic
     * representation.
     *
     * @type      string
     * @product   highcharts
     */
    className: void 0,
    /**
     * Individual color for the grouped point. By default the color is
     * pulled from the parent color.
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @product   highcharts
     */
    color: void 0,
    /**
     * Enable or disable Treemap grouping.
     *
     * @type {boolean}
     * @since 12.1.0
     * @product highcharts
     */
    enabled: false,
    /**
     * The pixel threshold width of area, which is used in Treemap grouping.
     *
     * @type {number}
     * @since 12.1.0
     * @product highcharts
     */
    pixelWidth: void 0,
    /**
     * The pixel threshold height of area, which is used in Treemap
     * grouping.
     *
     * @type {number}
     * @since 12.1.0
     * @product highcharts
     */
    pixelHeight: void 0,
    /**
     * The name of the point of grouped nodes shown in the tooltip,
     * dataLabels, etc. By default it is set to '+ n', where n is number of
     * grouped points.
     *
     * @type {string}
     * @since 12.1.0
     * @product highcharts
     */
    name: void 0,
    /**
     * A configuration property that specifies the factor by which the value
     * and size of a grouped node are reduced. This can be particularly
     * useful when a grouped node occupies a disproportionately large
     * portion of the graph, ensuring better visual balance and readability.
     *
     * @type {number}
     * @since 12.1.0
     * @product highcharts
     */
    reductionFactor: void 0,
    /**
     * Defines the minimum number of child nodes required to create a group
     * of small nodes.
     *
     * @type {number}
     * @since 12.1.0
     * @product highcharts
     */
    minimumClusterSize: 5,
    layoutAlgorithm: {
      distance: 0,
      gridSize: 0,
      kmeansThreshold: 0
    },
    marker: {
      lineWidth: 0,
      radius: 0
    }
  }
};
var TreemapUtilities;
(function(TreemapUtilities2) {
  function recursive(item, func, context) {
    const next = func.call(context || this, item);
    if (next !== false) {
      recursive(next, func, context);
    }
  }
  TreemapUtilities2.recursive = recursive;
})(TreemapUtilities || (TreemapUtilities = {}));
const TreemapUtilities$1 = TreemapUtilities;
const { extend: extend$f, isArray: isArray$5, isNumber: isNumber$e, isObject: isObject$7, merge: merge$j, pick: pick$i, relativeLength: relativeLength$4 } = Utilities;
function getColor$1(node, options2) {
  const index = options2.index, mapOptionsToLevel = options2.mapOptionsToLevel, parentColor = options2.parentColor, parentColorIndex = options2.parentColorIndex, series = options2.series, colors = options2.colors, siblings = options2.siblings, points = series.points, chartOptionsChart = series.chart.options.chart;
  let getColorByPoint, point, level, colorByPoint, colorIndexByPoint, color2, colorIndex;
  const variateColor = (color3) => {
    const colorVariation = level && level.colorVariation;
    if (colorVariation && colorVariation.key === "brightness" && index && siblings) {
      return Color.parse(color3).brighten(colorVariation.to * (index / siblings)).get();
    }
    return color3;
  };
  if (node) {
    point = points[node.i];
    level = mapOptionsToLevel[node.level] || {};
    getColorByPoint = point && level.colorByPoint;
    if (getColorByPoint) {
      colorIndexByPoint = point.index % (colors ? colors.length : chartOptionsChart.colorCount);
      colorByPoint = colors && colors[colorIndexByPoint];
    }
    if (!series.chart.styledMode) {
      color2 = pick$i(point && point.options.color, level && level.color, colorByPoint, parentColor && variateColor(parentColor), series.color);
    }
    colorIndex = pick$i(point && point.options.colorIndex, level && level.colorIndex, colorIndexByPoint, parentColorIndex, options2.colorIndex);
  }
  return {
    color: color2,
    colorIndex
  };
}
function getLevelOptions$3(params2) {
  const result = {};
  let defaults2, converted, i, from, to, levels;
  if (isObject$7(params2)) {
    from = isNumber$e(params2.from) ? params2.from : 1;
    levels = params2.levels;
    converted = {};
    defaults2 = isObject$7(params2.defaults) ? params2.defaults : {};
    if (isArray$5(levels)) {
      converted = levels.reduce((obj, item) => {
        let level, levelIsConstant, options2;
        if (isObject$7(item) && isNumber$e(item.level)) {
          options2 = merge$j({}, item);
          levelIsConstant = pick$i(options2.levelIsConstant, defaults2.levelIsConstant);
          delete options2.levelIsConstant;
          delete options2.level;
          level = item.level + (levelIsConstant ? 0 : from - 1);
          if (isObject$7(obj[level])) {
            merge$j(true, obj[level], options2);
          } else {
            obj[level] = options2;
          }
        }
        return obj;
      }, {});
    }
    to = isNumber$e(params2.to) ? params2.to : 1;
    for (i = 0; i <= to; i++) {
      result[i] = merge$j({}, defaults2, isObject$7(converted[i]) ? converted[i] : {});
    }
  }
  return result;
}
function updateRootId$1(series) {
  let rootId, options2;
  if (isObject$7(series)) {
    options2 = isObject$7(series.options) ? series.options : {};
    rootId = pick$i(series.rootNode, options2.rootId, "");
    if (isObject$7(series.userOptions)) {
      series.userOptions.rootId = rootId;
    }
    series.rootNode = rootId;
  }
  return rootId;
}
function getNodeWidth$1(series, columnCount) {
  const { chart, options: options2 } = series, { nodeDistance = 0, nodeWidth = 0 } = options2, { plotSizeX = 1 } = chart;
  if (nodeWidth === "auto") {
    if (typeof nodeDistance === "string" && /%$/.test(nodeDistance)) {
      const fraction = parseFloat(nodeDistance) / 100, total = columnCount + fraction * (columnCount - 1);
      return plotSizeX / total;
    }
    const nDistance = Number(nodeDistance);
    return (plotSizeX + nDistance) / (columnCount || 1) - nDistance;
  }
  return relativeLength$4(nodeWidth, plotSizeX);
}
const TreeUtilities = {
  getColor: getColor$1,
  getLevelOptions: getLevelOptions$3,
  getNodeWidth: getNodeWidth$1,
  updateRootId: updateRootId$1
};
const { parse: color$2 } = Color;
const { composed: composed$2, noop: noop$1 } = Highcharts;
const { column: ColumnSeries$4, scatter: ScatterSeries } = SeriesRegistry$1.seriesTypes;
const { getColor, getLevelOptions: getLevelOptions$2, updateRootId } = TreeUtilities;
const { addEvent: addEvent$c, arrayMax: arrayMax$1, clamp: clamp$4, correctFloat: correctFloat$1, crisp: crisp$3, defined: defined$c, error: error$2, extend: extend$e, fireEvent: fireEvent$1, isArray: isArray$4, isNumber: isNumber$d, isObject: isObject$6, isString: isString$1, merge: merge$i, pick: pick$h, pushUnique: pushUnique$2, splat: splat$3, stableSort: stableSort$1 } = Utilities;
Series$9.keepProps.push("simulation", "hadOutsideDataLabels");
const axisMax = 100;
let treemapAxisDefaultValues = false;
function onSeriesAfterBindAxes() {
  const series = this, xAxis2 = series.xAxis, yAxis2 = series.yAxis;
  let treeAxis;
  if (xAxis2 && yAxis2) {
    if (series.is("treemap")) {
      treeAxis = {
        endOnTick: false,
        gridLineWidth: 0,
        lineWidth: 0,
        min: 0,
        minPadding: 0,
        max: axisMax,
        maxPadding: 0,
        startOnTick: false,
        title: void 0,
        tickPositions: []
      };
      extend$e(yAxis2.options, treeAxis);
      extend$e(xAxis2.options, treeAxis);
      treemapAxisDefaultValues = true;
    } else if (treemapAxisDefaultValues) {
      yAxis2.setOptions(yAxis2.userOptions);
      xAxis2.setOptions(xAxis2.userOptions);
      treemapAxisDefaultValues = false;
    }
  }
}
class TreemapSeries extends ScatterSeries {
  constructor() {
    super(...arguments);
    this.simulation = 0;
  }
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(SeriesClass) {
    if (pushUnique$2(composed$2, "TreemapSeries")) {
      addEvent$c(SeriesClass, "afterBindAxes", onSeriesAfterBindAxes);
    }
  }
  /* *
   *
   *  Function
   *
   * */
  /* eslint-disable valid-jsdoc */
  algorithmCalcPoints(directionChange, last, group2, childrenArea) {
    const plot = group2.plot, end = group2.elArr.length - 1;
    let pX, pY, pW, pH, gW = group2.lW, gH = group2.lH, keep, i = 0;
    if (last) {
      gW = group2.nW;
      gH = group2.nH;
    } else {
      keep = group2.elArr[end];
    }
    for (const p of group2.elArr) {
      if (last || i < end) {
        if (group2.direction === 0) {
          pX = plot.x;
          pY = plot.y;
          pW = gW;
          pH = p / pW;
        } else {
          pX = plot.x;
          pY = plot.y;
          pH = gH;
          pW = p / pH;
        }
        childrenArea.push({
          x: pX,
          y: pY,
          width: pW,
          height: correctFloat$1(pH)
        });
        if (group2.direction === 0) {
          plot.y = plot.y + pH;
        } else {
          plot.x = plot.x + pW;
        }
      }
      i = i + 1;
    }
    group2.reset();
    if (group2.direction === 0) {
      group2.width = group2.width - gW;
    } else {
      group2.height = group2.height - gH;
    }
    plot.y = plot.parent.y + (plot.parent.height - group2.height);
    plot.x = plot.parent.x + (plot.parent.width - group2.width);
    if (directionChange) {
      group2.direction = 1 - group2.direction;
    }
    if (!last) {
      group2.addElement(keep);
    }
  }
  algorithmFill(directionChange, parent, children) {
    const childrenArea = [];
    let pTot, direction = parent.direction, x = parent.x, y = parent.y, width = parent.width, height = parent.height, pX, pY, pW, pH;
    for (const child of children) {
      pTot = parent.width * parent.height * (child.val / parent.val);
      pX = x;
      pY = y;
      if (direction === 0) {
        pH = height;
        pW = pTot / pH;
        width = width - pW;
        x = x + pW;
      } else {
        pW = width;
        pH = pTot / pW;
        height = height - pH;
        y = y + pH;
      }
      childrenArea.push({
        x: pX,
        y: pY,
        width: pW,
        height: pH,
        direction: 0,
        val: 0
      });
      if (directionChange) {
        direction = 1 - direction;
      }
    }
    return childrenArea;
  }
  algorithmLowAspectRatio(directionChange, parent, children) {
    const series = this, childrenArea = [], plot = {
      x: parent.x,
      y: parent.y,
      parent
    }, direction = parent.direction, end = children.length - 1, group2 = new TreemapAlgorithmGroup(parent.height, parent.width, direction, plot);
    let pTot, i = 0;
    for (const child of children) {
      pTot = parent.width * parent.height * (child.val / parent.val);
      group2.addElement(pTot);
      if (group2.lP.nR > group2.lP.lR) {
        series.algorithmCalcPoints(
          directionChange,
          false,
          group2,
          childrenArea,
          plot
          // @todo no supported
        );
      }
      if (i === end) {
        series.algorithmCalcPoints(
          directionChange,
          true,
          group2,
          childrenArea,
          plot
          // @todo not supported
        );
      }
      ++i;
    }
    return childrenArea;
  }
  /**
   * Over the alignment method by setting z index.
   * @private
   */
  alignDataLabel(point, dataLabel, labelOptions) {
    ColumnSeries$4.prototype.alignDataLabel.apply(this, arguments);
    if (point.dataLabel) {
      point.dataLabel.attr({ zIndex: (point.node.zIndex || 0) + 1 });
    }
  }
  applyTreeGrouping() {
    const series = this, parentList = series.parentList || {}, { cluster } = series.options, minimumClusterSize = cluster?.minimumClusterSize || 5;
    if (cluster?.enabled) {
      const parentGroups = {};
      const checkIfHide = (node) => {
        if (node?.point?.shapeArgs) {
          const { width = 0, height = 0 } = node.point.shapeArgs, area = width * height;
          const { pixelWidth = 0, pixelHeight = 0 } = cluster, compareHeight = defined$c(pixelHeight), thresholdArea = pixelHeight ? pixelWidth * pixelHeight : pixelWidth * pixelWidth;
          if (width < pixelWidth || height < (compareHeight ? pixelHeight : pixelWidth) || area < thresholdArea) {
            if (!node.isGroup && defined$c(node.parent)) {
              if (!parentGroups[node.parent]) {
                parentGroups[node.parent] = [];
              }
              parentGroups[node.parent].push(node);
            }
          }
        }
        node?.children.forEach((child) => {
          checkIfHide(child);
        });
      };
      checkIfHide(series.tree);
      for (const parent in parentGroups) {
        if (parentGroups[parent]) {
          if (parentGroups[parent].length > minimumClusterSize) {
            parentGroups[parent].forEach((node) => {
              const index = parentList[parent].indexOf(node.i);
              if (index !== -1) {
                parentList[parent].splice(index, 1);
                const id = `highcharts-grouped-treemap-points-${node.parent || "root"}`;
                let groupPoint = series.points.find((p) => p.id === id);
                if (!groupPoint) {
                  const PointClass = series.pointClass, pointIndex = series.points.length;
                  groupPoint = new PointClass(series, {
                    className: cluster.className,
                    color: cluster.color,
                    id,
                    index: pointIndex,
                    isGroup: true,
                    value: 0
                  });
                  extend$e(groupPoint, {
                    formatPrefix: "cluster"
                  });
                  series.points.push(groupPoint);
                  parentList[parent].push(pointIndex);
                  parentList[id] = [];
                }
                const amount = groupPoint.groupedPointsAmount + 1, val = series.points[groupPoint.index].options.value || 0, name = cluster.name || `+ ${amount}`;
                series.points[groupPoint.index].groupedPointsAmount = amount;
                series.points[groupPoint.index].options.value = val + (node.point.value || 0);
                series.points[groupPoint.index].name = name;
                parentList[id].push(node.point.index);
              }
            });
          }
        }
      }
      series.nodeMap = {};
      series.nodeList = [];
      series.parentList = parentList;
      const tree = series.buildTree("", -1, 0, series.parentList);
      series.translate(tree);
    }
  }
  /**
   * Recursive function which calculates the area for all children of a
   * node.
   *
   * @private
   * @function Highcharts.Series#calculateChildrenAreas
   *
   * @param {Object} parent
   * The node which is parent to the children.
   *
   * @param {Object} area
   * The rectangular area of the parent.
   */
  calculateChildrenAreas(parent, area) {
    const series = this, options2 = series.options, mapOptionsToLevel = series.mapOptionsToLevel, level = mapOptionsToLevel[parent.level + 1], algorithm = pick$h(level?.layoutAlgorithm && series[level?.layoutAlgorithm] && level.layoutAlgorithm, options2.layoutAlgorithm), alternate = options2.alternateStartingDirection, children = parent.children.filter((n) => parent.isGroup || !n.ignore), groupPadding = level?.groupPadding ?? options2.groupPadding ?? 0, rootNode = series.nodeMap[series.rootNode];
    if (!algorithm) {
      return;
    }
    let childrenValues = [], axisWidth = rootNode.pointValues?.width || 0, axisHeight = rootNode.pointValues?.height || 0;
    if (level?.layoutStartingDirection) {
      area.direction = level.layoutStartingDirection === "vertical" ? 0 : 1;
    }
    childrenValues = series[algorithm](area, children);
    let i = -1;
    for (const child of children) {
      const values = childrenValues[++i];
      if (child === rootNode) {
        axisWidth = axisWidth || values.width;
        axisHeight = values.height;
      }
      const groupPaddingXValues = groupPadding / (series.xAxis.len / axisHeight), groupPaddingYValues = groupPadding / (series.yAxis.len / axisHeight);
      child.values = merge$i(values, {
        val: child.childrenTotal,
        direction: alternate ? 1 - area.direction : area.direction
      });
      if (child.children.length && child.point.dataLabels?.length) {
        const dlHeight = arrayMax$1(child.point.dataLabels.map((dl) => dl.options?.headers && dl.height || 0)) / (series.yAxis.len / axisHeight);
        if (dlHeight < child.values.height / 2) {
          child.values.y += dlHeight;
          child.values.height -= dlHeight;
        }
      }
      if (groupPadding) {
        const xPad = Math.min(groupPaddingXValues, child.values.width / 4), yPad = Math.min(groupPaddingYValues, child.values.height / 4);
        child.values.x += xPad;
        child.values.width -= 2 * xPad;
        child.values.y += yPad;
        child.values.height -= 2 * yPad;
      }
      child.pointValues = merge$i(values, {
        x: values.x / series.axisRatio,
        // Flip y-values to avoid visual regression with csvCoord in
        // Axis.translate at setPointValues. #12488
        y: axisMax - values.y - values.height,
        width: values.width / series.axisRatio
      });
      if (child.children.length) {
        series.calculateChildrenAreas(child, child.values);
      }
    }
    const getChildrenRecursive = (node, result = [], getLeaves = true) => {
      node.children.forEach((child) => {
        if (getLeaves && child.isLeaf) {
          result.push(child.point);
        } else if (!getLeaves && !child.isLeaf) {
          result.push(child.point);
        }
        if (child.children.length) {
          getChildrenRecursive(child, result, getLeaves);
        }
      });
      return result;
    };
    if (options2.nodeSizeBy === "leaf" && parent === rootNode && this.hasOutsideDataLabels && // Sizing by leaf value is not possible if any of the groups have
    // explicit values
    !getChildrenRecursive(rootNode, void 0, false).some((point) => isNumber$d(point.options.value)) && !isNumber$d(rootNode.point?.options.value)) {
      const leaves = getChildrenRecursive(rootNode), values = leaves.map((point) => point.options.value || 0), areas = leaves.map(({ node: { pointValues } }) => pointValues ? pointValues.width * pointValues.height : 0), valueSum = values.reduce((sum2, value) => sum2 + value, 0), areaSum = areas.reduce((sum2, value) => sum2 + value, 0), expectedAreaPerValue = areaSum / valueSum;
      let minMiss = 0, maxMiss = 0;
      leaves.forEach((point, i2) => {
        const areaPerValue = values[i2] ? areas[i2] / values[i2] : 1, fit = clamp$4(areaPerValue / expectedAreaPerValue, 0.8, 1.4);
        let miss = 1 - fit;
        if (point.value) {
          if (areas[i2] < 20) {
            miss *= areas[i2] / 20;
          }
          if (miss > maxMiss) {
            maxMiss = miss;
          }
          if (miss < minMiss) {
            minMiss = miss;
          }
          point.simulatedValue = (point.simulatedValue || point.value) / fit;
        }
      });
      if (
        // An area error less than 5% is acceptable, the human ability
        // to assess area size is not that accurate
        (minMiss < -0.05 || maxMiss > 0.05) && // In case an eternal loop is brewing, pull the emergency brake
        this.simulation < 10
      ) {
        this.simulation++;
        this.setTreeValues(parent);
        area.val = parent.val;
        this.calculateChildrenAreas(parent, area);
      } else {
        leaves.forEach((point) => {
          delete point.simulatedValue;
        });
        this.setTreeValues(parent);
        this.simulation = 0;
      }
    }
  }
  /**
   * Create level list.
   * @private
   */
  createList(e) {
    const chart = this.chart, breadcrumbs = chart.breadcrumbs, list = [];
    if (breadcrumbs) {
      let currentLevelNumber = 0;
      list.push({
        level: currentLevelNumber,
        levelOptions: chart.series[0]
      });
      let node = e.target.nodeMap[e.newRootId];
      const extraNodes = [];
      while (node.parent || node.parent === "") {
        extraNodes.push(node);
        node = e.target.nodeMap[node.parent];
      }
      for (const node2 of extraNodes.reverse()) {
        list.push({
          level: ++currentLevelNumber,
          levelOptions: node2
        });
      }
      if (list.length <= 1) {
        list.length = 0;
      }
    }
    return list;
  }
  /**
   * Extend drawDataLabels with logic to handle custom options related to
   * the treemap series:
   *
   * - Points which is not a leaf node, has dataLabels disabled by
   *   default.
   *
   * - Options set on series.levels is merged in.
   *
   * - Width of the dataLabel is set to match the width of the point
   *   shape.
   *
   * @private
   */
  drawDataLabels() {
    const series = this, mapOptionsToLevel = series.mapOptionsToLevel, points = series.points.filter(function(n) {
      return n.node.visible || defined$c(n.dataLabel);
    }), padding = splat$3(series.options.dataLabels || {})[0]?.padding, positionsAreSet = points.some((p) => isNumber$d(p.plotY));
    for (const point of points) {
      const style = {}, options2 = { style }, level = mapOptionsToLevel[point.node.level];
      if (!point.node.isLeaf && !point.node.isGroup || point.node.isGroup && point.node.level <= series.nodeMap[series.rootNode].level) {
        options2.enabled = false;
      }
      if (level?.dataLabels) {
        merge$i(true, options2, splat$3(level.dataLabels)[0]);
        series.hasDataLabels = () => true;
      }
      if (point.node.isLeaf) {
        options2.inside = true;
      } else if (options2.headers) {
        options2.verticalAlign = "top";
      }
      if (point.shapeArgs && positionsAreSet) {
        const { height = 0, width = 0 } = point.shapeArgs;
        if (width > 32 && height > 16 && point.shouldDraw()) {
          const dataLabelWidth = width - 2 * (options2.padding || padding || 0);
          style.width = `${dataLabelWidth}px`;
          style.lineClamp ?? (style.lineClamp = Math.floor(height / 16));
          style.visibility = "inherit";
          if (options2.headers) {
            point.dataLabel?.attr({
              width: dataLabelWidth
            });
          }
        } else {
          style.width = `${width}px`;
          style.visibility = "hidden";
        }
      }
      point.dlOptions = merge$i(options2, point.options.dataLabels);
    }
    super.drawDataLabels(points);
  }
  /**
   * Override drawPoints
   * @private
   */
  drawPoints(points = this.points) {
    const series = this, chart = series.chart, renderer = chart.renderer, styledMode = chart.styledMode, options2 = series.options, shadow = styledMode ? {} : options2.shadow, borderRadius = options2.borderRadius, withinAnimationLimit = chart.pointCount < options2.animationLimit, allowTraversingTree = options2.allowTraversingTree;
    for (const point of points) {
      const levelDynamic = point.node.levelDynamic, animatableAttribs = {}, attribs = {}, css2 = {}, groupKey = "level-group-" + point.node.level, hasGraphic = !!point.graphic, shouldAnimate = withinAnimationLimit && hasGraphic, shapeArgs = point.shapeArgs;
      if (point.shouldDraw()) {
        point.isInside = true;
        if (borderRadius) {
          attribs.r = borderRadius;
        }
        merge$i(
          true,
          // Extend object
          // Which object to extend
          shouldAnimate ? animatableAttribs : attribs,
          // Add shapeArgs to animate/attr if graphic exists
          hasGraphic ? shapeArgs : {},
          // Add style attribs if !styleMode
          styledMode ? {} : series.pointAttribs(point, point.selected ? "select" : void 0)
        );
        if (series.colorAttribs && styledMode) {
          extend$e(css2, series.colorAttribs(point));
        }
        if (!series[groupKey]) {
          series[groupKey] = renderer.g(groupKey).attr({
            // @todo Set the zIndex based upon the number of
            // levels, instead of using 1000
            zIndex: 1e3 - (levelDynamic || 0)
          }).add(series.group);
          series[groupKey].survive = true;
        }
      }
      point.draw({
        animatableAttribs,
        attribs,
        css: css2,
        group: series[groupKey],
        imageUrl: point.imageUrl,
        renderer,
        shadow,
        shapeArgs,
        shapeType: point.shapeType
      });
      if (allowTraversingTree && point.graphic) {
        point.drillId = options2.interactByLeaf ? series.drillToByLeaf(point) : series.drillToByGroup(point);
      }
    }
  }
  /**
   * Finds the drill id for a parent node. Returns false if point should
   * not have a click event.
   * @private
   */
  drillToByGroup(point) {
    return !point.node.isLeaf || point.node.isGroup ? point.id : false;
  }
  /**
   * Finds the drill id for a leaf node. Returns false if point should not
   * have a click event
   * @private
   */
  drillToByLeaf(point) {
    const { traverseToLeaf } = point.series.options;
    let drillId = false, nodeParent;
    if (point.node.parent !== this.rootNode && point.node.isLeaf) {
      if (traverseToLeaf) {
        drillId = point.id;
      } else {
        nodeParent = point.node;
        while (!drillId) {
          if (typeof nodeParent.parent !== "undefined") {
            nodeParent = this.nodeMap[nodeParent.parent];
          }
          if (nodeParent.parent === this.rootNode) {
            drillId = nodeParent.id;
          }
        }
      }
    }
    return drillId;
  }
  /**
   * @todo remove this function at a suitable version.
   * @private
   */
  drillToNode(id, redraw) {
    error$2(32, false, void 0, { "treemap.drillToNode": "use treemap.setRootNode" });
    this.setRootNode(id, redraw);
  }
  drillUp() {
    const series = this, node = series.nodeMap[series.rootNode];
    if (node && isString$1(node.parent)) {
      series.setRootNode(node.parent, true, { trigger: "traverseUpButton" });
    }
  }
  getExtremes() {
    const { dataMin, dataMax } = super.getExtremes(this.colorValueData);
    this.valueMin = dataMin;
    this.valueMax = dataMax;
    return super.getExtremes();
  }
  /**
   * Creates an object map from parent id to childrens index.
   *
   * @private
   * @function Highcharts.Series#getListOfParents
   *
   * @param {Highcharts.SeriesTreemapDataOptions} [data]
   *        List of points set in options.
   *
   * @param {Array<string>} [existingIds]
   *        List of all point ids.
   *
   * @return {Object}
   *         Map from parent id to children index in data.
   */
  getListOfParents(data, existingIds) {
    const arr = isArray$4(data) ? data : [], ids = isArray$4(existingIds) ? existingIds : [], listOfParents = arr.reduce(function(prev, curr, i) {
      const parent = pick$h(curr.parent, "");
      if (typeof prev[parent] === "undefined") {
        prev[parent] = [];
      }
      prev[parent].push(i);
      return prev;
    }, {
      "": []
      // Root of tree
    });
    for (const parent of Object.keys(listOfParents)) {
      const children = listOfParents[parent];
      if (parent !== "" && ids.indexOf(parent) === -1) {
        for (const child of children) {
          listOfParents[""].push(child);
        }
        delete listOfParents[parent];
      }
    }
    return listOfParents;
  }
  /**
   * Creates a tree structured object from the series points.
   * @private
   */
  getTree() {
    const series = this, allIds = this.data.map(function(d) {
      return d.id;
    });
    series.parentList = series.getListOfParents(this.data, allIds);
    series.nodeMap = {};
    series.nodeList = [];
    return series.buildTree("", -1, 0, series.parentList || {});
  }
  buildTree(id, index, level, list, parent) {
    const series = this, children = [], point = series.points[index];
    let height = 0, child;
    for (const i of list[id] || []) {
      child = series.buildTree(series.points[i].id, i, level + 1, list, id);
      height = Math.max(child.height + 1, height);
      children.push(child);
    }
    const node = new series.NodeClass().init(id, index, children, height, level, series, parent);
    for (const child2 of children) {
      child2.parentNode = node;
    }
    series.nodeMap[node.id] = node;
    series.nodeList.push(node);
    if (point) {
      point.node = node;
      node.point = point;
    }
    return node;
  }
  /**
   * Define hasData function for non-cartesian series. Returns true if the
   * series has points at all.
   * @private
   */
  hasData() {
    return !!this.dataTable.rowCount;
  }
  init(chart, options2) {
    const series = this, breadcrumbsOptions = merge$i(options2.drillUpButton, options2.breadcrumbs), setOptionsEvent = addEvent$c(series, "setOptions", (event) => {
      const options3 = event.userOptions;
      if (defined$c(options3.allowDrillToNode) && !defined$c(options3.allowTraversingTree)) {
        options3.allowTraversingTree = options3.allowDrillToNode;
        delete options3.allowDrillToNode;
      }
      if (defined$c(options3.drillUpButton) && !defined$c(options3.traverseUpButton)) {
        options3.traverseUpButton = options3.drillUpButton;
        delete options3.drillUpButton;
      }
      const dataLabels = splat$3(options3.dataLabels || {});
      options3.levels?.forEach((level) => {
        dataLabels.push.apply(dataLabels, splat$3(level.dataLabels || {}));
      });
      this.hasOutsideDataLabels = dataLabels.some((dl) => dl.headers);
    });
    super.init(chart, options2);
    delete series.opacity;
    series.eventsToUnbind.push(setOptionsEvent);
    if (series.options.allowTraversingTree) {
      series.eventsToUnbind.push(addEvent$c(series, "click", series.onClickDrillToNode));
      series.eventsToUnbind.push(addEvent$c(series, "setRootNode", function(e) {
        const chart2 = series.chart;
        if (chart2.breadcrumbs) {
          chart2.breadcrumbs.updateProperties(series.createList(e));
        }
      }));
      series.eventsToUnbind.push(addEvent$c(
        series,
        "update",
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        function(e, redraw) {
          const breadcrumbs = this.chart.breadcrumbs;
          if (breadcrumbs && e.options.breadcrumbs) {
            breadcrumbs.update(e.options.breadcrumbs);
          }
          this.hadOutsideDataLabels = this.hasOutsideDataLabels;
        }
      ));
      series.eventsToUnbind.push(addEvent$c(series, "destroy", function destroyEvents(e) {
        const chart2 = this.chart;
        if (chart2.breadcrumbs && !e.keepEventsForUpdate) {
          chart2.breadcrumbs.destroy();
          chart2.breadcrumbs = void 0;
        }
      }));
    }
    if (!chart.breadcrumbs) {
      chart.breadcrumbs = new Breadcrumbs(chart, breadcrumbsOptions);
    }
    series.eventsToUnbind.push(addEvent$c(chart.breadcrumbs, "up", function(e) {
      const drillUpsNumber = this.level - e.newLevel;
      for (let i = 0; i < drillUpsNumber; i++) {
        series.drillUp();
      }
    }));
  }
  /**
   * Add drilling on the suitable points.
   * @private
   */
  onClickDrillToNode(event) {
    const series = this, point = event.point, drillId = point?.drillId;
    if (isString$1(drillId)) {
      point.setState("");
      series.setRootNode(drillId, true, { trigger: "click" });
    }
  }
  /**
   * Get presentational attributes
   * @private
   */
  pointAttribs(point, state) {
    const series = this, mapOptionsToLevel = isObject$6(series.mapOptionsToLevel) ? series.mapOptionsToLevel : {}, level = point && mapOptionsToLevel[point.node.level] || {}, options2 = this.options, stateOptions = state && options2.states && options2.states[state] || {}, className = point?.getClassName() || "", attr2 = {
      "stroke": point && point.borderColor || level.borderColor || stateOptions.borderColor || options2.borderColor,
      "stroke-width": pick$h(point && point.borderWidth, level.borderWidth, stateOptions.borderWidth, options2.borderWidth),
      "dashstyle": point?.borderDashStyle || level.borderDashStyle || stateOptions.borderDashStyle || options2.borderDashStyle,
      "fill": point?.color || this.color
    };
    if (className.indexOf("highcharts-above-level") !== -1) {
      attr2.fill = "none";
      attr2["stroke-width"] = 0;
    } else if (className.indexOf("highcharts-internal-node-interactive") !== -1) {
      attr2["fill-opacity"] = stateOptions.opacity ?? options2.opacity ?? 1;
      attr2.cursor = "pointer";
    } else if (className.indexOf("highcharts-internal-node") !== -1) {
      attr2.fill = "none";
    } else if (state && stateOptions.brightness) {
      attr2.fill = color$2(attr2.fill).brighten(stateOptions.brightness).get();
    }
    return attr2;
  }
  /**
   * Set the node's color recursively, from the parent down.
   * @private
   */
  setColorRecursive(node, parentColor, colorIndex, index, siblings) {
    const series = this, chart = series?.chart, colors = chart?.options?.colors;
    if (node) {
      const colorInfo = getColor(node, {
        colors,
        index,
        mapOptionsToLevel: series.mapOptionsToLevel,
        parentColor,
        parentColorIndex: colorIndex,
        series,
        siblings
      }), point = series.points[node.i];
      if (point) {
        point.color = colorInfo.color;
        point.colorIndex = colorInfo.colorIndex;
      }
      let i = -1;
      for (const child of node.children || []) {
        series.setColorRecursive(child, colorInfo.color, colorInfo.colorIndex, ++i, node.children.length);
      }
    }
  }
  setPointValues() {
    const series = this;
    const { points, xAxis: xAxis2, yAxis: yAxis2 } = series;
    const styledMode = series.chart.styledMode;
    const getStrokeWidth = (point) => styledMode ? 0 : series.pointAttribs(point)["stroke-width"] || 0;
    for (const point of points) {
      const { pointValues: values, visible } = point.node;
      if (values && visible) {
        const { height, width, x, y } = values, strokeWidth = getStrokeWidth(point), xValue = xAxis2.toPixels(x, true), x2Value = xAxis2.toPixels(x + width, true), yValue = yAxis2.toPixels(y, true), y2Value = yAxis2.toPixels(y + height, true), x1 = xValue === 0 ? strokeWidth / 2 : crisp$3(xAxis2.toPixels(x, true), strokeWidth, true), x2 = x2Value === xAxis2.len ? xAxis2.len - strokeWidth / 2 : crisp$3(xAxis2.toPixels(x + width, true), strokeWidth, true), y1 = yValue === yAxis2.len ? yAxis2.len - strokeWidth / 2 : crisp$3(yAxis2.toPixels(y, true), strokeWidth, true), y2 = y2Value === 0 ? strokeWidth / 2 : crisp$3(yAxis2.toPixels(y + height, true), strokeWidth, true);
        const shapeArgs = {
          x: Math.min(x1, x2),
          y: Math.min(y1, y2),
          width: Math.abs(x2 - x1),
          height: Math.abs(y2 - y1)
        };
        point.plotX = shapeArgs.x + shapeArgs.width / 2;
        point.plotY = shapeArgs.y + shapeArgs.height / 2;
        point.shapeArgs = shapeArgs;
      } else {
        delete point.plotX;
        delete point.plotY;
      }
    }
  }
  /**
   * Sets a new root node for the series.
   *
   * @private
   * @function Highcharts.Series#setRootNode
   *
   * @param {string} id
   * The id of the new root node.
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart or not.
   *
   * @param {Object} [eventArguments]
   * Arguments to be accessed in event handler.
   *
   * @param {string} [eventArguments.newRootId]
   * Id of the new root.
   *
   * @param {string} [eventArguments.previousRootId]
   * Id of the previous root.
   *
   * @param {boolean} [eventArguments.redraw]
   * Whether to redraw the chart after.
   *
   * @param {Object} [eventArguments.series]
   * The series to update the root of.
   *
   * @param {string} [eventArguments.trigger]
   * The action which triggered the event. Undefined if the setRootNode is
   * called directly.
   *
   * @emits Highcharts.Series#event:setRootNode
   */
  setRootNode(id, redraw, eventArguments) {
    const series = this, eventArgs = extend$e({
      newRootId: id,
      previousRootId: series.rootNode,
      redraw: pick$h(redraw, true),
      series
    }, eventArguments);
    const defaultFn = function(args) {
      const series2 = args.series;
      series2.idPreviousRoot = args.previousRootId;
      series2.rootNode = args.newRootId;
      series2.isDirty = true;
      if (args.redraw) {
        series2.chart.redraw();
      }
    };
    fireEvent$1(series, "setRootNode", eventArgs, defaultFn);
  }
  /**
   * Workaround for `inactive` state. Since `series.opacity` option is
   * already reserved, don't use that state at all by disabling
   * `inactiveOtherPoints` and not inheriting states by points.
   * @private
   */
  setState(state) {
    this.options.inactiveOtherPoints = true;
    super.setState(state, false);
    this.options.inactiveOtherPoints = false;
  }
  setTreeValues(tree) {
    const series = this, options2 = series.options, idRoot = series.rootNode, mapIdToNode = series.nodeMap, nodeRoot = mapIdToNode[idRoot], levelIsConstant = typeof options2.levelIsConstant === "boolean" ? options2.levelIsConstant : true, children = [], point = series.points[tree.i];
    let childrenTotal = 0;
    for (let child of tree.children) {
      child = series.setTreeValues(child);
      children.push(child);
      if (!child.ignore) {
        childrenTotal += child.val;
      }
    }
    stableSort$1(children, (a, b) => (a.sortIndex || 0) - (b.sortIndex || 0));
    let val = pick$h(point?.simulatedValue, point?.options.value, childrenTotal);
    if (point) {
      point.value = val;
    }
    if (point?.isGroup && options2.cluster?.reductionFactor) {
      val /= options2.cluster.reductionFactor;
    }
    if (tree.parentNode?.point?.isGroup && series.rootNode !== tree.parent) {
      tree.visible = false;
    }
    extend$e(tree, {
      children,
      childrenTotal,
      // Ignore this node if point is not visible
      ignore: !(pick$h(point?.visible, true) && val > 0),
      isLeaf: tree.visible && !childrenTotal,
      isGroup: point?.isGroup,
      levelDynamic: tree.level - (levelIsConstant ? 0 : nodeRoot.level),
      name: pick$h(point?.name, ""),
      sortIndex: pick$h(point?.sortIndex, -val),
      val
    });
    return tree;
  }
  sliceAndDice(parent, children) {
    return this.algorithmFill(true, parent, children);
  }
  squarified(parent, children) {
    return this.algorithmLowAspectRatio(true, parent, children);
  }
  strip(parent, children) {
    return this.algorithmLowAspectRatio(false, parent, children);
  }
  stripes(parent, children) {
    return this.algorithmFill(false, parent, children);
  }
  translate(tree) {
    const series = this, options2 = series.options, applyGrouping2 = !tree;
    let rootId = updateRootId(series), rootNode, pointValues, seriesArea, val;
    if (!tree && !rootId.startsWith("highcharts-grouped-treemap-points-")) {
      (this.points || []).forEach((point) => {
        if (point.isGroup) {
          point.destroy();
        }
      });
      super.translate();
      tree = series.getTree();
    }
    series.tree = tree = tree || series.tree;
    rootNode = series.nodeMap[rootId];
    if (rootId !== "" && !rootNode) {
      series.setRootNode("", false);
      rootId = series.rootNode;
      rootNode = series.nodeMap[rootId];
    }
    if (!rootNode.point?.isGroup) {
      series.mapOptionsToLevel = getLevelOptions$2({
        from: rootNode.level + 1,
        levels: options2.levels,
        to: tree.height,
        defaults: {
          levelIsConstant: series.options.levelIsConstant,
          colorByPoint: options2.colorByPoint
        }
      });
    }
    TreemapUtilities$1.recursive(series.nodeMap[series.rootNode], (node) => {
      const p = node.parent;
      let next = false;
      node.visible = true;
      if (p || p === "") {
        next = series.nodeMap[p];
      }
      return next;
    });
    TreemapUtilities$1.recursive(series.nodeMap[series.rootNode].children, (children) => {
      let next = false;
      for (const child of children) {
        child.visible = true;
        if (child.children.length) {
          next = (next || []).concat(child.children);
        }
      }
      return next;
    });
    series.setTreeValues(tree);
    series.axisRatio = series.xAxis.len / series.yAxis.len;
    series.nodeMap[""].pointValues = pointValues = {
      x: 0,
      y: 0,
      width: axisMax,
      height: axisMax
    };
    series.nodeMap[""].values = seriesArea = merge$i(pointValues, {
      width: pointValues.width * series.axisRatio,
      direction: options2.layoutStartingDirection === "vertical" ? 0 : 1,
      val: tree.val
    });
    if (this.hasOutsideDataLabels || this.hadOutsideDataLabels) {
      this.drawDataLabels();
    }
    series.calculateChildrenAreas(tree, seriesArea);
    if (!series.colorAxis && !options2.colorByPoint) {
      series.setColorRecursive(series.tree);
    }
    if (options2.allowTraversingTree && rootNode.pointValues) {
      val = rootNode.pointValues;
      series.xAxis.setExtremes(val.x, val.x + val.width, false);
      series.yAxis.setExtremes(val.y, val.y + val.height, false);
      series.xAxis.setScale();
      series.yAxis.setScale();
    }
    series.setPointValues();
    if (applyGrouping2) {
      series.applyTreeGrouping();
    }
  }
}
TreemapSeries.defaultOptions = merge$i(ScatterSeries.defaultOptions, TreemapSeriesDefaults);
extend$e(TreemapSeries.prototype, {
  buildKDTree: noop$1,
  colorAttribs: ColorMapComposition$1.seriesMembers.colorAttribs,
  colorKey: "colorValue",
  // Point color option key
  directTouch: true,
  getExtremesFromAll: true,
  getSymbol: noop$1,
  optionalAxis: "colorAxis",
  parallelArrays: ["x", "y", "value", "colorValue"],
  pointArrayMap: ["value", "colorValue"],
  pointClass: TreemapPoint,
  NodeClass: TreemapNode,
  trackerGroups: ["group", "dataLabelsGroup"],
  utils: TreemapUtilities$1
});
ColorMapComposition$1.compose(TreemapSeries);
SeriesRegistry$1.registerSeriesType("treemap", TreemapSeries);
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/treemap
 * @requires highcharts
 *
 * (c) 2014-2025 Highsoft AS
 * Authors: Jon Arild Nygard / Oystein Moseng
 *
 * License: www.highcharts.com/license
 */
const G$6 = Highcharts;
G$6.Breadcrumbs = G$6.Breadcrumbs || Breadcrumbs;
G$6.Breadcrumbs.compose(G$6.Chart, G$6.defaultOptions);
TreemapSeries.compose(G$6.Series);
const lang = {
  /**
   * The text to display when the chart contains no data.
   *
   * @see [noData](#noData)
   *
   * @sample highcharts/no-data-to-display/no-data-line
   *         No-data text
   *
   * @since    3.0.8
   * @product  highcharts highstock
   * @requires modules/no-data-to-display
   */
  noData: "No data to display"
};
const noData = {
  /**
   * An object of additional SVG attributes for the no-data label.
   *
   * @type      {Highcharts.SVGAttributes}
   * @since     3.0.8
   * @product   highcharts highstock gantt
   * @apioption noData.attr
   */
  attr: {
    zIndex: 1
  },
  /**
   * Whether to insert the label as HTML, or as pseudo-HTML rendered with
   * SVG.
   *
   * @type      {boolean}
   * @default   false
   * @since     4.1.10
   * @product   highcharts highstock gantt
   * @apioption noData.useHTML
   */
  /**
   * The position of the no-data label, relative to the plot area.
   *
   * @type  {Highcharts.AlignObject}
   * @since 3.0.8
   */
  position: {
    /**
     * Horizontal offset of the label, in pixels.
     */
    x: 0,
    /**
     * Vertical offset of the label, in pixels.
     */
    y: 0,
    /**
     * Horizontal alignment of the label.
     *
     * @type {Highcharts.AlignValue}
     */
    align: "center",
    /**
     * Vertical alignment of the label.
     *
     * @type {Highcharts.VerticalAlignValue}
     */
    verticalAlign: "middle"
  },
  /**
   * CSS styles for the no-data label.
   *
   * @sample highcharts/no-data-to-display/no-data-line
   *         Styled no-data text
   *
   * @type {Highcharts.CSSObject}
   */
  style: {
    /** @ignore */
    fontWeight: "bold",
    /** @ignore */
    fontSize: "0.8em",
    /** @ignore */
    color: "#666666"
    /* Palette.neutralColor60 */
  }
};
const NoDataDefaults = {
  lang,
  noData
};
const { addEvent: addEvent$b, extend: extend$d, merge: merge$h } = Utilities;
function chartHasData() {
  const chart = this, series = chart.series || [];
  let i = series.length;
  while (i--) {
    if (series[i].hasData() && !series[i].options.isInternal) {
      return true;
    }
  }
  return chart.loadingShown;
}
function chartHideNoData() {
  const chart = this;
  if (chart.noDataLabel) {
    chart.noDataLabel = chart.noDataLabel.destroy();
  }
}
function chartShowNoData(str) {
  const chart = this, options2 = chart.options, text = str || options2 && options2.lang.noData || "", noDataOptions = options2 && (options2.noData || {});
  if (chart.renderer) {
    if (!chart.noDataLabel) {
      chart.noDataLabel = chart.renderer.label(text, 0, 0, void 0, void 0, void 0, noDataOptions.useHTML, void 0, "no-data").add();
    }
    if (!chart.styledMode) {
      chart.noDataLabel.attr(AST.filterUserAttributes(noDataOptions.attr || {})).css(noDataOptions.style || {});
    }
    chart.noDataLabel.align(extend$d(chart.noDataLabel.getBBox(), noDataOptions.position || {}), false, "plotBox");
  }
}
function compose$7(ChartClass, highchartsDefaultOptions) {
  const chartProto = ChartClass.prototype;
  if (!chartProto.showNoData) {
    chartProto.hasData = chartHasData;
    chartProto.hideNoData = chartHideNoData;
    chartProto.showNoData = chartShowNoData;
    addEvent$b(ChartClass, "render", onChartRender$1);
    merge$h(true, highchartsDefaultOptions, NoDataDefaults);
  }
}
function onChartRender$1() {
  const chart = this;
  if (chart.hasData()) {
    chart.hideNoData();
  } else {
    chart.showNoData();
  }
}
const NoDataToDisplay = {
  compose: compose$7
};
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/no-data-to-display
 * @requires highcharts
 *
 * Plugin for displaying a message when there is no data visible in chart.
 *
 * (c) 2010-2025 Highsoft AS
 * Author: Oystein Moseng
 *
 * License: www.highcharts.com/license
 */
const G$5 = Highcharts;
NoDataToDisplay.compose(G$5.Chart, G$5.defaultOptions);
const { series: { prototype: seriesProto, prototype: { pointClass: { prototype: pointProto } } } } = SeriesRegistry$1;
const { defined: defined$b, extend: extend$c, find: find$4, merge: merge$g, pick: pick$g } = Utilities;
var NodesComposition;
(function(NodesComposition2) {
  function compose2(PointClass, SeriesClass) {
    const pointProto2 = PointClass.prototype, seriesProto2 = SeriesClass.prototype;
    pointProto2.setNodeState = setNodeState;
    pointProto2.setState = setNodeState;
    pointProto2.update = updateNode;
    seriesProto2.destroy = destroy;
    seriesProto2.setData = setData;
    return SeriesClass;
  }
  NodesComposition2.compose = compose2;
  function createNode2(id) {
    const PointClass = this.pointClass, findById = (nodes, id2) => find$4(nodes, (node2) => node2.id === id2);
    let node = findById(this.nodes, id), options2;
    if (!node) {
      options2 = this.options.nodes && findById(this.options.nodes, id);
      const newNode = new PointClass(this, extend$c({
        className: "highcharts-node",
        isNode: true,
        id,
        y: 1
        // Pass isNull test
      }, options2));
      newNode.linksTo = [];
      newNode.linksFrom = [];
      newNode.getSum = function() {
        let sumTo = 0, sumFrom = 0;
        newNode.linksTo.forEach((link) => {
          sumTo += link.weight || 0;
        });
        newNode.linksFrom.forEach((link) => {
          sumFrom += link.weight || 0;
        });
        return Math.max(sumTo, sumFrom);
      };
      newNode.offset = function(point, coll) {
        let offset2 = 0;
        for (let i = 0; i < newNode[coll].length; i++) {
          if (newNode[coll][i] === point) {
            return offset2;
          }
          offset2 += newNode[coll][i].weight;
        }
      };
      newNode.hasShape = function() {
        let outgoing = 0;
        newNode.linksTo.forEach((link) => {
          if (link.outgoing) {
            outgoing++;
          }
        });
        return !newNode.linksTo.length || outgoing !== newNode.linksTo.length;
      };
      newNode.index = this.nodes.push(newNode) - 1;
      node = newNode;
    }
    node.formatPrefix = "node";
    node.name = node.name || node.options.id || "";
    node.mass = pick$g(
      // Node:
      node.options.mass,
      node.options.marker && node.options.marker.radius,
      // Series:
      this.options.marker && this.options.marker.radius,
      // Default:
      4
    );
    return node;
  }
  NodesComposition2.createNode = createNode2;
  function destroy() {
    this.data = [].concat(this.points || [], this.nodes);
    return seriesProto.destroy.apply(this, arguments);
  }
  NodesComposition2.destroy = destroy;
  function generatePoints2() {
    const chart = this.chart, nodeLookup = {};
    seriesProto.generatePoints.call(this);
    if (!this.nodes) {
      this.nodes = [];
    }
    this.colorCounter = 0;
    this.nodes.forEach((node) => {
      node.linksFrom.length = 0;
      node.linksTo.length = 0;
      node.level = node.options.level;
    });
    this.points.forEach((point) => {
      if (defined$b(point.from)) {
        if (!nodeLookup[point.from]) {
          nodeLookup[point.from] = this.createNode(point.from);
        }
        nodeLookup[point.from].linksFrom.push(point);
        point.fromNode = nodeLookup[point.from];
        if (chart.styledMode) {
          point.colorIndex = pick$g(point.options.colorIndex, nodeLookup[point.from].colorIndex);
        } else {
          point.color = point.options.color || nodeLookup[point.from].color;
        }
      }
      if (defined$b(point.to)) {
        if (!nodeLookup[point.to]) {
          nodeLookup[point.to] = this.createNode(point.to);
        }
        nodeLookup[point.to].linksTo.push(point);
        point.toNode = nodeLookup[point.to];
      }
      point.name = point.name || point.id;
    }, this);
    this.nodeLookup = nodeLookup;
  }
  NodesComposition2.generatePoints = generatePoints2;
  function setData() {
    if (this.nodes) {
      this.nodes.forEach((node) => {
        node.destroy();
      });
      this.nodes.length = 0;
    }
    seriesProto.setData.apply(this, arguments);
  }
  function setNodeState(state) {
    const args = arguments, others = this.isNode ? this.linksTo.concat(this.linksFrom) : [this.fromNode, this.toNode];
    if (state !== "select") {
      others.forEach((linkOrNode) => {
        if (linkOrNode && linkOrNode.series) {
          pointProto.setState.apply(linkOrNode, args);
          if (!linkOrNode.isNode) {
            if (linkOrNode.fromNode.graphic) {
              pointProto.setState.apply(linkOrNode.fromNode, args);
            }
            if (linkOrNode.toNode && linkOrNode.toNode.graphic) {
              pointProto.setState.apply(linkOrNode.toNode, args);
            }
          }
        }
      });
    }
    pointProto.setState.apply(this, args);
  }
  NodesComposition2.setNodeState = setNodeState;
  function updateNode(options2, redraw, animation, runEvent) {
    const nodes = this.series.options.nodes, data = this.series.options.data, dataLength = data?.length || 0, linkConfig = data?.[this.index];
    pointProto.update.call(
      this,
      options2,
      this.isNode ? false : redraw,
      // Hold the redraw for nodes
      animation,
      runEvent
    );
    if (this.isNode) {
      const nodeIndex = (nodes || []).reduce(
        // Array.findIndex needs a polyfill
        (prevIndex, n, index) => this.id === n.id ? index : prevIndex,
        -1
      ), nodeConfig = merge$g(nodes && nodes[nodeIndex] || {}, data?.[this.index] || {});
      if (data) {
        if (linkConfig) {
          data[this.index] = linkConfig;
        } else {
          data.length = dataLength;
        }
      }
      if (nodes) {
        if (nodeIndex >= 0) {
          nodes[nodeIndex] = nodeConfig;
        } else {
          nodes.push(nodeConfig);
        }
      } else {
        this.series.options.nodes = [nodeConfig];
      }
      if (pick$g(redraw, true)) {
        this.series.chart.redraw(animation);
      }
    }
  }
  NodesComposition2.updateNode = updateNode;
})(NodesComposition || (NodesComposition = {}));
const NodesComposition$1 = NodesComposition;
const { column: ColumnSeries$3 } = SeriesRegistry$1.seriesTypes;
const { defined: defined$a } = Utilities;
class SankeyPoint extends ColumnSeries$3.prototype.pointClass {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  applyOptions(options2, x) {
    Point$3.prototype.applyOptions.call(this, options2, x);
    if (defined$a(this.options.level)) {
      this.options.column = this.column = this.options.level;
    }
    return this;
  }
  /**
   * @private
   */
  getClassName() {
    return (this.isNode ? "highcharts-node " : "highcharts-link ") + Point$3.prototype.getClassName.call(this);
  }
  /**
   * If there are incoming links, place it to the right of the
   * highest order column that links to this one.
   *
   * @private
   */
  getFromNode() {
    const node = this;
    let fromColumn = -1, fromNode;
    for (let i = 0; i < node.linksTo.length; i++) {
      const point = node.linksTo[i];
      if (point.fromNode.column > fromColumn && point.fromNode !== node) {
        fromNode = point.fromNode;
        fromColumn = fromNode.column;
      }
    }
    return { fromNode, fromColumn };
  }
  /**
   * Calculate node.column if it's not set by user
   * @private
   */
  setNodeColumn() {
    const node = this;
    if (!defined$a(node.options.column)) {
      if (node.linksTo.length === 0) {
        node.column = 0;
      } else {
        node.column = node.getFromNode().fromColumn + 1;
      }
    }
  }
  /**
   * @private
   */
  isValid() {
    return this.isNode || typeof this.weight === "number";
  }
}
const SankeySeriesDefaults = {
  borderWidth: 0,
  colorByPoint: true,
  /**
   * Higher numbers makes the links in a sankey diagram or dependency
   * wheelrender more curved. A `curveFactor` of 0 makes the lines
   * straight.
   *
   * @private
   */
  curveFactor: 0.33,
  /**
   * Options for the data labels appearing on top of the nodes and links.
   * For sankey charts, data labels are visible for the nodes by default,
   * but hidden for links. This is controlled by modifying the
   * `nodeFormat`, and the `format` that applies to links and is an empty
   * string by default.
   *
   * @declare Highcharts.SeriesSankeyDataLabelsOptionsObject
   *
   * @private
   */
  dataLabels: {
    enabled: true,
    backgroundColor: "none",
    // Enable padding
    crop: false,
    /**
     * The
     * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * specifying what to show for _nodes_ in the sankey diagram. By
     * default the `nodeFormatter` returns `{point.name}`.
     *
     * @sample highcharts/plotoptions/sankey-link-datalabels/
     *         Node and link data labels
     *
     * @type {string}
     */
    nodeFormat: void 0,
    /**
     * Callback to format data labels for _nodes_ in the sankey diagram.
     * The `nodeFormat` option takes precedence over the
     * `nodeFormatter`.
     *
     * @type  {Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction}
     * @since 6.0.2
     */
    nodeFormatter: function() {
      return this.point.name;
    },
    format: void 0,
    /**
     * @type {Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction}
     */
    formatter: function() {
      return;
    },
    inside: true
  },
  /**
   * @default   true
   * @extends   plotOptions.series.inactiveOtherPoints
   * @private
   */
  inactiveOtherPoints: true,
  /**
   * Set options on specific levels. Takes precedence over series options,
   * but not node and link options.
   *
   * @sample highcharts/demo/sunburst
   *         Sunburst chart
   *
   * @type      {Array<*>}
   * @since     7.1.0
   * @apioption plotOptions.sankey.levels
   */
  /**
   * Can set `borderColor` on all nodes which lay on the same level.
   *
   * @type      {Highcharts.ColorString}
   * @apioption plotOptions.sankey.levels.borderColor
   */
  /**
   * Can set `borderWidth` on all nodes which lay on the same level.
   *
   * @type      {number}
   * @apioption plotOptions.sankey.levels.borderWidth
   */
  /**
   * Can set `color` on all nodes which lay on the same level.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @apioption plotOptions.sankey.levels.color
   */
  /**
   * Can set `colorByPoint` on all nodes which lay on the same level.
   *
   * @type      {boolean}
   * @default   true
   * @apioption plotOptions.sankey.levels.colorByPoint
   */
  /**
   * Can set `dataLabels` on all points which lay on the same level.
   *
   * @extends   plotOptions.sankey.dataLabels
   * @apioption plotOptions.sankey.levels.dataLabels
   */
  /**
   * Decides which level takes effect from the options set in the levels
   * object.
   *
   * @type      {number}
   * @apioption plotOptions.sankey.levels.level
   */
  /**
   * Can set `linkOpacity` on all points which lay on the same level.
   *
   * @type      {number}
   * @default   0.5
   * @apioption plotOptions.sankey.levels.linkOpacity
   */
  /**
   * Can set `states` on all nodes and points which lay on the same level.
   *
   * @extends   plotOptions.sankey.states
   * @apioption plotOptions.sankey.levels.states
   */
  /**
   * Determines color mode for sankey links. Available options:
   *
   * - `from` color of the sankey link will be the same as the 'from node'
   *
   * - `gradient` color of the sankey link will be set to gradient between
   * colors of 'from node' and 'to node'
   *
   * - `to` color of the sankey link will be same as the 'to node'.
   *
   * @sample highcharts/demo/vertical-sankey
   *         Vertical sankey diagram with gradients
   * @sample highcharts/series-sankey/link-color-mode
   *         Sankey diagram with gradients and explanation
   *
   * @type      {('from'|'gradient'|'to')}
   * @since     11.2.0
   */
  linkColorMode: "from",
  /**
   * Opacity for the links between nodes in the sankey diagram.
   *
   * @private
   */
  linkOpacity: 0.5,
  /**
   * Opacity for the nodes in the sankey diagram.
   *
   * @private
   */
  opacity: 1,
  /**
   * The minimal width for a line of a sankey. By default,
   * 0 values are not shown.
   *
   * @sample highcharts/plotoptions/sankey-minlinkwidth
   *         Sankey diagram with minimal link height
   *
   * @type      {number}
   * @since     7.1.3
   * @default   0
   * @apioption plotOptions.sankey.minLinkWidth
   *
   * @private
   */
  minLinkWidth: 0,
  /**
   * Determines which side of the chart the nodes are to be aligned to. When
   * the chart is inverted, `top` aligns to the left and `bottom` to the
   * right.
   *
   * @sample highcharts/plotoptions/sankey-nodealignment
   *         Node alignment demonstrated
   *
   * @type      {'top'|'center'|'bottom'}
   * @apioption plotOptions.sankey.nodeAlignment
   */
  nodeAlignment: "center",
  /**
   * The pixel width of each node in a sankey diagram or dependency wheel, or
   * the height in case the chart is inverted.
   *
   * Can be a number or a percentage string.
   *
   * Sankey series also support setting it to `auto`. With this setting, the
   * nodes are sized to fill up the plot area in the longitudinal direction,
   * regardless of the number of levels.
   *
   * @see    [sankey.nodeDistance](#nodeDistance)
   * @sample highcharts/series-sankey/node-distance
   *         Sankey with auto node width combined with node distance
   * @sample highcharts/series-organization/node-distance
   *         Organization chart with node distance of 50%
   *
   * @type {number|string}
   */
  nodeWidth: 20,
  /**
   * The padding between nodes in a sankey diagram or dependency wheel, in
   * pixels. For sankey charts, this applies to the nodes of the same column,
   * so vertical distance by default, or horizontal distance in an inverted
   * (vertical) sankey.
   *
   * If the number of nodes is so great that it is impossible to lay them out
   * within the plot area with the given `nodePadding`, they will be rendered
   * with a smaller padding as a strategy to avoid overflow.
   */
  nodePadding: 10,
  /**
   * The distance between nodes in a sankey diagram in the longitudinal
   * direction. The longitudinal direction means the direction that the chart
   * flows - in a horizontal chart the distance is horizontal, in an inverted
   * chart (vertical), the distance is vertical.
   *
   * If a number is given, it denotes pixels. If a percentage string is given,
   * the distance is a percentage of the rendered node width. A `nodeDistance`
   * of `100%` will render equal widths for the nodes and the gaps between
   * them.
   *
   * This option applies only when the `nodeWidth` option is `auto`, making
   * the node width respond to the number of columns.
   *
   * @since 11.4.0
   * @sample highcharts/series-sankey/node-distance
   *         Sankey with dnode distance of 100% means equal to node width
   * @sample highcharts/series-organization/node-distance
   *         Organization chart with node distance of 50%
   * @type   {number|string}
   */
  nodeDistance: 30,
  showInLegend: false,
  states: {
    hover: {
      /**
       * Opacity for the links between nodes in the sankey diagram in
       * hover mode.
       */
      linkOpacity: 1,
      /**
       * Opacity for the nodes in the sankey diagram in hover mode.
       */
      opacity: 1
    },
    /**
     * The opposite state of a hover for a single point node/link.
     *
     * @declare Highcharts.SeriesStatesInactiveOptionsObject
     */
    inactive: {
      /**
       * Opacity for the links between nodes in the sankey diagram in
       * inactive mode.
       */
      linkOpacity: 0.1,
      /**
       * Opacity of the nodes in the sankey diagram in inactive mode.
       */
      opacity: 0.1,
      /**
       * Animation when not hovering over the marker.
       *
       * @type      {boolean|Partial<Highcharts.AnimationOptionsObject>}
       * @apioption plotOptions.series.states.inactive.animation
       */
      animation: {
        /** @internal */
        duration: 50
      }
    }
  },
  tooltip: {
    /**
     * A callback for defining the format for _nodes_ in the chart's
     * tooltip, as opposed to links.
     *
     * @type      {Highcharts.FormatterCallbackFunction<Highcharts.SankeyNodeObject>}
     * @since     6.0.2
     * @apioption plotOptions.sankey.tooltip.nodeFormatter
     */
    /**
     * Whether the tooltip should follow the pointer or stay fixed on
     * the item.
     */
    followPointer: true,
    headerFormat: '<span style="font-size: 0.8em">{series.name}</span><br/>',
    pointFormat: "{point.fromNode.name} → {point.toNode.name}: <b>{point.weight}</b><br/>",
    /**
     * The
     * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
     * specifying what to show for _nodes_ in tooltip of a diagram
     * series, as opposed to links.
     */
    nodeFormat: "{point.name}: <b>{point.sum}</b><br/>"
  }
};
const { defined: defined$9, getAlignFactor, relativeLength: relativeLength$3 } = Utilities;
var SankeyColumnComposition;
(function(SankeyColumnComposition2) {
  function compose2(points, series) {
    const sankeyColumnArray = points;
    sankeyColumnArray.sankeyColumn = new SankeyColumnAdditions(sankeyColumnArray, series);
    return sankeyColumnArray;
  }
  SankeyColumnComposition2.compose = compose2;
  class SankeyColumnAdditions {
    /* *
     *
     *  Constructor
     *
     * */
    constructor(points, series) {
      this.points = points;
      this.series = series;
    }
    /* *
     *
     *  Functions
     *
     * */
    /**
     * Calculate translation factor used in column and nodes distribution
     * @private
     * @function Highcharts.SankeyColumn#getTranslationFactor
     *
     * @param {SankeySeries} series
     * The Series
     * @return {number} TranslationFactor
     * Translation Factor
     */
    getTranslationFactor(series) {
      const column2 = this.points, nodes = column2.slice(), chart = series.chart, minLinkWidth = series.options.minLinkWidth || 0;
      let skipPoint, factor = 0, i, remainingHeight = (chart.plotSizeY || 0) - (series.options.borderWidth || 0) - (column2.length - 1) * series.nodePadding;
      while (column2.length) {
        factor = remainingHeight / column2.sankeyColumn.sum();
        skipPoint = false;
        i = column2.length;
        while (i--) {
          if (column2[i].getSum() * factor < minLinkWidth) {
            column2.splice(i, 1);
            remainingHeight = Math.max(0, remainingHeight - minLinkWidth);
            skipPoint = true;
          }
        }
        if (!skipPoint) {
          break;
        }
      }
      column2.length = 0;
      for (const node of nodes) {
        column2.push(node);
      }
      return factor;
    }
    /**
     * Get the top position of the column in pixels
     * @private
     * @function Highcharts.SankeyColumn#top
     *
     * @param {number} factor
     * The Translation Factor
     * @return {number} top
     * The top position of the column
     */
    top(factor) {
      const series = this.series, nodePadding = series.nodePadding, height = this.points.reduce((height2, node) => {
        if (height2 > 0) {
          height2 += nodePadding;
        }
        const nodeHeight = Math.max(node.getSum() * factor, series.options.minLinkWidth || 0);
        height2 += nodeHeight;
        return height2;
      }, 0);
      return getAlignFactor(series.options.nodeAlignment || "center") * ((series.chart.plotSizeY || 0) - height);
    }
    /**
     * Get the left position of the column in pixels
     * @private
     * @function Highcharts.SankeyColumn#top
     *
     * @param {number} factor
     * The Translation Factor
     * @return {number} left
     * The left position of the column
     */
    left(factor) {
      const series = this.series, chart = series.chart, equalNodes = series.options.equalNodes, maxNodesLength = chart.inverted ? chart.plotHeight : chart.plotWidth, nodePadding = series.nodePadding, width = this.points.reduce((width2, node) => {
        if (width2 > 0) {
          width2 += nodePadding;
        }
        const nodeWidth = equalNodes ? maxNodesLength / node.series.nodes.length - nodePadding : Math.max(node.getSum() * factor, series.options.minLinkWidth || 0);
        width2 += nodeWidth;
        return width2;
      }, 0);
      return ((chart.plotSizeX || 0) - Math.round(width)) / 2;
    }
    /**
     * Calculate sum of all nodes inside specific column
     * @private
     * @function Highcharts.SankeyColumn#sum
     *
     * @param {ArrayComposition} this
     * Sankey Column Array
     *
     * @return {number} sum
     * Sum of all nodes inside column
     */
    sum() {
      return this.points.reduce((sum2, node) => sum2 + node.getSum(), 0);
    }
    /**
     * Get the offset in pixels of a node inside the column
     * @private
     * @function Highcharts.SankeyColumn#offset
     *
     * @param {SankeyPoint} node
     * Sankey node
     * @param {number} factor
     * Translation Factor
     * @return {number} offset
     * Offset of a node inside column
     */
    offset(node, factor) {
      const column2 = this.points, series = this.series, nodePadding = series.nodePadding;
      let offset2 = 0, totalNodeOffset;
      if (series.is("organization") && node.hangsFrom) {
        return {
          absoluteTop: node.hangsFrom.nodeY
        };
      }
      for (let i = 0; i < column2.length; i++) {
        const sum2 = column2[i].getSum();
        const height = Math.max(sum2 * factor, series.options.minLinkWidth || 0);
        const directionOffset = node.options[series.chart.inverted ? "offsetHorizontal" : "offsetVertical"], optionOffset = node.options.offset || 0;
        if (sum2) {
          totalNodeOffset = height + nodePadding;
        } else {
          totalNodeOffset = 0;
        }
        if (column2[i] === node) {
          return {
            relativeTop: offset2 + (defined$9(directionOffset) ? (
              // `directionOffset` is a percent of the node
              // height
              relativeLength$3(directionOffset, height)
            ) : relativeLength$3(optionOffset, totalNodeOffset))
          };
        }
        offset2 += totalNodeOffset;
      }
    }
  }
  SankeyColumnComposition2.SankeyColumnAdditions = SankeyColumnAdditions;
})(SankeyColumnComposition || (SankeyColumnComposition = {}));
const SankeyColumnComposition$1 = SankeyColumnComposition;
const { column: ColumnSeries$2, line: LineSeries$1 } = SeriesRegistry$1.seriesTypes;
const { parse: color$1 } = Color;
const { getLevelOptions: getLevelOptions$1, getNodeWidth } = TreeUtilities;
const { clamp: clamp$3, crisp: crisp$2, extend: extend$b, isObject: isObject$5, merge: merge$f, pick: pick$f, relativeLength: relativeLength$2, stableSort } = Utilities;
TextPath.compose(SVGElement$1);
let SankeySeries$1 = class SankeySeries2 extends ColumnSeries$2 {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static getDLOptions(params2) {
    const optionsPoint = isObject$5(params2.optionsPoint) ? params2.optionsPoint.dataLabels : {}, optionsLevel = isObject$5(params2.level) ? params2.level.dataLabels : {}, options2 = merge$f({
      style: {}
    }, optionsLevel, optionsPoint);
    return options2;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Create node columns by analyzing the nodes and the relations between
   * incoming and outgoing links.
   * @private
   */
  createNodeColumns() {
    const columns = [];
    for (const node of this.nodes) {
      node.setNodeColumn();
      if (!columns[node.column]) {
        columns[node.column] = SankeyColumnComposition$1.compose([], this);
      }
      columns[node.column].push(node);
    }
    for (let i = 0; i < columns.length; i++) {
      if (typeof columns[i] === "undefined") {
        columns[i] = SankeyColumnComposition$1.compose([], this);
      }
    }
    return columns;
  }
  /**
   * Order the nodes, starting with the root node(s). (#9818)
   * @private
   */
  order(node, level) {
    const series = this;
    if (typeof node.level === "undefined") {
      node.level = level;
      for (const link of node.linksFrom) {
        if (link.toNode) {
          series.order(link.toNode, level + 1);
        }
      }
    }
  }
  /**
   * Extend generatePoints by adding the nodes, which are Point objects
   * but pushed to the this.nodes array.
   * @private
   */
  generatePoints() {
    NodesComposition$1.generatePoints.apply(this, arguments);
    if (this.orderNodes) {
      for (const node of this.nodes) {
        if (node.linksTo.length === 0) {
          this.order(node, 0);
        }
      }
      stableSort(this.nodes, (a, b) => a.level - b.level);
    }
  }
  /**
   * Overridable function to get node padding, overridden in dependency
   * wheel series type.
   * @private
   */
  getNodePadding() {
    let nodePadding = this.options.nodePadding || 0;
    if (this.nodeColumns) {
      const maxLength = this.nodeColumns.reduce((acc, col) => Math.max(acc, col.length), 0);
      if (maxLength * nodePadding > this.chart.plotSizeY) {
        nodePadding = this.chart.plotSizeY / maxLength;
      }
    }
    return nodePadding;
  }
  /**
   * Define hasData function for non-cartesian series.
   * @private
   * @return {boolean}
   *         Returns true if the series has points at all.
   */
  hasData() {
    return !!this.dataTable.rowCount;
  }
  /**
   * Return the presentational attributes.
   * @private
   */
  pointAttribs(point, state) {
    if (!point) {
      return {};
    }
    const series = this, level = point.isNode ? point.level : point.fromNode.level, levelOptions = series.mapOptionsToLevel[level || 0] || {}, options2 = point.options, stateOptions = levelOptions.states && levelOptions.states[state || ""] || {}, values = [
      "colorByPoint",
      "borderColor",
      "borderWidth",
      "linkOpacity",
      "opacity"
    ].reduce((obj, key2) => {
      obj[key2] = pick$f(stateOptions[key2], options2[key2], levelOptions[key2], series.options[key2]);
      return obj;
    }, {}), color2 = pick$f(stateOptions.color, options2.color, values.colorByPoint ? point.color : levelOptions.color);
    if (point.isNode) {
      return {
        fill: color2,
        stroke: values.borderColor,
        "stroke-width": values.borderWidth,
        opacity: values.opacity
      };
    }
    return {
      fill: color2,
      "fill-opacity": values.linkOpacity
    };
  }
  drawTracker() {
    ColumnSeries$2.prototype.drawTracker.call(this, this.points);
    ColumnSeries$2.prototype.drawTracker.call(this, this.nodes);
  }
  drawPoints() {
    ColumnSeries$2.prototype.drawPoints.call(this, this.points);
    ColumnSeries$2.prototype.drawPoints.call(this, this.nodes);
  }
  drawDataLabels() {
    ColumnSeries$2.prototype.drawDataLabels.call(this, this.points);
    ColumnSeries$2.prototype.drawDataLabels.call(this, this.nodes);
  }
  /**
   * Run pre-translation by generating the nodeColumns.
   * @private
   */
  translate() {
    this.generatePoints();
    this.nodeColumns = this.createNodeColumns();
    const series = this, chart = this.chart, options2 = this.options, nodeColumns = this.nodeColumns, columnCount = nodeColumns.length;
    this.nodeWidth = getNodeWidth(this, columnCount);
    this.nodePadding = this.getNodePadding();
    this.translationFactor = nodeColumns.reduce((translationFactor, column2) => Math.min(translationFactor, column2.sankeyColumn.getTranslationFactor(series)), Infinity);
    this.colDistance = (chart.plotSizeX - this.nodeWidth - options2.borderWidth) / Math.max(1, nodeColumns.length - 1);
    series.mapOptionsToLevel = getLevelOptions$1({
      // NOTE: if support for allowTraversingTree is added, then from
      // should be the level of the root node.
      from: 1,
      levels: options2.levels,
      to: nodeColumns.length - 1,
      // Height of the tree
      defaults: {
        borderColor: options2.borderColor,
        borderRadius: options2.borderRadius,
        // Organization series
        borderWidth: options2.borderWidth,
        color: series.color,
        colorByPoint: options2.colorByPoint,
        // NOTE: if support for allowTraversingTree is added, then
        // levelIsConstant should be optional.
        levelIsConstant: true,
        linkColor: options2.linkColor,
        // Organization series
        linkLineWidth: options2.linkLineWidth,
        // Organization series
        linkOpacity: options2.linkOpacity,
        states: options2.states
      }
    });
    for (const column2 of nodeColumns) {
      for (const node of column2) {
        series.translateNode(node, column2);
      }
    }
    for (const node of this.nodes) {
      for (const linkPoint of node.linksFrom) {
        if ((linkPoint.weight || linkPoint.isNull) && linkPoint.to) {
          series.translateLink(linkPoint);
          linkPoint.allowShadow = false;
        }
      }
    }
  }
  /**
   * Run translation operations for one link.
   * @private
   */
  translateLink(point) {
    const getY = (node, fromOrTo) => {
      const linkTop = node.offset(point, fromOrTo) * translationFactor;
      const y = Math.min(
        node.nodeY + linkTop,
        // Prevent links from spilling below the node (#12014)
        node.nodeY + (node.shapeArgs && node.shapeArgs.height || 0) - linkHeight
      );
      return y;
    };
    const fromNode = point.fromNode, toNode = point.toNode, chart = this.chart, { inverted } = chart, translationFactor = this.translationFactor, options2 = this.options, linkColorMode = pick$f(point.linkColorMode, options2.linkColorMode), curvy = (chart.inverted ? -this.colDistance : this.colDistance) * options2.curveFactor, nodeLeft = fromNode.nodeX, right = toNode.nodeX, outgoing = point.outgoing;
    let linkHeight = Math.max(point.weight * translationFactor, this.options.minLinkWidth), fromY = getY(fromNode, "linksFrom"), toY = getY(toNode, "linksTo"), nodeW = this.nodeWidth, straight2 = right > nodeLeft + nodeW;
    if (chart.inverted) {
      fromY = chart.plotSizeY - fromY;
      toY = (chart.plotSizeY || 0) - toY;
      nodeW = -nodeW;
      linkHeight = -linkHeight;
      straight2 = nodeLeft > right;
    }
    point.shapeType = "path";
    point.linkBase = [
      fromY,
      fromY + linkHeight,
      toY,
      toY + linkHeight
    ];
    if (straight2 && typeof toY === "number") {
      point.shapeArgs = {
        d: [
          ["M", nodeLeft + nodeW, fromY],
          [
            "C",
            nodeLeft + nodeW + curvy,
            fromY,
            right - curvy,
            toY,
            right,
            toY
          ],
          ["L", right + (outgoing ? nodeW : 0), toY + linkHeight / 2],
          ["L", right, toY + linkHeight],
          [
            "C",
            right - curvy,
            toY + linkHeight,
            nodeLeft + nodeW + curvy,
            fromY + linkHeight,
            nodeLeft + nodeW,
            fromY + linkHeight
          ],
          ["Z"]
        ]
      };
    } else if (typeof toY === "number") {
      const bend = 20, vDist = chart.plotHeight - fromY - linkHeight, x1 = right - bend - linkHeight, x2 = right - bend, x3 = right, x4 = nodeLeft + nodeW, x5 = x4 + bend, x6 = x5 + linkHeight, fy1 = fromY, fy2 = fromY + linkHeight, fy3 = fy2 + bend, y4 = fy3 + vDist, y5 = y4 + bend, y6 = y5 + linkHeight, ty1 = toY, ty2 = ty1 + linkHeight, ty3 = ty2 + bend, cfy1 = fy2 - linkHeight * 0.7, cy2 = y5 + linkHeight * 0.7, cty1 = ty2 - linkHeight * 0.7, cx1 = x3 - linkHeight * 0.7, cx2 = x4 + linkHeight * 0.7;
      point.shapeArgs = {
        d: [
          ["M", x4, fy1],
          ["C", cx2, fy1, x6, cfy1, x6, fy3],
          ["L", x6, y4],
          ["C", x6, cy2, cx2, y6, x4, y6],
          ["L", x3, y6],
          ["C", cx1, y6, x1, cy2, x1, y4],
          ["L", x1, ty3],
          ["C", x1, cty1, cx1, ty1, x3, ty1],
          ["L", x3, ty2],
          ["C", x2, ty2, x2, ty2, x2, ty3],
          ["L", x2, y4],
          ["C", x2, y5, x2, y5, x3, y5],
          ["L", x4, y5],
          ["C", x5, y5, x5, y5, x5, y4],
          ["L", x5, fy3],
          ["C", x5, fy2, x5, fy2, x4, fy2],
          ["Z"]
        ]
      };
    }
    point.dlBox = {
      x: nodeLeft + (right - nodeLeft + nodeW) / 2,
      y: fromY + (toY - fromY) / 2,
      height: linkHeight,
      width: 0
    };
    point.tooltipPos = chart.inverted ? [
      chart.plotSizeY - point.dlBox.y - linkHeight / 2,
      chart.plotSizeX - point.dlBox.x
    ] : [
      point.dlBox.x,
      point.dlBox.y + linkHeight / 2
    ];
    point.y = point.plotY = 1;
    point.x = point.plotX = 1;
    if (!point.options.color) {
      if (linkColorMode === "from") {
        point.color = fromNode.color;
      } else if (linkColorMode === "to") {
        point.color = toNode.color;
      } else if (linkColorMode === "gradient") {
        const fromColor = color$1(fromNode.color).get(), toColor = color$1(toNode.color).get();
        point.color = {
          linearGradient: {
            x1: 1,
            x2: 0,
            y1: 0,
            y2: 0
          },
          stops: [
            [0, inverted ? fromColor : toColor],
            [1, inverted ? toColor : fromColor]
          ]
        };
      }
    }
  }
  /**
   * Run translation operations for one node.
   * @private
   */
  translateNode(node, column2) {
    const translationFactor = this.translationFactor, chart = this.chart, options2 = this.options, { borderRadius, borderWidth = 0 } = options2, sum2 = node.getSum(), nodeHeight = Math.max(Math.round(sum2 * translationFactor), this.options.minLinkWidth), nodeWidth = Math.round(this.nodeWidth), nodeOffset = column2.sankeyColumn.offset(node, translationFactor), fromNodeTop = crisp$2(pick$f(nodeOffset.absoluteTop, column2.sankeyColumn.top(translationFactor) + nodeOffset.relativeTop), borderWidth), left = crisp$2(this.colDistance * node.column + borderWidth / 2, borderWidth) + relativeLength$2(node.options[chart.inverted ? "offsetVertical" : "offsetHorizontal"] || 0, nodeWidth), nodeLeft = chart.inverted ? chart.plotSizeX - left : left;
    node.sum = sum2;
    if (sum2) {
      node.shapeType = "roundedRect";
      node.nodeX = nodeLeft;
      node.nodeY = fromNodeTop;
      let x = nodeLeft, y = fromNodeTop, width = node.options.width || options2.width || nodeWidth, height = node.options.height || options2.height || nodeHeight;
      const r = clamp$3(relativeLength$2(typeof borderRadius === "object" ? borderRadius.radius : borderRadius || 0, width), 0, nodeHeight / 2);
      if (chart.inverted) {
        x = nodeLeft - nodeWidth;
        y = chart.plotSizeY - fromNodeTop - nodeHeight;
        width = node.options.height || options2.height || nodeWidth;
        height = node.options.width || options2.width || nodeHeight;
      }
      node.dlOptions = SankeySeries2.getDLOptions({
        level: this.mapOptionsToLevel[node.level],
        optionsPoint: node.options
      });
      node.plotX = 1;
      node.plotY = 1;
      node.tooltipPos = chart.inverted ? [
        chart.plotSizeY - y - height / 2,
        chart.plotSizeX - x - width / 2
      ] : [
        x + width / 2,
        y + height / 2
      ];
      node.shapeArgs = {
        x,
        y,
        width,
        height,
        r,
        display: node.hasShape() ? "" : "none"
      };
    } else {
      node.dlOptions = {
        enabled: false
      };
    }
  }
};
SankeySeries$1.defaultOptions = merge$f(ColumnSeries$2.defaultOptions, SankeySeriesDefaults);
NodesComposition$1.compose(SankeyPoint, SankeySeries$1);
extend$b(SankeySeries$1.prototype, {
  animate: LineSeries$1.prototype.animate,
  // Create a single node that holds information on incoming and outgoing
  // links.
  createNode: NodesComposition$1.createNode,
  forceDL: true,
  invertible: true,
  isCartesian: false,
  orderNodes: true,
  noSharedTooltip: true,
  pointArrayMap: ["from", "to", "weight"],
  pointClass: SankeyPoint,
  searchPoint: Highcharts.noop
});
SeriesRegistry$1.registerSeriesType("sankey", SankeySeries$1);
const { line: { prototype: { pointClass: LinePoint } }, pie: { prototype: { pointClass: PiePoint } } } = SeriesRegistry$1.seriesTypes;
const { defined: defined$8, isNumber: isNumber$c, merge: merge$e, objectEach: objectEach$1, pick: pick$e } = Utilities;
class TimelinePoint extends LinePoint {
  /* *
   *
   *  Functions
   *
   * */
  alignConnector() {
    const point = this, series = point.series, dataLabel = point.dataLabel, connector = dataLabel.connector, dlOptions = dataLabel.options || {}, connectorWidth = dlOptions.connectorWidth || 0, chart = point.series.chart, bBox = connector.getBBox(), plotPos = {
      x: bBox.x + (dataLabel.translateX || 0),
      y: bBox.y + (dataLabel.translateY || 0)
    };
    if (chart.inverted) {
      plotPos.y -= connectorWidth / 2;
    } else {
      plotPos.x += connectorWidth / 2;
    }
    const isVisible = chart.isInsidePlot(plotPos.x, plotPos.y);
    connector[isVisible ? "animate" : "attr"]({
      d: point.getConnectorPath()
    });
    connector.addClass("highcharts-color-" + point.colorIndex);
    if (!series.chart.styledMode) {
      connector.attr({
        stroke: dlOptions.connectorColor || point.color,
        "stroke-width": dlOptions.connectorWidth,
        opacity: dataLabel[defined$8(dataLabel.newOpacity) ? "newOpacity" : "opacity"]
      });
    }
  }
  drawConnector() {
    const point = this, { dataLabel, series } = point;
    if (dataLabel) {
      if (!dataLabel.connector) {
        dataLabel.connector = series.chart.renderer.path(point.getConnectorPath()).attr({
          zIndex: -1
        }).add(dataLabel);
      }
      if (point.series.chart.isInsidePlot(
        // #10507
        dataLabel.x || 0,
        dataLabel.y || 0
      )) {
        point.alignConnector();
      }
    }
  }
  getConnectorPath() {
    const { plotX = 0, plotY = 0, series, dataLabel } = this, chart = series.chart, xAxisLen = series.xAxis.len, inverted = chart.inverted, direction = inverted ? "x2" : "y2";
    if (dataLabel) {
      const targetDLPos = dataLabel.targetPosition, negativeDistance = (dataLabel.alignAttr || dataLabel)[direction[0]] < series.yAxis.len / 2;
      let coords = {
        x1: plotX,
        y1: plotY,
        x2: plotX,
        y2: isNumber$c(targetDLPos.y) ? targetDLPos.y : dataLabel.y
      };
      if (inverted) {
        coords = {
          x1: plotY,
          y1: xAxisLen - plotX,
          x2: targetDLPos.x || dataLabel.x,
          y2: xAxisLen - plotX
        };
      }
      if (negativeDistance) {
        coords[direction] += dataLabel[inverted ? "width" : "height"] || 0;
      }
      objectEach$1(coords, (_coord, i) => {
        coords[i] -= (dataLabel.alignAttr || dataLabel)[i[0]];
      });
      return chart.renderer.crispLine([
        ["M", coords.x1, coords.y1],
        ["L", coords.x2, coords.y2]
      ], dataLabel.options?.connectorWidth || 0);
    }
    return [];
  }
  constructor(series, options2) {
    super(series, options2);
    this.name ?? (this.name = // If options is null, we are dealing with a null point
    (options2 && options2.y !== null || !series.options.nullInteraction) && "Event" || "Null");
    this.y = 1;
  }
  isValid() {
    return this.options.y !== null || this.series.options.nullInteraction || true;
  }
  setState() {
    const proceed = super.setState;
    if (!this.isNull || this.series.options.nullInteraction) {
      proceed.apply(this, arguments);
    }
  }
  setVisible(visible, redraw) {
    const point = this, series = point.series;
    redraw = pick$e(redraw, series.options.ignoreHiddenPoint);
    PiePoint.prototype.setVisible.call(point, visible, false);
    series.processData();
    if (redraw) {
      series.chart.redraw();
    }
  }
  applyOptions(options2, x) {
    const isNull = this.isNull || options2 === null || options2.y === null, series = this.series;
    if (!x && !options2?.x) {
      if (isNumber$c(this.x)) {
        x = this.x;
      } else if (isNumber$c(series?.xIncrement) || NaN) {
        x = series.xIncrement || 0;
        series.autoIncrement();
      }
    }
    options2 = Point$3.prototype.optionsToObject.call(this, options2 ?? (series.options.nullInteraction && { y: 0 } || null));
    const p = super.applyOptions(options2, x);
    this.userDLOptions = merge$e(this.userDLOptions, options2.dataLabels);
    p.isNull = isNull;
    return p;
  }
}
const TimelineSeriesDefaults = {
  colorByPoint: true,
  stickyTracking: false,
  ignoreHiddenPoint: true,
  /**
   * @ignore
   */
  legendType: "point",
  /**
   * Pixel width of the graph line.
   */
  lineWidth: 4,
  tooltip: {
    headerFormat: '<span style="color:{point.color}">●</span> <span style="font-size: 0.8em"> {point.key}</span><br/>',
    pointFormat: "{point.description}"
  },
  states: {
    hover: {
      lineWidthPlus: 0
    }
  },
  /**
   * @declare Highcharts.TimelineDataLabelsOptionsObject
   */
  dataLabels: {
    enabled: true,
    allowOverlap: true,
    /**
     * Whether to position data labels alternately. For example, if
     * [distance](#plotOptions.timeline.dataLabels.distance)
     * is set equal to `100`, then data labels will be positioned
     * alternately (on both sides of the point) at a distance of 100px.
     *
     * @sample {highcharts} highcharts/series-timeline/alternate-disabled
     *         Alternate disabled
     */
    alternate: true,
    backgroundColor: "#ffffff",
    borderWidth: 1,
    borderColor: "#999999",
    borderRadius: 3,
    color: "#333333",
    /**
     * The color of the line connecting the data label to the point.
     * The default color is the same as the point's color.
     *
     * In styled mode, the connector stroke is given in the
     * `.highcharts-data-label-connector` class.
     *
     * @sample {highcharts} highcharts/series-timeline/connector-styles
     *         Custom connector width and color
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption plotOptions.timeline.dataLabels.connectorColor
     */
    /**
     * The width of the line connecting the data label to the point.
     *
     * In styled mode, the connector stroke width is given in the
     * `.highcharts-data-label-connector` class.
     *
     * @sample {highcharts} highcharts/series-timeline/connector-styles
     *         Custom connector width and color
     */
    connectorWidth: 1,
    /**
     * A pixel value defining the distance between the data label and
     * the point. Negative numbers puts the label on top of the point in a
     * non-inverted chart. Defaults to 100 for horizontal and 20 for
     * vertical timeline (`chart.inverted: true`).
     */
    distance: void 0,
    // eslint-disable-next-line jsdoc/require-description
    /**
     * @default function () {
     *   let format;
     *
     *   if (!this.series.chart.styledMode) {
     *       format = '<span style="color:' + this.point.color +
     *           '">● </span>';
     *   } else {
     *       format = '<span class="highcharts-color-' +
     *          this.point.colorIndex + '">● </span>';
     *   }
     *   format += '<span>' + (this.key || '') + '</span><br/>' +
     *       (this.point.label || '');
     *   return format;
     * }
     */
    formatter: function() {
      let format2;
      if (!this.series.chart.styledMode) {
        format2 = '<span style="color:' + this.point.color + '">● </span>';
      } else {
        format2 = '<span class="highcharts-color-' + this.point.colorIndex + '">● </span>';
      }
      format2 += '<span class="highcharts-strong">' + (this.key || "") + "</span><br/>" + (this.label || "");
      return format2;
    },
    style: {
      /** @internal */
      textOutline: "none",
      /** @internal */
      fontWeight: "normal",
      /** @internal */
      fontSize: "0.8em",
      /** @internal */
      textAlign: "left"
    },
    /**
     * Shadow options for the data label.
     *
     * @type {boolean|Highcharts.CSSObject}
     */
    shadow: false,
    /**
     * @type      {number}
     * @apioption plotOptions.timeline.dataLabels.width
     */
    verticalAlign: "middle"
  },
  marker: {
    enabledThreshold: 0,
    symbol: "square",
    radius: 6,
    lineWidth: 2,
    height: 15
  },
  showInLegend: false,
  colorKey: "x",
  legendSymbol: "rectangle"
};
const { column: ColumnSeries$1, line: LineSeries } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$a, arrayMax, arrayMin, defined: defined$7, extend: extend$a, merge: merge$d, pick: pick$d } = Utilities;
class TimelineSeries extends LineSeries {
  /* *
   *
   *  Functions
   *
   * */
  alignDataLabel(point, dataLabel, _options, _alignTo) {
    const series = this, isInverted = series.chart.inverted, visiblePoints = series.visibilityMap.filter((point2) => !!point2), visiblePointsCount = series.visiblePointsCount || 0, pointIndex = visiblePoints.indexOf(point), isFirstOrLast = !pointIndex || pointIndex === visiblePointsCount - 1, dataLabelsOptions = series.options.dataLabels, userDLOptions = point.userDLOptions || {}, multiplier = dataLabelsOptions.alternate ? isFirstOrLast ? 1.5 : 2 : 1, availableSpace = Math.floor(series.xAxis.len / visiblePointsCount), pad2 = dataLabel.padding;
    let distance, targetDLWidth, styles;
    if (point.visible) {
      distance = Math.abs(userDLOptions.x || point.options.dataLabels.x);
      if (isInverted) {
        targetDLWidth = (distance - pad2) * 2 - (point.itemHeight || 0) / 2;
        styles = {
          width: pick$d(dataLabelsOptions.style?.width, `${series.yAxis.len * 0.4}px`),
          // Apply ellipsis when data label height is exceeded.
          textOverflow: (dataLabel.width || 0) / targetDLWidth * (dataLabel.height || 0) / 2 > availableSpace * multiplier ? "ellipsis" : "none"
        };
      } else {
        styles = {
          width: (userDLOptions.width || dataLabelsOptions.width || availableSpace * multiplier - pad2 * 2) + "px"
        };
      }
      dataLabel.css(styles);
      if (!series.chart.styledMode) {
        dataLabel.shadow(dataLabelsOptions.shadow);
      }
    }
    super.alignDataLabel.apply(series, arguments);
  }
  bindAxes() {
    const series = this;
    super.bindAxes();
    if (!series.xAxis.userOptions.type) {
      series.xAxis.categories = series.xAxis.hasNames = true;
    }
  }
  distributeDL() {
    const series = this, dataLabelsOptions = series.options.dataLabels, inverted = series.chart.inverted;
    let visibilityIndex = 1;
    if (dataLabelsOptions) {
      const distance = pick$d(dataLabelsOptions.distance, inverted ? 20 : 100);
      for (const point of series.points) {
        const defaults2 = {
          [inverted ? "x" : "y"]: dataLabelsOptions.alternate && visibilityIndex % 2 ? -distance : distance
        };
        if (inverted) {
          defaults2.align = dataLabelsOptions.alternate && visibilityIndex % 2 ? "right" : "left";
        }
        point.options.dataLabels = merge$d(defaults2, point.userDLOptions);
        visibilityIndex++;
      }
    }
  }
  generatePoints() {
    super.generatePoints();
    const series = this, points = series.points, pointsLen = points.length, xData = series.getColumn("x");
    for (let i = 0, iEnd = pointsLen; i < iEnd; ++i) {
      const x = xData[i];
      points[i].applyOptions({ x }, x);
    }
  }
  getVisibilityMap() {
    const series = this, nullInteraction = series.options.nullInteraction, map = ((series.data.length ? series.data : series.options.data) || []).map((point) => point && point.visible !== false && (!point.isNull || nullInteraction) ? point : false);
    return map;
  }
  getXExtremes(xData) {
    const series = this, filteredData = xData.filter((_x, i) => series.points[i].isValid() && series.points[i].visible);
    return {
      min: arrayMin(filteredData),
      max: arrayMax(filteredData)
    };
  }
  init() {
    const series = this;
    super.init.apply(series, arguments);
    series.eventsToUnbind.push(addEvent$a(series, "afterTranslate", function() {
      let lastPlotX, closestPointRangePx = Number.MAX_VALUE;
      for (const point of series.points) {
        point.isInside = point.isInside && point.visible;
        if (point.visible && (!point.isNull || series.options.nullInteraction)) {
          if (defined$7(lastPlotX)) {
            closestPointRangePx = Math.min(closestPointRangePx, Math.abs(point.plotX - lastPlotX));
          }
          lastPlotX = point.plotX;
        }
      }
      series.closestPointRangePx = closestPointRangePx;
    }));
    series.eventsToUnbind.push(addEvent$a(series, "drawDataLabels", function() {
      series.distributeDL();
    }));
    series.eventsToUnbind.push(addEvent$a(series, "afterDrawDataLabels", function() {
      let dataLabel;
      for (const point of series.points) {
        dataLabel = point.dataLabel;
        if (dataLabel) {
          dataLabel.animate = function(params2) {
            if (this.targetPosition) {
              this.targetPosition = params2;
            }
            return this.renderer.Element.prototype.animate.apply(this, arguments);
          };
          if (!dataLabel.targetPosition) {
            dataLabel.targetPosition = {};
          }
          point.drawConnector();
        }
      }
    }));
    series.eventsToUnbind.push(addEvent$a(series.chart, "afterHideOverlappingLabel", function() {
      for (const p of series.points) {
        if (p.dataLabel && p.dataLabel.connector && p.dataLabel.oldOpacity !== p.dataLabel.newOpacity) {
          p.alignConnector();
        }
      }
    }));
  }
  markerAttribs(point, state) {
    const series = this, seriesMarkerOptions = series.options.marker, pointMarkerOptions = point.marker || {}, symbol = pointMarkerOptions.symbol || seriesMarkerOptions.symbol, width = pick$d(pointMarkerOptions.width, seriesMarkerOptions.width, series.closestPointRangePx), height = pick$d(pointMarkerOptions.height, seriesMarkerOptions.height);
    let seriesStateOptions, pointStateOptions, radius = 0;
    if (series.xAxis.dateTime) {
      return super.markerAttribs(point, state);
    }
    if (state) {
      seriesStateOptions = seriesMarkerOptions.states[state] || {};
      pointStateOptions = pointMarkerOptions.states && pointMarkerOptions.states[state] || {};
      radius = pick$d(pointStateOptions.radius, seriesStateOptions.radius, radius + (seriesStateOptions.radiusPlus || 0));
    }
    point.hasImage = symbol && symbol.indexOf("url") === 0;
    const attribs = {
      x: Math.floor(point.plotX) - width / 2 - radius / 2,
      y: point.plotY - height / 2 - radius / 2,
      width: width + radius,
      height: height + radius
    };
    return series.chart.inverted ? {
      y: attribs.x && attribs.width && series.xAxis.len - attribs.x - attribs.width,
      x: attribs.y && attribs.y,
      width: attribs.height,
      height: attribs.width
    } : attribs;
  }
}
TimelineSeries.defaultOptions = merge$d(LineSeries.defaultOptions, TimelineSeriesDefaults);
addEvent$a(TimelineSeries, "afterProcessData", function() {
  const series = this, xData = series.getColumn("x");
  let visiblePoints = 0;
  series.visibilityMap = series.getVisibilityMap();
  for (const point of series.visibilityMap) {
    if (point) {
      visiblePoints++;
    }
  }
  series.visiblePointsCount = visiblePoints;
  this.dataTable.setColumn("y", new Array(xData.length).fill(1));
});
extend$a(TimelineSeries.prototype, {
  // Use a group of trackers from TrackerMixin
  drawTracker: ColumnSeries$1.prototype.drawTracker,
  pointClass: TimelinePoint,
  trackerGroups: ["markerGroup", "dataLabelsGroup"]
});
SeriesRegistry$1.registerSeriesType("timeline", TimelineSeries);
const { sankey: { prototype: { pointClass: SankeyPointClass } } } = SeriesRegistry$1.seriesTypes;
const { defined: defined$6, find: find$3, pick: pick$c } = Utilities;
function getOffset(node) {
  let offset2 = node.linksFrom.length;
  node.linksFrom.forEach((link) => {
    if (link.id === link.toNode.linksTo[0].id) {
      offset2 += getOffset(link.toNode);
    } else {
      offset2--;
    }
  });
  return offset2;
}
class OrganizationPoint extends SankeyPointClass {
  /* *
   *
   *  Functions
   *
   * */
  constructor(series, options2, x) {
    super(series, options2, x);
    if (!this.isNode) {
      this.dataLabelOnNull = true;
      this.formatPrefix = "link";
    }
  }
  /**
   * All nodes in an org chart are equal width.
   * @private
   */
  getSum() {
    return 1;
  }
  /**
   * Set node.column for hanging layout
   * @private
   */
  setNodeColumn() {
    super.setNodeColumn();
    const node = this, fromNode = node.getFromNode().fromNode;
    if (
      // Not defined by user
      !defined$6(node.options.column) && // Has links to
      node.linksTo.length !== 0 && // And parent uses hanging layout
      fromNode && fromNode.options.layout === "hanging"
    ) {
      let i = -1, link;
      node.options.layout = pick$c(node.options.layout, "hanging");
      node.hangsFrom = fromNode;
      find$3(fromNode.linksFrom, (link2, index) => {
        const found = link2.toNode === node;
        if (found) {
          i = index;
        }
        return found;
      });
      for (let j = 0; j < fromNode.linksFrom.length; ++j) {
        link = fromNode.linksFrom[j];
        if (link.toNode.id === node.id) {
          j = fromNode.linksFrom.length;
        } else {
          i += getOffset(link.toNode);
        }
      }
      node.column = (node.column || 0) + i;
    }
  }
}
const OrganizationSeriesDefaults = {
  /**
   * The border color of the node cards.
   *
   * @type {Highcharts.ColorString}
   */
  borderColor: "#666666",
  /**
   * The border radius of the node cards.
   *
   * @private
   */
  borderRadius: 3,
  /**
   * Radius for the rounded corners of the links between nodes. This
   * option is now deprecated, and moved to
   * [link.radius](#plotOptions.organization.link.radius).
   *
   * @sample   highcharts/series-organization/link-options
   *           Square links
   *
   * @deprecated
   * @apioption series.organization.linkRadius
   */
  /**
   * Link Styling options
   * @since 10.3.0
   * @product highcharts
   */
  link: {
    /**
     * Modifier of the shape of the curved link. Works best for values
     * between 0 and 1, where 0 is a straight line, and 1 is a shape
     * close to the default one.
     *
     * @default 0.5
     * @type {number}
     * @since 10.3.0
     * @product highcharts
     * @apioption series.organization.link.offset
     */
    /**
     * The color of the links between nodes.
     *
     * @type {Highcharts.ColorString}
     */
    color: "#666666",
    /**
     * The line width of the links connecting nodes, in pixels.
     *
     * @sample   highcharts/series-organization/link-options
     *           Square links
     */
    lineWidth: 1,
    /**
     * Radius for the rounded corners of the links between nodes.
     * Works for `default` link type.
     *
     * @sample   highcharts/series-organization/link-options
     *           Square links
     */
    radius: 10,
    /**
     * Type of the link shape.
     *
     * @sample   highcharts/series-organization/different-link-types
     *           Different link types
     *
     * @declare Highcharts.OrganizationLinkTypeValue
     * @type {'default' | 'curved' | 'straight'}
     * @default 'default'
     * @product highcharts
     */
    type: "default"
  },
  borderWidth: 1,
  /**
   * @declare Highcharts.SeriesOrganizationDataLabelsOptionsObject
   *
   * @private
   */
  dataLabels: {
    /* eslint-disable valid-jsdoc */
    /**
     * A callback for defining the format for _nodes_ in the
     * organization chart. The `nodeFormat` option takes precedence
     * over `nodeFormatter`.
     *
     * In an organization chart, the `nodeFormatter` is a quite complex
     * function of the available options, striving for a good default
     * layout of cards with or without images. In organization chart,
     * the data labels come with `useHTML` set to true, meaning they
     * will be rendered as true HTML above the SVG.
     *
     * @sample highcharts/series-organization/datalabels-nodeformatter
     *         Modify the default label format output
     *
     * @type  {Highcharts.SeriesSankeyDataLabelsFormatterCallbackFunction}
     * @since 6.0.2
     */
    nodeFormatter: function() {
      const outerStyle = {
        width: "100%",
        height: "100%",
        display: "flex",
        "flex-direction": "row",
        "align-items": "center",
        "justify-content": "center"
      }, imageStyle = {
        "max-height": "100%",
        "border-radius": "50%"
      }, innerStyle = {
        width: "100%",
        padding: 0,
        "text-align": "center",
        "white-space": "normal"
      }, nameStyle = {
        margin: 0
      }, titleStyle = {
        margin: 0
      }, descriptionStyle = {
        opacity: 0.75,
        margin: "5px"
      };
      function styleAttr(style) {
        return Object.keys(style).reduce(function(str, key2) {
          return str + key2 + ":" + style[key2] + ";";
        }, 'style="') + '"';
      }
      const { description, image, title } = this.point;
      if (image) {
        imageStyle["max-width"] = "30%";
        innerStyle.width = "70%";
      }
      if (this.series.chart.renderer.forExport) {
        outerStyle.display = "block";
        innerStyle.position = "absolute";
        innerStyle.left = image ? "30%" : 0;
        innerStyle.top = 0;
      }
      let html2 = "<div " + styleAttr(outerStyle) + ">";
      if (image) {
        html2 += '<img src="' + image + '" ' + styleAttr(imageStyle) + ">";
      }
      html2 += "<div " + styleAttr(innerStyle) + ">";
      if (this.point.name) {
        html2 += "<h4 " + styleAttr(nameStyle) + ">" + this.point.name + "</h4>";
      }
      if (title) {
        html2 += "<p " + styleAttr(titleStyle) + ">" + (title || "") + "</p>";
      }
      if (description) {
        html2 += "<p " + styleAttr(descriptionStyle) + ">" + description + "</p>";
      }
      html2 += "</div></div>";
      return html2;
    },
    /* eslint-enable valid-jsdoc */
    style: {
      /** @internal */
      fontWeight: "normal",
      /** @internal */
      fontSize: "0.9em",
      /** @internal */
      textAlign: "left"
    },
    useHTML: true,
    linkTextPath: {
      attributes: {
        startOffset: "95%",
        textAnchor: "end"
      }
    }
  },
  /**
   * The indentation in pixels of hanging nodes, nodes which parent has
   * [layout](#series.organization.nodes.layout) set to `hanging`.
   *
   * @private
   */
  hangingIndent: 20,
  /**
   * Defines the indentation of a `hanging` layout parent's children.
   * Possible options:
   *
   * - `inherit` (default): Only the first child adds the indentation,
   * children of a child with indentation inherit the indentation.
   * - `cumulative`: All children of a child with indentation add its
   * own indent. The option may cause overlapping of nodes.
   * Then use `shrink` option:
   * - `shrink`: Nodes shrink by the
   * [hangingIndent](#plotOptions.organization.hangingIndent)
   * value until they reach the
   * [minNodeLength](#plotOptions.organization.minNodeLength).
   *
   * @sample highcharts/series-organization/hanging-cumulative
   *         Every indent increases the indentation
   *
   * @sample highcharts/series-organization/hanging-shrink
   *         Every indent decreases the nodes' width
   *
   * @type {Highcharts.OrganizationHangingIndentTranslationValue}
   * @since 10.0.0
   * @default inherit
   *
   * @private
   */
  hangingIndentTranslation: "inherit",
  /**
   * Whether links connecting hanging nodes should be drawn on the left
   * or right side. Useful for RTL layouts.
   * **Note:** Only effects inverted charts (vertical layout).
   *
   * @sample highcharts/series-organization/hanging-side
   *         Nodes hanging from right side.
   *
   * @type {'left'|'right'}
   * @since 11.3.0
   * @default 'left'
   */
  hangingSide: "left",
  /**
   *
   * The color of the links between nodes. This option is moved to
   * [link.color](#plotOptions.organization.link.color).
   *
   * @type {Highcharts.ColorString}
   * @deprecated
   * @apioption series.organization.linkColor
   * @private
   */
  /**
   * The line width of the links connecting nodes, in pixels. This option
   * is now deprecated and moved to the
   * [link.radius](#plotOptions.organization.link.lineWidth).
   *
   * @sample   highcharts/series-organization/link-options
   *           Square links
   *
   * @deprecated
   * @apioption series.organization.linkLineWidth
   * @private
   */
  /**
   * In a horizontal chart, the minimum width of the **hanging** nodes
   * only, in pixels. In a vertical chart, the minimum height of the
   * **haning** nodes only, in pixels too.
   *
   * Note: Used only when
   * [hangingIndentTranslation](#plotOptions.organization.hangingIndentTranslation)
   * is set to `shrink`.
   *
   * @see [nodeWidth](#plotOptions.organization.nodeWidth)
   *
   * @private
   */
  minNodeLength: 10,
  /**
   * In a horizontal chart, the width of the nodes in pixels. Note that
   * most organization charts are inverted (vertical), so the name of this
   * option is counterintuitive.
   *
   * @see [minNodeLength](#plotOptions.organization.minNodeLength)
   *
   * @private
   */
  nodeWidth: 50,
  tooltip: {
    nodeFormat: "{point.name}<br>{point.title}<br>{point.description}"
  }
};
const getLinkPath = {
  "default": getDefaultPath,
  straight: getStraightPath,
  curved: getCurvedPath
};
function getDefaultPath(pathParams) {
  const { x1, y1, x2, y2, width = 0, inverted = false, radius, parentVisible } = pathParams;
  const path = [
    ["M", x1, y1],
    ["L", x1, y1],
    ["C", x1, y1, x1, y2, x1, y2],
    ["L", x1, y2],
    ["C", x1, y1, x1, y2, x1, y2],
    ["L", x1, y2]
  ];
  return parentVisible ? applyRadius([
    ["M", x1, y1],
    ["L", x1 + width * (inverted ? -0.5 : 0.5), y1],
    ["L", x1 + width * (inverted ? -0.5 : 0.5), y2],
    ["L", x2, y2]
  ], radius) : path;
}
function getStraightPath(pathParams) {
  const { x1, y1, x2, y2, width = 0, inverted = false, parentVisible } = pathParams;
  return parentVisible ? [
    ["M", x1, y1],
    ["L", x1 + width * (inverted ? -1 : 1), y2],
    ["L", x2, y2]
  ] : [
    ["M", x1, y1],
    ["L", x1, y2],
    ["L", x1, y2]
  ];
}
function getCurvedPath(pathParams) {
  const { x1, y1, x2, y2, offset: offset2 = 0, width = 0, inverted = false, parentVisible } = pathParams;
  return parentVisible ? [
    ["M", x1, y1],
    [
      "C",
      x1 + offset2,
      y1,
      x1 - offset2 + width * (inverted ? -1 : 1),
      y2,
      x1 + width * (inverted ? -1 : 1),
      y2
    ],
    ["L", x2, y2]
  ] : [
    ["M", x1, y1],
    ["C", x1, y1, x1, y2, x1, y2],
    ["L", x2, y2]
  ];
}
function applyRadius(path, r) {
  const d = [];
  for (let i = 0; i < path.length; i++) {
    const x = path[i][1];
    const y = path[i][2];
    if (typeof x === "number" && typeof y === "number") {
      if (i === 0) {
        d.push(["M", x, y]);
      } else if (i === path.length - 1) {
        d.push(["L", x, y]);
      } else if (r) {
        const prevSeg = path[i - 1];
        const nextSeg = path[i + 1];
        if (prevSeg && nextSeg) {
          const x1 = prevSeg[1], y1 = prevSeg[2], x2 = nextSeg[1], y2 = nextSeg[2];
          if (typeof x1 === "number" && typeof x2 === "number" && typeof y1 === "number" && typeof y2 === "number" && x1 !== x2 && y1 !== y2) {
            const directionX = x1 < x2 ? 1 : -1, directionY = y1 < y2 ? 1 : -1;
            d.push([
              "L",
              x - directionX * Math.min(Math.abs(x - x1), r),
              y - directionY * Math.min(Math.abs(y - y1), r)
            ], [
              "C",
              x,
              y,
              x,
              y,
              x + directionX * Math.min(Math.abs(x - x2), r),
              y + directionY * Math.min(Math.abs(y - y2), r)
            ]);
          }
        }
      } else {
        d.push(["L", x, y]);
      }
    }
  }
  return d;
}
const PathUtilities = {
  applyRadius,
  getLinkPath
};
const { sankey: SankeySeries } = SeriesRegistry$1.seriesTypes;
const { css, crisp: crisp$1, extend: extend$9, isNumber: isNumber$b, merge: merge$c, pick: pick$b } = Utilities;
TextPath.compose(SVGElement$1);
class OrganizationSeries extends SankeySeries {
  /* *
   *
   *  Functions
   *
   * */
  alignDataLabel(point, dataLabel, options2) {
    const shapeArgs = point.shapeArgs, text = dataLabel.text;
    if (options2.useHTML && shapeArgs) {
      const padjust = this.options.borderWidth + 2 * this.options.dataLabels.padding;
      let width = shapeArgs.width || 0, height = shapeArgs.height || 0;
      if (this.chart.inverted) {
        width = height;
        height = shapeArgs.width || 0;
      }
      height -= padjust;
      width -= padjust;
      text.foreignObject?.attr({
        x: 0,
        y: 0,
        width,
        height
      });
      css(text.element.parentNode, {
        width: width + "px",
        height: height + "px"
      });
      css(text.element, {
        left: 0,
        top: 0,
        width: "100%",
        height: "100%",
        overflow: "hidden"
      });
      dataLabel.getBBox = () => ({ width, height, x: 0, y: 0 });
      dataLabel.width = width;
      dataLabel.height = height;
    }
    super.alignDataLabel.apply(this, arguments);
  }
  createNode(id) {
    const node = super.createNode.call(this, id);
    node.getSum = () => 1;
    return node;
  }
  pointAttribs(point, state) {
    const series = this, attribs = SankeySeries.prototype.pointAttribs.call(series, point, state), level = point.isNode ? point.level : point.fromNode.level, levelOptions = series.mapOptionsToLevel[level || 0] || {}, options2 = point.options, stateOptions = levelOptions.states && levelOptions.states[state] || {}, borderRadius = pick$b(stateOptions.borderRadius, options2.borderRadius, levelOptions.borderRadius, series.options.borderRadius), linkColor = pick$b(stateOptions.linkColor, options2.linkColor, levelOptions.linkColor, series.options.linkColor, stateOptions.link && stateOptions.link.color, options2.link && options2.link.color, levelOptions.link && levelOptions.link.color, series.options.link && series.options.link.color), linkLineWidth = pick$b(stateOptions.linkLineWidth, options2.linkLineWidth, levelOptions.linkLineWidth, series.options.linkLineWidth, stateOptions.link && stateOptions.link.lineWidth, options2.link && options2.link.lineWidth, levelOptions.link && levelOptions.link.lineWidth, series.options.link && series.options.link.lineWidth), linkOpacity = pick$b(stateOptions.linkOpacity, options2.linkOpacity, levelOptions.linkOpacity, series.options.linkOpacity, stateOptions.link && stateOptions.link.linkOpacity, options2.link && options2.link.linkOpacity, levelOptions.link && levelOptions.link.linkOpacity, series.options.link && series.options.link.linkOpacity);
    if (!point.isNode) {
      attribs.stroke = linkColor;
      attribs["stroke-width"] = linkLineWidth;
      attribs.opacity = linkOpacity;
      delete attribs.fill;
    } else {
      if (isNumber$b(borderRadius)) {
        attribs.r = borderRadius;
      }
    }
    return attribs;
  }
  translateLink(point) {
    const chart = this.chart, options2 = this.options, fromNode = point.fromNode, toNode = point.toNode, linkWidth = pick$b(options2.linkLineWidth, options2.link.lineWidth, 0), factor = pick$b(options2.link.offset, 0.5), type = pick$b(point.options.link && point.options.link.type, options2.link.type);
    if (fromNode.shapeArgs && toNode.shapeArgs) {
      const hangingIndent = options2.hangingIndent, hangingRight = options2.hangingSide === "right", toOffset = toNode.options.offset, percentOffset = /%$/.test(toOffset) && parseInt(toOffset, 10), inverted = chart.inverted;
      let x1 = crisp$1((fromNode.shapeArgs.x || 0) + (fromNode.shapeArgs.width || 0), linkWidth), y1 = crisp$1((fromNode.shapeArgs.y || 0) + (fromNode.shapeArgs.height || 0) / 2, linkWidth), x2 = crisp$1(toNode.shapeArgs.x || 0, linkWidth), y2 = crisp$1((toNode.shapeArgs.y || 0) + (toNode.shapeArgs.height || 0) / 2, linkWidth), xMiddle;
      if (inverted) {
        x1 -= fromNode.shapeArgs.width || 0;
        x2 += toNode.shapeArgs.width || 0;
      }
      xMiddle = this.colDistance ? crisp$1(x2 + (inverted ? 1 : -1) * (this.colDistance - this.nodeWidth) / 2, linkWidth) : crisp$1((x2 + x1) / 2, linkWidth);
      if (percentOffset && (percentOffset >= 50 || percentOffset <= -50)) {
        xMiddle = x2 = crisp$1(x2 + (inverted ? -0.5 : 0.5) * (toNode.shapeArgs.width || 0), linkWidth);
        y2 = toNode.shapeArgs.y || 0;
        if (percentOffset > 0) {
          y2 += toNode.shapeArgs.height || 0;
        }
      }
      if (toNode.hangsFrom === fromNode) {
        if (chart.inverted) {
          y1 = !hangingRight ? crisp$1((fromNode.shapeArgs.y || 0) + (fromNode.shapeArgs.height || 0) - hangingIndent / 2, linkWidth) : crisp$1((fromNode.shapeArgs.y || 0) + hangingIndent / 2, linkWidth);
          y2 = !hangingRight ? (toNode.shapeArgs.y || 0) + (toNode.shapeArgs.height || 0) : (toNode.shapeArgs.y || 0) + hangingIndent / 2;
        } else {
          y1 = crisp$1((fromNode.shapeArgs.y || 0) + hangingIndent / 2, linkWidth);
        }
        xMiddle = x2 = crisp$1((toNode.shapeArgs.x || 0) + (toNode.shapeArgs.width || 0) / 2, linkWidth);
      }
      point.plotX = xMiddle;
      point.plotY = (y1 + y2) / 2;
      point.shapeType = "path";
      if (type === "straight") {
        point.shapeArgs = {
          d: [
            ["M", x1, y1],
            ["L", x2, y2]
          ]
        };
      } else if (type === "curved") {
        const offset2 = Math.abs(x2 - x1) * factor * (inverted ? -1 : 1);
        point.shapeArgs = {
          d: [
            ["M", x1, y1],
            ["C", x1 + offset2, y1, x2 - offset2, y2, x2, y2]
          ]
        };
      } else {
        point.shapeArgs = {
          d: PathUtilities.applyRadius([
            ["M", x1, y1],
            ["L", xMiddle, y1],
            ["L", xMiddle, y2],
            ["L", x2, y2]
          ], pick$b(options2.linkRadius, options2.link.radius))
        };
      }
      point.dlBox = {
        x: (x1 + x2) / 2,
        y: (y1 + y2) / 2,
        height: linkWidth,
        width: 0
      };
    }
  }
  translateNode(node, column2) {
    super.translateNode(node, column2);
    const chart = this.chart, options2 = this.options, sum2 = node.getSum(), translationFactor = this.translationFactor, nodeHeight = Math.max(Math.round(sum2 * translationFactor), options2.minLinkWidth || 0), hangingRight = options2.hangingSide === "right", indent = options2.hangingIndent || 0, indentLogic = options2.hangingIndentTranslation, minLength = options2.minNodeLength || 10, nodeWidth = Math.round(this.nodeWidth), shapeArgs = node.shapeArgs, sign2 = chart.inverted ? -1 : 1;
    let parentNode = node.hangsFrom;
    if (parentNode) {
      if (indentLogic === "cumulative") {
        shapeArgs.height -= indent;
        if (chart.inverted && !hangingRight) {
          shapeArgs.y -= sign2 * indent;
        }
        while (parentNode) {
          shapeArgs.y += (hangingRight ? 1 : sign2) * indent;
          parentNode = parentNode.hangsFrom;
        }
      } else if (indentLogic === "shrink") {
        while (parentNode && shapeArgs.height > indent + minLength) {
          shapeArgs.height -= indent;
          if (!chart.inverted || hangingRight) {
            shapeArgs.y += indent;
          }
          parentNode = parentNode.hangsFrom;
        }
      } else {
        shapeArgs.height -= indent;
        if (!chart.inverted || hangingRight) {
          shapeArgs.y += indent;
        }
      }
    }
    node.nodeHeight = chart.inverted ? shapeArgs.width : shapeArgs.height;
    if (node.shapeArgs && !node.hangsFrom) {
      node.shapeArgs = merge$c(node.shapeArgs, {
        x: (node.shapeArgs.x || 0) + nodeWidth / 2 - (node.shapeArgs.width || 0) / 2,
        y: (node.shapeArgs.y || 0) + nodeHeight / 2 - (node.shapeArgs.height || 0) / 2
      });
    }
  }
  drawDataLabels() {
    const dlOptions = this.options.dataLabels;
    if (dlOptions.linkTextPath && dlOptions.linkTextPath.enabled) {
      for (const link of this.points) {
        link.options.dataLabels = merge$c(link.options.dataLabels, { useHTML: false });
      }
    }
    super.drawDataLabels();
  }
}
OrganizationSeries.defaultOptions = merge$c(SankeySeries.defaultOptions, OrganizationSeriesDefaults);
extend$9(OrganizationSeries.prototype, {
  pointClass: OrganizationPoint
});
SeriesRegistry$1.registerSeriesType("organization", OrganizationSeries);
const { correctFloat, isNumber: isNumber$a, isObject: isObject$4 } = Utilities;
const XRangeSeriesDefaults = {
  /**
   * A partial fill for each point, typically used to visualize how much
   * of a task is performed. The partial fill object can be set either on
   * series or point level.
   *
   * @sample {highcharts} highcharts/demo/x-range
   *         X-range with partial fill
   *
   * @product   highcharts highstock gantt
   * @apioption plotOptions.xrange.partialFill
   */
  /**
   * The fill color to be used for partial fills. Defaults to a darker
   * shade of the point color.
   *
   * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
   * @product   highcharts highstock gantt
   * @apioption plotOptions.xrange.partialFill.fill
   */
  /**
   * A partial fill for each point, typically used to visualize how much
   * of a task is performed. See [completed](series.gantt.data.completed).
   *
   * @sample gantt/demo/progress-indicator
   *         Gantt with progress indicator
   *
   * @product   gantt
   * @apioption plotOptions.gantt.partialFill
   */
  /**
   * In an X-range series, this option makes all points of the same Y-axis
   * category the same color.
   */
  colorByPoint: true,
  dataLabels: {
    formatter: function() {
      let amount = this.partialFill;
      if (isObject$4(amount)) {
        amount = amount.amount;
      }
      if (isNumber$a(amount) && amount > 0) {
        return correctFloat(amount * 100) + "%";
      }
    },
    inside: true,
    verticalAlign: "middle",
    style: {
      whiteSpace: "nowrap"
    }
  },
  tooltip: {
    headerFormat: '<span style="font-size: 0.8em">{ucfirst point.x} - {point.x2}</span><br/>',
    pointFormat: '<span style="color:{point.color}">●</span> {series.name}: <b>{point.yCategory}</b><br/>'
  },
  borderRadius: 3,
  pointRange: 0
};
const { column: { prototype: { pointClass: ColumnPoint } } } = SeriesRegistry$1.seriesTypes;
const { extend: extend$8 } = Utilities;
let XRangePoint$1 = class XRangePoint2 extends ColumnPoint {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * Return color of a point based on its category.
   *
   * @private
   * @function getColorByCategory
   *
   * @param {object} series
   *        The series which the point belongs to.
   *
   * @param {object} point
   *        The point to calculate its color for.
   *
   * @return {object}
   *         Returns an object containing the properties color and colorIndex.
   */
  static getColorByCategory(series, point) {
    const colors = series.options.colors || series.chart.options.colors, colorCount = colors ? colors.length : series.chart.options.chart.colorCount, colorIndex = point.y % colorCount, color2 = colors?.[colorIndex];
    return {
      colorIndex,
      color: color2
    };
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  resolveColor() {
    const series = this.series;
    if (series.options.colorByPoint && !this.options.color) {
      const colorByPoint = XRangePoint2.getColorByCategory(series, this);
      if (!series.chart.styledMode) {
        this.color = colorByPoint.color;
      }
      if (!this.options.colorIndex) {
        this.colorIndex = colorByPoint.colorIndex;
      }
    } else {
      this.color = this.options.color || series.color;
    }
  }
  /**
   * Extend init to have y default to 0.
   *
   * @private
   */
  constructor(series, options2) {
    super(series, options2);
    if (!this.y) {
      this.y = 0;
    }
  }
  /**
   * Extend applyOptions to handle time strings for x2
   *
   * @private
   */
  applyOptions(options2, x) {
    super.applyOptions(options2, x);
    this.x2 = this.series.chart.time.parse(this.x2);
    this.isNull = !this.isValid?.();
    return this;
  }
  /**
   * @private
   */
  setState() {
    super.setState.apply(this, arguments);
    this.series.drawPoint(this, this.series.getAnimationVerb());
  }
  /**
   * @private
   */
  isValid() {
    return typeof this.x === "number" && typeof this.x2 === "number";
  }
};
extend$8(XRangePoint$1.prototype, {
  ttBelow: false,
  tooltipDateKeys: ["x", "x2"]
});
const { composed: composed$1, noop } = Highcharts;
const { parse: color } = Color;
const { column: ColumnSeries } = SeriesRegistry$1.seriesTypes;
const { addEvent: addEvent$9, clamp: clamp$2, crisp, defined: defined$5, extend: extend$7, find: find$2, isNumber: isNumber$9, isObject: isObject$3, merge: merge$b, pick: pick$a, pushUnique: pushUnique$1, relativeLength: relativeLength$1 } = Utilities;
function onAxisAfterGetSeriesExtremes() {
  let dataMax, modMax;
  if (this.isXAxis) {
    dataMax = pick$a(this.dataMax, -Number.MAX_VALUE);
    for (const series of this.series) {
      const column2 = series.dataTable.getColumn("x2", true) || series.dataTable.getColumn("end", true);
      if (column2) {
        for (const val of column2) {
          if (isNumber$9(val) && val > dataMax) {
            dataMax = val;
            modMax = true;
          }
        }
      }
    }
    if (modMax) {
      this.dataMax = dataMax;
    }
  }
}
let XRangeSeries$1 = class XRangeSeries2 extends ColumnSeries {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AxisClass) {
    if (pushUnique$1(composed$1, "Series.XRange")) {
      addEvent$9(AxisClass, "afterGetSeriesExtremes", onAxisAfterGetSeriesExtremes);
    }
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * @private
   */
  init() {
    super.init.apply(this, arguments);
    this.options.stacking = void 0;
  }
  /**
   * Borrow the column series metrics, but with swapped axes. This gives
   * free access to features like groupPadding, grouping, pointWidth etc.
   * @private
   */
  getColumnMetrics() {
    const swapAxes = () => {
      for (const series of this.chart.series) {
        const xAxis2 = series.xAxis;
        series.xAxis = series.yAxis;
        series.yAxis = xAxis2;
      }
    };
    swapAxes();
    const metrics = super.getColumnMetrics();
    swapAxes();
    return metrics;
  }
  /**
   * Override cropData to show a point where x or x2 is outside visible range,
   * but one of them is inside.
   * @private
   */
  cropData(table, min2, max2) {
    const xData = table.getColumn("x") || [], x2Data = table.getColumn("x2");
    table.setColumn("x", x2Data, void 0, { silent: true });
    const croppedData = super.cropData(table, min2, max2);
    table.setColumn("x", xData.slice(croppedData.start, croppedData.end), void 0, { silent: true });
    return croppedData;
  }
  /**
   * Finds the index of an existing point that matches the given point
   * options.
   *
   * @private
   *
   * @param {Highcharts.XRangePointOptions} options
   *        The options of the point.
   *
   * @return {number|undefined}
   *         Returns index of a matching point, or undefined if no match is
   *         found.
   */
  findPointIndex(options2) {
    const { cropStart, points } = this;
    const { id } = options2;
    let pointIndex;
    if (id) {
      const point = find$2(points, (point2) => point2.id === id);
      pointIndex = point ? point.index : void 0;
    }
    if (typeof pointIndex === "undefined") {
      const point = find$2(points, (point2) => point2.x === options2.x && point2.x2 === options2.x2 && !point2.touched);
      pointIndex = point ? point.index : void 0;
    }
    if (this.cropped && isNumber$9(pointIndex) && isNumber$9(cropStart) && pointIndex >= cropStart) {
      pointIndex -= cropStart;
    }
    return pointIndex;
  }
  alignDataLabel(point) {
    const oldPlotX = point.plotX;
    point.plotX = pick$a(point.dlBox?.centerX, point.plotX);
    if (point.dataLabel && point.shapeArgs?.width) {
      point.dataLabel.css({
        width: `${point.shapeArgs.width}px`
      });
    }
    super.alignDataLabel.apply(this, arguments);
    point.plotX = oldPlotX;
  }
  /**
   * @private
   */
  translatePoint(point) {
    const xAxis2 = this.xAxis, yAxis2 = this.yAxis, metrics = this.columnMetrics, options2 = this.options, minPointLength = options2.minPointLength || 0, oldColWidth = (point.shapeArgs?.width || 0) / 2, seriesXOffset = this.pointXOffset = metrics.offset, posX = pick$a(point.x2, point.x + (point.len || 0)), borderRadius = options2.borderRadius, plotTop = this.chart.plotTop, plotLeft = this.chart.plotLeft;
    let plotX = point.plotX, plotX2 = xAxis2.translate(posX, 0, 0, 0, 1);
    const length = Math.abs(plotX2 - plotX), inverted = this.chart.inverted, borderWidth = pick$a(options2.borderWidth, 1);
    let widthDifference, partialFill, yOffset = metrics.offset, pointHeight = Math.round(metrics.width), dlLeft, dlRight, dlWidth, clipRectWidth;
    if (minPointLength) {
      widthDifference = minPointLength - length;
      if (widthDifference < 0) {
        widthDifference = 0;
      }
      plotX -= widthDifference / 2;
      plotX2 += widthDifference / 2;
    }
    plotX = Math.max(plotX, -10);
    plotX2 = clamp$2(plotX2, -10, xAxis2.len + 10);
    if (defined$5(point.options.pointWidth)) {
      yOffset -= (Math.ceil(point.options.pointWidth) - pointHeight) / 2;
      pointHeight = Math.ceil(point.options.pointWidth);
    }
    if (options2.pointPlacement && isNumber$9(point.plotY) && yAxis2.categories) {
      point.plotY = yAxis2.translate(point.y, 0, 1, 0, 1, options2.pointPlacement);
    }
    const x = crisp(Math.min(plotX, plotX2), borderWidth), x2 = crisp(Math.max(plotX, plotX2), borderWidth), width = x2 - x;
    const r = Math.min(relativeLength$1(typeof borderRadius === "object" ? borderRadius.radius : borderRadius || 0, pointHeight), Math.min(width, pointHeight) / 2);
    const shapeArgs = {
      x,
      y: crisp((point.plotY || 0) + yOffset, borderWidth),
      width,
      height: pointHeight,
      r
    };
    point.shapeArgs = shapeArgs;
    if (!inverted) {
      point.tooltipPos[0] -= oldColWidth + seriesXOffset - shapeArgs.width / 2;
    } else {
      point.tooltipPos[1] += seriesXOffset + oldColWidth;
    }
    dlLeft = shapeArgs.x;
    dlRight = dlLeft + shapeArgs.width;
    if (dlLeft < 0 || dlRight > xAxis2.len) {
      dlLeft = clamp$2(dlLeft, 0, xAxis2.len);
      dlRight = clamp$2(dlRight, 0, xAxis2.len);
      dlWidth = dlRight - dlLeft;
      point.dlBox = merge$b(shapeArgs, {
        x: dlLeft,
        width: dlRight - dlLeft,
        centerX: dlWidth ? dlWidth / 2 : null
      });
    } else {
      point.dlBox = null;
    }
    const tooltipPos = point.tooltipPos;
    const xIndex = !inverted ? 0 : 1;
    const yIndex = !inverted ? 1 : 0;
    const tooltipYOffset = this.columnMetrics ? this.columnMetrics.offset : -metrics.width / 2;
    if (inverted) {
      tooltipPos[xIndex] += shapeArgs.width / 2;
    } else {
      tooltipPos[xIndex] = clamp$2(tooltipPos[xIndex] + (xAxis2.reversed ? -1 : 0) * shapeArgs.width, xAxis2.left - plotLeft, xAxis2.left + xAxis2.len - plotLeft - 1);
    }
    tooltipPos[yIndex] = clamp$2(tooltipPos[yIndex] + (inverted ? -1 : 1) * tooltipYOffset, yAxis2.top - plotTop, yAxis2.top + yAxis2.len - plotTop - 1);
    partialFill = point.partialFill;
    if (partialFill) {
      if (isObject$3(partialFill)) {
        partialFill = partialFill.amount;
      }
      if (!isNumber$9(partialFill)) {
        partialFill = 0;
      }
      point.partShapeArgs = merge$b(shapeArgs);
      clipRectWidth = Math.max(Math.round(length * partialFill + point.plotX - plotX), 0);
      point.clipRectArgs = {
        x: xAxis2.reversed ? (
          // #10717
          shapeArgs.x + length - clipRectWidth
        ) : shapeArgs.x,
        y: shapeArgs.y,
        width: clipRectWidth,
        height: shapeArgs.height
      };
    }
    point.key = point.category || point.name;
    point.yCategory = yAxis2.categories?.[point.y ?? -1];
  }
  /**
   * @private
   */
  translate() {
    super.translate.apply(this, arguments);
    for (const point of this.points) {
      this.translatePoint(point);
    }
  }
  /**
   * Draws a single point in the series. Needed for partial fill.
   *
   * This override turns point.graphic into a group containing the
   * original graphic and an overlay displaying the partial fill.
   *
   * @private
   *
   * @param {Highcharts.Point} point
   *        An instance of Point in the series.
   *
   * @param {"animate"|"attr"} verb
   *        'animate' (animates changes) or 'attr' (sets options)
   */
  drawPoint(point, verb) {
    const seriesOpts = this.options, renderer = this.chart.renderer, type = point.shapeType, shapeArgs = point.shapeArgs, partShapeArgs = point.partShapeArgs, clipRectArgs = point.clipRectArgs, pointState = point.state, stateOpts = seriesOpts.states[pointState || "normal"] || {}, pointStateVerb = typeof pointState === "undefined" ? "attr" : verb, pointAttr = this.pointAttribs(point, pointState), animation = pick$a(this.chart.options.chart.animation, stateOpts.animation);
    let graphic = point.graphic, pfOptions = point.partialFill;
    if (!point.isNull && point.visible !== false) {
      if (graphic) {
        graphic.rect[verb](shapeArgs);
      } else {
        point.graphic = graphic = renderer.g("point").addClass(point.getClassName()).add(point.group || this.group);
        graphic.rect = renderer[type](merge$b(shapeArgs)).addClass(point.getClassName()).addClass("highcharts-partfill-original").add(graphic);
      }
      if (partShapeArgs) {
        if (graphic.partRect) {
          graphic.partRect[verb](merge$b(partShapeArgs));
          graphic.partialClipRect[verb](merge$b(clipRectArgs));
        } else {
          graphic.partialClipRect = renderer.clipRect(clipRectArgs.x, clipRectArgs.y, clipRectArgs.width, clipRectArgs.height);
          graphic.partRect = renderer[type](partShapeArgs).addClass("highcharts-partfill-overlay").add(graphic).clip(graphic.partialClipRect);
        }
      }
      if (!this.chart.styledMode) {
        graphic.rect[verb](pointAttr, animation).shadow(seriesOpts.shadow);
        if (partShapeArgs) {
          if (!isObject$3(pfOptions)) {
            pfOptions = {};
          }
          if (isObject$3(seriesOpts.partialFill)) {
            pfOptions = merge$b(seriesOpts.partialFill, pfOptions);
          }
          const fill = pfOptions.fill || color(pointAttr.fill).brighten(-0.3).get() || color(point.color || this.color).brighten(-0.3).get();
          pointAttr.fill = fill;
          graphic.partRect[pointStateVerb](pointAttr, animation).shadow(seriesOpts.shadow);
        }
      }
    } else if (graphic) {
      point.graphic = graphic.destroy();
    }
  }
  /**
   * @private
   */
  drawPoints() {
    const verb = this.getAnimationVerb();
    for (const point of this.points) {
      this.drawPoint(point, verb);
    }
  }
  /**
   * Returns "animate", or "attr" if the number of points is above the
   * animation limit.
   *
   * @private
   */
  getAnimationVerb() {
    return this.chart.pointCount < (this.options.animationLimit || 250) ? "animate" : "attr";
  }
  /**
   * @private
   */
  isPointInside(point) {
    const shapeArgs = point.shapeArgs, plotX = point.plotX, plotY = point.plotY;
    if (!shapeArgs) {
      return super.isPointInside.apply(this, arguments);
    }
    const isInside = typeof plotX !== "undefined" && typeof plotY !== "undefined" && plotY >= 0 && plotY <= this.yAxis.len && (shapeArgs.x || 0) + (shapeArgs.width || 0) >= 0 && plotX <= this.xAxis.len;
    return isInside;
  }
};
XRangeSeries$1.defaultOptions = merge$b(ColumnSeries.defaultOptions, XRangeSeriesDefaults);
extend$7(XRangeSeries$1.prototype, {
  pointClass: XRangePoint$1,
  pointArrayMap: ["x2", "y"],
  getExtremesFromAll: true,
  keysAffectYAxis: ["y"],
  parallelArrays: ["x", "x2", "y"],
  requireSorting: false,
  type: "xrange",
  animate: SeriesRegistry$1.series.prototype.animate,
  autoIncrement: noop,
  buildKDTree: noop
});
SeriesRegistry$1.registerSeriesType("xrange", XRangeSeries$1);
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/xrange
 * @requires highcharts
 *
 * X-range series
 *
 * (c) 2010-2025 Torstein Honsi, Lars A. V. Cabrera
 *
 * License: www.highcharts.com/license
 */
const G$4 = Highcharts;
XRangeSeries$1.compose(G$4.Axis);
class BulletPoint extends ColumnSeries$f.prototype.pointClass {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Destroys target graphic.
   * @private
   */
  destroy() {
    const series = this;
    if (series.targetGraphic) {
      series.targetGraphic = series.targetGraphic.destroy();
    }
    super.destroy.apply(series, arguments);
    return;
  }
}
const BulletSeriesDefaults = {
  /**
   * All options related with look and positioning of targets.
   *
   * @since 6.0.0
   */
  targetOptions: {
    /**
     * The width of the rectangle representing the target. Could be set
     * as a pixel value or as a percentage of a column width.
     *
     * @type  {number|string}
     * @since 6.0.0
     */
    width: "140%",
    /**
     * The height of the rectangle representing the target.
     *
     * @since 6.0.0
     */
    height: 3,
    /**
     * The border color of the rectangle representing the target. When
     * not set, the point's border color is used.
     *
     * In styled mode, use class `highcharts-bullet-target` instead.
     *
     * @type      {Highcharts.ColorString}
     * @since     6.0.0
     * @product   highcharts
     * @apioption plotOptions.bullet.targetOptions.borderColor
     */
    /**
     * The color of the rectangle representing the target. When not set,
     * point's color (if set in point's options -
     * [`color`](#series.bullet.data.color)) or zone of the target value
     * (if [`zones`](#plotOptions.bullet.zones) or
     * [`negativeColor`](#plotOptions.bullet.negativeColor) are set)
     * or the same color as the point has is used.
     *
     * In styled mode, use class `highcharts-bullet-target` instead.
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     6.0.0
     * @product   highcharts
     * @apioption plotOptions.bullet.targetOptions.color
     */
    /**
     * The border width of the rectangle representing the target.
     *
     * In styled mode, use class `highcharts-bullet-target` instead.
     *
     * @since   6.0.0
     */
    borderWidth: 0,
    /**
     * The border radius of the rectangle representing the target.
     */
    borderRadius: 0
  },
  tooltip: {
    pointFormat: '<span style="color:{series.color}">●</span> {series.name}: <b>{point.y}</b>. Target: <b>{point.target}</b><br/>'
  }
};
const { extend: extend$6, isNumber: isNumber$8, merge: merge$a, pick: pick$9, relativeLength } = Utilities;
class BulletSeries extends ColumnSeries$f {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Draws the targets. For inverted chart, the `series.group` is rotated,
   * so the same coordinates apply. This method is based on column series
   * drawPoints function.
   *
   * @ignore
   * @function Highcharts.Series#drawPoints
   */
  drawPoints() {
    const series = this, chart = series.chart, options2 = series.options, animationLimit = options2.animationLimit || 250;
    super.drawPoints.apply(this, arguments);
    for (const point of series.points) {
      const pointOptions = point.options, targetVal = point.target, pointVal = point.y;
      let targetShapeArgs, targetGraphic = point.targetGraphic, width, height, targetOptions, y;
      if (isNumber$8(targetVal) && targetVal !== null) {
        targetOptions = merge$a(options2.targetOptions, pointOptions.targetOptions);
        height = targetOptions.height;
        let shapeArgs = point.shapeArgs;
        if (point.dlBox && shapeArgs && !isNumber$8(shapeArgs.width)) {
          shapeArgs = point.dlBox;
        }
        width = relativeLength(targetOptions.width, shapeArgs.width);
        y = series.yAxis.translate(targetVal, false, true, false, true) - targetOptions.height / 2 - 0.5;
        targetShapeArgs = series.crispCol.apply({
          // Use fake series object to set borderWidth of target
          chart,
          borderWidth: targetOptions.borderWidth,
          options: {
            crisp: options2.crisp
          }
        }, [
          shapeArgs.x + shapeArgs.width / 2 - width / 2,
          y,
          width,
          height
        ]);
        if (targetGraphic) {
          targetGraphic[chart.pointCount < animationLimit ? "animate" : "attr"](targetShapeArgs);
          if (isNumber$8(pointVal) && pointVal !== null) {
            targetGraphic.element.point = point;
          } else {
            targetGraphic.element.point = void 0;
          }
        } else {
          point.targetGraphic = targetGraphic = chart.renderer.rect().attr(targetShapeArgs).add(series.group);
        }
        if (!chart.styledMode) {
          targetGraphic.attr({
            fill: pick$9(targetOptions.color, pointOptions.color, series.zones.length && (point.getZone.call({
              series,
              x: point.x,
              y: targetVal,
              options: {}
            }).color || series.color) || void 0, point.color, series.color),
            stroke: pick$9(targetOptions.borderColor, point.borderColor, series.options.borderColor),
            "stroke-width": targetOptions.borderWidth,
            r: targetOptions.borderRadius
          });
        }
        if (isNumber$8(pointVal) && pointVal !== null) {
          targetGraphic.element.point = point;
        }
        targetGraphic.addClass(point.getClassName() + " highcharts-bullet-target", true);
      } else if (targetGraphic) {
        point.targetGraphic = targetGraphic.destroy();
      }
    }
  }
  /**
   * Includes target values to extend extremes from y values.
   *
   * @ignore
   * @function Highcharts.Series#getExtremes
   */
  getExtremes(yData) {
    const dataExtremes = super.getExtremes.call(this, yData), targetData = this.targetData;
    if (targetData && targetData.length) {
      const targetExtremes = super.getExtremes.call(this, targetData);
      if (isNumber$8(targetExtremes.dataMin)) {
        dataExtremes.dataMin = Math.min(pick$9(dataExtremes.dataMin, Infinity), targetExtremes.dataMin);
      }
      if (isNumber$8(targetExtremes.dataMax)) {
        dataExtremes.dataMax = Math.max(pick$9(dataExtremes.dataMax, -Infinity), targetExtremes.dataMax);
      }
    }
    return dataExtremes;
  }
}
BulletSeries.defaultOptions = merge$a(ColumnSeries$f.defaultOptions, BulletSeriesDefaults);
extend$6(BulletSeries.prototype, {
  parallelArrays: ["x", "y", "target"],
  pointArrayMap: ["y", "target"]
});
BulletSeries.prototype.pointClass = BulletPoint;
SeriesRegistry$1.registerSeriesType("bullet", BulletSeries);
function arrow(x, y, w, h) {
  return [
    ["M", x, y + h / 2],
    ["L", x + w, y],
    ["L", x, y + h / 2],
    ["L", x + w, y + h]
  ];
}
function arrowHalf(x, y, w, h) {
  return arrow(x, y, w / 2, h);
}
function compose$6(SVGRendererClass) {
  const symbols2 = SVGRendererClass.prototype.symbols;
  symbols2.arrow = arrow;
  symbols2["arrow-filled"] = triangleLeft;
  symbols2["arrow-filled-half"] = triangleLeftHalf;
  symbols2["arrow-half"] = arrowHalf;
  symbols2["triangle-left"] = triangleLeft;
  symbols2["triangle-left-half"] = triangleLeftHalf;
}
function triangleLeft(x, y, w, h) {
  return [
    ["M", x + w, y],
    ["L", x, y + h / 2],
    ["L", x + w, y + h],
    ["Z"]
  ];
}
function triangleLeftHalf(x, y, w, h) {
  return triangleLeft(x, y, w / 2, h);
}
const ArrowSymbols = {
  compose: compose$6
};
const { defined: defined$4, error: error$1, merge: merge$9, objectEach } = Utilities;
const deg2rad = Highcharts.deg2rad, max$2 = Math.max, min$2 = Math.min;
class Connection {
  constructor(from, to, options2) {
    this.init(from, to, options2);
  }
  /**
   * Initialize the Connection object. Used as constructor only.
   *
   * @function Highcharts.Connection#init
   *
   * @param {Highcharts.Point} from
   *        Connection runs from this Point.
   *
   * @param {Highcharts.Point} to
   *        Connection runs to this Point.
   *
   * @param {Highcharts.ConnectorsOptions} [options]
   *        Connection options.
   */
  init(from, to, options2) {
    this.fromPoint = from;
    this.toPoint = to;
    this.options = options2;
    this.chart = from.series.chart;
    this.pathfinder = this.chart.pathfinder;
  }
  /**
   * Add (or update) this connection's path on chart. Stores reference to the
   * created element on this.graphics.path.
   *
   * @function Highcharts.Connection#renderPath
   *
   * @param {Highcharts.SVGPathArray} path
   *        Path to render, in array format. E.g. ['M', 0, 0, 'L', 10, 10]
   *
   * @param {Highcharts.SVGAttributes} [attribs]
   *        SVG attributes for the path.
   *
   * @param {Partial<Highcharts.AnimationOptionsObject>} [animation]
   *        Animation options for the rendering.
   */
  renderPath(path, attribs) {
    const connection = this, chart = this.chart, styledMode = chart.styledMode, pathfinder = this.pathfinder, anim = {};
    let pathGraphic = connection.graphics && connection.graphics.path;
    if (!pathfinder.group) {
      pathfinder.group = chart.renderer.g().addClass("highcharts-pathfinder-group").attr({ zIndex: -1 }).add(chart.seriesGroup);
    }
    pathfinder.group.translate(chart.plotLeft, chart.plotTop);
    if (!(pathGraphic && pathGraphic.renderer)) {
      pathGraphic = chart.renderer.path().add(pathfinder.group);
      if (!styledMode) {
        pathGraphic.attr({
          opacity: 0
        });
      }
    }
    pathGraphic.attr(attribs);
    anim.d = path;
    if (!styledMode) {
      anim.opacity = 1;
    }
    pathGraphic.animate(anim);
    this.graphics = this.graphics || {};
    this.graphics.path = pathGraphic;
  }
  /**
   * Calculate and add marker graphics for connection to the chart. The
   * created/updated elements are stored on this.graphics.start and
   * this.graphics.end.
   *
   * @function Highcharts.Connection#addMarker
   *
   * @param {string} type
   *        Marker type, either 'start' or 'end'.
   *
   * @param {Highcharts.ConnectorsMarkerOptions} options
   *        All options for this marker. Not calculated or merged with other
   *        options.
   *
   * @param {Highcharts.SVGPathArray} path
   *        Connection path in array format. This is used to calculate the
   *        rotation angle of the markers.
   */
  addMarker(type, options2, path) {
    const connection = this, chart = connection.fromPoint.series.chart, pathfinder = chart.pathfinder, renderer = chart.renderer, point = type === "start" ? connection.fromPoint : connection.toPoint, anchor = point.getPathfinderAnchorPoint(options2);
    let markerVector, radians, rotation, box, width, height, pathVector, segment;
    if (!options2.enabled) {
      return;
    }
    if (type === "start") {
      segment = path[1];
    } else {
      segment = path[path.length - 2];
    }
    if (segment && segment[0] === "M" || segment[0] === "L") {
      pathVector = {
        x: segment[1],
        y: segment[2]
      };
      radians = point.getRadiansToVector(pathVector, anchor);
      markerVector = point.getMarkerVector(radians, options2.radius, anchor);
      rotation = -radians / deg2rad;
      if (options2.width && options2.height) {
        width = options2.width;
        height = options2.height;
      } else {
        width = height = options2.radius * 2;
      }
      connection.graphics = connection.graphics || {};
      box = {
        x: markerVector.x - width / 2,
        y: markerVector.y - height / 2,
        width,
        height,
        rotation,
        rotationOriginX: markerVector.x,
        rotationOriginY: markerVector.y
      };
      if (!connection.graphics[type]) {
        connection.graphics[type] = renderer.symbol(options2.symbol).addClass("highcharts-point-connecting-path-" + type + "-marker highcharts-color-" + this.fromPoint.colorIndex).attr(box).add(pathfinder.group);
        if (!renderer.styledMode) {
          connection.graphics[type].attr({
            fill: options2.color || connection.fromPoint.color,
            stroke: options2.lineColor,
            "stroke-width": options2.lineWidth,
            opacity: 0
          }).animate({
            opacity: 1
          }, point.series.options.animation);
        }
      } else {
        connection.graphics[type].animate(box);
      }
    }
  }
  /**
   * Calculate and return connection path.
   * Note: Recalculates chart obstacles on demand if they aren't calculated.
   *
   * @function Highcharts.Connection#getPath
   *
   * @param {Highcharts.ConnectorsOptions} options
   *        Connector options. Not calculated or merged with other options.
   *
   * @return {object|undefined}
   *         Calculated SVG path data in array format.
   */
  getPath(options2) {
    const pathfinder = this.pathfinder, chart = this.chart, algorithm = pathfinder.algorithms[options2.type];
    let chartObstacles = pathfinder.chartObstacles;
    if (typeof algorithm !== "function") {
      error$1('"' + options2.type + '" is not a Pathfinder algorithm.');
      return {
        path: [],
        obstacles: []
      };
    }
    if (algorithm.requiresObstacles && !chartObstacles) {
      chartObstacles = pathfinder.chartObstacles = pathfinder.getChartObstacles(options2);
      chart.options.connectors.algorithmMargin = options2.algorithmMargin;
      pathfinder.chartObstacleMetrics = pathfinder.getObstacleMetrics(chartObstacles);
    }
    return algorithm(
      // From
      this.fromPoint.getPathfinderAnchorPoint(options2.startMarker),
      // To
      this.toPoint.getPathfinderAnchorPoint(options2.endMarker),
      merge$9({
        chartObstacles,
        lineObstacles: pathfinder.lineObstacles || [],
        obstacleMetrics: pathfinder.chartObstacleMetrics,
        hardBounds: {
          xMin: 0,
          xMax: chart.plotWidth,
          yMin: 0,
          yMax: chart.plotHeight
        },
        obstacleOptions: {
          margin: options2.algorithmMargin
        },
        startDirectionX: pathfinder.getAlgorithmStartDirection(options2.startMarker)
      }, options2)
    );
  }
  /**
   * (re)Calculate and (re)draw the connection.
   *
   * @function Highcharts.Connection#render
   */
  render() {
    const connection = this, fromPoint = connection.fromPoint, series = fromPoint.series, chart = series.chart, pathfinder = chart.pathfinder, attribs = {};
    let options2 = merge$9(chart.options.connectors, series.options.connectors, fromPoint.options.connectors, connection.options);
    if (!chart.styledMode) {
      attribs.stroke = options2.lineColor || fromPoint.color;
      attribs["stroke-width"] = options2.lineWidth;
      if (options2.dashStyle) {
        attribs.dashstyle = options2.dashStyle;
      }
    }
    attribs["class"] = // eslint-disable-line dot-notation
    "highcharts-point-connecting-path highcharts-color-" + fromPoint.colorIndex;
    options2 = merge$9(attribs, options2);
    if (!defined$4(options2.marker.radius)) {
      options2.marker.radius = min$2(max$2(Math.ceil((options2.algorithmMargin || 8) / 2) - 1, 1), 5);
    }
    const pathResult = connection.getPath(options2), path = pathResult.path;
    if (pathResult.obstacles) {
      pathfinder.lineObstacles = pathfinder.lineObstacles || [];
      pathfinder.lineObstacles = pathfinder.lineObstacles.concat(pathResult.obstacles);
    }
    connection.renderPath(path, attribs);
    connection.addMarker("start", merge$9(options2.marker, options2.startMarker), path);
    connection.addMarker("end", merge$9(options2.marker, options2.endMarker), path);
  }
  /**
   * Destroy connection by destroying the added graphics elements.
   *
   * @function Highcharts.Connection#destroy
   */
  destroy() {
    if (this.graphics) {
      objectEach(this.graphics, function(val) {
        val.destroy();
      });
      delete this.graphics;
    }
  }
}
const { composed } = Highcharts;
const { addEvent: addEvent$8, merge: merge$8, pushUnique, wrap: wrap$4 } = Utilities;
const defaultOptions$2 = {
  color: "#ccd3ff",
  width: 2,
  /**
   * @declare Highcharts.AxisCurrentDateIndicatorLabelOptions
   */
  label: {
    /**
     * Format of the label. This options is passed as the first argument to
     * [dateFormat](/class-reference/Highcharts.Time#dateFormat) function.
     *
     * @type      {string|Intl.DateTimeFormatOptions}
     * @product   gantt
     * @apioption xAxis.currentDateIndicator.label.format
     */
    format: "%[abdYHM]",
    formatter: function(value, format2) {
      return this.axis.chart.time.dateFormat(format2 || "", value, true);
    },
    rotation: 0,
    /**
     * @type {Highcharts.CSSObject}
     */
    style: {
      /** @internal */
      fontSize: "0.7em"
    }
  }
};
function compose$5(AxisClass, PlotLineOrBandClass) {
  if (pushUnique(composed, "CurrentDateIndication")) {
    addEvent$8(AxisClass, "afterSetOptions", onAxisAfterSetOptions$1);
    addEvent$8(PlotLineOrBandClass, "render", onPlotLineOrBandRender);
    wrap$4(PlotLineOrBandClass.prototype, "getLabelText", wrapPlotLineOrBandGetLabelText);
  }
}
function onAxisAfterSetOptions$1() {
  const options2 = this.options, cdiOptions = options2.currentDateIndicator;
  if (cdiOptions) {
    const plotLineOptions = typeof cdiOptions === "object" ? merge$8(defaultOptions$2, cdiOptions) : merge$8(defaultOptions$2);
    plotLineOptions.value = Date.now();
    plotLineOptions.className = "highcharts-current-date-indicator";
    if (!options2.plotLines) {
      options2.plotLines = [];
    }
    options2.plotLines.push(plotLineOptions);
  }
}
function onPlotLineOrBandRender() {
  if (this.label) {
    this.label.attr({
      text: this.getLabelText(this.options.label)
    });
  }
}
function wrapPlotLineOrBandGetLabelText(defaultMethod, defaultLabelOptions) {
  const options2 = this.options;
  if (options2 && options2.className && options2.className.indexOf("highcharts-current-date-indicator") !== -1 && options2.label && typeof options2.label.formatter === "function") {
    options2.value = Date.now();
    return options2.label.formatter.call(this, options2.value, options2.label.format);
  }
  return defaultMethod.call(this, defaultLabelOptions);
}
const CurrentDateIndication = {
  compose: compose$5
};
const { defaultOptions: defaultOptions$1 } = DefaultOptions;
const { isArray: isArray$3, merge: merge$7, splat: splat$2 } = Utilities;
class GanttChart extends Chart$1 {
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initializes the chart. The constructor's arguments are passed on
   * directly.
   *
   * @function Highcharts.GanttChart#init
   *
   * @param {Highcharts.Options} userOptions
   *        Custom options.
   *
   * @param {Function} [callback]
   *        Function to run when the chart has loaded and all external
   *        images are loaded.
   *
   *
   * @emits Highcharts.GanttChart#event:init
   * @emits Highcharts.GanttChart#event:afterInit
   */
  init(userOptions, callback) {
    const xAxisOptions = userOptions.xAxis, yAxisOptions = userOptions.yAxis;
    let defaultLinkedTo;
    userOptions.xAxis = userOptions.yAxis = void 0;
    const options2 = merge$7(
      true,
      {
        chart: {
          type: "gantt"
        },
        title: {
          text: ""
        },
        legend: {
          enabled: false
        },
        navigator: {
          series: { type: "gantt" },
          // Bars were clipped, #14060.
          yAxis: {
            type: "category"
          }
        }
      },
      userOptions,
      // User's options
      // forced options
      {
        isGantt: true
      }
    );
    userOptions.xAxis = xAxisOptions;
    userOptions.yAxis = yAxisOptions;
    options2.xAxis = (!isArray$3(userOptions.xAxis) ? [userOptions.xAxis || {}, {}] : userOptions.xAxis).map((xAxisOptions2, i) => {
      if (i === 1) {
        defaultLinkedTo = 0;
      }
      return merge$7(
        // Defaults
        {
          grid: {
            borderColor: "#cccccc",
            enabled: true
          },
          opposite: defaultOptions$1.xAxis?.opposite ?? xAxisOptions2.opposite ?? true,
          linkedTo: defaultLinkedTo
        },
        // User options
        xAxisOptions2,
        // Forced options
        {
          type: "datetime"
        }
      );
    });
    options2.yAxis = splat$2(userOptions.yAxis || {}).map((yAxisOptions2) => merge$7(
      // Defaults
      {
        grid: {
          borderColor: "#cccccc",
          enabled: true
        },
        staticScale: 50,
        reversed: true,
        // Set default type treegrid, but only if 'categories' is
        // undefined
        type: yAxisOptions2.categories ? yAxisOptions2.type : "treegrid"
      },
      // User options
      yAxisOptions2
    ));
    super.init(options2, callback);
  }
}
(function(GanttChart2) {
  function ganttChart(a, b, c) {
    return new GanttChart2(a, b, c);
  }
  GanttChart2.ganttChart = ganttChart;
})(GanttChart || (GanttChart = {}));
const GanttChart$1 = GanttChart;
const { pick: pick$8 } = Utilities;
const { min: min$1, max: max$1, abs } = Math;
function findLastObstacleBefore(obstacles, xMin, startIx) {
  const min2 = xMin - 1e-7;
  let left = 0, right = obstacles.length - 1, cursor, cmp;
  while (left <= right) {
    cursor = right + left >> 1;
    cmp = min2 - obstacles[cursor].xMin;
    if (cmp > 0) {
      left = cursor + 1;
    } else if (cmp < 0) {
      right = cursor - 1;
    } else {
      return cursor;
    }
  }
  return left > 0 ? left - 1 : 0;
}
function pointWithinObstacle(obstacle, point) {
  return point.x <= obstacle.xMax && point.x >= obstacle.xMin && point.y <= obstacle.yMax && point.y >= obstacle.yMin;
}
function findObstacleFromPoint(obstacles, point) {
  let i = findLastObstacleBefore(obstacles, point.x + 1) + 1;
  while (i--) {
    if (obstacles[i].xMax >= point.x && // Optimization using lazy evaluation
    pointWithinObstacle(obstacles[i], point)) {
      return i;
    }
  }
  return -1;
}
function pathFromSegments(segments) {
  const path = [];
  if (segments.length) {
    path.push(["M", segments[0].start.x, segments[0].start.y]);
    for (let i = 0; i < segments.length; ++i) {
      path.push(["L", segments[i].end.x, segments[i].end.y]);
    }
  }
  return path;
}
function limitObstacleToBounds(obstacle, bounds) {
  obstacle.yMin = max$1(obstacle.yMin, bounds.yMin);
  obstacle.yMax = min$1(obstacle.yMax, bounds.yMax);
  obstacle.xMin = max$1(obstacle.xMin, bounds.xMin);
  obstacle.xMax = min$1(obstacle.xMax, bounds.xMax);
}
function straight(start2, end) {
  return {
    path: [
      ["M", start2.x, start2.y],
      ["L", end.x, end.y]
    ],
    obstacles: [{ start: start2, end }]
  };
}
const simpleConnect = function(start2, end, options2) {
  const segments = [], chartObstacles = options2.chartObstacles, startObstacleIx = findObstacleFromPoint(chartObstacles, start2), endObstacleIx = findObstacleFromPoint(chartObstacles, end);
  let endSegment, dir = pick$8(options2.startDirectionX, abs(end.x - start2.x) > abs(end.y - start2.y)) ? "x" : "y", startObstacle, endObstacle, waypoint, useMax, endPoint;
  function copyFromPoint(from, fromKey, to, toKey, offset2) {
    const point = {
      x: from.x,
      y: from.y
    };
    point[fromKey] = to[toKey || fromKey] + (offset2 || 0);
    return point;
  }
  function getMeOut(obstacle, point, direction) {
    const useMax2 = abs(point[direction] - obstacle[direction + "Min"]) > abs(point[direction] - obstacle[direction + "Max"]);
    return copyFromPoint(point, direction, obstacle, direction + (useMax2 ? "Max" : "Min"), useMax2 ? 1 : -1);
  }
  if (endObstacleIx > -1) {
    endObstacle = chartObstacles[endObstacleIx];
    waypoint = getMeOut(endObstacle, end, dir);
    endSegment = {
      start: waypoint,
      end
    };
    endPoint = waypoint;
  } else {
    endPoint = end;
  }
  if (startObstacleIx > -1) {
    startObstacle = chartObstacles[startObstacleIx];
    waypoint = getMeOut(startObstacle, start2, dir);
    segments.push({
      start: start2,
      end: waypoint
    });
    if (
      // Going towards max from start:
      waypoint[dir] >= start2[dir] === // Going towards min to end:
      waypoint[dir] >= endPoint[dir]
    ) {
      dir = dir === "y" ? "x" : "y";
      useMax = start2[dir] < end[dir];
      segments.push({
        start: waypoint,
        end: copyFromPoint(waypoint, dir, startObstacle, dir + (useMax ? "Max" : "Min"), useMax ? 1 : -1)
      });
      dir = dir === "y" ? "x" : "y";
    }
  }
  const prevWaypoint = segments.length ? segments[segments.length - 1].end : start2;
  waypoint = copyFromPoint(prevWaypoint, dir, endPoint);
  segments.push({
    start: prevWaypoint,
    end: waypoint
  });
  dir = dir === "y" ? "x" : "y";
  const waypoint2 = copyFromPoint(waypoint, dir, endPoint);
  segments.push({
    start: waypoint,
    end: waypoint2
  });
  segments.push(endSegment);
  const path = PathUtilities.applyRadius(pathFromSegments(segments), options2.radius);
  return {
    path,
    obstacles: segments
  };
};
simpleConnect.requiresObstacles = true;
function fastAvoid(start2, end, options2) {
  const dirIsX = pick$8(options2.startDirectionX, abs(end.x - start2.x) > abs(end.y - start2.y)), dir = dirIsX ? "x" : "y", endSegments = [], metrics = options2.obstacleMetrics, softMinX = min$1(start2.x, end.x) - metrics.maxWidth - 10, softMaxX = max$1(start2.x, end.x) + metrics.maxWidth + 10, softMinY = min$1(start2.y, end.y) - metrics.maxHeight - 10, softMaxY = max$1(start2.y, end.y) + metrics.maxHeight + 10;
  let segments, useMax, extractedEndPoint, forceObstacleBreak = false, chartObstacles = options2.chartObstacles, endObstacleIx = findLastObstacleBefore(chartObstacles, softMaxX);
  const startObstacleIx = findLastObstacleBefore(chartObstacles, softMinX);
  function pivotPoint(fromPoint, toPoint2, directionIsX) {
    const searchDirection = fromPoint.x < toPoint2.x ? 1 : -1;
    let firstPoint, lastPoint, highestPoint, lowestPoint;
    if (fromPoint.x < toPoint2.x) {
      firstPoint = fromPoint;
      lastPoint = toPoint2;
    } else {
      firstPoint = toPoint2;
      lastPoint = fromPoint;
    }
    if (fromPoint.y < toPoint2.y) {
      lowestPoint = fromPoint;
      highestPoint = toPoint2;
    } else {
      lowestPoint = toPoint2;
      highestPoint = fromPoint;
    }
    let i = searchDirection < 0 ? (
      // Searching backwards, start at last obstacle before last point
      min$1(findLastObstacleBefore(chartObstacles, lastPoint.x), chartObstacles.length - 1)
    ) : (
      // Forwards. Since we're not sorted by xMax, we have to look
      // at all obstacles.
      0
    );
    while (chartObstacles[i] && (searchDirection > 0 && chartObstacles[i].xMin <= lastPoint.x || searchDirection < 0 && chartObstacles[i].xMax >= firstPoint.x)) {
      if (chartObstacles[i].xMin <= lastPoint.x && chartObstacles[i].xMax >= firstPoint.x && chartObstacles[i].yMin <= highestPoint.y && chartObstacles[i].yMax >= lowestPoint.y) {
        if (directionIsX) {
          return {
            y: fromPoint.y,
            x: fromPoint.x < toPoint2.x ? chartObstacles[i].xMin - 1 : chartObstacles[i].xMax + 1,
            obstacle: chartObstacles[i]
          };
        }
        return {
          x: fromPoint.x,
          y: fromPoint.y < toPoint2.y ? chartObstacles[i].yMin - 1 : chartObstacles[i].yMax + 1,
          obstacle: chartObstacles[i]
        };
      }
      i += searchDirection;
    }
    return toPoint2;
  }
  function getDodgeDirection(obstacle, fromPoint, toPoint2, dirIsX2, bounds) {
    const softBounds = bounds.soft, hardBounds = bounds.hard, dir2 = dirIsX2 ? "x" : "y", toPointMax = { x: fromPoint.x, y: fromPoint.y }, toPointMin = { x: fromPoint.x, y: fromPoint.y }, maxOutOfSoftBounds = obstacle[dir2 + "Max"] >= softBounds[dir2 + "Max"], minOutOfSoftBounds = obstacle[dir2 + "Min"] <= softBounds[dir2 + "Min"], maxOutOfHardBounds = obstacle[dir2 + "Max"] >= hardBounds[dir2 + "Max"], minOutOfHardBounds = obstacle[dir2 + "Min"] <= hardBounds[dir2 + "Min"], minDistance = abs(obstacle[dir2 + "Min"] - fromPoint[dir2]), maxDistance = abs(obstacle[dir2 + "Max"] - fromPoint[dir2]);
    let useMax2 = abs(minDistance - maxDistance) < 10 ? fromPoint[dir2] < toPoint2[dir2] : maxDistance < minDistance;
    toPointMin[dir2] = obstacle[dir2 + "Min"];
    toPointMax[dir2] = obstacle[dir2 + "Max"];
    const minPivot = pivotPoint(fromPoint, toPointMin, dirIsX2)[dir2] !== toPointMin[dir2], maxPivot = pivotPoint(fromPoint, toPointMax, dirIsX2)[dir2] !== toPointMax[dir2];
    useMax2 = minPivot ? maxPivot ? useMax2 : true : maxPivot ? false : useMax2;
    useMax2 = minOutOfSoftBounds ? maxOutOfSoftBounds ? useMax2 : true : (
      // Out on min
      maxOutOfSoftBounds ? false : useMax2
    );
    useMax2 = minOutOfHardBounds ? maxOutOfHardBounds ? useMax2 : true : (
      // Out on min
      maxOutOfHardBounds ? false : useMax2
    );
    return useMax2;
  }
  function clearPathTo(fromPoint, toPoint2, dirIsX2) {
    if (fromPoint.x === toPoint2.x && fromPoint.y === toPoint2.y) {
      return [];
    }
    const dir2 = dirIsX2 ? "x" : "y", obstacleMargin = options2.obstacleOptions.margin, bounds = {
      soft: {
        xMin: softMinX,
        xMax: softMaxX,
        yMin: softMinY,
        yMax: softMaxY
      },
      hard: options2.hardBounds
    };
    let pivot, segments2, waypoint, waypointUseMax, envelopingObstacle, secondEnvelopingObstacle, envelopWaypoint;
    envelopingObstacle = findObstacleFromPoint(chartObstacles, fromPoint);
    if (envelopingObstacle > -1) {
      envelopingObstacle = chartObstacles[envelopingObstacle];
      waypointUseMax = getDodgeDirection(envelopingObstacle, fromPoint, toPoint2, dirIsX2, bounds);
      limitObstacleToBounds(envelopingObstacle, options2.hardBounds);
      envelopWaypoint = dirIsX2 ? {
        y: fromPoint.y,
        x: envelopingObstacle[waypointUseMax ? "xMax" : "xMin"] + (waypointUseMax ? 1 : -1)
      } : {
        x: fromPoint.x,
        y: envelopingObstacle[waypointUseMax ? "yMax" : "yMin"] + (waypointUseMax ? 1 : -1)
      };
      secondEnvelopingObstacle = findObstacleFromPoint(chartObstacles, envelopWaypoint);
      if (secondEnvelopingObstacle > -1) {
        secondEnvelopingObstacle = chartObstacles[secondEnvelopingObstacle];
        limitObstacleToBounds(secondEnvelopingObstacle, options2.hardBounds);
        envelopWaypoint[dir2] = waypointUseMax ? max$1(envelopingObstacle[dir2 + "Max"] - obstacleMargin + 1, (secondEnvelopingObstacle[dir2 + "Min"] + envelopingObstacle[dir2 + "Max"]) / 2) : min$1(envelopingObstacle[dir2 + "Min"] + obstacleMargin - 1, (secondEnvelopingObstacle[dir2 + "Max"] + envelopingObstacle[dir2 + "Min"]) / 2);
        if (fromPoint.x === envelopWaypoint.x && fromPoint.y === envelopWaypoint.y) {
          if (forceObstacleBreak) {
            envelopWaypoint[dir2] = waypointUseMax ? max$1(envelopingObstacle[dir2 + "Max"], secondEnvelopingObstacle[dir2 + "Max"]) + 1 : min$1(envelopingObstacle[dir2 + "Min"], secondEnvelopingObstacle[dir2 + "Min"]) - 1;
          }
          forceObstacleBreak = !forceObstacleBreak;
        } else {
          forceObstacleBreak = false;
        }
      }
      segments2 = [{
        start: fromPoint,
        end: envelopWaypoint
      }];
    } else {
      pivot = pivotPoint(fromPoint, {
        x: dirIsX2 ? toPoint2.x : fromPoint.x,
        y: dirIsX2 ? fromPoint.y : toPoint2.y
      }, dirIsX2);
      segments2 = [{
        start: fromPoint,
        end: {
          x: pivot.x,
          y: pivot.y
        }
      }];
      if (pivot[dirIsX2 ? "x" : "y"] !== toPoint2[dirIsX2 ? "x" : "y"]) {
        waypointUseMax = getDodgeDirection(pivot.obstacle, pivot, toPoint2, !dirIsX2, bounds);
        limitObstacleToBounds(pivot.obstacle, options2.hardBounds);
        waypoint = {
          x: dirIsX2 ? pivot.x : pivot.obstacle[waypointUseMax ? "xMax" : "xMin"] + (waypointUseMax ? 1 : -1),
          y: dirIsX2 ? pivot.obstacle[waypointUseMax ? "yMax" : "yMin"] + (waypointUseMax ? 1 : -1) : pivot.y
        };
        dirIsX2 = !dirIsX2;
        segments2 = segments2.concat(clearPathTo({
          x: pivot.x,
          y: pivot.y
        }, waypoint, dirIsX2));
      }
    }
    segments2 = segments2.concat(clearPathTo(segments2[segments2.length - 1].end, toPoint2, !dirIsX2));
    return segments2;
  }
  function extractFromObstacle(obstacle, point, goalPoint) {
    const dirIsX2 = min$1(obstacle.xMax - point.x, point.x - obstacle.xMin) < min$1(obstacle.yMax - point.y, point.y - obstacle.yMin), bounds = {
      soft: options2.hardBounds,
      hard: options2.hardBounds
    }, useMax2 = getDodgeDirection(obstacle, point, goalPoint, dirIsX2, bounds);
    return dirIsX2 ? {
      y: point.y,
      x: obstacle[useMax2 ? "xMax" : "xMin"] + (useMax2 ? 1 : -1)
    } : {
      x: point.x,
      y: obstacle[useMax2 ? "yMax" : "yMin"] + (useMax2 ? 1 : -1)
    };
  }
  chartObstacles = chartObstacles.slice(startObstacleIx, endObstacleIx + 1);
  if ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
    extractedEndPoint = extractFromObstacle(chartObstacles[endObstacleIx], end, start2);
    endSegments.push({
      end,
      start: extractedEndPoint
    });
    end = extractedEndPoint;
  }
  while ((endObstacleIx = findObstacleFromPoint(chartObstacles, end)) > -1) {
    useMax = end[dir] - start2[dir] < 0;
    extractedEndPoint = {
      x: end.x,
      y: end.y
    };
    extractedEndPoint[dir] = chartObstacles[endObstacleIx][useMax ? dir + "Max" : dir + "Min"] + (useMax ? 1 : -1);
    endSegments.push({
      end,
      start: extractedEndPoint
    });
    end = extractedEndPoint;
  }
  segments = clearPathTo(start2, end, dirIsX);
  segments = segments.concat(endSegments.reverse());
  return {
    path: pathFromSegments(segments),
    obstacles: segments
  };
}
fastAvoid.requiresObstacles = true;
const algorithms = {
  fastAvoid,
  straight,
  simpleConnect
};
const connectorsDefaults = {
  /**
   * The Pathfinder module allows you to define connections between any two
   * points, represented as lines - optionally with markers for the start
   * and/or end points. Multiple algorithms are available for calculating how
   * the connecting lines are drawn.
   *
   * Connector functionality requires Highcharts Gantt to be loaded. In Gantt
   * charts, the connectors are used to draw dependencies between tasks.
   *
   * @see [dependency](series.gantt.data.dependency)
   *
   * @sample gantt/pathfinder/demo
   *         Pathfinder connections
   *
   * @declare      Highcharts.ConnectorsOptions
   * @product      gantt
   * @optionparent connectors
   */
  connectors: {
    /**
     * Enable connectors for this chart. Requires Highcharts Gantt.
     *
     * @type      {boolean}
     * @default   true
     * @since     6.2.0
     * @apioption connectors.enabled
     */
    /**
     * Set the default dash style for this chart's connecting lines.
     *
     * @type      {string}
     * @default   solid
     * @since     6.2.0
     * @apioption connectors.dashStyle
     */
    /**
     * Set the default color for this chart's Pathfinder connecting lines.
     * Defaults to the color of the point being connected.
     *
     * @type      {Highcharts.ColorString}
     * @since     6.2.0
     * @apioption connectors.lineColor
     */
    /**
     * Set the default pathfinder margin to use, in pixels. Some Pathfinder
     * algorithms attempt to avoid obstacles, such as other points in the
     * chart. These algorithms use this margin to determine how close lines
     * can be to an obstacle. The default is to compute this automatically
     * from the size of the obstacles in the chart.
     *
     * To draw connecting lines close to existing points, set this to a low
     * number. For more space around existing points, set this number
     * higher.
     *
     * @sample gantt/pathfinder/algorithm-margin
     *         Small algorithmMargin
     *
     * @type      {number}
     * @since     6.2.0
     * @apioption connectors.algorithmMargin
     */
    /**
     * Set the default pathfinder algorithm to use for this chart. It is
     * possible to define your own algorithms by adding them to the
     * Highcharts.Pathfinder.prototype.algorithms object before the chart
     * has been created.
     *
     * The default algorithms are as follows:
     *
     * `straight`:      Draws a straight line between the connecting
     *                  points. Does not avoid other points when drawing.
     *
     * `simpleConnect`: Finds a path between the points using right angles
     *                  only. Takes only starting/ending points into
     *                  account, and will not avoid other points.
     *
     * `fastAvoid`:     Finds a path between the points using right angles
     *                  only. Will attempt to avoid other points, but its
     *                  focus is performance over accuracy. Works well with
     *                  less dense datasets.
     *
     * Default value: `straight` is used as default for most series types,
     * while `simpleConnect` is used as default for Gantt series, to show
     * dependencies between points.
     *
     * @sample gantt/pathfinder/demo
     *         Different types used
     *
     * @type    {Highcharts.PathfinderTypeValue}
     * @default undefined
     * @since   6.2.0
     */
    type: "straight",
    /**
     * The corner radius for the connector line.
     *
     * @since 11.2.0
     */
    radius: 0,
    /**
     * Set the default pixel width for this chart's Pathfinder connecting
     * lines.
     *
     * @since 6.2.0
     */
    lineWidth: 1,
    /**
     * Marker options for this chart's Pathfinder connectors. Note that
     * this option is overridden by the `startMarker` and `endMarker`
     * options.
     *
     * @declare Highcharts.ConnectorsMarkerOptions
     * @since   6.2.0
     */
    marker: {
      /**
       * Set the radius of the connector markers. The default is
       * automatically computed based on the algorithmMargin setting.
       *
       * Setting marker.width and marker.height will override this
       * setting.
       *
       * @type      {number}
       * @since     6.2.0
       * @apioption connectors.marker.radius
       */
      /**
       * Set the width of the connector markers. If not supplied, this
       * is inferred from the marker radius.
       *
       * @type      {number}
       * @since     6.2.0
       * @apioption connectors.marker.width
       */
      /**
       * Set the height of the connector markers. If not supplied, this
       * is inferred from the marker radius.
       *
       * @type      {number}
       * @since     6.2.0
       * @apioption connectors.marker.height
       */
      /**
       * Set the color of the connector markers. By default this is the
       * same as the connector color.
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @since     6.2.0
       * @apioption connectors.marker.color
       */
      /**
       * Set the line/border color of the connector markers. By default
       * this is the same as the marker color.
       *
       * @type      {Highcharts.ColorString}
       * @since     6.2.0
       * @apioption connectors.marker.lineColor
       */
      /**
       * Enable markers for the connectors.
       */
      enabled: false,
      /**
       * Horizontal alignment of the markers relative to the points.
       *
       * @type {Highcharts.AlignValue}
       */
      align: "center",
      /**
       * Vertical alignment of the markers relative to the points.
       *
       * @type {Highcharts.VerticalAlignValue}
       */
      verticalAlign: "middle",
      /**
       * Whether or not to draw the markers inside the points.
       */
      inside: false,
      /**
       * Set the line/border width of the pathfinder markers.
       */
      lineWidth: 1
    },
    /**
     * Marker options specific to the start markers for this chart's
     * Pathfinder connectors. Overrides the generic marker options.
     *
     * @declare Highcharts.ConnectorsStartMarkerOptions
     * @extends connectors.marker
     * @since   6.2.0
     */
    startMarker: {
      /**
       * Set the symbol of the connector start markers.
       */
      symbol: "diamond"
    },
    /**
     * Marker options specific to the end markers for this chart's
     * Pathfinder connectors. Overrides the generic marker options.
     *
     * @declare Highcharts.ConnectorsEndMarkerOptions
     * @extends connectors.marker
     * @since   6.2.0
     */
    endMarker: {
      /**
       * Set the symbol of the connector end markers.
       */
      symbol: "arrow-filled"
    }
  }
};
const { setOptions } = DefaultOptions;
const { defined: defined$3, error, merge: merge$6 } = Utilities;
function getPointBB$1(point) {
  const shapeArgs = point.shapeArgs;
  if (shapeArgs) {
    return {
      xMin: shapeArgs.x || 0,
      xMax: (shapeArgs.x || 0) + (shapeArgs.width || 0),
      yMin: shapeArgs.y || 0,
      yMax: (shapeArgs.y || 0) + (shapeArgs.height || 0)
    };
  }
  const bb = point.graphic && point.graphic.getBBox();
  return bb ? {
    xMin: point.plotX - bb.width / 2,
    xMax: point.plotX + bb.width / 2,
    yMin: point.plotY - bb.height / 2,
    yMax: point.plotY + bb.height / 2
  } : null;
}
function warnLegacy(chart) {
  if (chart.options.pathfinder || chart.series.reduce(function(acc, series) {
    if (series.options) {
      merge$6(true, series.options.connectors = series.options.connectors || {}, series.options.pathfinder);
    }
    return acc || series.options && series.options.pathfinder;
  }, false)) {
    merge$6(true, chart.options.connectors = chart.options.connectors || {}, chart.options.pathfinder);
    error('WARNING: Pathfinder options have been renamed. Use "chart.connectors" or "series.connectors" instead.');
  }
}
var ConnectionComposition;
(function(ConnectionComposition2) {
  function compose2(ChartClass, PathfinderClass, PointClass) {
    const pointProto2 = PointClass.prototype;
    if (!pointProto2.getPathfinderAnchorPoint) {
      ChartClass.prototype.callbacks.push(function(chart) {
        const options2 = chart.options;
        if (options2.connectors.enabled !== false) {
          warnLegacy(chart);
          this.pathfinder = new PathfinderClass(this);
          this.pathfinder.update(true);
        }
      });
      pointProto2.getMarkerVector = pointGetMarkerVector;
      pointProto2.getPathfinderAnchorPoint = pointGetPathfinderAnchorPoint;
      pointProto2.getRadiansToVector = pointGetRadiansToVector;
      setOptions(connectorsDefaults);
    }
  }
  ConnectionComposition2.compose = compose2;
  function pointGetPathfinderAnchorPoint(markerOptions) {
    const bb = getPointBB$1(this);
    let x, y;
    switch (markerOptions.align) {
      // eslint-disable-line default-case
      case "right":
        x = "xMax";
        break;
      case "left":
        x = "xMin";
    }
    switch (markerOptions.verticalAlign) {
      // eslint-disable-line default-case
      case "top":
        y = "yMin";
        break;
      case "bottom":
        y = "yMax";
    }
    return {
      x: x ? bb[x] : (bb.xMin + bb.xMax) / 2,
      y: y ? bb[y] : (bb.yMin + bb.yMax) / 2
    };
  }
  function pointGetRadiansToVector(v1, v2) {
    let box;
    if (!defined$3(v2)) {
      box = getPointBB$1(this);
      if (box) {
        v2 = {
          x: (box.xMin + box.xMax) / 2,
          y: (box.yMin + box.yMax) / 2
        };
      }
    }
    return Math.atan2(v2.y - v1.y, v1.x - v2.x);
  }
  function pointGetMarkerVector(radians, markerRadius, anchor) {
    const twoPI = Math.PI * 2, bb = getPointBB$1(this), rectWidth = bb.xMax - bb.xMin, rectHeight = bb.yMax - bb.yMin, rAtan = Math.atan2(rectHeight, rectWidth), rectHalfWidth = rectWidth / 2, rectHalfHeight = rectHeight / 2, rectHorizontalCenter = bb.xMin + rectHalfWidth, rectVerticalCenter = bb.yMin + rectHalfHeight, edgePoint = {
      x: rectHorizontalCenter,
      y: rectVerticalCenter
    };
    let theta = radians, tanTheta = 1, leftOrRightRegion = false, xFactor = 1, yFactor = 1;
    while (theta < -Math.PI) {
      theta += twoPI;
    }
    while (theta > Math.PI) {
      theta -= twoPI;
    }
    tanTheta = Math.tan(theta);
    if (theta > -rAtan && theta <= rAtan) {
      yFactor = -1;
      leftOrRightRegion = true;
    } else if (theta > rAtan && theta <= Math.PI - rAtan) {
      yFactor = -1;
    } else if (theta > Math.PI - rAtan || theta <= -(Math.PI - rAtan)) {
      xFactor = -1;
      leftOrRightRegion = true;
    } else {
      xFactor = -1;
    }
    if (leftOrRightRegion) {
      edgePoint.x += xFactor * rectHalfWidth;
      edgePoint.y += yFactor * rectHalfWidth * tanTheta;
    } else {
      edgePoint.x += xFactor * (rectHeight / (2 * tanTheta));
      edgePoint.y += yFactor * rectHalfHeight;
    }
    if (anchor.x !== rectHorizontalCenter) {
      edgePoint.x = anchor.x;
    }
    if (anchor.y !== rectVerticalCenter) {
      edgePoint.y = anchor.y;
    }
    return {
      x: edgePoint.x + markerRadius * Math.cos(theta),
      y: edgePoint.y - markerRadius * Math.sin(theta)
    };
  }
})(ConnectionComposition || (ConnectionComposition = {}));
const PathfinderComposition = ConnectionComposition;
const { addEvent: addEvent$7, defined: defined$2, pick: pick$7, splat: splat$1 } = Utilities;
const max = Math.max, min = Math.min;
function getPointBB(point) {
  const shapeArgs = point.shapeArgs;
  if (shapeArgs) {
    return {
      xMin: shapeArgs.x || 0,
      xMax: (shapeArgs.x || 0) + (shapeArgs.width || 0),
      yMin: shapeArgs.y || 0,
      yMax: (shapeArgs.y || 0) + (shapeArgs.height || 0)
    };
  }
  const bb = point.graphic && point.graphic.getBBox();
  return bb ? {
    xMin: point.plotX - bb.width / 2,
    xMax: point.plotX + bb.width / 2,
    yMin: point.plotY - bb.height / 2,
    yMax: point.plotY + bb.height / 2
  } : null;
}
function calculateObstacleDistance(a, b, bbMargin) {
  const margin = pick$7(bbMargin, 10), yOverlap = a.yMax + margin > b.yMin - margin && a.yMin - margin < b.yMax + margin, xOverlap = a.xMax + margin > b.xMin - margin && a.xMin - margin < b.xMax + margin, xDistance = yOverlap ? a.xMin > b.xMax ? a.xMin - b.xMax : b.xMin - a.xMax : Infinity, yDistance = xOverlap ? a.yMin > b.yMax ? a.yMin - b.yMax : b.yMin - a.yMax : Infinity;
  if (xOverlap && yOverlap) {
    return margin ? calculateObstacleDistance(a, b, Math.floor(margin / 2)) : Infinity;
  }
  return min(xDistance, yDistance);
}
function calculateObstacleMargin(obstacles) {
  const len = obstacles.length, distances = [];
  let onstacleDistance;
  for (let i = 0; i < len; ++i) {
    for (let j = i + 1; j < len; ++j) {
      onstacleDistance = calculateObstacleDistance(obstacles[i], obstacles[j]);
      if (onstacleDistance < 80) {
        distances.push(onstacleDistance);
      }
    }
  }
  distances.push(80);
  return max(
    Math.floor(
      distances.sort(function(a, b) {
        return a - b;
      })[
        // Discard first 10% of the relevant distances, and then grab
        // the smallest one.
        Math.floor(distances.length / 10)
      ] / 2 - 1
      // Divide the distance by 2 and subtract 1.
    ),
    1
    // 1 is the minimum margin
  );
}
class Pathfinder {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(ChartClass, PointClass) {
    PathfinderComposition.compose(ChartClass, Pathfinder, PointClass);
  }
  /* *
   *
   *  Constructor
   *
   * */
  constructor(chart) {
    this.init(chart);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Initialize the Pathfinder object.
   *
   * @function Highcharts.Pathfinder#init
   *
   * @param {Highcharts.Chart} chart
   *        The chart context.
   */
  init(chart) {
    this.chart = chart;
    this.connections = [];
    addEvent$7(chart, "redraw", function() {
      this.pathfinder.update();
    });
  }
  /**
   * Update Pathfinder connections from scratch.
   *
   * @function Highcharts.Pathfinder#update
   *
   * @param {boolean} [deferRender]
   *        Whether or not to defer rendering of connections until
   *        series.afterAnimate event has fired. Used on first render.
   */
  update(deferRender) {
    const chart = this.chart, pathfinder = this, oldConnections = pathfinder.connections;
    pathfinder.connections = [];
    chart.series.forEach(function(series) {
      if (series.visible && !series.options.isInternal) {
        series.points.forEach(function(point) {
          const ganttPointOptions = point.options;
          if (ganttPointOptions && ganttPointOptions.dependency) {
            ganttPointOptions.connect = ganttPointOptions.dependency;
          }
          const connects = point.options?.connect ? splat$1(point.options.connect) : [];
          let to;
          if (point.visible && point.isInside !== false) {
            connects.forEach((connect) => {
              const toId = typeof connect === "string" ? connect : connect.to;
              if (toId) {
                to = chart.get(toId);
              }
              if (to instanceof Point$3 && to.series.visible && to.visible && to.isInside !== false) {
                pathfinder.connections.push(new Connection(
                  point,
                  // From
                  to,
                  typeof connect === "string" ? {} : connect
                ));
              }
            });
          }
        });
      }
    });
    for (let j = 0, k, found, lenOld = oldConnections.length, lenNew = pathfinder.connections.length; j < lenOld; ++j) {
      found = false;
      const oldCon = oldConnections[j];
      for (k = 0; k < lenNew; ++k) {
        const newCon = pathfinder.connections[k];
        if ((oldCon.options && oldCon.options.type) === (newCon.options && newCon.options.type) && oldCon.fromPoint === newCon.fromPoint && oldCon.toPoint === newCon.toPoint) {
          newCon.graphics = oldCon.graphics;
          found = true;
          break;
        }
      }
      if (!found) {
        oldCon.destroy();
      }
    }
    delete this.chartObstacles;
    delete this.lineObstacles;
    pathfinder.renderConnections(deferRender);
  }
  /**
   * Draw the chart's connecting paths.
   *
   * @function Highcharts.Pathfinder#renderConnections
   *
   * @param {boolean} [deferRender]
   *        Whether or not to defer render until series animation is finished.
   *        Used on first render.
   */
  renderConnections(deferRender) {
    if (deferRender) {
      this.chart.series.forEach(function(series) {
        const render2 = function() {
          const pathfinder = series.chart.pathfinder, conns = pathfinder && pathfinder.connections || [];
          conns.forEach(function(connection) {
            if (connection.fromPoint && connection.fromPoint.series === series) {
              connection.render();
            }
          });
          if (series.pathfinderRemoveRenderEvent) {
            series.pathfinderRemoveRenderEvent();
            delete series.pathfinderRemoveRenderEvent;
          }
        };
        if (series.options.animation === false) {
          render2();
        } else {
          series.pathfinderRemoveRenderEvent = addEvent$7(series, "afterAnimate", render2);
        }
      });
    } else {
      this.connections.forEach(function(connection) {
        connection.render();
      });
    }
  }
  /**
       * Get obstacles for the points in the chart. Does not include connecting
       * lines from Pathfinder. Applies algorithmMargin to the obstacles.
       *
       * @function Highcharts.Pathfinder#getChartObstacles
       *
       * @param {Object} options
       *        Options for the calculation. Currently only
       *        `options.algorithmMargin`.
       *
       * @param {number} options.algorithmMargin
       *        The algorithm margin to use for the obstacles.
  
      * @return {Array<object>}
       *         An array of calculated obstacles. Each obstacle is defined as an
       *         object with xMin, xMax, yMin and yMax properties.
       */
  getChartObstacles(options2) {
    const series = this.chart.series, margin = pick$7(options2.algorithmMargin, 0);
    let obstacles = [], calculatedMargin;
    for (let i = 0, sLen = series.length; i < sLen; ++i) {
      if (series[i].visible && !series[i].options.isInternal) {
        for (let j = 0, pLen = series[i].points.length, bb, point; j < pLen; ++j) {
          point = series[i].points[j];
          if (point.visible) {
            bb = getPointBB(point);
            if (bb) {
              obstacles.push({
                xMin: bb.xMin - margin,
                xMax: bb.xMax + margin,
                yMin: bb.yMin - margin,
                yMax: bb.yMax + margin
              });
            }
          }
        }
      }
    }
    obstacles = obstacles.sort(function(a, b) {
      return a.xMin - b.xMin;
    });
    if (!defined$2(options2.algorithmMargin)) {
      calculatedMargin = options2.algorithmMargin = calculateObstacleMargin(obstacles);
      obstacles.forEach(function(obstacle) {
        obstacle.xMin -= calculatedMargin;
        obstacle.xMax += calculatedMargin;
        obstacle.yMin -= calculatedMargin;
        obstacle.yMax += calculatedMargin;
      });
    }
    return obstacles;
  }
  /**
   * Utility function to get metrics for obstacles:
   * - Widest obstacle width
   * - Tallest obstacle height
   *
   * @function Highcharts.Pathfinder#getObstacleMetrics
   *
   * @param {Array<object>} obstacles
   *        An array of obstacles to inspect.
   *
   * @return {Object}
   *         The calculated metrics, as an object with maxHeight and maxWidth
   *         properties.
   */
  getObstacleMetrics(obstacles) {
    let maxWidth = 0, maxHeight = 0, width, height, i = obstacles.length;
    while (i--) {
      width = obstacles[i].xMax - obstacles[i].xMin;
      height = obstacles[i].yMax - obstacles[i].yMin;
      if (maxWidth < width) {
        maxWidth = width;
      }
      if (maxHeight < height) {
        maxHeight = height;
      }
    }
    return {
      maxHeight,
      maxWidth
    };
  }
  /**
   * Utility to get which direction to start the pathfinding algorithm
   * (X vs Y), calculated from a set of marker options.
   *
   * @function Highcharts.Pathfinder#getAlgorithmStartDirection
   *
   * @param {Highcharts.ConnectorsMarkerOptions} markerOptions
   *        Marker options to calculate from.
   *
   * @return {boolean}
   *         Returns true for X, false for Y, and undefined for autocalculate.
   */
  getAlgorithmStartDirection(markerOptions) {
    const xCenter = markerOptions.align !== "left" && markerOptions.align !== "right", yCenter = markerOptions.verticalAlign !== "top" && markerOptions.verticalAlign !== "bottom";
    return xCenter ? yCenter ? void 0 : false : (
      // When x is centered
      yCenter ? true : void 0
    );
  }
}
Pathfinder.prototype.algorithms = algorithms;
/**
 * @license Highcharts Gantt JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/pathfinder
 * @requires highcharts
 *
 * Pathfinder
 *
 * (c) 2016-2025 Øystein Moseng
 *
 * License: www.highcharts.com/license
 */
const G$3 = Highcharts;
G$3.Pathfinder = G$3.Pathfinder || Pathfinder;
ArrowSymbols.compose(G$3.SVGRenderer);
G$3.Pathfinder.compose(G$3.Chart, G$3.Point);
const { addEvent: addEvent$6, defined: defined$1, isNumber: isNumber$7, pick: pick$6 } = Utilities;
function compose$4(AxisClass, ChartClass) {
  const chartProto = ChartClass.prototype;
  if (!chartProto.adjustHeight) {
    addEvent$6(AxisClass, "afterSetOptions", onAxisAfterSetOptions);
    chartProto.adjustHeight = chartAdjustHeight;
    addEvent$6(ChartClass, "render", chartProto.adjustHeight);
  }
}
function onAxisAfterSetOptions() {
  const chartOptions = this.chart.options.chart;
  if (!this.horiz && isNumber$7(this.options.staticScale) && (!chartOptions.height || chartOptions.scrollablePlotArea && chartOptions.scrollablePlotArea.minHeight)) {
    this.staticScale = this.options.staticScale;
  }
}
function chartAdjustHeight() {
  const chart = this;
  if (chart.redrawTrigger !== "adjustHeight") {
    for (const axis of chart.axes || []) {
      const chart2 = axis.chart, animate2 = !!chart2.initiatedScale && chart2.options.animation, staticScale = axis.options.staticScale;
      if (axis.staticScale && defined$1(axis.min)) {
        let height = pick$6(axis.brokenAxis && axis.brokenAxis.unitLength, axis.max + axis.tickInterval - axis.min) * staticScale;
        height = Math.max(height, staticScale);
        const diff = height - chart2.plotHeight;
        if (!chart2.scrollablePixelsY && Math.abs(diff) >= 1) {
          chart2.plotHeight = height;
          chart2.redrawTrigger = "adjustHeight";
          chart2.setSize(void 0, chart2.chartHeight + diff, animate2);
        }
        axis.series.forEach(function(series) {
          const clipRect = series.sharedClipKey && chart2.sharedClips[series.sharedClipKey];
          if (clipRect) {
            clipRect.attr(chart2.inverted ? {
              width: chart2.plotHeight
            } : {
              height: chart2.plotHeight
            });
          }
        });
      }
    }
    this.initiatedScale = true;
  }
  this.redrawTrigger = null;
}
const StaticScale = {
  compose: compose$4
};
/**
 * @license Highcharts Gantt JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/static-scale
 * @requires highcharts
 *
 * StaticScale
 *
 * (c) 2016-2025 Torstein Honsi, Lars A. V. Cabrera
 *
 * License: www.highcharts.com/license
 */
const G$2 = Highcharts;
StaticScale.compose(G$2.Axis, G$2.Chart);
const { xrange: { prototype: { pointClass: XRangePoint } } } = SeriesRegistry$1.seriesTypes;
class GanttPoint extends XRangePoint {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static setGanttPointAliases(options2, chart) {
    options2.x = options2.start = chart.time.parse(options2.start ?? options2.x);
    options2.x2 = options2.end = chart.time.parse(options2.end ?? options2.x2);
    options2.partialFill = options2.completed = options2.completed ?? options2.partialFill;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Applies the options containing the x and y data and possible some
   * extra properties. This is called on point init or from point.update.
   *
   * @private
   * @function Highcharts.Point#applyOptions
   *
   * @param {Object} options
   *        The point options
   *
   * @param {number} x
   *        The x value
   *
   * @return {Highcharts.Point}
   *         The Point instance
   */
  applyOptions(options2, x) {
    const ganttPoint = super.applyOptions(options2, x);
    GanttPoint.setGanttPointAliases(ganttPoint, ganttPoint.series.chart);
    this.isNull = !this.isValid?.();
    return ganttPoint;
  }
  isValid() {
    return (typeof this.start === "number" || typeof this.x === "number") && (typeof this.end === "number" || typeof this.x2 === "number" || this.milestone);
  }
}
const { isNumber: isNumber$6 } = Utilities;
const GanttSeriesDefaults = {
  // Options - default options merged with parent
  grouping: false,
  dataLabels: {
    enabled: true
  },
  tooltip: {
    headerFormat: '<span style="font-size: 0.8em">{series.name}</span><br/>',
    pointFormat: null,
    pointFormatter: function() {
      const point = this, series = point.series, xAxis2 = series.xAxis, formats = series.tooltipOptions.dateTimeLabelFormats, startOfWeek2 = xAxis2.options.startOfWeek, ttOptions = series.tooltipOptions, milestone = point.options.milestone;
      let format2 = ttOptions.xDateFormat, retVal = "<b>" + (point.name || point.yCategory) + "</b>";
      if (ttOptions.pointFormat) {
        return point.tooltipFormatter(ttOptions.pointFormat);
      }
      if (!format2 && isNumber$6(point.start)) {
        format2 = series.chart.time.getDateFormat(xAxis2.closestPointRange, point.start, startOfWeek2, formats || {});
      }
      const start2 = series.chart.time.dateFormat(format2, point.start), end = series.chart.time.dateFormat(format2, point.end);
      retVal += "<br/>";
      if (!milestone) {
        retVal += "Start: " + start2 + "<br/>";
        retVal += "End: " + end + "<br/>";
      } else {
        retVal += start2 + "<br/>";
      }
      return retVal;
    }
  },
  connectors: {
    type: "simpleConnect",
    /**
     * @declare Highcharts.ConnectorsAnimationOptionsObject
     */
    animation: {
      reversed: true
      // Dependencies go from child to parent
    },
    radius: 0,
    startMarker: {
      enabled: true,
      symbol: "arrow-filled",
      radius: 4,
      fill: "#fa0",
      align: "left"
    },
    endMarker: {
      enabled: false,
      // Only show arrow on the dependent task
      align: "right"
    }
  }
};
const { dateFormats: dateFormats$1 } = Highcharts;
const { addEvent: addEvent$5, defined, erase, find: find$1, isArray: isArray$2, isNumber: isNumber$5, merge: merge$5, pick: pick$5, timeUnits, wrap: wrap$3 } = Utilities;
var GridAxisSide;
(function(GridAxisSide2) {
  GridAxisSide2[GridAxisSide2["top"] = 0] = "top";
  GridAxisSide2[GridAxisSide2["right"] = 1] = "right";
  GridAxisSide2[GridAxisSide2["bottom"] = 2] = "bottom";
  GridAxisSide2[GridAxisSide2["left"] = 3] = "left";
})(GridAxisSide || (GridAxisSide = {}));
function argsToArray(args) {
  return Array.prototype.slice.call(args, 1);
}
function isObject$2(x) {
  return Utilities.isObject(x, true);
}
function applyGridOptions(axis) {
  const options2 = axis.options;
  options2.labels.align = pick$5(options2.labels.align, "center");
  if (!axis.categories) {
    options2.showLastLabel = false;
  }
  axis.labelRotation = 0;
  options2.labels.rotation = 0;
  options2.minTickInterval = 1;
}
function compose$3(AxisClass, ChartClass, TickClass) {
  if (!AxisClass.keepProps.includes("grid")) {
    AxisClass.keepProps.push("grid");
    AxisClass.prototype.getMaxLabelDimensions = getMaxLabelDimensions;
    wrap$3(AxisClass.prototype, "unsquish", wrapUnsquish);
    wrap$3(AxisClass.prototype, "getOffset", wrapGetOffset);
    addEvent$5(AxisClass, "init", onInit);
    addEvent$5(AxisClass, "afterGetTitlePosition", onAfterGetTitlePosition);
    addEvent$5(AxisClass, "afterInit", onAfterInit);
    addEvent$5(AxisClass, "afterRender", onAfterRender);
    addEvent$5(AxisClass, "afterSetAxisTranslation", onAfterSetAxisTranslation);
    addEvent$5(AxisClass, "afterSetOptions", onAfterSetOptions);
    addEvent$5(AxisClass, "afterSetOptions", onAfterSetOptions2);
    addEvent$5(AxisClass, "afterSetScale", onAfterSetScale);
    addEvent$5(AxisClass, "afterTickSize", onAfterTickSize);
    addEvent$5(AxisClass, "trimTicks", onTrimTicks);
    addEvent$5(AxisClass, "destroy", onDestroy);
    addEvent$5(ChartClass, "afterSetChartSize", onChartAfterSetChartSize);
    addEvent$5(TickClass, "afterGetLabelPosition", onTickAfterGetLabelPosition);
    addEvent$5(TickClass, "labelFormat", onTickLabelFormat);
  }
  return AxisClass;
}
function getMaxLabelDimensions(ticks, tickPositions) {
  const dimensions = {
    width: 0,
    height: 0
  };
  tickPositions.forEach(function(pos) {
    const tick = ticks[pos];
    let labelHeight = 0, labelWidth = 0, label;
    if (isObject$2(tick)) {
      label = isObject$2(tick.label) ? tick.label : {};
      labelHeight = label.getBBox ? label.getBBox().height : 0;
      if (label.textStr && !isNumber$5(label.textPxLength)) {
        label.textPxLength = label.getBBox().width;
      }
      labelWidth = isNumber$5(label.textPxLength) ? (
        // Math.round ensures crisp lines
        Math.round(label.textPxLength)
      ) : 0;
      if (label.textStr) {
        labelWidth = Math.round(label.getBBox().width);
      }
      dimensions.height = Math.max(labelHeight, dimensions.height);
      dimensions.width = Math.max(labelWidth, dimensions.width);
    }
  });
  if (this.type === "treegrid" && this.treeGrid && this.treeGrid.mapOfPosToGridNode) {
    const treeDepth = this.treeGrid.mapOfPosToGridNode[-1].height || 0;
    dimensions.width += this.options.labels.indentation * (treeDepth - 1);
  }
  return dimensions;
}
function wrapGetOffset(proceed) {
  const { grid } = this, columnsFirst = this.side === 3;
  if (!columnsFirst) {
    proceed.apply(this);
  }
  if (!grid?.isColumn) {
    let columns = grid?.columns || [];
    if (columnsFirst) {
      columns = columns.slice().reverse();
    }
    columns.forEach((column2) => {
      column2.getOffset();
    });
  }
  if (columnsFirst) {
    proceed.apply(this);
  }
}
function onAfterGetTitlePosition(e) {
  const axis = this;
  const options2 = axis.options;
  const gridOptions = options2.grid || {};
  if (gridOptions.enabled === true) {
    const { axisTitle, height: axisHeight, horiz, left: axisLeft, offset: offset2, opposite, options: options3, top: axisTop, width: axisWidth } = axis;
    const tickSize = axis.tickSize();
    const titleWidth = axisTitle?.getBBox().width;
    const xOption = options3.title.x;
    const yOption = options3.title.y;
    const titleMargin = pick$5(options3.title.margin, horiz ? 5 : 10);
    const titleFontSize = axisTitle ? axis.chart.renderer.fontMetrics(axisTitle).f : 0;
    const crispCorr = tickSize ? tickSize[0] / 2 : 0;
    const offAxis = (horiz ? axisTop + axisHeight : axisLeft) + (horiz ? 1 : -1) * // Horizontal axis reverses the margin
    (opposite ? -1 : 1) * // So does opposite axes
    crispCorr + (axis.side === GridAxisSide.bottom ? titleFontSize : 0);
    e.titlePosition.x = horiz ? axisLeft - (titleWidth || 0) / 2 - titleMargin + xOption : offAxis + (opposite ? axisWidth : 0) + offset2 + xOption;
    e.titlePosition.y = horiz ? offAxis - (opposite ? axisHeight : 0) + (opposite ? titleFontSize : -titleFontSize) / 2 + offset2 + yOption : axisTop - titleMargin + yOption;
  }
}
function onAfterInit() {
  const axis = this;
  const { chart, options: { grid: gridOptions = {} }, userOptions } = axis;
  if (gridOptions.enabled) {
    applyGridOptions(axis);
  }
  if (gridOptions.columns) {
    const columns = axis.grid.columns = [];
    let columnIndex = axis.grid.columnIndex = 0;
    while (++columnIndex < gridOptions.columns.length) {
      const columnOptions = merge$5(
        userOptions,
        gridOptions.columns[columnIndex],
        {
          isInternal: true,
          linkedTo: 0,
          // Disable by default the scrollbar on the grid axis
          scrollbar: {
            enabled: false
          }
        },
        // Avoid recursion
        {
          grid: {
            columns: void 0
          }
        }
      );
      const column2 = new Axis(axis.chart, columnOptions, "yAxis");
      column2.grid.isColumn = true;
      column2.grid.columnIndex = columnIndex;
      erase(chart.axes, column2);
      erase(chart[axis.coll] || [], column2);
      columns.push(column2);
    }
  }
}
function onAfterRender() {
  const axis = this, { axisTitle, grid, options: options2 } = axis, gridOptions = options2.grid || {};
  if (gridOptions.enabled === true) {
    const min2 = axis.min || 0, max2 = axis.max || 0, firstTick = axis.ticks[axis.tickPositions[0]];
    if (axisTitle && !axis.chart.styledMode && firstTick?.slotWidth && !axis.options.title.style.width) {
      axisTitle.css({ width: `${firstTick.slotWidth}px` });
    }
    axis.maxLabelDimensions = axis.getMaxLabelDimensions(axis.ticks, axis.tickPositions);
    if (axis.rightWall) {
      axis.rightWall.destroy();
    }
    if (axis.grid?.isOuterAxis() && axis.axisLine) {
      const lineWidth = options2.lineWidth;
      if (lineWidth) {
        const linePath = axis.getLinePath(lineWidth), startPoint = linePath[0], endPoint = linePath[1], tickLength = (axis.tickSize("tick") || [1])[0], distance = tickLength * (axis.side === GridAxisSide.top || axis.side === GridAxisSide.left ? -1 : 1);
        if (startPoint[0] === "M" && endPoint[0] === "L") {
          if (axis.horiz) {
            startPoint[2] += distance;
            endPoint[2] += distance;
          } else {
            startPoint[1] += distance;
            endPoint[1] += distance;
          }
        }
        if (!axis.horiz && axis.chart.marginRight) {
          const upperBorderStartPoint = startPoint, upperBorderEndPoint = [
            "L",
            axis.left,
            startPoint[2] || 0
          ], upperBorderPath = [
            upperBorderStartPoint,
            upperBorderEndPoint
          ], lowerBorderEndPoint = [
            "L",
            axis.chart.chartWidth - axis.chart.marginRight,
            axis.toPixels(max2 + axis.tickmarkOffset)
          ], lowerBorderStartPoint = [
            "M",
            endPoint[1] || 0,
            axis.toPixels(max2 + axis.tickmarkOffset)
          ], lowerBorderPath = [
            lowerBorderStartPoint,
            lowerBorderEndPoint
          ];
          if (!axis.grid.upperBorder && min2 % 1 !== 0) {
            axis.grid.upperBorder = axis.grid.renderBorder(upperBorderPath);
          }
          if (axis.grid.upperBorder) {
            axis.grid.upperBorder.attr({
              stroke: options2.lineColor,
              "stroke-width": options2.lineWidth
            });
            axis.grid.upperBorder.animate({
              d: upperBorderPath
            });
          }
          if (!axis.grid.lowerBorder && max2 % 1 !== 0) {
            axis.grid.lowerBorder = axis.grid.renderBorder(lowerBorderPath);
          }
          if (axis.grid.lowerBorder) {
            axis.grid.lowerBorder.attr({
              stroke: options2.lineColor,
              "stroke-width": options2.lineWidth
            });
            axis.grid.lowerBorder.animate({
              d: lowerBorderPath
            });
          }
        }
        if (!axis.grid.axisLineExtra) {
          axis.grid.axisLineExtra = axis.grid.renderBorder(linePath);
        } else {
          axis.grid.axisLineExtra.attr({
            stroke: options2.lineColor,
            "stroke-width": options2.lineWidth
          });
          axis.grid.axisLineExtra.animate({
            d: linePath
          });
        }
        axis.axisLine[axis.showAxis ? "show" : "hide"]();
      }
    }
    (grid?.columns || []).forEach((column2) => column2.render());
    if (!axis.horiz && axis.chart.hasRendered && (axis.scrollbar || axis.linkedParent?.scrollbar) && axis.tickPositions.length) {
      const tickmarkOffset = axis.tickmarkOffset, lastTick = axis.tickPositions[axis.tickPositions.length - 1], firstTick2 = axis.tickPositions[0];
      let label, tickMark;
      while ((label = axis.hiddenLabels.pop()) && label.element) {
        label.show();
      }
      while ((tickMark = axis.hiddenMarks.pop()) && tickMark.element) {
        tickMark.show();
      }
      label = axis.ticks[firstTick2].label;
      if (label) {
        if (min2 - firstTick2 > tickmarkOffset) {
          axis.hiddenLabels.push(label.hide());
        } else {
          label.show();
        }
      }
      label = axis.ticks[lastTick].label;
      if (label) {
        if (lastTick - max2 > tickmarkOffset) {
          axis.hiddenLabels.push(label.hide());
        } else {
          label.show();
        }
      }
      const mark = axis.ticks[lastTick].mark;
      if (mark && lastTick - max2 < tickmarkOffset && lastTick - max2 > 0 && axis.ticks[lastTick].isLast) {
        axis.hiddenMarks.push(mark.hide());
      }
    }
  }
}
function onAfterSetAxisTranslation() {
  const axis = this;
  const tickInfo = axis.tickPositions?.info;
  const options2 = axis.options;
  const gridOptions = options2.grid || {};
  const userLabels = axis.userOptions.labels || {};
  if (gridOptions.enabled) {
    if (axis.horiz) {
      axis.series.forEach((series) => {
        series.options.pointRange = 0;
      });
      if (tickInfo && options2.dateTimeLabelFormats && options2.labels && !defined(userLabels.align) && (options2.dateTimeLabelFormats[tickInfo.unitName].range === false || tickInfo.count > 1)) {
        options2.labels.align = "left";
        if (!defined(userLabels.x)) {
          options2.labels.x = 3;
        }
      }
    } else {
      if (this.type !== "treegrid" && axis.grid && axis.grid.columns) {
        this.minPointOffset = this.tickInterval;
      }
    }
  }
}
function onAfterSetOptions(e) {
  const options2 = this.options, userOptions = e.userOptions, gridOptions = options2 && isObject$2(options2.grid) ? options2.grid : {};
  let gridAxisOptions;
  if (gridOptions.enabled === true) {
    gridAxisOptions = merge$5(true, {
      className: "highcharts-grid-axis " + (userOptions.className || ""),
      dateTimeLabelFormats: {
        hour: {
          list: ["%[HM]", "%[H]"]
        },
        day: {
          list: ["%[AeB]", "%[aeb]", "%[E]"]
        },
        week: {
          list: ["Week %W", "W%W"]
        },
        month: {
          list: ["%[B]", "%[b]", "%o"]
        }
      },
      grid: {
        borderWidth: 1
      },
      labels: {
        padding: 2,
        style: {
          fontSize: "0.9em"
        }
      },
      margin: 0,
      title: {
        text: null,
        reserveSpace: false,
        rotation: 0,
        style: {
          textOverflow: "ellipsis"
        }
      },
      // In a grid axis, only allow one unit of certain types,
      // for example we shouldn't have one grid cell spanning
      // two days.
      units: [[
        "millisecond",
        // Unit name
        [1, 10, 100]
      ], [
        "second",
        [1, 10]
      ], [
        "minute",
        [1, 5, 15]
      ], [
        "hour",
        [1, 6]
      ], [
        "day",
        [1]
      ], [
        "week",
        [1]
      ], [
        "month",
        [1]
      ], [
        "year",
        null
      ]]
    }, userOptions);
    if (this.coll === "xAxis") {
      if (defined(userOptions.linkedTo) && !defined(userOptions.tickPixelInterval)) {
        gridAxisOptions.tickPixelInterval = 350;
      }
      if (
        // Check for tick pixel interval in options
        !defined(userOptions.tickPixelInterval) && // Only for linked axes
        defined(userOptions.linkedTo) && !defined(userOptions.tickPositioner) && !defined(userOptions.tickInterval) && !defined(userOptions.units)
      ) {
        gridAxisOptions.tickPositioner = function(min2, max2) {
          const parentInfo = this.linkedParent?.tickPositions?.info;
          if (parentInfo) {
            const units2 = gridAxisOptions.units || [];
            let unitIdx, count = 1, unitName = "year";
            for (let i = 0; i < units2.length; i++) {
              const unit2 = units2[i];
              if (unit2 && unit2[0] === parentInfo.unitName) {
                unitIdx = i;
                break;
              }
            }
            const unit = isNumber$5(unitIdx) && units2[unitIdx + 1];
            if (unit) {
              unitName = unit[0] || "year";
              const counts = unit[1];
              count = counts?.[0] || 1;
            } else if (parentInfo.unitName === "year") {
              count = parentInfo.count * 10;
            }
            const unitRange = timeUnits[unitName];
            this.tickInterval = unitRange * count;
            return this.chart.time.getTimeTicks({ unitRange, count, unitName }, min2, max2, this.options.startOfWeek);
          }
        };
      }
    }
    merge$5(true, this.options, gridAxisOptions);
    if (this.horiz) {
      options2.minPadding = pick$5(userOptions.minPadding, 0);
      options2.maxPadding = pick$5(userOptions.maxPadding, 0);
    }
    if (isNumber$5(options2.grid.borderWidth)) {
      options2.tickWidth = options2.lineWidth = gridOptions.borderWidth;
    }
  }
}
function onAfterSetOptions2(e) {
  const axis = this;
  const userOptions = e.userOptions;
  const gridOptions = userOptions?.grid || {};
  const columns = gridOptions.columns;
  if (gridOptions.enabled && columns) {
    merge$5(true, axis.options, columns[0]);
  }
}
function onAfterSetScale() {
  const axis = this;
  (axis.grid.columns || []).forEach((column2) => column2.setScale());
}
function onAfterTickSize(e) {
  const { horiz, maxLabelDimensions, options: { grid: gridOptions = {} } } = this;
  if (gridOptions.enabled && maxLabelDimensions) {
    const labelPadding = this.options.labels.distance * 2;
    const distance = horiz ? gridOptions.cellHeight || labelPadding + maxLabelDimensions.height : labelPadding + maxLabelDimensions.width;
    if (isArray$2(e.tickSize)) {
      e.tickSize[0] = distance;
    } else {
      e.tickSize = [distance, 0];
    }
  }
}
function onChartAfterSetChartSize() {
  this.axes.forEach((axis) => {
    (axis.grid?.columns || []).forEach((column2) => {
      column2.setAxisSize();
      column2.setAxisTranslation();
    });
  });
}
function onDestroy(e) {
  const { grid } = this;
  (grid.columns || []).forEach((column2) => column2.destroy(e.keepEvents));
  grid.columns = void 0;
}
function onInit(e) {
  const axis = this;
  const userOptions = e.userOptions || {};
  const gridOptions = userOptions.grid || {};
  if (gridOptions.enabled && defined(gridOptions.borderColor)) {
    userOptions.tickColor = userOptions.lineColor = gridOptions.borderColor;
  }
  if (!axis.grid) {
    axis.grid = new GridAxisAdditions(axis);
  }
  axis.hiddenLabels = [];
  axis.hiddenMarks = [];
}
function onTickAfterGetLabelPosition(e) {
  const tick = this, label = tick.label, axis = tick.axis, reversed = axis.reversed, chart = axis.chart, options2 = axis.options, gridOptions = options2.grid || {}, labelOpts = axis.options.labels, align = labelOpts.align, side = GridAxisSide[axis.side], tickmarkOffset = e.tickmarkOffset, tickPositions = axis.tickPositions, tickPos = tick.pos - tickmarkOffset, nextTickPos = isNumber$5(tickPositions[e.index + 1]) ? tickPositions[e.index + 1] - tickmarkOffset : (axis.max || 0) + tickmarkOffset, tickSize = axis.tickSize("tick"), tickWidth = tickSize ? tickSize[0] : 0, crispCorr = tickSize ? tickSize[1] / 2 : 0;
  if (gridOptions.enabled === true) {
    let bottom, top, left, right;
    if (side === "top") {
      bottom = axis.top + axis.offset;
      top = bottom - tickWidth;
    } else if (side === "bottom") {
      top = chart.chartHeight - axis.bottom + axis.offset;
      bottom = top + tickWidth;
    } else {
      bottom = axis.top + axis.len - (axis.translate(reversed ? nextTickPos : tickPos) || 0);
      top = axis.top + axis.len - (axis.translate(reversed ? tickPos : nextTickPos) || 0);
    }
    if (side === "right") {
      left = chart.chartWidth - axis.right + axis.offset;
      right = left + tickWidth;
    } else if (side === "left") {
      right = axis.left + axis.offset;
      left = right - tickWidth;
    } else {
      left = Math.round(axis.left + (axis.translate(reversed ? nextTickPos : tickPos) || 0)) - crispCorr;
      right = Math.min(
        // #15742
        Math.round(axis.left + (axis.translate(reversed ? tickPos : nextTickPos) || 0)) - crispCorr,
        axis.left + axis.len
      );
    }
    tick.slotWidth = right - left;
    e.pos.x = align === "left" ? left : align === "right" ? right : left + (right - left) / 2;
    e.pos.y = top + (bottom - top) / 2;
    if (label) {
      const lblMetrics = chart.renderer.fontMetrics(label), labelHeight = label.getBBox().height;
      if (!labelOpts.useHTML) {
        const lines = Math.round(labelHeight / lblMetrics.h);
        e.pos.y += // Center the label
        // TODO: why does this actually center the label?
        (lblMetrics.b - (lblMetrics.h - lblMetrics.f)) / 2 + // Adjust for height of additional lines.
        -((lines - 1) * lblMetrics.h / 2);
      } else {
        e.pos.y += // Readjust yCorr in htmlUpdateTransform
        lblMetrics.b + // Adjust for height of html label
        -(labelHeight / 2);
      }
    }
    e.pos.x += axis.horiz && labelOpts.x || 0;
  }
}
function onTickLabelFormat(ctx) {
  const { axis, value } = ctx;
  if (axis.options.grid?.enabled) {
    const tickPos = axis.tickPositions;
    const series = (axis.linkedParent || axis).series[0];
    const isFirst = value === tickPos[0];
    const isLast = value === tickPos[tickPos.length - 1];
    const point = series && find$1(series.options.data, function(p) {
      return p[axis.isXAxis ? "x" : "y"] === value;
    });
    let pointCopy;
    if (point && series.is("gantt")) {
      pointCopy = merge$5(point);
      Highcharts.seriesTypes.gantt.prototype.pointClass.setGanttPointAliases(pointCopy, axis.chart);
    }
    ctx.isFirst = isFirst;
    ctx.isLast = isLast;
    ctx.point = pointCopy;
  }
}
function onTrimTicks() {
  const axis = this, options2 = axis.options, gridOptions = options2.grid || {}, categoryAxis = axis.categories, tickPositions = axis.tickPositions, firstPos = tickPositions[0], secondPos = tickPositions[1], lastPos = tickPositions[tickPositions.length - 1], beforeLastPos = tickPositions[tickPositions.length - 2], linkedMin = axis.linkedParent?.min, linkedMax = axis.linkedParent?.max, min2 = linkedMin || axis.min, max2 = linkedMax || axis.max, tickInterval = axis.tickInterval, startLessThanMin = (
    // #19845
    isNumber$5(min2) && min2 >= firstPos + tickInterval && min2 < secondPos
  ), endMoreThanMin = isNumber$5(min2) && firstPos < min2 && firstPos + tickInterval > min2, startLessThanMax = isNumber$5(max2) && lastPos > max2 && lastPos - tickInterval < max2, endMoreThanMax = isNumber$5(max2) && max2 <= lastPos - tickInterval && max2 > beforeLastPos;
  if (gridOptions.enabled === true && !categoryAxis && (axis.isXAxis || axis.isLinked)) {
    if ((endMoreThanMin || startLessThanMin) && !options2.startOnTick) {
      tickPositions[0] = min2;
    }
    if ((startLessThanMax || endMoreThanMax) && !options2.endOnTick) {
      tickPositions[tickPositions.length - 1] = max2;
    }
  }
}
function wrapUnsquish(proceed) {
  const axis = this;
  const { options: { grid: gridOptions = {} } } = axis;
  if (gridOptions.enabled === true && axis.categories) {
    return axis.tickInterval;
  }
  return proceed.apply(axis, argsToArray(arguments));
}
class GridAxisAdditions {
  /* *
  *
  *  Constructors
  *
  * */
  constructor(axis) {
    this.axis = axis;
  }
  /* *
  *
  *  Functions
  *
  * */
  /**
   * Checks if an axis is the outer axis in its dimension. Since
   * axes are placed outwards in order, the axis with the highest
   * index is the outermost axis.
   *
   * Example: If there are multiple x-axes at the top of the chart,
   * this function returns true if the axis supplied is the last
   * of the x-axes.
   *
   * @private
   *
   * @return {boolean}
   * True if the axis is the outermost axis in its dimension; false if
   * not.
   */
  isOuterAxis() {
    const axis = this.axis;
    const chart = axis.chart;
    const columnIndex = axis.grid.columnIndex;
    const columns = axis.linkedParent?.grid.columns || axis.grid.columns || [];
    const parentAxis = columnIndex ? axis.linkedParent : axis;
    let thisIndex = -1, lastIndex = 0;
    if (axis.side === 3 && !chart.inverted && columns.length) {
      return !axis.linkedParent;
    }
    (chart[axis.coll] || []).forEach((otherAxis, index) => {
      if (otherAxis.side === axis.side && !otherAxis.options.isInternal) {
        lastIndex = index;
        if (otherAxis === parentAxis) {
          thisIndex = index;
        }
      }
    });
    return lastIndex === thisIndex && (isNumber$5(columnIndex) ? columns.length === columnIndex : true);
  }
  /**
   * Add extra border based on the provided path.
   * @private
   * @param {SVGPath} path
   * The path of the border.
   * @return {Highcharts.SVGElement}
   * Border
   */
  renderBorder(path) {
    const axis = this.axis, renderer = axis.chart.renderer, options2 = axis.options, extraBorderLine = renderer.path(path).addClass("highcharts-axis-line").add(axis.axisGroup);
    if (!renderer.styledMode) {
      extraBorderLine.attr({
        stroke: options2.lineColor,
        "stroke-width": options2.lineWidth,
        zIndex: 7
      });
    }
    return extraBorderLine;
  }
}
dateFormats$1.E = function(timestamp) {
  return this.dateFormat("%a", timestamp, true).charAt(0);
};
dateFormats$1.W = function(timestamp) {
  const d = this.toParts(timestamp), firstDay = (d[7] + 6) % 7, thursday = d.slice(0);
  thursday[2] = d[2] - firstDay + 3;
  const firstThursday = this.toParts(this.makeTime(thursday[0], 0, 1));
  if (firstThursday[7] !== 4) {
    d[1] = 0;
    d[2] = 1 + (11 - firstThursday[7]) % 7;
  }
  const thursdayTS = this.makeTime(thursday[0], thursday[1], thursday[2]), firstThursdayTS = this.makeTime(firstThursday[0], firstThursday[1], firstThursday[2]);
  return (1 + Math.floor((thursdayTS - firstThursdayTS) / 6048e5)).toString();
};
const GridAxis = {
  compose: compose$3
};
const { extend: extend$5, isNumber: isNumber$4, pick: pick$4 } = Utilities;
function getListOfParents(data) {
  const root = "", ids = [], listOfParents = data.reduce((prev, curr) => {
    const { parent = "", id } = curr;
    if (typeof prev[parent] === "undefined") {
      prev[parent] = [];
    }
    prev[parent].push(curr);
    if (id) {
      ids.push(id);
    }
    return prev;
  }, {});
  Object.keys(listOfParents).forEach((node) => {
    if (node !== root && ids.indexOf(node) === -1) {
      const adoptedByRoot = listOfParents[node].map(function(orphan) {
        const { ...parentExcluded } = orphan;
        return parentExcluded;
      });
      listOfParents[root].push(...adoptedByRoot);
      delete listOfParents[node];
    }
  });
  return listOfParents;
}
function getNode$1(id, parent, level, data, mapOfIdToChildren, options2) {
  const after = options2 && options2.after, before = options2 && options2.before, node = {
    data,
    depth: level - 1,
    id,
    level,
    parent: parent || ""
  };
  let descendants = 0, height = 0, start2, end;
  if (typeof before === "function") {
    before(node, options2);
  }
  const children = (mapOfIdToChildren[id] || []).map((child) => {
    const node2 = getNode$1(child.id, id, level + 1, child, mapOfIdToChildren, options2), childStart = child.start || NaN, childEnd = child.milestone === true ? childStart : child.end || NaN;
    start2 = !isNumber$4(start2) || childStart < start2 ? childStart : start2;
    end = !isNumber$4(end) || childEnd > end ? childEnd : end;
    descendants = descendants + 1 + node2.descendants;
    height = Math.max(node2.height + 1, height);
    return node2;
  });
  if (data) {
    data.start = pick$4(data.start, start2);
    data.end = pick$4(data.end, end);
  }
  extend$5(node, {
    children,
    descendants,
    height
  });
  if (typeof after === "function") {
    after(node, options2);
  }
  return node;
}
function getTree(data, options2) {
  return getNode$1("", null, 1, null, getListOfParents(data), options2);
}
const Tree = {
  getNode: getNode$1,
  getTree
};
const { addEvent: addEvent$4, removeEvent: removeEvent$1, isObject: isObject$1, isNumber: isNumber$3, pick: pick$3, wrap: wrap$2 } = Utilities;
function onTickInit() {
  const tick = this;
  if (!tick.treeGrid) {
    tick.treeGrid = new TreeGridTickAdditions(tick);
  }
}
function onTickHover(label) {
  label.addClass("highcharts-treegrid-node-active");
  if (!label.renderer.styledMode) {
    label.css({
      textDecoration: "underline"
    });
  }
}
function onTickHoverExit(label, options2) {
  const css2 = isObject$1(options2.style) ? options2.style : {};
  label.removeClass("highcharts-treegrid-node-active");
  if (!label.renderer.styledMode) {
    label.css({ textDecoration: css2.textDecoration || "none" });
  }
}
function renderLabelIcon(tick, params2) {
  const treeGrid = tick.treeGrid, isNew = !treeGrid.labelIcon, renderer = params2.renderer, labelBox = params2.xy, options2 = params2.options, width = options2.width || 0, height = options2.height || 0, padding = options2.padding ?? tick.axis.linkedParent ? 0 : 5, iconCenter = {
    x: labelBox.x - width / 2 - padding,
    y: labelBox.y - height / 2
  }, rotation = params2.collapsed ? 90 : 180, shouldRender = params2.show && isNumber$3(iconCenter.y);
  let icon = treeGrid.labelIcon;
  if (!icon) {
    treeGrid.labelIcon = icon = renderer.path(renderer.symbols[options2.type](options2.x || 0, options2.y || 0, width, height)).addClass("highcharts-label-icon").add(params2.group);
  }
  icon[shouldRender ? "show" : "hide"]();
  if (!renderer.styledMode) {
    icon.attr({
      cursor: "pointer",
      "fill": pick$3(
        params2.color,
        "#666666"
        /* Palette.neutralColor60 */
      ),
      "stroke-width": 1,
      stroke: options2.lineColor,
      strokeWidth: options2.lineWidth || 0
    });
  }
  icon[isNew ? "attr" : "animate"]({
    translateX: iconCenter.x,
    translateY: iconCenter.y,
    rotation
  });
}
function wrapGetLabelPosition(proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
  const tick = this, lbOptions = pick$3(tick.options?.labels, labelOptions), pos = tick.pos, axis = tick.axis, isTreeGrid = axis.type === "treegrid", result = proceed.apply(tick, [x, y, label, horiz, lbOptions, tickmarkOffset, index, step]);
  let mapOfPosToGridNode, node, level;
  if (isTreeGrid) {
    const { width = 0, padding = axis.linkedParent ? 0 : 5 } = lbOptions && isObject$1(lbOptions.symbol, true) ? lbOptions.symbol : {}, indentation = lbOptions && isNumber$3(lbOptions.indentation) ? lbOptions.indentation : 0;
    mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode;
    node = mapOfPosToGridNode?.[pos];
    level = node?.depth || 1;
    result.x += // Add space for symbols
    width + padding * 2 + // Apply indentation
    (level - 1) * indentation;
  }
  return result;
}
function wrapRenderLabel(proceed) {
  const tick = this, { pos, axis, label, treeGrid: tickGrid, options: tickOptions } = tick, icon = tickGrid?.labelIcon, labelElement = label?.element, { treeGrid: axisGrid, options: axisOptions, chart, tickPositions } = axis, mapOfPosToGridNode = axisGrid.mapOfPosToGridNode, labelOptions = pick$3(tickOptions?.labels, axisOptions?.labels), symbolOptions = labelOptions && isObject$1(labelOptions.symbol, true) ? labelOptions.symbol : {}, node = mapOfPosToGridNode?.[pos], { descendants, depth } = node || {}, hasDescendants = node && descendants && descendants > 0, level = depth, isTreeGridElement = axis.type === "treegrid" && labelElement, shouldRender = tickPositions.indexOf(pos) > -1, prefixClassName = "highcharts-treegrid-node-", prefixLevelClass = prefixClassName + "level-", styledMode = chart.styledMode;
  let collapsed, addClassName, removeClassName;
  if (isTreeGridElement && node) {
    label.removeClass(new RegExp(prefixLevelClass + ".*")).addClass(prefixLevelClass + level);
  }
  proceed.apply(tick, Array.prototype.slice.call(arguments, 1));
  if (isTreeGridElement && hasDescendants) {
    collapsed = axisGrid.isCollapsed(node);
    renderLabelIcon(tick, {
      color: !styledMode && label.styles.color || "",
      collapsed,
      group: label.parentGroup,
      options: symbolOptions,
      renderer: label.renderer,
      show: shouldRender,
      xy: label.xy
    });
    addClassName = prefixClassName + (collapsed ? "collapsed" : "expanded");
    removeClassName = prefixClassName + (collapsed ? "expanded" : "collapsed");
    label.addClass(addClassName).removeClass(removeClassName);
    if (!styledMode) {
      label.css({
        cursor: "pointer"
      });
    }
    [label, icon].forEach((object) => {
      if (object && !object.attachedTreeGridEvents) {
        addEvent$4(object.element, "mouseover", function() {
          onTickHover(label);
        });
        addEvent$4(object.element, "mouseout", function() {
          onTickHoverExit(label, labelOptions);
        });
        addEvent$4(object.element, "click", function() {
          tickGrid.toggleCollapse();
        });
        object.attachedTreeGridEvents = true;
      }
    });
  } else if (icon) {
    removeEvent$1(labelElement);
    label?.css({ cursor: "default" });
    icon.destroy();
  }
}
class TreeGridTickAdditions {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static compose(TickClass) {
    const tickProto = TickClass.prototype;
    if (!tickProto.toggleCollapse) {
      addEvent$4(TickClass, "init", onTickInit);
      wrap$2(tickProto, "getLabelPosition", wrapGetLabelPosition);
      wrap$2(tickProto, "renderLabel", wrapRenderLabel);
      tickProto.collapse = function(redraw) {
        this.treeGrid.collapse(redraw);
      };
      tickProto.expand = function(redraw) {
        this.treeGrid.expand(redraw);
      };
      tickProto.toggleCollapse = function(redraw) {
        this.treeGrid.toggleCollapse(redraw);
      };
    }
  }
  /* *
   *
   *  Constructors
   *
   * */
  /**
   * @private
   */
  constructor(tick) {
    this.tick = tick;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Collapse the grid cell. Used when axis is of type treegrid.
   *
   * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
   *
   * @private
   * @function Highcharts.Tick#collapse
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart or wait for an explicit call to
   * {@link Highcharts.Chart#redraw}
   */
  collapse(redraw) {
    const tick = this.tick, axis = tick.axis, brokenAxis = axis.brokenAxis;
    if (brokenAxis && axis.treeGrid.mapOfPosToGridNode) {
      const pos = tick.pos, node = axis.treeGrid.mapOfPosToGridNode[pos], breaks = axis.treeGrid.collapse(node);
      brokenAxis.setBreaks(breaks, pick$3(redraw, true));
    }
  }
  /**
   * Destroy remaining labelIcon if exist.
   *
   * @private
   * @function Highcharts.Tick#destroy
   */
  destroy() {
    if (this.labelIcon) {
      this.labelIcon.destroy();
    }
  }
  /**
   * Expand the grid cell. Used when axis is of type treegrid.
   *
   * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
   *
   * @private
   * @function Highcharts.Tick#expand
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart or wait for an explicit call to
   * {@link Highcharts.Chart#redraw}
   */
  expand(redraw) {
    const { pos, axis } = this.tick, { treeGrid, brokenAxis } = axis, posMappedNodes = treeGrid.mapOfPosToGridNode;
    if (brokenAxis && posMappedNodes) {
      const node = posMappedNodes[pos], breaks = treeGrid.expand(node);
      brokenAxis.setBreaks(breaks, pick$3(redraw, true));
    }
  }
  /**
   * Toggle the collapse/expand state of the grid cell. Used when axis is
   * of type treegrid.
   *
   * @see gantt/treegrid-axis/collapsed-dynamically/demo.js
   *
   * @private
   * @function Highcharts.Tick#toggleCollapse
   *
   * @param {boolean} [redraw=true]
   * Whether to redraw the chart or wait for an explicit call to
   * {@link Highcharts.Chart#redraw}
   */
  toggleCollapse(redraw) {
    const tick = this.tick, axis = tick.axis, brokenAxis = axis.brokenAxis;
    if (brokenAxis && axis.treeGrid.mapOfPosToGridNode) {
      const pos = tick.pos, node = axis.treeGrid.mapOfPosToGridNode[pos], breaks = axis.treeGrid.toggleCollapse(node);
      brokenAxis.setBreaks(breaks, pick$3(redraw, true));
    }
  }
}
const { getLevelOptions } = TreeUtilities;
const { addEvent: addEvent$3, isArray: isArray$1, splat, find, fireEvent, isObject, isString, merge: merge$4, pick: pick$2, removeEvent, wrap: wrap$1 } = Utilities;
let TickConstructor;
function getBreakFromNode(node, max2) {
  const to = node.collapseEnd || 0;
  let from = node.collapseStart || 0;
  if (to >= max2) {
    from -= 0.5;
  }
  return {
    from,
    to,
    showPoints: false
  };
}
function getTreeGridFromData(data, uniqueNames, numberOfSeries) {
  const categories = [], collapsedNodes = [], mapOfIdToNode = {}, uniqueNamesEnabled = uniqueNames || false;
  let mapOfPosToGridNode = {}, posIterator = -1;
  const treeParams = {
    // After the children has been created.
    after: function(node) {
      const gridNode = mapOfPosToGridNode[node.pos];
      let height = 0, descendants = 0;
      gridNode.children.forEach(function(child) {
        descendants += (child.descendants || 0) + 1;
        height = Math.max((child.height || 0) + 1, height);
      });
      gridNode.descendants = descendants;
      gridNode.height = height;
      if (gridNode.collapsed) {
        collapsedNodes.push(gridNode);
      }
    },
    // Before the children has been created.
    before: function(node) {
      const data2 = isObject(node.data, true) ? node.data : {}, name = isString(data2.name) ? data2.name : "", parentNode = mapOfIdToNode[node.parent], parentGridNode = isObject(parentNode, true) ? mapOfPosToGridNode[parentNode.pos] : null, hasSameName = function(x) {
        return x.name === name;
      };
      let gridNode, pos;
      if (uniqueNamesEnabled && isObject(parentGridNode, true) && !!(gridNode = find(parentGridNode.children, hasSameName))) {
        pos = gridNode.pos;
        gridNode.nodes.push(node);
      } else {
        pos = posIterator++;
      }
      if (!mapOfPosToGridNode[pos]) {
        mapOfPosToGridNode[pos] = gridNode = {
          depth: parentGridNode ? parentGridNode.depth + 1 : 0,
          name,
          id: data2.id,
          nodes: [node],
          children: [],
          pos
        };
        if (pos !== -1) {
          categories.push(name);
        }
        if (isObject(parentGridNode, true)) {
          parentGridNode.children.push(gridNode);
        }
      }
      if (isString(node.id)) {
        mapOfIdToNode[node.id] = node;
      }
      if (gridNode && data2.collapsed === true) {
        gridNode.collapsed = true;
      }
      node.pos = pos;
    }
  };
  const updateYValuesAndTickPos = function(map, numberOfSeries2) {
    const setValues = function(gridNode, start2, result) {
      const nodes = gridNode.nodes, padding = 0.5;
      let end = start2 + (start2 === -1 ? 0 : numberOfSeries2 - 1);
      const diff = (end - start2) / 2, pos = start2 + diff;
      nodes.forEach(function(node) {
        const data2 = node.data;
        if (isObject(data2, true)) {
          data2.y = start2 + (data2.seriesIndex || 0);
          delete data2.seriesIndex;
        }
        node.pos = pos;
      });
      result[pos] = gridNode;
      gridNode.pos = pos;
      gridNode.tickmarkOffset = diff + padding;
      gridNode.collapseStart = end + padding;
      gridNode.children.forEach(function(child) {
        setValues(child, end + 1, result);
        end = (child.collapseEnd || 0) - padding;
      });
      gridNode.collapseEnd = end + padding;
      return result;
    };
    return setValues(map["-1"], -1, {});
  };
  const tree = Tree.getTree(data, treeParams);
  mapOfPosToGridNode = updateYValuesAndTickPos(mapOfPosToGridNode, numberOfSeries);
  return {
    categories,
    mapOfIdToNode,
    mapOfPosToGridNode,
    collapsedNodes,
    tree
  };
}
function onBeforeRender(e) {
  const chart = e.target, axes = chart.axes;
  axes.filter((axis) => axis.type === "treegrid").forEach(function(axis) {
    const options2 = axis.options || {}, labelOptions = options2.labels, uniqueNames = axis.uniqueNames, max2 = chart.time.parse(options2.max), isDirty = !axis.treeGrid.mapOfPosToGridNode || axis.series.some(function(series) {
      return !series.hasRendered || series.isDirtyData || series.isDirty;
    });
    let numberOfSeries = 0, data, treeGrid;
    if (isDirty) {
      const seriesHasPrimitivePoints = [];
      data = axis.series.reduce(function(arr, s) {
        const seriesData = s.options.data || [], firstPoint = seriesData[0], foundPrimitivePoint = Array.isArray(firstPoint) && !firstPoint.find((value) => typeof value === "object");
        seriesHasPrimitivePoints.push(foundPrimitivePoint);
        if (s.visible) {
          seriesData.forEach(function(pointOptions) {
            if (foundPrimitivePoint || s.options.keys?.length) {
              pointOptions = s.pointClass.prototype.optionsToObject.call({ series: s }, pointOptions);
              s.pointClass.setGanttPointAliases(pointOptions, chart);
            }
            if (isObject(pointOptions, true)) {
              pointOptions.seriesIndex = numberOfSeries;
              arr.push(pointOptions);
            }
          });
          if (uniqueNames === true) {
            numberOfSeries++;
          }
        }
        return arr;
      }, []);
      if (max2 && data.length < max2) {
        for (let i = data.length; i <= max2; i++) {
          data.push({
            // Use the zero-width character
            // to avoid conflict with uniqueNames
            name: i + "​"
          });
        }
      }
      treeGrid = getTreeGridFromData(data, uniqueNames || false, uniqueNames === true ? numberOfSeries : 1);
      axis.categories = treeGrid.categories;
      axis.treeGrid.mapOfPosToGridNode = treeGrid.mapOfPosToGridNode;
      axis.hasNames = true;
      axis.treeGrid.tree = treeGrid.tree;
      axis.series.forEach(function(series, index) {
        const axisData = (series.options.data || []).map(function(d) {
          if (seriesHasPrimitivePoints[index] || isArray$1(d) && series.options.keys && series.options.keys.length) {
            data.forEach(function(point) {
              const toArray = splat(d);
              if (toArray.indexOf(point.x || 0) >= 0 && toArray.indexOf(point.x2 || 0) >= 0) {
                d = point;
              }
            });
          }
          return isObject(d, true) ? merge$4(d) : d;
        });
        if (series.visible) {
          series.setData(axisData, false);
        }
      });
      axis.treeGrid.mapOptionsToLevel = getLevelOptions({
        defaults: labelOptions,
        from: 1,
        levels: labelOptions?.levels,
        to: axis.treeGrid.tree?.height
      });
      if (e.type === "beforeRender") {
        axis.treeGrid.collapsedNodes = treeGrid.collapsedNodes;
      }
    }
  });
}
function wrapGenerateTick(proceed, pos) {
  const axis = this, mapOptionsToLevel = axis.treeGrid.mapOptionsToLevel || {}, isTreeGrid = axis.type === "treegrid", ticks = axis.ticks;
  let tick = ticks[pos], levelOptions, options2, gridNode;
  if (isTreeGrid && axis.treeGrid.mapOfPosToGridNode) {
    gridNode = axis.treeGrid.mapOfPosToGridNode[pos];
    levelOptions = mapOptionsToLevel[gridNode.depth];
    if (levelOptions) {
      options2 = {
        labels: levelOptions
      };
    }
    if (!tick && TickConstructor) {
      ticks[pos] = tick = new TickConstructor(axis, pos, void 0, void 0, {
        category: gridNode.name,
        tickmarkOffset: gridNode.tickmarkOffset,
        options: options2
      });
    } else {
      tick.parameters.category = gridNode.name;
      tick.options = options2;
      tick.addLabel();
    }
  } else {
    proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  }
}
function wrapInit(proceed, chart, userOptions, coll) {
  const axis = this, isTreeGrid = userOptions.type === "treegrid";
  if (!axis.treeGrid) {
    axis.treeGrid = new TreeGridAxisAdditions(axis);
  }
  if (isTreeGrid) {
    addEvent$3(chart, "beforeRender", onBeforeRender);
    addEvent$3(chart, "beforeRedraw", onBeforeRender);
    addEvent$3(chart, "addSeries", function(e) {
      if (e.options.data) {
        const treeGrid = getTreeGridFromData(e.options.data, userOptions.uniqueNames || false, 1);
        axis.treeGrid.collapsedNodes = (axis.treeGrid.collapsedNodes || []).concat(treeGrid.collapsedNodes);
      }
    });
    addEvent$3(axis, "foundExtremes", function() {
      if (axis.treeGrid.collapsedNodes) {
        axis.treeGrid.collapsedNodes.forEach(function(node) {
          const breaks = axis.treeGrid.collapse(node);
          if (axis.brokenAxis) {
            axis.brokenAxis.setBreaks(breaks, false);
            if (axis.treeGrid.collapsedNodes) {
              axis.treeGrid.collapsedNodes = axis.treeGrid.collapsedNodes.filter((n) => node.collapseStart !== n.collapseStart || node.collapseEnd !== n.collapseEnd);
            }
          }
        });
      }
    });
    addEvent$3(axis, "afterBreaks", function() {
      if (axis.coll === "yAxis" && !axis.staticScale && axis.chart.options.chart.height) {
        axis.isDirty = true;
      }
    });
    userOptions = merge$4({
      // Default options
      grid: {
        enabled: true
      },
      // TODO: add support for align in treegrid.
      labels: {
        align: "left",
        /**
        * Set options on specific levels in a tree grid axis. Takes
        * precedence over labels options.
        *
        * @sample {gantt} gantt/treegrid-axis/labels-levels
        *         Levels on TreeGrid Labels
        *
        * @type      {Array<*>}
        * @product   gantt
        * @apioption yAxis.labels.levels
        *
        * @private
        */
        levels: [{
          /**
          * Specify the level which the options within this object
          * applies to.
          *
          * @type      {number}
          * @product   gantt
          * @apioption yAxis.labels.levels.level
          *
          * @private
          */
          level: void 0
        }, {
          level: 1,
          /**
           * @type      {Highcharts.CSSObject}
           * @product   gantt
           * @apioption yAxis.labels.levels.style
           *
           * @private
           */
          style: {
            /** @ignore-option */
            fontWeight: "bold"
          }
        }],
        /**
         * The symbol for the collapse and expand icon in a
         * treegrid.
         *
         * @product      gantt
         * @optionparent yAxis.labels.symbol
         *
         * @private
         */
        symbol: {
          /**
           * The symbol type. Points to a definition function in
           * the `Highcharts.Renderer.symbols` collection.
           *
           * @type {Highcharts.SymbolKeyValue}
           *
           * @private
           */
          type: "triangle",
          x: -5,
          y: -5,
          height: 10,
          width: 10
        }
      },
      uniqueNames: false
    }, userOptions, {
      // Forced options
      reversed: true
    });
  }
  proceed.apply(axis, [chart, userOptions, coll]);
  if (isTreeGrid) {
    axis.hasNames = true;
    axis.options.showLastLabel = true;
  }
}
function wrapSetTickInterval(proceed) {
  const axis = this, options2 = axis.options, time = axis.chart.time, linkedParent = typeof options2.linkedTo === "number" ? this.chart[axis.coll]?.[options2.linkedTo] : void 0, isTreeGrid = axis.type === "treegrid";
  if (isTreeGrid) {
    axis.min = axis.userMin ?? time.parse(options2.min) ?? axis.dataMin;
    axis.max = axis.userMax ?? time.parse(options2.max) ?? axis.dataMax;
    fireEvent(axis, "foundExtremes");
    axis.setAxisTranslation();
    axis.tickInterval = 1;
    axis.tickmarkOffset = 0.5;
    axis.tickPositions = axis.treeGrid.mapOfPosToGridNode ? axis.treeGrid.getTickPositions() : [];
    if (linkedParent) {
      const linkedParentExtremes = linkedParent.getExtremes();
      axis.min = pick$2(linkedParentExtremes.min, linkedParentExtremes.dataMin);
      axis.max = pick$2(linkedParentExtremes.max, linkedParentExtremes.dataMax);
      axis.tickPositions = linkedParent.tickPositions;
    }
    axis.linkedParent = linkedParent;
  } else {
    proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
  }
}
function wrapRedraw(proceed) {
  const axis = this, isTreeGrid = this.type === "treegrid";
  if (isTreeGrid && axis.visible) {
    axis.tickPositions.forEach(function(pos) {
      const tick = axis.ticks[pos];
      if (tick.label?.attachedTreeGridEvents) {
        removeEvent(tick.label.element);
        tick.label.attachedTreeGridEvents = false;
      }
    });
  }
  proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
}
class TreeGridAxisAdditions {
  /* *
   *
   *  Static Functions
   *
   * */
  /**
   * @private
   */
  static compose(AxisClass, ChartClass, SeriesClass, TickClass) {
    if (!AxisClass.keepProps.includes("treeGrid")) {
      const axisProps = AxisClass.prototype;
      AxisClass.keepProps.push("treeGrid");
      wrap$1(axisProps, "generateTick", wrapGenerateTick);
      wrap$1(axisProps, "init", wrapInit);
      wrap$1(axisProps, "setTickInterval", wrapSetTickInterval);
      wrap$1(axisProps, "redraw", wrapRedraw);
      axisProps.utils = {
        getNode: Tree.getNode
      };
      if (!TickConstructor) {
        TickConstructor = TickClass;
      }
    }
    GridAxis.compose(AxisClass, ChartClass, TickClass);
    BrokenAxis$1.compose(AxisClass, SeriesClass);
    TreeGridTickAdditions.compose(TickClass);
    return AxisClass;
  }
  /* *
   *
   *  Constructors
   *
   * */
  /**
   * @private
   */
  constructor(axis) {
    this.axis = axis;
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Set the collapse status.
   *
   * @private
   *
   * @param {Highcharts.Axis} axis
   * The axis to check against.
   *
   * @param {Highcharts.GridNode} node
   * The node to collapse.
   */
  setCollapsedStatus(node) {
    const axis = this.axis, chart = axis.chart;
    axis.series.forEach(function(series) {
      const data = series.options.data;
      if (node.id && data) {
        const point = chart.get(node.id), dataPoint = data[series.data.indexOf(point)];
        if (point && dataPoint) {
          point.collapsed = node.collapsed;
          dataPoint.collapsed = node.collapsed;
        }
      }
    });
  }
  /**
   * Calculates the new axis breaks to collapse a node.
   *
   * @private
   *
   * @param {Highcharts.Axis} axis
   * The axis to check against.
   *
   * @param {Highcharts.GridNode} node
   * The node to collapse.
   *
   * @param {number} pos
   * The tick position to collapse.
   *
   * @return {Array<object>}
   * Returns an array of the new breaks for the axis.
   */
  collapse(node) {
    const axis = this.axis, breaks = axis.options.breaks || [], obj = getBreakFromNode(node, axis.max);
    breaks.push(obj);
    node.collapsed = true;
    axis.treeGrid.setCollapsedStatus(node);
    return breaks;
  }
  /**
   * Calculates the new axis breaks to expand a node.
   *
   * @private
   *
   * @param {Highcharts.Axis} axis
   * The axis to check against.
   *
   * @param {Highcharts.GridNode} node
   * The node to expand.
   *
   * @param {number} pos
   * The tick position to expand.
   *
   * @return {Array<object>}
   * Returns an array of the new breaks for the axis.
   */
  expand(node) {
    const axis = this.axis, breaks = axis.options.breaks || [], obj = getBreakFromNode(node, axis.max);
    node.collapsed = false;
    axis.treeGrid.setCollapsedStatus(node);
    return breaks.reduce(function(arr, b) {
      if (b.to !== obj.to || b.from !== obj.from) {
        arr.push(b);
      }
      return arr;
    }, []);
  }
  /**
   * Creates a list of positions for the ticks on the axis. Filters out
   * positions that are outside min and max, or is inside an axis break.
   *
   * @private
   *
   * @return {Array<number>}
   * List of positions.
   */
  getTickPositions() {
    const axis = this.axis, roundedMin = Math.floor(axis.min / axis.tickInterval) * axis.tickInterval, roundedMax = Math.ceil(axis.max / axis.tickInterval) * axis.tickInterval;
    return Object.keys(axis.treeGrid.mapOfPosToGridNode || {}).reduce(function(arr, key2) {
      const pos = +key2;
      if (pos >= roundedMin && pos <= roundedMax && !axis.brokenAxis?.isInAnyBreak(pos)) {
        arr.push(pos);
      }
      return arr;
    }, []);
  }
  /**
   * Check if a node is collapsed.
   *
   * @private
   *
   * @param {Highcharts.Axis} axis
   * The axis to check against.
   *
   * @param {Object} node
   * The node to check if is collapsed.
   *
   * @param {number} pos
   * The tick position to collapse.
   *
   * @return {boolean}
   * Returns true if collapsed, false if expanded.
   */
  isCollapsed(node) {
    const axis = this.axis, breaks = axis.options.breaks || [], obj = getBreakFromNode(node, axis.max);
    return breaks.some(function(b) {
      return b.from === obj.from && b.to === obj.to;
    });
  }
  /**
   * Calculates the new axis breaks after toggling the collapse/expand
   * state of a node. If it is collapsed it will be expanded, and if it is
   * expanded it will be collapsed.
   *
   * @private
   *
   * @param {Highcharts.Axis} axis
   * The axis to check against.
   *
   * @param {Highcharts.GridNode} node
   * The node to toggle.
   *
   * @return {Array<object>}
   * Returns an array of the new breaks for the axis.
   */
  toggleCollapse(node) {
    return this.isCollapsed(node) ? this.expand(node) : this.collapse(node);
  }
}
const { series: Series, seriesTypes: { xrange: XRangeSeries } } = SeriesRegistry$1;
const { extend: extend$4, isNumber: isNumber$2, merge: merge$3 } = Utilities;
class GanttSeries extends XRangeSeries {
  /* *
   *
   *  Static Functions
   *
   * */
  static compose(AxisClass, ChartClass, SeriesClass, TickClass) {
    XRangeSeries.compose(AxisClass);
    if (!ChartClass) {
      return;
    }
    StaticScale.compose(AxisClass, ChartClass);
    if (!SeriesClass) {
      return;
    }
    Pathfinder.compose(ChartClass, SeriesClass.prototype.pointClass);
    if (!TickClass) {
      return;
    }
    TreeGridAxisAdditions.compose(AxisClass, ChartClass, SeriesClass, TickClass);
  }
  /* *
   *
   *  Functions
   *
   * */
  /**
   * Draws a single point in the series.
   *
   * This override draws the point as a diamond if point.options.milestone
   * is true, and uses the original drawPoint() if it is false or not set.
   *
   * @requires highcharts-gantt
   *
   * @private
   * @function Highcharts.seriesTypes.gantt#drawPoint
   *
   * @param {Highcharts.Point} point
   *        An instance of Point in the series
   *
   * @param {"animate"|"attr"} verb
   *        'animate' (animates changes) or 'attr' (sets options)
   */
  drawPoint(point, verb) {
    const series = this, seriesOpts = series.options, renderer = series.chart.renderer, shapeArgs = point.shapeArgs, plotY = point.plotY, state = point.selected && "select", cutOff = seriesOpts.stacking && !seriesOpts.borderRadius;
    let graphic = point.graphic, diamondShape;
    if (point.options.milestone) {
      if (isNumber$2(plotY) && point.y !== null && point.visible !== false) {
        diamondShape = renderer.symbols.diamond(shapeArgs.x || 0, shapeArgs.y || 0, shapeArgs.width || 0, shapeArgs.height || 0);
        if (graphic) {
          graphic[verb]({
            d: diamondShape
          });
        } else {
          point.graphic = graphic = renderer.path(diamondShape).addClass(point.getClassName(), true).add(point.group || series.group);
        }
        if (!series.chart.styledMode) {
          point.graphic.attr(series.pointAttribs(point, state)).shadow(seriesOpts.shadow, null, cutOff);
        }
      } else if (graphic) {
        point.graphic = graphic.destroy();
      }
    } else {
      super.drawPoint(point, verb);
    }
  }
  /**
   * Handle milestones, as they have no x2.
   * @private
   */
  translatePoint(point) {
    let shapeArgs, size;
    super.translatePoint(point);
    if (point.options.milestone) {
      shapeArgs = point.shapeArgs;
      size = shapeArgs.height || 0;
      point.shapeArgs = {
        x: (shapeArgs.x || 0) - size / 2,
        y: shapeArgs.y,
        width: size,
        height: size
      };
    }
  }
}
GanttSeries.defaultOptions = merge$3(XRangeSeries.defaultOptions, GanttSeriesDefaults);
extend$4(GanttSeries.prototype, {
  pointArrayMap: ["start", "end", "y"],
  pointClass: GanttPoint,
  setData: Series.prototype.setData
});
SeriesRegistry$1.registerSeriesType("gantt", GanttSeries);
/**
 * @license Highcharts Gantt JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/gantt
 * @requires highcharts
 *
 * Gantt series
 *
 * (c) 2016-2025 Lars A. V. Cabrera
 *
 * License: www.highcharts.com/license
 */
const G$1 = Highcharts;
G$1.Connection = G$1.Connection || Connection;
G$1.GanttChart = G$1.GanttChart || GanttChart$1;
G$1.Navigator = G$1.Navigator || Navigator;
G$1.RangeSelector = G$1.RangeSelector || RangeSelector;
G$1.Scrollbar = G$1.Scrollbar || Scrollbar;
G$1.ganttChart = G$1.GanttChart.ganttChart;
ArrowSymbols.compose(G$1.SVGRenderer);
CurrentDateIndication.compose(G$1.Axis, G$1.PlotLineOrBand);
GanttSeries.compose(G$1.Axis, G$1.Chart, G$1.Series, G$1.Tick);
G$1.Navigator.compose(G$1.Chart, G$1.Axis, G$1.Series);
G$1.RangeSelector.compose(G$1.Axis, G$1.Chart);
G$1.Scrollbar.compose(G$1.Axis);
const { addEvent: addEvent$2 } = Utilities;
function addEvents$2(el, types, fn, options2) {
  const removeFuncs = types.map((type) => addEvent$2(el, type, fn, options2));
  return function() {
    for (const fn2 of removeFuncs) {
      fn2();
    }
  };
}
function countProps$1(obj) {
  return Object.keys(obj).length;
}
function getFirstProp$1(obj) {
  for (const p in obj) {
    if (Object.hasOwnProperty.call(obj, p)) {
      return obj[p];
    }
  }
}
function getNormalizedEvent$2(e, chart) {
  return typeof e.chartX === "undefined" || typeof e.chartY === "undefined" ? chart.pointer?.normalize(e) || e : e;
}
const DragDropUtilities = {
  addEvents: addEvents$2,
  countProps: countProps$1,
  getFirstProp: getFirstProp$1,
  getNormalizedEvent: getNormalizedEvent$2
};
const DragDropDefaults = {
  /**
   * Set the minimum X value the points can be moved to.
   *
   * @sample {gantt} gantt/dragdrop/drag-gantt
   *         Limit dragging
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Limit dragging
   *
   * @type      {number|string}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.dragMinX
   */
  /**
   * Set the maximum X value the points can be moved to.
   *
   * @sample {gantt} gantt/dragdrop/drag-gantt
   *         Limit dragging
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Limit dragging
   *
   * @type      {number|string}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.dragMaxX
   */
  /**
   * Set the minimum Y value the points can be moved to.
   *
   * @sample {gantt} gantt/dragdrop/drag-gantt
   *         Limit dragging
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Limit dragging
   *
   * @type      {number}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.dragMinY
   */
  /**
   * Set the maximum Y value the points can be moved to.
   *
   * @sample {gantt} gantt/dragdrop/drag-gantt
   *         Limit dragging
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Limit dragging
   *
   * @type      {number}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.dragMaxY
   */
  /**
   * The X precision value to drag to for this series. Set to 0 to disable. By
   * default this is disabled, except for category axes, where the default is
   * `1`.
   *
   * @type      {number}
   * @default   0
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.dragPrecisionX
   */
  /**
   * The Y precision value to drag to for this series. Set to 0 to disable. By
   * default this is disabled, except for category axes, where the default is
   * `1`.
   *
   * @type      {number}
   * @default   0
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.dragPrecisionY
   */
  /**
   * Enable dragging in the X dimension.
   *
   * @type      {boolean}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.draggableX
   */
  /**
   * Enable dragging in the Y dimension. Note that this is not supported for
   * TreeGrid axes (the default axis type in Gantt charts).
   *
   * @type      {boolean}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.draggableY
   */
  /**
   * Group the points by a property. Points with the same property value will
   * be grouped together when moving.
   *
   * @sample {gantt} gantt/dragdrop/drag-gantt
   *         Drag grouped points
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Drag grouped points
   *
   * @type      {string}
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.groupBy
   */
  /**
   * Update points as they are dragged. If false, a guide box is drawn to
   * illustrate the new point size.
   *
   * @sample {gantt} gantt/dragdrop/drag-gantt
   *         liveRedraw disabled
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         liveRedraw disabled
   *
   * @type      {boolean}
   * @default   true
   * @since     6.2.0
   * @apioption plotOptions.series.dragDrop.liveRedraw
   */
  /**
   * Set a key to hold when dragging to zoom the chart. This is useful to
   * avoid zooming while moving points. Should be set different than
   * [chart.panKey](#chart.panKey).
   *
   * @type       {string}
   * @since      6.2.0
   * @validvalue ["alt", "ctrl", "meta", "shift"]
   * @deprecated
   * @requires  modules/draggable-points
   * @apioption  chart.zoomKey
   */
  /**
   * Callback that fires when starting to drag a point. The mouse event object
   * is passed in as an argument. If a drag handle is used, `e.updateProp` is
   * set to the data property being dragged. The `this` context is the point.
   * See [drag and drop options](plotOptions.series.dragDrop).
   *
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Drag events
   *
   * @type      {Highcharts.PointDragStartCallbackFunction}
   * @since     6.2.0
   * @requires  modules/draggable-points
   * @apioption plotOptions.series.point.events.dragStart
   */
  /**
   * Callback that fires while dragging a point. The mouse event is passed in
   * as parameter. The original data can be accessed from `e.origin`, and the
   * new point values can be accessed from `e.newPoints`. If there is only a
   * single point being updated, it can be accessed from `e.newPoint` for
   * simplicity, and its ID can be accessed from `e.newPointId`. The `this`
   * context is the point being dragged. To stop the default drag action,
   * return false. See [drag and drop options](plotOptions.series.dragDrop).
   *
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Drag events
   * @sample {highcharts|highstock} highcharts/dragdrop/undraggable-points
   *         Dragging disabled for specific points
   *
   * @type      {Highcharts.PointDragCallbackFunction}
   * @since     6.2.0
   * @requires  modules/draggable-points
   * @apioption plotOptions.series.point.events.drag
   */
  /**
   * Callback that fires when the point is dropped. The parameters passed are
   * the same as for [drag](#plotOptions.series.point.events.drag). To stop
   * the default drop action, return false. See
   * [drag and drop options](plotOptions.series.dragDrop).
   *
   * @sample {highcharts} highcharts/dragdrop/drag-xrange
   *         Drag events
   * @sample {highcharts|highstock} highcharts/dragdrop/undraggable-points
   *         Dragging disabled for specific points
   *
   * @type      {Highcharts.PointDropCallbackFunction}
   * @since     6.2.0
   * @requires  modules/draggable-points
   * @apioption plotOptions.series.point.events.drop
   */
  /**
   * Point specific options for the draggable-points module. Overrides options
   * on `series.dragDrop`.
   *
   * @declare   Highcharts.SeriesLineDataDragDropOptions
   * @extends   plotOptions.series.dragDrop
   * @since     6.2.0
   * @requires  modules/draggable-points
   * @apioption series.line.data.dragDrop
   */
  /**
   * The amount of pixels to drag the pointer before it counts as a drag
   * operation. This prevents drag/drop to fire when just clicking or
   * selecting points.
   *
   * @type      {number}
   * @default   2
   * @since     6.2.0
   */
  dragSensitivity: 2,
  /**
   * Options for the drag handles available in column series.
   *
   * @declare      Highcharts.DragDropHandleOptionsObject
   * @since        6.2.0
   * @optionparent plotOptions.column.dragDrop.dragHandle
   */
  dragHandle: {
    /**
     * Function to define the SVG path to use for the drag handles. Takes
     * the point as argument. Should return an SVG path in array format. The
     * SVG path is automatically positioned on the point.
     *
     * @type      {Function}
     * @since     6.2.0
     * @apioption plotOptions.column.dragDrop.dragHandle.pathFormatter
     */
    // pathFormatter: null,
    /**
     * The mouse cursor to use for the drag handles. By default this is
     * intelligently switching between `ew-resize` and `ns-resize` depending on
     * the direction the point is being dragged.
     *
     * @type      {string}
     * @since     6.2.0
     * @apioption plotOptions.column.dragDrop.dragHandle.cursor
     */
    // cursor: null,
    /**
     * The class name of the drag handles. Defaults to `highcharts-drag-handle`.
     *
     * @since 6.2.0
     */
    className: "highcharts-drag-handle",
    /**
     * The fill color of the drag handles.
     *
     * @type  {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since 6.2.0
     */
    color: "#fff",
    /**
     * The line color of the drag handles.
     *
     * @type  {Highcharts.ColorString}
     * @since 6.2.0
     */
    lineColor: "rgba(0, 0, 0, 0.6)",
    /**
     * The line width for the drag handles.
     *
     * @since 6.2.0
     */
    lineWidth: 1,
    /**
     * The z index for the drag handles.
     *
     * @since 6.2.0
     */
    zIndex: 901
  },
  /**
   * Style options for the guide box. The guide box has one state by default,
   * the `default` state.
   *
   * @declare Highcharts.PlotOptionsSeriesDragDropGuideBoxOptions
   * @since 6.2.0
   * @type  {Highcharts.Dictionary<Highcharts.DragDropGuideBoxOptionsObject>}
   */
  guideBox: {
    /**
     * Style options for the guide box default state.
     *
     * @declare Highcharts.DragDropGuideBoxOptionsObject
     * @since   6.2.0
     */
    "default": {
      /**
       * CSS class name of the guide box in this state. Defaults to
       * `highcharts-drag-box-default`.
       *
       * @since 6.2.0
       */
      className: "highcharts-drag-box-default",
      /**
       * Width of the line around the guide box.
       *
       * @since 6.2.0
       */
      lineWidth: 1,
      /**
       * Color of the border around the guide box.
       *
       * @type  {Highcharts.ColorString}
       * @since 6.2.0
       */
      lineColor: "#888",
      /**
       * Guide box fill color.
       *
       * @type  {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @since 6.2.0
       */
      color: "rgba(0, 0, 0, 0.1)",
      /**
       * Guide box cursor.
       *
       * @since 6.2.0
       */
      cursor: "move",
      /**
       * Guide box zIndex.
       *
       * @since 6.2.0
       */
      zIndex: 900
    }
  }
};
const { animObject } = animationExports;
const { addEvents: addEvents$1, countProps, getFirstProp, getNormalizedEvent: getNormalizedEvent$1 } = DragDropUtilities;
const { doc } = Highcharts;
const { addEvent: addEvent$1, isArray, merge: merge$2, pick: pick$1 } = Utilities;
function addDragDropEvents(chart) {
  const container = chart.container;
  if (isChartDraggable(chart)) {
    addEvents$1(container, ["mousedown", "touchstart"], (e) => {
      mouseDown(getNormalizedEvent$1(e, chart), chart);
    });
    addEvents$1(container, ["mousemove", "touchmove"], (e) => {
      mouseMove(getNormalizedEvent$1(e, chart), chart);
    }, {
      passive: false
    });
    addEvent$1(container, "mouseleave", (e) => {
      mouseUp(getNormalizedEvent$1(e, chart), chart);
    });
    chart.unbindDragDropMouseUp = addEvents$1(doc, ["mouseup", "touchend"], (e) => {
      mouseUp(getNormalizedEvent$1(e, chart), chart);
    }, {
      passive: false
    });
    chart.hasAddedDragDropEvents = true;
    addEvent$1(chart, "destroy", () => {
      if (chart.unbindDragDropMouseUp) {
        chart.unbindDragDropMouseUp();
      }
    });
  }
}
function chartHideDragHandles() {
  const chart = this, dragHandles = chart.dragHandles || {};
  if (dragHandles) {
    for (const key2 of Object.keys(dragHandles)) {
      if (dragHandles[key2].destroy) {
        dragHandles[key2].destroy();
      }
    }
    delete chart.dragHandles;
  }
}
function chartSetGuideBoxState(state, options2) {
  const guideBox = this.dragGuideBox, guideBoxOptions = merge$2(DragDropDefaults.guideBox, options2), stateOptions = merge$2(
    guideBoxOptions["default"],
    // eslint-disable-line dot-notation
    guideBoxOptions[state]
  );
  return guideBox.attr({
    "class": stateOptions.className,
    stroke: stateOptions.lineColor,
    strokeWidth: stateOptions.lineWidth,
    fill: stateOptions.color,
    cursor: stateOptions.cursor,
    zIndex: stateOptions.zIndex
  }).css({ pointerEvents: "none" });
}
function chartZoomOrPanKeyPressed(e) {
  const chart = this, chartOptions = chart.options.chart || {}, panKey = chartOptions.panKey && chartOptions.panKey + "Key", zoomKey = chart.zooming.key && chart.zooming.key + "Key";
  return e[zoomKey] || e[panKey];
}
function compose$2(ChartClass) {
  const chartProto = ChartClass.prototype;
  if (!chartProto.hideDragHandles) {
    chartProto.hideDragHandles = chartHideDragHandles;
    chartProto.setGuideBoxState = chartSetGuideBoxState;
    chartProto.zoomOrPanKeyPressed = chartZoomOrPanKeyPressed;
    addEvent$1(ChartClass, "render", onChartRender);
  }
}
function dragMove(e, point) {
  const series = point.series, chart = series.chart, data = chart.dragDropData, options2 = merge$2(series.options.dragDrop, point.options.dragDrop), draggableX = options2.draggableX, draggableY = options2.draggableY, origin = data.origin, updateProp = data.updateProp;
  let dX = e.chartX - origin.chartX, dY = e.chartY - origin.chartY;
  const oldDx = dX;
  if (chart.inverted) {
    dX = -dY;
    dY = -oldDx;
  }
  if (pick$1(options2.liveRedraw, true)) {
    updatePoints(chart, false);
    point.showDragHandles();
  } else {
    if (updateProp) {
      resizeGuideBox(point, dX, dY);
    } else {
      chart.dragGuideBox.translate(draggableX ? dX : 0, draggableY ? dY : 0);
    }
  }
  origin.prevdX = dX;
  origin.prevdY = dY;
}
function flipResizeSide$1(side) {
  return {
    left: "right",
    right: "left",
    top: "bottom",
    bottom: "top"
  }[side];
}
function getGroupedPoints(point) {
  const series = point.series, data = series.options.data || [], groupKey = series.options.dragDrop.groupBy;
  let points = [];
  if (series.boosted && isArray(data)) {
    for (let i = 0, iEnd = data.length; i < iEnd; ++i) {
      points.push(new series.pointClass(
        // eslint-disable-line new-cap
        series,
        data[i]
      ));
      points[points.length - 1].index = i;
    }
  } else {
    points = series.points;
  }
  return point.options[groupKey] ? (
    // If we have a grouping option, filter the points by that
    points.filter((comparePoint) => comparePoint.options[groupKey] === point.options[groupKey])
  ) : (
    // Otherwise return the point by itself only
    [point]
  );
}
function getNewPoints(dragDropData, newPos) {
  const point = dragDropData.point, series = point.series, chart = series.chart, options2 = merge$2(series.options.dragDrop, point.options.dragDrop), updateProps = {}, resizeProp = dragDropData.updateProp, hashmap = {}, dragDropProps = point.series.dragDropProps;
  for (const key2 in dragDropProps) {
    const val = dragDropProps[key2];
    if (resizeProp && (resizeProp !== key2 || !val.resize || val.optionName && options2[val.optionName] === false)) {
      continue;
    }
    if (resizeProp || val.move && (val.axis === "x" && options2.draggableX || val.axis === "y" && options2.draggableY)) {
      if (chart.mapView) {
        updateProps[key2 === "x" ? "lon" : "lat"] = val;
      } else {
        updateProps[key2] = val;
      }
    }
  }
  for (
    const p of
    // If resizing).forEach(only update the point we are resizing
    resizeProp ? [point] : dragDropData.groupedPoints
  ) {
    hashmap[p.id] = {
      point: p,
      newValues: p.getDropValues(dragDropData.origin, newPos, updateProps)
    };
  }
  return hashmap;
}
function getPositionSnapshot(e, points, guideBox) {
  const res = {
    chartX: e.chartX,
    chartY: e.chartY,
    guideBox: guideBox && {
      x: guideBox.attr("x"),
      y: guideBox.attr("y"),
      width: guideBox.attr("width"),
      height: guideBox.attr("height")
    },
    points: {}
  };
  for (const point of points) {
    const dragDropProps = point.series.dragDropProps || {}, pointProps = {};
    for (const key2 of Object.keys(dragDropProps)) {
      const val = dragDropProps[key2], axis = point.series[val.axis + "Axis"];
      pointProps[key2] = point[key2];
      if (point.series.chart.mapView && point.plotX && point.plotY) {
        pointProps[key2 + "Offset"] = key2 === "x" ? point.plotX : point.plotY;
      } else {
        pointProps[key2 + "Offset"] = // E.g. yAxis.toPixels(point.high), xAxis.toPixels
        // (point.end)
        axis.toPixels(point[key2]) - (axis.horiz ? e.chartX : e.chartY);
      }
    }
    pointProps.point = point;
    res.points[point.id] = pointProps;
  }
  return res;
}
function hasDraggedPastSensitivity(e, chart, sensitivity) {
  const orig = chart.dragDropData.origin, oldX = orig.chartX, oldY = orig.chartY, newX = e.chartX, newY = e.chartY, distance = Math.sqrt((newX - oldX) * (newX - oldX) + (newY - oldY) * (newY - oldY));
  return distance > sensitivity;
}
function initDragDrop$1(e, point) {
  const groupedPoints = getGroupedPoints(point), series = point.series, chart = series.chart;
  let guideBox;
  if (!pick$1(series.options.dragDrop && series.options.dragDrop.liveRedraw, true)) {
    chart.dragGuideBox = guideBox = series.getGuideBox(groupedPoints);
    chart.setGuideBoxState("default", series.options.dragDrop.guideBox).add(series.group);
  }
  chart.dragDropData = {
    origin: getPositionSnapshot(e, groupedPoints, guideBox),
    point,
    groupedPoints,
    isDragging: true
  };
}
function isChartDraggable(chart) {
  let i = chart.series ? chart.series.length : 0;
  if (chart.hasCartesianSeries && !chart.polar || chart.mapView) {
    while (i--) {
      if (chart.series[i].options.dragDrop && isSeriesDraggable(chart.series[i])) {
        return true;
      }
    }
  }
  return false;
}
function isPointMovable(point) {
  const series = point.series, chart = series.chart, seriesDragDropOptions = series.options.dragDrop || {}, pointDragDropOptions = point.options && point.options.dragDrop, updateProps = series.dragDropProps;
  let p, hasMovableX, hasMovableY;
  for (const key2 in updateProps) {
    p = updateProps[key2];
    if (p.axis === "x" && p.move) {
      hasMovableX = true;
    } else if (p.axis === "y" && p.move) {
      hasMovableY = true;
    }
  }
  return (seriesDragDropOptions.draggableX && hasMovableX || seriesDragDropOptions.draggableY && hasMovableY) && !(pointDragDropOptions && pointDragDropOptions.draggableX === false && pointDragDropOptions.draggableY === false) && (!!(series.yAxis && series.xAxis) || chart.mapView);
}
function isSeriesDraggable(series) {
  const props = ["draggableX", "draggableY"], dragDropProps = series.dragDropProps || {};
  let val;
  for (const key2 of Object.keys(dragDropProps)) {
    val = dragDropProps[key2];
    if (val.optionName) {
      props.push(val.optionName);
    }
  }
  let i = props.length;
  while (i--) {
    if (series.options.dragDrop[props[i]]) {
      return true;
    }
  }
}
function mouseDown(e, chart) {
  const dragPoint = chart.hoverPoint, dragDropOptions = merge$2(dragPoint && dragPoint.series.options.dragDrop, dragPoint && dragPoint.options.dragDrop), draggableX = dragDropOptions.draggableX || false, draggableY = dragDropOptions.draggableY || false;
  chart.cancelClick = false;
  if (
    // Option is disabled for the point
    !(draggableX || draggableY) || // Zoom/pan key is pressed
    chart.zoomOrPanKeyPressed(e) || // Dragging an annotation
    chart.hasDraggedAnnotation
  ) {
    return;
  }
  if (chart.dragDropData && chart.dragDropData.isDragging) {
    mouseUp(e, chart);
    return;
  }
  if (dragPoint && isPointMovable(dragPoint)) {
    chart.mouseIsDown = false;
    initDragDrop$1(e, dragPoint);
    dragPoint.firePointEvent("dragStart", e);
  }
}
function mouseMove(e, chart) {
  if (chart.zoomOrPanKeyPressed(e)) {
    return;
  }
  const dragDropData = chart.dragDropData;
  let point, seriesDragDropOpts, newPoints, numNewPoints = 0, newPoint;
  if (dragDropData && dragDropData.isDragging && dragDropData.point.series) {
    point = dragDropData.point;
    seriesDragDropOpts = point.series.options.dragDrop;
    e.preventDefault();
    if (!dragDropData.draggedPastSensitivity) {
      dragDropData.draggedPastSensitivity = hasDraggedPastSensitivity(e, chart, pick$1(point.options.dragDrop && point.options.dragDrop.dragSensitivity, seriesDragDropOpts && seriesDragDropOpts.dragSensitivity, DragDropDefaults.dragSensitivity));
    }
    if (dragDropData.draggedPastSensitivity) {
      dragDropData.newPoints = getNewPoints(dragDropData, e);
      newPoints = dragDropData.newPoints;
      numNewPoints = countProps(newPoints);
      newPoint = numNewPoints === 1 ? getFirstProp(newPoints) : null;
      point.firePointEvent("drag", {
        origin: dragDropData.origin,
        newPoints: dragDropData.newPoints,
        newPoint: newPoint && newPoint.newValues,
        newPointId: newPoint && newPoint.point.id,
        numNewPoints,
        chartX: e.chartX,
        chartY: e.chartY
      }, function() {
        dragMove(e, point);
      });
    }
  }
}
function mouseUp(e, chart) {
  const dragDropData = chart.dragDropData;
  if (dragDropData && dragDropData.isDragging && dragDropData.draggedPastSensitivity && dragDropData.point.series) {
    const point = dragDropData.point, newPoints = dragDropData.newPoints, numNewPoints = countProps(newPoints), newPoint = numNewPoints === 1 ? getFirstProp(newPoints) : null;
    if (chart.dragHandles) {
      chart.hideDragHandles();
    }
    e.preventDefault();
    chart.cancelClick = true;
    point.firePointEvent("drop", {
      origin: dragDropData.origin,
      chartX: e.chartX,
      chartY: e.chartY,
      newPoints,
      numNewPoints,
      newPoint: newPoint && newPoint.newValues,
      newPointId: newPoint && newPoint.point.id
    }, function() {
      updatePoints(chart);
    });
  }
  delete chart.dragDropData;
  if (chart.dragGuideBox) {
    chart.dragGuideBox.destroy();
    delete chart.dragGuideBox;
  }
}
function onChartRender() {
  if (!this.hasAddedDragDropEvents) {
    addDragDropEvents(this);
  }
}
function resizeGuideBox(point, dX, dY) {
  const series = point.series, chart = series.chart, dragDropData = chart.dragDropData, resizeProp = series.dragDropProps[dragDropData.updateProp], newPoint = dragDropData.newPoints[point.id].newValues, resizeSide = typeof resizeProp.resizeSide === "function" ? resizeProp.resizeSide(newPoint, point) : resizeProp.resizeSide;
  if (resizeProp.beforeResize) {
    resizeProp.beforeResize(chart.dragGuideBox, newPoint, point);
  }
  resizeRect(chart.dragGuideBox, resizeProp.axis === "x" && series.xAxis.reversed || resizeProp.axis === "y" && series.yAxis.reversed ? flipResizeSide$1(resizeSide) : resizeSide, {
    x: resizeProp.axis === "x" ? dX - (dragDropData.origin.prevdX || 0) : 0,
    y: resizeProp.axis === "y" ? dY - (dragDropData.origin.prevdY || 0) : 0
  });
}
function resizeRect(rect2, updateSide, update) {
  let resizeAttrs;
  switch (updateSide) {
    case "left":
      resizeAttrs = {
        x: rect2.attr("x") + update.x,
        width: Math.max(1, rect2.attr("width") - update.x)
      };
      break;
    case "right":
      resizeAttrs = {
        width: Math.max(1, rect2.attr("width") + update.x)
      };
      break;
    case "top":
      resizeAttrs = {
        y: rect2.attr("y") + update.y,
        height: Math.max(1, rect2.attr("height") - update.y)
      };
      break;
    case "bottom":
      resizeAttrs = {
        height: Math.max(1, rect2.attr("height") + update.y)
      };
      break;
  }
  rect2.attr(resizeAttrs);
}
function updatePoints(chart, animation) {
  const newPoints = chart.dragDropData.newPoints, animOptions = animObject(animation);
  chart.isDragDropAnimating = true;
  let newPoint;
  for (const key2 of Object.keys(newPoints)) {
    newPoint = newPoints[key2];
    newPoint.point.update(newPoint.newValues, false);
  }
  chart.redraw(animOptions);
  setTimeout(() => {
    delete chart.isDragDropAnimating;
    if (chart.hoverPoint && !chart.dragHandles) {
      chart.hoverPoint.showDragHandles();
    }
  }, animOptions.duration);
}
const DraggableChart = {
  compose: compose$2,
  flipResizeSide: flipResizeSide$1,
  initDragDrop: initDragDrop$1
};
const { flipResizeSide } = DraggableChart;
const { isNumber: isNumber$1, merge: merge$1, pick } = Utilities;
const line = {
  x: {
    axis: "x",
    move: true
  },
  y: {
    axis: "y",
    move: true
  }
};
const flags = line;
const column = {
  x: {
    axis: "x",
    move: true
  },
  y: {
    axis: "y",
    move: false,
    resize: true,
    // Force guideBox start coordinates
    beforeResize: (guideBox, pointVals, point) => {
      const plotThreshold = pick(
        point.yBottom,
        // Added support for stacked series. (#18741)
        point.series.translatedThreshold
      ), plotY = guideBox.attr("y"), threshold = isNumber$1(point.stackY) ? point.stackY - (point.y || 0) : point.series.options.threshold || 0, y = threshold + pointVals.y;
      let height, diff;
      if (point.series.yAxis.reversed ? y < threshold : y >= threshold) {
        height = guideBox.attr("height");
        diff = plotThreshold ? plotThreshold - plotY - height : 0;
        guideBox.attr({
          height: Math.max(0, Math.round(height + diff))
        });
      } else {
        guideBox.attr({
          y: Math.round(plotY + (plotThreshold ? plotThreshold - plotY : 0))
        });
      }
    },
    // Flip the side of the resize handle if column is below threshold.
    // Make sure we remove the handle on the other side.
    resizeSide: (pointVals, point) => {
      const chart = point.series.chart, dragHandles = chart.dragHandles, side = pointVals.y >= (point.series.options.threshold || 0) ? "top" : "bottom", flipSide = flipResizeSide(side);
      if (dragHandles && dragHandles[flipSide]) {
        dragHandles[flipSide].destroy();
        delete dragHandles[flipSide];
      }
      return side;
    },
    // Position handle at bottom if column is below threshold
    handlePositioner: (point) => {
      const bBox = point.shapeArgs || point.graphic && point.graphic.getBBox() || {}, reversed = point.series.yAxis.reversed, threshold = point.series.options.threshold || 0, y = point.y || 0, bottom = !reversed && y >= threshold || reversed && y < threshold;
      return {
        x: bBox.x || 0,
        y: bottom ? bBox.y || 0 : (bBox.y || 0) + (bBox.height || 0)
      };
    },
    // Horizontal handle
    handleFormatter: (point) => {
      const shapeArgs = point.shapeArgs || {}, radius = shapeArgs.r || 0, width = shapeArgs.width || 0, centerX = width / 2;
      return [
        // Left wick
        ["M", radius, 0],
        ["L", centerX - 5, 0],
        // Circle
        ["A", 1, 1, 0, 0, 0, centerX + 5, 0],
        ["A", 1, 1, 0, 0, 0, centerX - 5, 0],
        // Right wick
        ["M", centerX + 5, 0],
        ["L", width - radius, 0]
      ];
    }
  }
};
const boxplot = {
  x: column.x,
  /**
   * Allow low value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.boxplot.dragDrop.draggableLow
   */
  low: {
    optionName: "draggableLow",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "bottom",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x || 0,
      y: point.lowPlot
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.q1
  },
  /**
   * Allow Q1 value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.boxplot.dragDrop.draggableQ1
   */
  q1: {
    optionName: "draggableQ1",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "bottom",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x || 0,
      y: point.q1Plot
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.median && val >= point.low
  },
  median: {
    // Median cannot be dragged individually, just move the whole
    // point for this.
    axis: "y",
    move: true
  },
  /**
   * Allow Q3 value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.boxplot.dragDrop.draggableQ3
   */
  q3: {
    optionName: "draggableQ3",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "top",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x || 0,
      y: point.q3Plot
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.high && val >= point.median
  },
  /**
   * Allow high value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.boxplot.dragDrop.draggableHigh
   */
  high: {
    optionName: "draggableHigh",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "top",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x || 0,
      y: point.highPlot
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val >= point.q3
  }
};
const errorbar = {
  x: column.x,
  low: {
    ...boxplot.low,
    propValidate: (val, point) => val <= point.high
  },
  high: {
    ...boxplot.high,
    propValidate: (val, point) => val >= point.low
  }
};
const bullet = {
  x: column.x,
  y: column.y,
  /**
   * Allow target value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.bullet.dragDrop.draggableTarget
   */
  target: {
    optionName: "draggableTarget",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "top",
    handlePositioner: (point) => {
      const bBox = point.targetGraphic.getBBox();
      return {
        x: point.barX,
        y: bBox.y + bBox.height / 2
      };
    },
    handleFormatter: column.y.handleFormatter
  }
};
const ohlc = {
  x: column.x,
  /**
   * Allow low value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.ohlc.dragDrop.draggableLow
   */
  low: {
    optionName: "draggableLow",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "bottom",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x,
      y: point.plotLow
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.open && val <= point.close
  },
  /**
   * Allow high value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.ohlc.dragDrop.draggableHigh
   */
  high: {
    optionName: "draggableHigh",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "top",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x,
      y: point.plotHigh
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val >= point.open && val >= point.close
  },
  /**
   * Allow open value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.ohlc.dragDrop.draggableOpen
   */
  open: {
    optionName: "draggableOpen",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: (point) => point.open >= point.close ? "top" : "bottom",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x,
      y: point.plotOpen
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.high && val >= point.low
  },
  /**
   * Allow close value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.ohlc.dragDrop.draggableClose
   */
  close: {
    optionName: "draggableClose",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: (point) => point.open >= point.close ? "bottom" : "top",
    handlePositioner: (point) => ({
      x: point.shapeArgs.x,
      y: point.plotClose
    }),
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.high && val >= point.low
  }
};
const waterfall = {
  x: column.x,
  y: merge$1(column.y, {
    handleFormatter: (point) => point.isSum || point.isIntermediateSum ? null : column?.y?.handleFormatter?.(point) || null
  })
};
const columnrange = {
  x: {
    axis: "x",
    move: true
  },
  /**
   * Allow low value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.columnrange.dragDrop.draggableLow
   */
  low: {
    optionName: "draggableLow",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "bottom",
    handlePositioner: (point) => {
      const bBox = point.shapeArgs || point.graphic.getBBox();
      return {
        x: bBox.x || 0,
        y: (bBox.y || 0) + (bBox.height || 0)
      };
    },
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val <= point.high
  },
  /**
   * Allow high value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.columnrange.dragDrop.draggableHigh
   */
  high: {
    optionName: "draggableHigh",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "top",
    handlePositioner: (point) => {
      const bBox = point.shapeArgs || point.graphic.getBBox();
      return {
        x: bBox.x || 0,
        y: bBox.y || 0
      };
    },
    handleFormatter: column.y.handleFormatter,
    propValidate: (val, point) => val >= point.low
  }
};
const arearange = {
  x: columnrange.x,
  /**
   * Allow low value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.arearange.dragDrop.draggableLow
   */
  low: {
    optionName: "draggableLow",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "bottom",
    handlePositioner: (point) => {
      const bBox = point.graphics && point.graphics[0] && point.graphics[0].getBBox();
      return bBox ? {
        x: bBox.x + bBox.width / 2,
        y: bBox.y + bBox.height / 2
      } : { x: -999, y: -999 };
    },
    handleFormatter: arearangeHandleFormatter,
    propValidate: columnrange.low.propValidate
  },
  /**
   * Allow high value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.arearange.dragDrop.draggableHigh
   */
  high: {
    optionName: "draggableHigh",
    axis: "y",
    move: true,
    resize: true,
    resizeSide: "top",
    handlePositioner: (point) => {
      const bBox = point.graphics && point.graphics[1] && point.graphics[1].getBBox();
      return bBox ? {
        x: bBox.x + bBox.width / 2,
        y: bBox.y + bBox.height / 2
      } : { x: -999, y: -999 };
    },
    handleFormatter: arearangeHandleFormatter,
    propValidate: columnrange.high.propValidate
  }
};
const xrange = {
  y: {
    axis: "y",
    move: true
  },
  /**
   * Allow x value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.xrange.dragDrop.draggableX1
   */
  x: {
    optionName: "draggableX1",
    axis: "x",
    move: true,
    resize: true,
    resizeSide: "left",
    handlePositioner: (point) => xrangeHandlePositioner(point, "x"),
    handleFormatter: horizHandleFormatter,
    propValidate: (val, point) => val <= point.x2
  },
  /**
   * Allow x2 value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.xrange.dragDrop.draggableX2
   */
  x2: {
    optionName: "draggableX2",
    axis: "x",
    move: true,
    resize: true,
    resizeSide: "right",
    handlePositioner: (point) => xrangeHandlePositioner(point, "x2"),
    handleFormatter: horizHandleFormatter,
    propValidate: (val, point) => val >= point.x
  }
};
const gantt = {
  y: xrange.y,
  /**
   * Allow start value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.gantt.dragDrop.draggableStart
   */
  start: merge$1(xrange.x, {
    optionName: "draggableStart",
    // Do not allow individual drag handles for milestones
    validateIndividualDrag: (point) => !point.milestone
  }),
  /**
   * Allow end value to be dragged individually.
   *
   * @type      {boolean}
   * @default   true
   * @requires  modules/draggable-points
   * @apioption plotOptions.gantt.dragDrop.draggableEnd
   */
  end: merge$1(xrange.x2, {
    optionName: "draggableEnd",
    // Do not allow individual drag handles for milestones
    validateIndividualDrag: (point) => !point.milestone
  })
};
function arearangeHandleFormatter(point) {
  const radius = point.graphic ? point.graphic.getBBox().width / 2 + 1 : 4;
  return [
    ["M", 0 - radius, 0],
    ["a", radius, radius, 0, 1, 0, radius * 2, 0],
    ["a", radius, radius, 0, 1, 0, radius * -2, 0]
  ];
}
function horizHandleFormatter(point) {
  const shapeArgs = point.shapeArgs || point.graphic.getBBox(), top = shapeArgs.r || 0, bottom = shapeArgs.height - top, centerY = shapeArgs.height / 2;
  return [
    // Top wick
    ["M", 0, top],
    ["L", 0, centerY - 5],
    // Circle
    ["A", 1, 1, 0, 0, 0, 0, centerY + 5],
    ["A", 1, 1, 0, 0, 0, 0, centerY - 5],
    // Bottom wick
    ["M", 0, centerY + 5],
    ["L", 0, bottom]
  ];
}
function xrangeHandlePositioner(point, xProp) {
  const series = point.series, xAxis2 = series.xAxis, yAxis2 = series.yAxis, inverted = series.chart.inverted, offsetY = series.columnMetrics ? series.columnMetrics.offset : -point.shapeArgs.height / 2;
  let newX = xAxis2.toPixels(point[xProp], true), newY = yAxis2.toPixels(point.y, true);
  if (inverted) {
    newX = xAxis2.len - newX;
    newY = yAxis2.len - newY;
  }
  newY += offsetY;
  return {
    x: Math.round(newX),
    y: Math.round(newY)
  };
}
const DragDropProps = {
  arearange,
  boxplot,
  bullet,
  column,
  columnrange,
  errorbar,
  flags,
  gantt,
  line,
  ohlc,
  waterfall,
  xrange
};
const { addEvents, getNormalizedEvent } = DragDropUtilities;
const { initDragDrop } = DraggableChart;
const { addEvent, clamp: clamp$1, isNumber, merge } = Utilities;
function compose$1(ChartClass, SeriesClass) {
  DraggableChart.compose(ChartClass);
  const seriesProto2 = SeriesClass.prototype;
  if (!seriesProto2.dragDropProps) {
    const PointClass = SeriesClass.prototype.pointClass, seriesTypes2 = SeriesClass.types, pointProto2 = PointClass.prototype;
    pointProto2.getDropValues = pointGetDropValues;
    pointProto2.showDragHandles = pointShowDragHandles;
    addEvent(PointClass, "mouseOut", onPointMouseOut);
    addEvent(PointClass, "mouseOver", onPointMouseOver);
    addEvent(PointClass, "remove", onPointRemove);
    seriesProto2.dragDropProps = DragDropProps.line;
    seriesProto2.getGuideBox = seriesGetGuideBox;
    const seriesWithDragDropProps = [
      "arearange",
      "boxplot",
      "bullet",
      "column",
      "columnrange",
      "errorbar",
      "flags",
      "gantt",
      "ohlc",
      "waterfall",
      "xrange"
    ];
    for (const seriesType of seriesWithDragDropProps) {
      if (seriesTypes2[seriesType]) {
        seriesTypes2[seriesType].prototype.dragDropProps = DragDropProps[seriesType];
      }
    }
    const seriesWithoutDragDropProps = [
      "bellcurve",
      "gauge",
      "histogram",
      "map",
      "mapline",
      "pareto",
      "pie",
      "sankey",
      "sma",
      "sunburst",
      "treemap",
      "vector",
      "windbarb",
      "wordcloud"
    ];
    for (const seriesType of seriesWithoutDragDropProps) {
      if (seriesTypes2[seriesType]) {
        seriesTypes2[seriesType].prototype.dragDropProps = null;
      }
    }
  }
}
function mouseOut(point) {
  const chart = point.series && point.series.chart, dragDropData = chart && chart.dragDropData;
  if (chart && chart.dragHandles && !(dragDropData && (dragDropData.isDragging && dragDropData.draggedPastSensitivity || dragDropData.isHoveringHandle === point.id))) {
    chart.hideDragHandles();
  }
}
function mouseOver(point) {
  const series = point.series, chart = series && series.chart, dragDropData = chart && chart.dragDropData, is3d = chart && chart.is3d && chart.is3d();
  if (chart && !(dragDropData && dragDropData.isDragging && // Ignore if dragging a point
  dragDropData.draggedPastSensitivity) && !chart.isDragDropAnimating && // Ignore if animating
  series.options.dragDrop && // No need to compute handles without this
  !is3d) {
    if (chart.dragHandles) {
      chart.hideDragHandles();
    }
    point.showDragHandles();
  }
}
function onPointMouseOut() {
  const point = this;
  setTimeout(() => {
    if (point.series) {
      mouseOut(point);
    }
  }, 10);
}
function onPointMouseOver() {
  const point = this;
  setTimeout(() => mouseOver(point), 12);
}
function onPointRemove() {
  const chart = this.series.chart, dragHandles = chart.dragHandles;
  if (dragHandles && dragHandles.point === this.id) {
    chart.hideDragHandles();
  }
}
function onResizeHandleMouseOut(point) {
  const chart = point.series.chart;
  if (chart.dragDropData && point.id === chart.dragDropData.isHoveringHandle) {
    delete chart.dragDropData.isHoveringHandle;
  }
  if (!chart.hoverPoint) {
    mouseOut(point);
  }
}
function onResizeHandleMouseDown(e, point, updateProp) {
  const chart = point.series.chart;
  if (chart.zoomOrPanKeyPressed(e)) {
    return;
  }
  chart.mouseIsDown = false;
  initDragDrop(e, point);
  chart.dragDropData.updateProp = e.updateProp = updateProp;
  point.firePointEvent("dragStart", e);
  e.stopPropagation();
  e.preventDefault();
}
function pointGetDropValues(origin, newPos, updateProps) {
  const point = this, series = point.series, chart = series.chart, mapView = chart.mapView, options2 = merge(series.options.dragDrop, point.options.dragDrop), result = {}, pointOrigin = origin.points[point.id], updateSingleProp = Object.keys(updateProps).length === 1;
  const limitToRange = (val, dir) => {
    const direction = dir.toUpperCase(), time = series.chart.time, defaultPrecision = series[`${dir}Axis`].categories ? 1 : 0, precision = options2[`dragPrecision${direction}`] ?? defaultPrecision, min2 = time.parse(options2[`dragMin${direction}`]) ?? -Infinity, max2 = time.parse(options2[`dragMax${direction}`]) ?? Infinity;
    let res = val;
    if (precision) {
      res = Math.round(res / precision) * precision;
    }
    return clamp$1(res, min2, max2);
  };
  const limitToMapRange = (newPos2, dir, key2) => {
    if (mapView) {
      const direction = dir.toUpperCase(), precision = options2[`dragPrecision${direction}`] ?? 0, lonLatMin = mapView.pixelsToLonLat({
        x: 0,
        y: 0
      }), lonLatMax = mapView.pixelsToLonLat({
        x: chart.plotBox.width,
        y: chart.plotBox.height
      });
      let min2 = options2[`dragMin${direction}`] ?? lonLatMin?.[key2] ?? -Infinity, max2 = options2[`dragMax${direction}`] ?? lonLatMax?.[key2] ?? Infinity, res = newPos2[key2];
      if (mapView.projection.options.name === "Orthographic") {
        return res;
      }
      if (key2 === "lat") {
        if (isNaN(min2) || min2 > mapView.projection.maxLatitude) {
          min2 = mapView.projection.maxLatitude;
        }
        if (isNaN(max2) || max2 < -1 * mapView.projection.maxLatitude) {
          max2 = -1 * mapView.projection.maxLatitude;
        }
        const temp = max2;
        max2 = min2;
        min2 = temp;
      }
      if (!mapView.projection.hasCoordinates) {
        const lonLatRes = mapView.pixelsToLonLat({
          x: newPos2.chartX - chart.plotLeft,
          y: chart.plotHeight - newPos2.chartY + chart.plotTop
        });
        if (lonLatRes) {
          res = lonLatRes[key2];
        }
      }
      if (precision) {
        res = Math.round(res / precision) * precision;
      }
      return clamp$1(res, min2, max2);
    }
  };
  for (const key2 of Object.keys(updateProps)) {
    const val = updateProps[key2], oldVal = pointOrigin.point[key2], axis = series[val.axis + "Axis"], newVal = mapView ? limitToMapRange(newPos, val.axis, key2) : limitToRange(axis.toValue((axis.horiz ? newPos.chartX : newPos.chartY) + pointOrigin[key2 + "Offset"]), val.axis);
    if (isNumber(newVal) && !(updateSingleProp && val.propValidate && !val.propValidate(newVal, point)) && typeof oldVal !== "undefined") {
      result[key2] = newVal;
    }
  }
  return result;
}
function pointShowDragHandles() {
  const point = this, series = point.series, chart = series.chart, { inverted, renderer } = chart, options2 = merge(series.options.dragDrop, point.options.dragDrop), dragDropProps = series.dragDropProps || {};
  let dragHandles = chart.dragHandles;
  for (const key2 of Object.keys(dragDropProps)) {
    const val = dragDropProps[key2], handleOptions = merge(DragDropDefaults.dragHandle, val.handleOptions, options2.dragHandle), handleAttrs = {
      "class": handleOptions.className,
      "stroke-width": handleOptions.lineWidth,
      fill: handleOptions.color,
      stroke: handleOptions.lineColor
    }, pathFormatter = handleOptions.pathFormatter || val.handleFormatter, handlePositioner = val.handlePositioner, validate = val.validateIndividualDrag ? val.validateIndividualDrag(point) : true;
    let pos, handle, path;
    if (val.resize && validate && val.resizeSide && pathFormatter && (options2["draggable" + val.axis.toUpperCase()] || options2[val.optionName]) && options2[val.optionName] !== false) {
      if (!dragHandles) {
        dragHandles = chart.dragHandles = {
          group: renderer.g("drag-drop-handles").add(series.markerGroup || series.group),
          point: point.id
        };
      } else {
        dragHandles.point = point.id;
      }
      pos = handlePositioner(point);
      handleAttrs.d = path = pathFormatter(point);
      const minEdge = point.series.xAxis.categories ? -0.5 : 0;
      if (!path || pos.x < minEdge || pos.y < 0) {
        return;
      }
      handleAttrs.cursor = handleOptions.cursor || (val.axis === "x" !== !!inverted ? "ew-resize" : "ns-resize");
      handle = dragHandles[val.optionName];
      if (!handle) {
        handle = dragHandles[val.optionName] = renderer.path().add(dragHandles.group);
      }
      handleAttrs.translateX = inverted ? series.yAxis.len - pos.y : pos.x;
      handleAttrs.translateY = inverted ? series.xAxis.len - pos.x : pos.y;
      if (inverted) {
        handleAttrs.rotation = -90;
      }
      handle.attr(handleAttrs);
      addEvents(handle.element, ["touchstart", "mousedown"], (e) => {
        onResizeHandleMouseDown(getNormalizedEvent(e, chart), point, key2);
      }, {
        passive: false
      });
      addEvent(dragHandles.group.element, "mouseover", () => {
        chart.dragDropData = chart.dragDropData || {};
        chart.dragDropData.isHoveringHandle = point.id;
      });
      addEvents(dragHandles.group.element, ["touchend", "mouseout"], () => {
        onResizeHandleMouseOut(point);
      });
    }
  }
}
function seriesGetGuideBox(points) {
  const chart = this.chart;
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity, changed;
  for (const point of points) {
    const bBox = point.graphic && point.graphic.getBBox() || point.shapeArgs;
    if (bBox) {
      let plotX2;
      const x2 = point.x2;
      if (isNumber(x2)) {
        plotX2 = point.series.xAxis.translate(x2, false, false, false, true);
      }
      const skipBBox = !(bBox.width || bBox.height || bBox.x || bBox.y);
      changed = true;
      minX = Math.min(point.plotX || 0, plotX2 || 0, skipBBox ? Infinity : bBox.x || 0, minX);
      maxX = Math.max(point.plotX || 0, plotX2 || 0, (bBox.x || 0) + (bBox.width || 0), maxX);
      minY = Math.min(point.plotY || 0, skipBBox ? Infinity : bBox.y || 0, minY);
      maxY = Math.max((bBox.y || 0) + (bBox.height || 0), maxY);
    }
  }
  return changed ? chart.renderer.rect(minX, minY, maxX - minX, maxY - minY) : chart.renderer.g();
}
const DraggablePoints = {
  compose: compose$1
};
/**
 * @license Highcharts JS v12.2.0 (2025-04-07)
 * @module highcharts/modules/draggable-points
 * @requires highcharts
 *
 * (c) 2009-2025 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
const G = Highcharts;
DraggablePoints.compose(G.Chart, G.Series);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
["exportChart", "exportChartLocal", "getSVG"].forEach((methodName) => {
  G$k.wrap(G$k.Chart.prototype, methodName, function(proceed, ...args) {
    G$k.fireEvent(this, "beforeExport");
    const result = proceed.apply(this, args);
    G$k.fireEvent(this, "afterExport");
    return result;
  });
});
Pointer$1.prototype.onDocumentMouseMove = function(e) {
  const chart = this.chart;
  const chartPosition = this.chartPosition;
  const pEvt = this.normalize(e, chartPosition);
  const tooltip = chart.tooltip;
  if (chartPosition && (!tooltip || !tooltip.isSticky) && !chart.isInsidePlot(pEvt.chartX - chart.plotLeft, pEvt.chartY - chart.plotTop, {
    visiblePlotOnly: true
  }) && // Use the first element from the composed path instead of the actual target
  !this.inClass(pEvt.composedPath()[0], "highcharts-tracker")) {
    this.reset();
  }
};
const { simulatedEventTarget } = HTMLUtilities;
KeyboardNavigation$1.prototype.onMouseUp = function(e) {
  delete this.isClickingChart;
  if (!this.keyboardReset && e.relatedTarget !== simulatedEventTarget) {
    const chart = this.chart;
    const target = e.composedPath()[0];
    if (!target || !chart.container.contains(target)) {
      const curMod = this.modules && this.modules[this.currentModuleIx || 0];
      if (curMod && curMod.terminate) {
        curMod.terminate();
      }
      this.currentModuleIx = 0;
    }
    if (chart.focusElement) {
      chart.focusElement.removeFocusBorder();
      delete chart.focusElement;
    }
    this.keyboardReset = true;
  }
};
G$k.setOptions({ lang: { noData: "" } });
const ChartMixin = (superClass) => class extends ResizeMixin(superClass) {
  static get properties() {
    return {
      /**
       * Configuration object that exposes the JS Api to configure the chart.
       *
       * Most important methods are:
       * - `addSeries (Object options, [Boolean redraw], [Mixed animation])`
       * - `addAxis (Object options, [Boolean isX], [Boolean redraw], [Mixed animation])`
       * - `setTitle (Object title, object subtitle, Boolean redraw)`
       *
       * Most important properties are:
       * - `configuration.series`: An array of the chart's series. Detailed API for Series object is
       *     available in [API Site](http://api.highcharts.com/class-reference/Highcharts.Series)
       * - `configuration.xAxis`: An array of the chart's x axes. Detailed API for Axis object is
       *     available in [API Site](http://api.highcharts.com/class-reference/Highcharts.Axis)
       * - `configuration.yAxis`: An array of the chart's y axes. Detailed API for Axis object is
       *     available in [API Site](http://api.highcharts.com/class-reference/Highcharts.Axis)
       * - `configuration.title`: The chart title.
       *
       * For detailed documentation of available API check the [API site](http://api.highcharts.com/class-reference/classes.list)
       * @type {!Highcharts.Chart | undefined}
       */
      configuration: {
        type: Object,
        sync: true
      },
      /**
       * If categories are present names are used instead of numbers for the category axis.
       * The format of categories can be an `Array` with a list of categories, such as `['2010', '2011', '2012']`
       * or a mapping `Object`, like `{0:'1',9:'Target (10)', 15: 'Max'}`.
       * @type {ChartCategories | undefined}
       */
      categories: {
        type: Object,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Category-axis maximum value. Defaults to `undefined`.
       * @attr {number} category-max
       */
      categoryMax: {
        type: Number,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Category-axis minimum value. Defaults to `undefined`.
       * @attr {number} category-min
       */
      categoryMin: {
        type: Number,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * The position of the category axis. Acceptable values are `left`, `right`, `top` and `bottom`
       * except for bar charts which only accept `left` and `right`.
       * With the default value, charts appear as though they have `category-position="bottom"`
       * except for bar charts that appear as though they have `category-position="left"`.
       *
       * Defaults to `undefined`
       *
       * @attr {left|right|top|bottom} category-position
       */
      categoryPosition: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Specifies whether to hide legend or show.
       * Legend configuration can be set up via additionalOptions property
       * @attr {boolean} no-legend
       */
      noLegend: {
        type: Boolean,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Specifies how series are stacked on top of each other.
       * Possible values are null, "normal" or "percent".
       * If "stack" property is not defined on the vaadin-chart-series elements, then series will be put into
       * the default stack.
       * @attr {normal|percent} stacking
       */
      stacking: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Specifies whether the chart is a normal chart or a timeline chart.
       * Value of this property is ignored for Gantt charts (type="gantt").
       */
      timeline: {
        type: Boolean,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Represents the title of the chart.
       */
      title: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Whether or not to show tooltip when hovering data points.
       */
      tooltip: {
        type: Boolean,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Sets the default series type of the chart.
       * Note that `'bar'`, `'gauge'` and `'solidgauge'` should be set as default series type.
       */
      type: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Represents the subtitle of the chart.
       */
      subtitle: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Specifies whether to show chart in 3 or in 2 dimensions.
       * Some display angles are added by default to the "chart.options3d" (`{alpha: 15, beta: 15, depth: 50}`).
       * 3D display options can be modified via `additionalOptions`.
       * The thickness of a Pie chart can be set on `additionalOptions` through `plotOptions.pie.depth`.
       * 3D is supported by Bar, Column, Pie and Scatter3D charts.
       * More info available at [Highcharts](https://www.highcharts.com/docs/chart-concepts/3d-charts).
       */
      chart3d: {
        type: Boolean,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Specifies the message displayed on a chart without displayable data.
       * @attr {string} empty-text
       */
      emptyText: {
        type: String,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Represents additional JSON configuration.
       * @type {Options | undefined}
       */
      additionalOptions: {
        type: Object,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * When present, cartesian charts like line, spline, area and column are transformed
       * into the polar coordinate system.
       */
      polar: {
        type: Boolean,
        reflectToAttribute: true,
        sync: true
      },
      /** @private */
      __styledMode: {
        type: Boolean,
        sync: true
      }
    };
  }
  static get observers() {
    return [
      "__chart3dObserver(chart3d, configuration)",
      "__emptyTextObserver(emptyText, configuration)",
      "__hideLegend(noLegend, configuration)",
      "__polarObserver(polar, configuration)",
      "__stackingObserver(stacking, configuration)",
      "__tooltipObserver(tooltip, configuration)",
      "__updateCategories(categories, configuration)",
      "__updateCategoryMax(categoryMax, configuration)",
      "__updateCategoryMin(categoryMin, configuration)",
      "__updateCategoryPosition(categoryPosition, configuration)",
      "__updateSubtitle(subtitle, configuration)",
      "__updateTitle(title, configuration)",
      "__updateType(type, configuration)",
      "__updateAdditionalOptions(additionalOptions)"
    ];
  }
  /** @private */
  static __callHighchartsFunction(functionName, redrawCharts, ...args) {
    const functionToCall = G$k[functionName];
    if (functionToCall && typeof functionToCall === "function") {
      args.forEach((arg) => inflateFunctions(arg));
      functionToCall.apply(this.configuration, args);
      if (redrawCharts) {
        const lang2 = G$k.defaultOptions.lang;
        G$k.charts.forEach((c) => {
          if (c !== void 0) {
            c.time.lang = lang2;
            c.redraw();
          }
        });
      }
    }
  }
  constructor() {
    super();
    this._baseConfig = {
      annotations: [],
      chart: {
        styledMode: true
      },
      credits: {
        enabled: false
      },
      exporting: {
        enabled: false
      },
      title: {
        text: null
      },
      series: [],
      xAxis: {},
      yAxis: {
        axisGenerated: true
      }
    };
    this._baseChart3d = {
      enabled: true,
      alpha: 15,
      beta: 15,
      depth: 50
    };
  }
  /**
   * @return {!Options}
   */
  get options() {
    const options2 = { ...this._baseConfig };
    deepMerge(options2, this.additionalOptions);
    if (this.type) {
      options2.chart.type = this.type;
    }
    if (this.polar) {
      options2.chart.polar = true;
    }
    if (this.title) {
      options2.title = {
        text: this.title
      };
    }
    if (!options2.tooltip) {
      options2.tooltip = {};
      if (!this.tooltip) {
        options2.tooltip.enabled = false;
      }
    }
    if (this.subtitle) {
      options2.subtitle = {
        text: this.subtitle
      };
    }
    if (this.categories) {
      if (Array.isArray(options2.xAxis)) {
        options2.xAxis[0].categories = this.categories;
      } else {
        options2.xAxis.categories = this.categories;
      }
    }
    if (isFinite(this.categoryMin)) {
      if (Array.isArray(options2.xAxis)) {
        options2.xAxis[0].min = this.categoryMin;
      } else {
        options2.xAxis.min = this.categoryMin;
      }
    }
    if (isFinite(this.categoryMax)) {
      if (Array.isArray(options2.xAxis)) {
        options2.xAxis[0].max = this.categoryMax;
      } else {
        options2.xAxis.max = this.categoryMax;
      }
    }
    if (this.noLegend) {
      options2.legend = {
        enabled: false
      };
    }
    if (this.emptyText) {
      if (!options2.lang) {
        options2.lang = {};
      }
      options2.lang.noData = this.emptyText;
    }
    if (this.categoryPosition) {
      options2.chart.inverted = this.__shouldInvert();
      if (Array.isArray(options2.xAxis)) {
        options2.xAxis.forEach((e) => {
          e.opposite = this.__shouldFlipOpposite();
        });
      } else if (options2.xAxis) {
        options2.xAxis.opposite = this.__shouldFlipOpposite();
      }
    }
    if (this.stacking) {
      if (!options2.plotOptions) {
        options2.plotOptions = {};
      }
      if (!options2.plotOptions.series) {
        options2.plotOptions.series = {};
      }
      options2.plotOptions.series.stacking = this.stacking;
    }
    if (this.chart3d) {
      options2.chart.options3d = { ...this._baseChart3d, ...options2.chart.options3d };
    }
    return options2;
  }
  /*
   * Name of the chart events to add to the configuration and its corresponding event for the chart element
   * @private
   */
  get __chartEventNames() {
    return {
      /**
       * Fired when a new series is added.
       * @event chart-add-series
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      addSeries: "chart-add-series",
      /**
       * Fired after a chart is exported.
       * @event chart-after-export
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      afterExport: "chart-after-export",
      /**
       * Fired after a chart is printed.
       * @event chart-after-print
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      afterPrint: "chart-after-print",
      /**
       * Fired before a chart is exported.
       * @event chart-before-export
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      beforeExport: "chart-before-export",
      /**
       * Fired before a chart is printed.
       * @event chart-before-print
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      beforePrint: "chart-before-print",
      /**
       * Fired when clicking on the plot background.
       * @event chart-click
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      click: "chart-click",
      /**
       * Fired when drilldown point is clicked.
       * @event chart-drilldown
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      drilldown: "chart-drilldown",
      /**
       * Fired when drilling up from a drilldown series.
       * @event chart-drillup
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      drillup: "chart-drillup",
      /**
       * Fired after all the series has been drilled up if chart has multiple drilldown series.
       * @event chart-drillupall
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      drillupall: "chart-drillupall",
      /**
       * Fired when the chart is finished loading.
       * @event chart-load
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      load: "chart-load",
      /**
       * Fired when the chart is redraw. Can be called after a `Chart.configuration.redraw()`
       * or after an axis, series or point is modified with the `redraw` option set to `true`.
       * @event chart-redraw
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      redraw: "chart-redraw",
      /**
       * Fired when an area of the chart has been selected.
       * @event chart-selection
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      selection: "chart-selection",
      /**
       * Fired when the chart finishes resizing.
       * @event chart-end-resize
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} chart Chart object where the event was sent from
       */
      endResize: "chart-end-resize"
    };
  }
  /**
   * Name of the series events to add to the configuration and its corresponding event for the chart element
   * @private
   */
  get __seriesEventNames() {
    return {
      /**
       * Fired when the series has finished its initial animation.
       * @event series-after-animate
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      afterAnimate: "series-after-animate",
      /**
       * Fired when the checkbox next to the series' name in the legend is clicked.
       * @event series-checkbox-click
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      checkboxClick: "series-checkbox-click",
      /**
       * Fired when the series is clicked.
       * @event series-click
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      click: "series-click",
      /**
       * Fired when the series is hidden after chart generation time.
       * @event series-hide
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      hide: "series-hide",
      /**
       * Fired when the legend item belonging to the series is clicked.
       * @event series-legend-item-click
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      /**
       * Fired when the mouses leave the graph.
       * @event series-mouse-out
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      mouseOut: "series-mouse-out",
      /**
       * Fired when the mouse enters the graph.
       * @event series-mouse-over
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      mouseOver: "series-mouse-over",
      /**
       * Fired when the series is show after chart generation time.
       * @event series-show
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} series Series object where the event was sent from
       */
      show: "series-show"
    };
  }
  /**
   * Name of the point events to add to the configuration and its corresponding event for the chart element
   * @private
   */
  get __pointEventNames() {
    return {
      /**
       * Fired when the point is clicked.
       * @event point-click
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      click: "point-click",
      /**
       * Fired when the legend item belonging to the point is clicked.
       * @event point-legend-item-click
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      /**
       * Fired when the mouse leaves the area close to the point.
       * @event point-mouse-out
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      mouseOut: "point-mouse-out",
      /**
       * Fired when the mouse enters the area close to the point.
       * @event point-mouse-over
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      mouseOver: "point-mouse-over",
      /**
       * Fired when the point is removed from the series.
       * @event point-remove
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      remove: "point-remove",
      /**
       * Fired when the point is selected either programmatically or by clicking on the point.
       * @event point-select
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      select: "point-select",
      /**
       * Fired when the point is unselected either programmatically or by clicking on the point
       * @event point-unselect
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      unselect: "point-unselect",
      /**
       * Fired when the point is updated programmatically through `.updateConfiguration()` method.
       * @event point-update
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      update: "point-update",
      /**
       * Fired when starting to drag a point.
       * @event point-drag-start
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      dragStart: "point-drag-start",
      /**
       * Fired when the point is dropped.
       * @event point-drop
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      drop: "point-drop",
      /**
       * Fired while dragging a point.
       * @event point-drag
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} point Point object where the event was sent from
       */
      drag: "point-drag"
    };
  }
  /** @private */
  get __xAxesEventNames() {
    return {
      /**
       * Fired when the minimum and maximum is set for the x axis.
       * @event xaxes-extremes-set
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} axis Point object where the event was sent from
       */
      afterSetExtremes: "xaxes-extremes-set"
    };
  }
  /** @private */
  get __yAxesEventNames() {
    return {
      /**
       * Fired when the minimum and maximum is set for the y axis.
       * @event yaxes-extremes-set
       * @param {Object} detail.originalEvent object with details about the event sent
       * @param {Object} axis Point object where the event was sent from
       */
      afterSetExtremes: "yaxes-extremes-set"
    };
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this.__updateStyles();
    queueMicrotask(() => {
      if (this.configuration) {
        return;
      }
      this.__resetChart();
      this.__addChildObserver();
      this.__checkTurboMode();
    });
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("chart-redraw", this.__onRedraw.bind(this));
  }
  /**
   * Implements resize callback from `ResizeMixin`
   * to reflow when the chart element is resized.
   * @protected
   * @override
   */
  _onResize(contentRect) {
    if (!this.configuration) {
      return;
    }
    const { height, width } = contentRect;
    const { chartHeight, chartWidth } = this.configuration;
    this.$.wrapper.style.minHeight = "";
    if (this.$.wrapper.offsetHeight <= 1) {
      this.$.wrapper.style.minHeight = `${chartHeight}px`;
    }
    this.$.wrapper.style.minWidth = "";
    if (this.$.wrapper.offsetWidth <= 1) {
      this.$.wrapper.style.minWidth = `${chartWidth}px`;
    }
    if (height !== chartHeight || width !== chartWidth) {
      this.__reflow();
    }
  }
  /** @private */
  __reflow() {
    if (!this.configuration) {
      return;
    }
    this.configuration.reflow();
  }
  /** @private */
  __addChildObserver() {
    this._childObserver = new SlotObserver(this.$.slot, (info) => {
      this.__addSeries(info.addedNodes.filter(this.__filterSeriesNodes));
      this.__removeSeries(info.removedNodes.filter(this.__filterSeriesNodes));
      this.__cleanupAfterSeriesRemoved(info.removedNodes.filter(this.__filterSeriesNodes));
    });
  }
  /** @private */
  __filterSeriesNodes(node) {
    const ChartSeries2 = customElements.get("vaadin-chart-series");
    return node.nodeType === Node.ELEMENT_NODE && node instanceof ChartSeries2;
  }
  /** @private */
  __addSeries(series) {
    if (this.__isSeriesEmpty(series)) {
      return;
    }
    const seriesNodes = Array.from(this.childNodes).filter(this.__filterSeriesNodes);
    const yAxes = this.configuration.yAxis.reduce((acc, axis, index) => {
      acc[axis.options.id || index] = axis;
      return acc;
    }, {});
    for (let i = 0, len = series.length; i < len; i++) {
      const seriesElement = series[i];
      const { yAxis: unit, yAxisValueMin: valueMin, yAxisValueMax: valueMax } = seriesElement.options;
      const idxOnChildList = seriesNodes.indexOf(seriesElement);
      if (!unit && !this.configuration.yAxis.some((e) => e.userOptions.id === void 0)) {
        yAxes[unit] = this.__addAxis({ axisGenerated: true });
      } else if (unit && !yAxes[unit]) {
        yAxes[unit] = this.__addAxis({ id: unit, title: { text: unit }, axisGenerated: true });
      }
      if (isFinite(valueMin)) {
        this.__setYAxisProps(yAxes, unit, { min: valueMin });
      }
      if (isFinite(valueMax)) {
        this.__setYAxisProps(yAxes, unit, { max: valueMax });
      }
      const seriesConfiguration = this.__updateOrAddSeriesInstance(seriesElement.options, idxOnChildList, false);
      seriesElement.setSeries(seriesConfiguration);
    }
    this.__removeAxisIfEmpty();
    this.configuration.redraw();
  }
  /** @private */
  __removeSeries(seriesNodes) {
    if (this.__isSeriesEmpty(seriesNodes)) {
      return;
    }
    const ChartSeries2 = customElements.get("vaadin-chart-series");
    seriesNodes.forEach((series) => {
      if (series instanceof ChartSeries2) {
        series._series.remove();
      }
    });
  }
  /** @private */
  __setYAxisProps(yAxes, yAxisId, props) {
    if (yAxisId) {
      yAxes[yAxisId].update(props);
    } else {
      this.configuration.yAxis[0].update(props);
    }
  }
  /** @private */
  __isSeriesEmpty(series) {
    return series === null || series.length === 0;
  }
  /** @private */
  __cleanupAfterSeriesRemoved(series) {
    if (this.__isSeriesEmpty(series)) {
      return;
    }
    this.__removeAxisIfEmpty();
    this.__updateNoDataElement(this.configuration);
  }
  /** @private */
  __initChart(options2) {
    this.__initEventsListeners(options2);
    this.__styledMode = options2.chart.styledMode;
    if (options2.chart.type === "gantt") {
      this.configuration = G$k.ganttChart(this.$.chart, options2);
    } else if (this.timeline) {
      this.configuration = G$k.stockChart(this.$.chart, options2);
    } else {
      this.configuration = G$k.chart(this.$.chart, options2);
    }
    this.__forceResize();
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (this.configuration) {
      this._jsonConfigurationBuffer = deepMerge({}, this.configuration.userOptions);
    }
    queueMicrotask(() => {
      if (this.isConnected) {
        return;
      }
      if (this.configuration) {
        this.configuration.destroy();
        this.configuration = void 0;
        const seriesNodes = Array.from(this.childNodes).filter(this.__filterSeriesNodes);
        seriesNodes.forEach((series) => {
          series.setSeries(null);
        });
      }
      if (this._childObserver) {
        this._childObserver.disconnect();
      }
    });
  }
  /** @private */
  __resetChart() {
    const initialOptions = { ...this.options, ...this._jsonConfigurationBuffer };
    this.__initChart(initialOptions);
    this._jsonConfigurationBuffer = null;
  }
  /**
   * Search for axis with given `id`.
   *
   * @param {string} id contains the id that will be searched
   * @param {boolean} isXAxis indicates if it will remove x or y axes. Defaults to `false`.
   * @return {Axis}
   * @protected
   */
  __getAxis(id, isXAxis) {
    id = Number.parseInt(id) || id;
    if (this.configuration) {
      return (isXAxis ? this.configuration.xAxis : this.configuration.yAxis).find((axis) => axis.options.id === id);
    }
  }
  /**
   * Add an axis with given options
   *
   * @param {Object} options axis options
   * @param {boolean} isXAxis indicates if axis is X (`true`) or Y (`false`). Defaults to `false`.
   * @return {!Axis}
   * @protected
   */
  __addAxis(options2, isXAxis) {
    if (this.configuration) {
      this.__createEventListeners(
        isXAxis ? this.__xAxesEventNames : this.__yAxesEventNames,
        options2,
        "events",
        "axis"
      );
      return this.configuration.addAxis(options2, isXAxis);
    }
  }
  /**
   * Iterates over axes (y or x) and removes whenever it doesn't contain any series and was created for unit
   *
   * @param {boolean} isXAxis indicates if it will remove x or y axes. Defaults to `false`.
   * @protected
   */
  __removeAxisIfEmpty(isXAxis) {
    if (this.configuration) {
      (isXAxis ? this.configuration.xAxis : this.configuration.yAxis).forEach((axis) => {
        if (axis.userOptions.axisGenerated && axis.series.length === 0) {
          axis.remove();
        }
      });
    }
  }
  /**
   * Update the chart configuration.
   * This JSON API provides a simple single-argument alternative to the configuration property.
   *
   * Styling properties specified in this configuration will be ignored. To learn about chart styling
   * please see the CSS Styling section above.
   *
   * @param {!Options} jsonConfiguration Object chart configuration. Most important properties are:
   *
   * - annotations `Object[]` custom labels or shapes that can be tied to points, axis coordinates or chart pixel coordinates.
   *    Detailed API for annotations object is available in [API Site](http://api.highcharts.com/highcharts/annotations)
   * - chart `Object` with options regarding the chart area and plot area as well as general chart options.
   *    Detailed API for chart object is available in [API Site](http://api.highcharts.com/highcharts/chart)
   * - credits `Object` with options regarding the chart area and plot area as well as general chart options.
   *    Detailed API for credits object is available in [API Site](http://api.highcharts.com/highcharts/credits)
   * - plotOptions `Object` wrapper for config objects for each series type.
   *    Detailed API for plotOptions object is available in [API Site](http://api.highcharts.com/highcharts/plotOptions)
   * - series `Object[]` the actual series to append to the chart.
   *    Detailed API for series object is available in [API Site](http://api.highcharts.com/highcharts/series)
   * - subtitle `Object` the chart's subtitle.
   *    Detailed API for subtitle object is available in [API Site](http://api.highcharts.com/highcharts/subtitle)
   * - title `Object` the chart's main title.
   *    Detailed API for title object is available in [API Site](http://api.highcharts.com/highcharts/title)
   * - tooltip `Object` Options for the tooltip that appears when the user hovers over a series or point.
   *    Detailed API for tooltip object is available in [API Site](http://api.highcharts.com/highcharts/tooltip)
   * - xAxis `Object[]` The X axis or category axis. Normally this is the horizontal axis.
   *    Detailed API for xAxis object is available in [API Site](http://api.highcharts.com/highcharts/xAxis)
   * - yAxis `Object[]` The Y axis or value axis. Normally this is the vertical axis.
   *    Detailed API for yAxis object is available in [API Site](http://api.highcharts.com/highcharts/yAxis)
   * - zAxis `Object[]` The Z axis or depth axis for 3D plots.
   *    Detailed API for zAxis object is available in [API Site](http://api.highcharts.com/highcharts/zAxis)
   *
   * @param {boolean=} resetConfiguration Optional boolean that should be set to true if no other chart configuration was set before or
   *    if existing configuration should be discarded.
   */
  updateConfiguration(jsonConfiguration, resetConfiguration) {
    if (resetConfiguration || !this._jsonConfigurationBuffer) {
      this._jsonConfigurationBuffer = {};
    }
    const configCopy = deepMerge({}, jsonConfiguration);
    inflateFunctions(configCopy);
    this._jsonConfigurationBuffer = this.__makeConfigurationBuffer(this._jsonConfigurationBuffer, configCopy);
    queueMicrotask(() => {
      if (!this.configuration || !this._jsonConfigurationBuffer) {
        return;
      }
      if (resetConfiguration) {
        this.__resetChart();
        return;
      }
      this.configuration.update(this._jsonConfigurationBuffer, false);
      if (this._jsonConfigurationBuffer.credits) {
        this.__updateOrAddCredits(this._jsonConfigurationBuffer.credits);
      }
      if (this._jsonConfigurationBuffer.xAxis) {
        this.__updateOrAddAxes(this._jsonConfigurationBuffer.xAxis, true, false);
      }
      if (this._jsonConfigurationBuffer.yAxis) {
        this.__updateOrAddAxes(this._jsonConfigurationBuffer.yAxis, false, false);
      }
      if (this._jsonConfigurationBuffer.series) {
        this.__updateOrAddSeries(this._jsonConfigurationBuffer.series, false);
      }
      this._jsonConfigurationBuffer = null;
      this.configuration.redraw();
    });
  }
  /** @private */
  __makeConfigurationBuffer(target, source) {
    const _source = G$k.merge(source);
    const _target = G$k.merge(target);
    this.__mergeConfigurationArray(_target, _source, "series");
    this.__mergeConfigurationArray(_target, _source, "xAxis");
    this.__mergeConfigurationArray(_target, _source, "yAxis");
    return G$k.merge(_target, _source);
  }
  /** @private */
  __mergeConfigurationArray(target, configuration, entry) {
    if (!configuration || !configuration[entry] || !Array.isArray(configuration[entry])) {
      return;
    }
    if (!target[entry]) {
      target[entry] = Array.from(configuration[entry]);
      return;
    }
    const maxLength = Math.max(target[entry].length, configuration[entry].length);
    for (let i = 0; i < maxLength; i++) {
      target[entry][i] = G$k.merge(target[entry][i], configuration[entry][i]);
    }
    delete configuration[entry];
  }
  /** @private */
  __initEventsListeners(configuration) {
    this.__initChartEventsListeners(configuration);
    this.__initSeriesEventsListeners(configuration);
    this.__initPointsEventsListeners(configuration);
    this.__initAxisEventsListeners(configuration, true);
    this.__initLegendItemClickEventListener(configuration);
    this.__initAxisEventsListeners(configuration, false);
  }
  /** @private */
  __initChartEventsListeners(configuration) {
    this.__createEventListeners(this.__chartEventNames, configuration, "chart.events", "chart");
  }
  /** @private */
  __initSeriesEventsListeners(configuration) {
    this.__createEventListeners(this.__seriesEventNames, configuration, "plotOptions.series.events", "series");
  }
  /** @private */
  __initPointsEventsListeners(configuration) {
    this.__createEventListeners(this.__pointEventNames, configuration, "plotOptions.series.point.events", "point");
  }
  /** @private */
  __initLegendItemClickEventListener(configuration) {
    const eventObject = this.__ensureObjectPath(configuration, "legend.events");
    eventObject.itemClick = (event) => {
      const customEvent = {
        bubbles: false,
        composed: true,
        detail: {
          originalEvent: event,
          legend: event.target
        }
      };
      const legendItemMatch = [
        { clazz: G$k.Series, type: "series" },
        { clazz: G$k.Point, type: "point" }
      ].find(({ clazz }) => event.legendItem instanceof clazz);
      if (legendItemMatch) {
        const { type: legendItemClickType } = legendItemMatch;
        customEvent.detail[legendItemClickType] = event.legendItem;
        this.dispatchEvent(new CustomEvent(`${legendItemClickType}-legend-item-click`, customEvent));
        if (this._visibilityTogglingDisabled) {
          return false;
        }
      }
    };
  }
  /** @private */
  __initAxisEventsListeners(configuration, isXAxis) {
    let eventNames, axes;
    if (isXAxis) {
      eventNames = this.__xAxesEventNames;
      axes = configuration.xAxis;
    } else {
      eventNames = this.__yAxesEventNames;
      axes = configuration.yAxis;
    }
    if (Array.isArray(axes)) {
      axes.forEach((axis) => this.__createEventListeners(eventNames, axis, "events", "axis"));
    } else {
      this.__createEventListeners(eventNames, axes, "events", "axis");
    }
  }
  /** @private */
  __createEventListeners(eventList, configuration, pathToAdd, eventType) {
    const eventObject = this.__ensureObjectPath(configuration, pathToAdd);
    const self2 = this;
    for (let keys = Object.keys(eventList), i = 0; i < keys.length; i++) {
      const key2 = keys[i];
      if (!eventObject[key2]) {
        eventObject[key2] = function(event) {
          const customEvent = {
            bubbles: false,
            composed: true,
            detail: {
              originalEvent: event,
              [eventType]: event.target
            }
          };
          if (key2 === "dragStart") {
            customEvent.detail[eventType] = this;
          }
          if (event.type === "afterSetExtremes") {
            if (event.min == null || event.max == null) {
              return;
            }
          }
          if (event.type === "selection") {
            if (event.xAxis && event.xAxis[0]) {
              customEvent.detail.xAxisMin = event.xAxis[0].min;
              customEvent.detail.xAxisMax = event.xAxis[0].max;
            }
            if (event.yAxis && event.yAxis[0]) {
              customEvent.detail.yAxisMin = event.yAxis[0].min;
              customEvent.detail.yAxisMax = event.yAxis[0].max;
            }
          }
          if (event.type === "click") {
            if (event.xAxis && event.xAxis[0]) {
              customEvent.detail.xValue = event.xAxis[0].value;
            }
            if (event.yAxis && event.yAxis[0]) {
              customEvent.detail.yValue = event.yAxis[0].value;
            }
          }
          if (["beforePrint", "beforeExport"].indexOf(event.type) >= 0) {
            prepareExport(self2);
          }
          if (["afterPrint", "afterExport"].indexOf(event.type) >= 0) {
            cleanupExport(self2);
          }
          self2.dispatchEvent(new CustomEvent(eventList[key2], customEvent));
        };
      }
    }
  }
  /** @private */
  __ensureObjectPath(object, path) {
    if (typeof path !== "string") {
      return;
    }
    path = path.split(".");
    return path.reduce((obj, key2) => {
      if (!obj[key2]) {
        obj[key2] = {};
      }
      return obj[key2];
    }, object);
  }
  /** @private */
  __hasConfigurationBuffer(path, property) {
    if (property && path.startsWith(property) && this._jsonConfigurationBuffer && Array.isArray(this._jsonConfigurationBuffer[property])) {
      return get$5(path.split(".")[1], this._jsonConfigurationBuffer[property][0]);
    }
    return get$5(path, this._jsonConfigurationBuffer) !== void 0;
  }
  /** @private */
  __updateOrAddCredits(credits) {
    if (this.configuration.credits) {
      this.configuration.credits.update(credits);
    } else {
      this.configuration.addCredits(credits);
    }
  }
  /** @private */
  __updateOrAddAxes(axes, isX, redraw) {
    if (!Array.isArray(axes)) {
      axes = [axes];
    }
    const confAxes = isX ? this.configuration.xAxis : this.configuration.yAxis;
    for (let i = 0; i < axes.length; i++) {
      const axis = axes[i];
      if (confAxes[i]) {
        confAxes[i].update(axis, redraw);
      } else {
        this.configuration.addAxis(axis, isX, redraw);
      }
    }
  }
  /** @private */
  __updateOrAddSeries(series, redraw) {
    if (!Array.isArray(series)) {
      throw new Error("The type of jsonConfiguration.series should be Object[]");
    }
    for (let i = 0; i < series.length; i++) {
      const currentSeries = series[i];
      this.__updateOrAddSeriesInstance(currentSeries, i, redraw);
    }
  }
  /** @private */
  __updateOrAddSeriesInstance(seriesOptions, position, redraw) {
    if (this.configuration.series[position]) {
      this.configuration.series[position].update(seriesOptions, redraw);
    } else {
      this.configuration.addSeries(seriesOptions, redraw);
    }
    return this.configuration.series[position];
  }
  /** @private */
  __updateCategories(categories, config2) {
    if (categories === void 0 || !config2 || this.__hasConfigurationBuffer("xAxis.categories", "xAxis")) {
      return;
    }
    this.__updateOrAddAxes([{ categories }], true);
  }
  /** @private */
  __updateCategoryMax(max2, config2) {
    if (max2 === void 0 || !config2 || this.__hasConfigurationBuffer("xAxis.max", "xAxis")) {
      return;
    }
    if (!isFinite(max2)) {
      console.warn('<vaadin-chart> Acceptable value for "category-max" are Numbers or null');
      return;
    }
    this.__updateOrAddAxes([{ max: max2 }], true);
  }
  /** @private */
  __updateCategoryMin(min2, config2) {
    if (min2 === void 0 || !config2 || this.__hasConfigurationBuffer("xAxis.min", "xAxis")) {
      return;
    }
    if (!isFinite(min2)) {
      console.warn('<vaadin-chart> Acceptable value for "category-min" are Numbers or null');
      return;
    }
    this.__updateOrAddAxes([{ min: min2 }], true);
  }
  /** @private */
  __shouldInvert() {
    if (this.type === "bar" && ["top", "bottom"].indexOf(this.categoryPosition) >= 0) {
      console.warn(`<vaadin-chart> Acceptable "category-position" values for bar charts are
          "left" and "right". For "top" and "bottom" positions please consider using a column chart.`);
      return;
    }
    const inverted = ["left", "right"];
    return inverted.indexOf(this.categoryPosition) >= 0;
  }
  /** @private */
  __shouldFlipOpposite() {
    const opposite = ["top", "right"];
    const oppositeBar = ["right"];
    return (this.type === "bar" ? oppositeBar : opposite).indexOf(this.categoryPosition) >= 0;
  }
  /** @private */
  __updateCategoryPosition(categoryPosition, config2) {
    if (categoryPosition === void 0 || !config2 || this.__hasConfigurationBuffer("chart.inverted")) {
      return;
    }
    const validPositions = ["left", "right", "top", "bottom"];
    if (validPositions.indexOf(categoryPosition) < 0) {
      console.warn(`<vaadin-chart> Acceptable "category-position" values are ${validPositions}`);
      return;
    }
    config2.update({
      chart: {
        inverted: this.__shouldInvert()
      }
    });
    config2.xAxis.forEach(
      (e) => e.update({
        opposite: this.__shouldFlipOpposite()
      })
    );
  }
  /** @private */
  __hideLegend(noLegend, config2) {
    if (noLegend === void 0 || !config2 || this.__hasConfigurationBuffer("legend")) {
      return;
    }
    if (config2.legend) {
      config2.legend.update({ enabled: !noLegend });
    } else {
      config2.legend = { enabled: !noLegend };
    }
  }
  /** @private */
  __updateTitle(title, config2) {
    if (title === void 0 || !config2 || this.__hasConfigurationBuffer("title")) {
      return;
    }
    config2.title.update({ text: title });
  }
  /** @private */
  __tooltipObserver(tooltip, config2) {
    if (tooltip === void 0 || !config2 || this.__hasConfigurationBuffer("tooltip")) {
      return;
    }
    config2.tooltip.update({ enabled: tooltip });
  }
  /** @private */
  __updateType(type, config2) {
    if (type === void 0 || !config2 || this.__hasConfigurationBuffer("chart.type")) {
      return;
    }
    config2.update({
      chart: { type: type || "line" }
    });
  }
  /** @private */
  __updateSubtitle(subtitle, config2) {
    if (subtitle === void 0 || !config2 || this.__hasConfigurationBuffer("subtitle")) {
      return;
    }
    if (!config2.subtitle) {
      config2.setSubtitle({ text: subtitle });
    } else {
      config2.subtitle.update({ text: subtitle });
    }
  }
  /** @private */
  __updateAdditionalOptions(options2) {
    if (this.configuration && options2) {
      this.updateConfiguration(options2);
    }
  }
  /** @private */
  __isStackingValid() {
    if (["normal", "percent", null].indexOf(this.stacking) === -1) {
      this.__showWarn("stacking", '"normal", "percent" or null');
      return false;
    }
    return true;
  }
  /** @private */
  __stackingObserver(stacking, config2) {
    if (stacking === void 0 || !config2 || this.__hasConfigurationBuffer("plotOptions.series.stacking")) {
      return;
    }
    if (!this.__isStackingValid()) {
      this.stacking = null;
      return;
    }
    config2.update({
      plotOptions: {
        series: { stacking }
      }
    });
  }
  /** @private */
  __chart3dObserver(chart3d, config2) {
    if (chart3d === void 0 || !config2 || this.__hasConfigurationBuffer("chart.options3d")) {
      return;
    }
    if (chart3d) {
      config2.update({
        chart: {
          options3d: {
            ...this._baseChart3d,
            ...this.additionalOptions && this.additionalOptions.chart && this.additionalOptions.chart.options3d,
            enabled: true
          }
        }
      });
    } else {
      config2.update({
        chart: {
          options3d: {
            enabled: false
          }
        }
      });
    }
  }
  /** @private */
  __polarObserver(polar, config2) {
    if (polar === void 0 || !config2 || this.__hasConfigurationBuffer("chart.polar")) {
      return;
    }
    config2.update({
      chart: { polar }
    });
  }
  /** @private */
  __emptyTextObserver(emptyText, config2) {
    if (emptyText === void 0 || !config2 || this.__hasConfigurationBuffer("lang.noData")) {
      return;
    }
    config2.update({
      lang: {
        noData: emptyText
      }
    });
    this.__updateNoDataElement(config2);
  }
  /**
   * Force the no data text element to become visible if the chart has no data.
   * This is necessary in cases where Highcharts does not update the element
   * automatically, for example when setting the language config
   * @private
   */
  __updateNoDataElement(config2) {
    const isEmpty2 = config2.series.every((e) => e.data.length === 0);
    if (isEmpty2) {
      config2.hideNoData();
      config2.showNoData(this.emptyText);
    }
  }
  /** @private */
  __callChartFunction(functionName, ...args) {
    if (this.configuration) {
      const functionToCall = this.configuration[functionName];
      if (functionToCall && typeof functionToCall === "function") {
        args.forEach((arg) => inflateFunctions(arg));
        functionToCall.apply(this.configuration, args);
      }
    }
  }
  /** @private */
  __callSeriesFunction(functionName, seriesIndex, ...args) {
    if (this.configuration && this.configuration.series[seriesIndex]) {
      const series = this.configuration.series[seriesIndex];
      const functionToCall = series[functionName];
      if (functionToCall && typeof functionToCall === "function") {
        args.forEach((arg) => inflateFunctions(arg));
        functionToCall.apply(series, args);
      }
    }
  }
  /** @private */
  __callAxisFunction(functionName, axisCategory, axisIndex, ...args) {
    if (this.configuration) {
      let axes;
      switch (axisCategory) {
        case 0:
          axes = this.configuration.xAxis;
          break;
        case 1:
          axes = this.configuration.yAxis;
          break;
        case 2:
          axes = this.configuration.zAxis;
          break;
        case 3:
          axes = this.configuration.colorAxis;
          break;
      }
      if (axes && axes[axisIndex]) {
        const axis = axes[axisIndex];
        const functionToCall = axis[functionName];
        if (functionToCall && typeof functionToCall === "function") {
          args.forEach((arg) => inflateFunctions(arg));
          functionToCall.apply(axis, args);
        }
      }
    }
  }
  /** @private */
  __callPointFunction(functionName, seriesIndex, pointIndex, ...args) {
    if (this.configuration && this.configuration.series[seriesIndex] && this.configuration.series[seriesIndex].data[pointIndex]) {
      const point = this.configuration.series[seriesIndex].data[pointIndex];
      const functionToCall = point[functionName];
      if (functionToCall && typeof functionToCall === "function") {
        functionToCall.apply(point, args);
      }
    }
  }
  /**
   * Updates chart container and current chart style property depending on flex status
   * @private
   */
  __updateStyles() {
    const isFlex = getComputedStyle(this).flex !== "0 1 auto";
    if (isFlex) {
      this.style.display = "flex";
      this.$.wrapper.style.display = "flex";
      this.$.chart.style.flex = 1;
    } else {
      this.style.display = "";
      this.$.wrapper.style.display = "";
      this.$.chart.style.flex = "";
    }
  }
  /** @private */
  __showWarn(propertyName, acceptedValues) {
    console.warn(`<vaadin-chart> Acceptable values for "${propertyName}" are ${acceptedValues}`);
  }
  /**
   * @private
   * Workaround for https://github.com/highcharts/highcharts/issues/23443
   * Forces a resize in the chart to make it calculate the labels positions
   * correctly in a chart with "organization" series
   *
   * TODO: Remove when the related ticket is fixed
   */
  __forceResize() {
    const chart = this.configuration;
    const { options: options2 } = chart;
    const hasOrganizationSeries = options2.chart.styledMode && (options2.chart.type === "organization" || options2.series.some((series) => series.type === "organization"));
    if (!hasOrganizationSeries) {
      return;
    }
    requestAnimationFrame(() => {
      chart.setSize(chart.chartWidth - 10, chart.chartHeight);
      chart.setSize(null, null);
    });
  }
  /** @private */
  __onRedraw() {
    this.__checkTurboMode();
  }
  /** @private */
  __checkTurboMode() {
    const isDevelopmentMode = !!window.Vaadin.developmentMode;
    if (!this.configuration || !isDevelopmentMode || this.__turboModeWarningAlreadyLogged) {
      return;
    }
    const exceedsTurboThreshold = this.configuration.series.some((series) => {
      const threshold = series.options && series.options.turboThreshold || 0;
      const dataLength = series.data.length;
      return threshold > 0 && dataLength > threshold;
    });
    if (exceedsTurboThreshold) {
      this.__turboModeWarningAlreadyLogged = true;
      console.warn(
        "<vaadin-chart> Turbo mode has been enabled for one or more series, because the number of data items exceeds the configured threshold. Turbo mode improves the performance of charts with lots of data, but is not compatible with every type of series. Please consult the documentation on compatibility, or how to disable turbo mode."
      );
    }
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class Chart extends ChartMixin(ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-chart";
  }
  static get cvdlName() {
    return "vaadin-chart";
  }
  static get styles() {
    return chartStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <div id="wrapper" style="height: 100%; width: 100%; position: relative;">
        <div
          id="chart"
          ?styled-mode="${this.__styledMode}"
          style="height: 100%; width: 100%; position: absolute;"
        ></div>
      </div>
      <slot id="slot"></slot>
    `;
  }
}
defineCustomElement(Chart);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const checkboxGroupStyles = [field, group];
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const CheckboxGroupMixin = (superclass) => class CheckboxGroupMixinClass extends FieldMixin(FocusMixin(DisabledMixin(superclass))) {
  static get properties() {
    return {
      /**
       * An array containing values of the currently checked checkboxes.
       *
       * The array is immutable so toggling checkboxes always results in
       * creating a new array.
       */
      value: {
        type: Array,
        value: () => [],
        notify: true,
        sync: true,
        observer: "__valueChanged"
      },
      /**
       * When true, the user cannot modify the value of the checkbox group.
       * The difference between `disabled` and `readonly` is that in the
       * read-only checkbox group, all the checkboxes are also read-only,
       * and therefore remain focusable and announced by screen readers.
       */
      readonly: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        observer: "__readonlyChanged"
      }
    };
  }
  constructor() {
    super();
    this.__registerCheckbox = this.__registerCheckbox.bind(this);
    this.__unregisterCheckbox = this.__unregisterCheckbox.bind(this);
    this.__onCheckboxCheckedChanged = this.__onCheckboxCheckedChanged.bind(this);
    this._tooltipController = new TooltipController(this);
    this._tooltipController.addEventListener("tooltip-changed", (event) => {
      const tooltip = event.detail.node;
      if (tooltip && tooltip.isConnected) {
        const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
        this._tooltipController.setAriaTarget(inputs);
      } else {
        this._tooltipController.setAriaTarget([]);
      }
    });
  }
  /**
   * A collection of the checkboxes.
   *
   * @return {!Array<!Checkbox>}
   * @private
   */
  get __checkboxes() {
    return this.__filterCheckboxes([...this.children]);
  }
  /** @protected */
  ready() {
    super.ready();
    this.ariaTarget = this;
    this.setAttribute("role", "group");
    const slot = this.shadowRoot.querySelector("slot:not([name])");
    this._observer = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
      const addedCheckboxes = this.__filterCheckboxes(addedNodes);
      const removedCheckboxes = this.__filterCheckboxes(removedNodes);
      addedCheckboxes.forEach(this.__registerCheckbox);
      removedCheckboxes.forEach(this.__unregisterCheckbox);
      const inputs = this.__checkboxes.map((checkbox) => checkbox.inputElement);
      this._tooltipController.setAriaTarget(inputs);
      this.__warnOfCheckboxesWithoutValue(addedCheckboxes);
    });
    this.addController(this._tooltipController);
  }
  /**
   * Override method inherited from `ValidateMixin`
   * to validate the value array.
   *
   * @override
   * @return {boolean}
   */
  checkValidity() {
    return !this.required || Boolean(this.value && this.value.length > 0);
  }
  /**
   * @param {!Array<!Node>} nodes
   * @return {!Array<!Checkbox>}
   * @private
   */
  __filterCheckboxes(nodes) {
    return nodes.filter((node) => node.nodeType === Node.ELEMENT_NODE && node.localName === "vaadin-checkbox");
  }
  /**
   * @param {!Array<!Checkbox>} checkboxes
   * @private
   */
  __warnOfCheckboxesWithoutValue(checkboxes) {
    const hasCheckboxesWithoutValue = checkboxes.some((checkbox) => {
      const { value } = checkbox;
      return !checkbox.hasAttribute("value") && (!value || value === "on");
    });
    if (hasCheckboxesWithoutValue) {
      console.warn("Please provide the value attribute to all the checkboxes inside the checkbox group.");
    }
  }
  /**
   * Registers the checkbox after adding it to the group.
   *
   * @param {!Checkbox} checkbox
   * @private
   */
  __registerCheckbox(checkbox) {
    checkbox.addEventListener("checked-changed", this.__onCheckboxCheckedChanged);
    if (this.disabled) {
      checkbox.disabled = true;
    }
    if (this.readonly) {
      checkbox.readonly = true;
    }
    if (checkbox.checked) {
      this.__addCheckboxToValue(checkbox.value);
    } else if (this.value && this.value.includes(checkbox.value)) {
      checkbox.checked = true;
    }
  }
  /**
   * Unregisters the checkbox before removing it from the group.
   *
   * @param {!Checkbox} checkbox
   * @private
   */
  __unregisterCheckbox(checkbox) {
    checkbox.removeEventListener("checked-changed", this.__onCheckboxCheckedChanged);
    if (checkbox.checked) {
      this.__removeCheckboxFromValue(checkbox.value);
    }
  }
  /**
   * Override method inherited from `DisabledMixin`
   * to propagate the `disabled` property to the checkboxes.
   *
   * @param {boolean} newValue
   * @param {boolean} oldValue
   * @override
   * @protected
   */
  _disabledChanged(newValue, oldValue) {
    super._disabledChanged(newValue, oldValue);
    if (!newValue && oldValue === void 0) {
      return;
    }
    if (oldValue !== newValue) {
      this.__checkboxes.forEach((checkbox) => {
        checkbox.disabled = newValue;
      });
    }
  }
  /**
   * @param {string} value
   * @private
   */
  __addCheckboxToValue(value) {
    if (!this.value) {
      this.value = [value];
    } else if (!this.value.includes(value)) {
      this.value = [...this.value, value];
    }
  }
  /**
   * @param {string} value
   * @private
   */
  __removeCheckboxFromValue(value) {
    if (this.value && this.value.includes(value)) {
      this.value = this.value.filter((v) => v !== value);
    }
  }
  /**
   * @param {!CustomEvent} event
   * @private
   */
  __onCheckboxCheckedChanged(event) {
    const checkbox = event.target;
    if (checkbox.checked) {
      this.__addCheckboxToValue(checkbox.value);
    } else {
      this.__removeCheckboxFromValue(checkbox.value);
    }
  }
  /**
   * @param {string[] | null | undefined} value
   * @param {string[] | null | undefined} oldValue
   * @private
   */
  __valueChanged(value, oldValue) {
    if (value && value.length === 0 && oldValue === void 0) {
      return;
    }
    this.toggleAttribute("has-value", value && value.length > 0);
    this.__checkboxes.forEach((checkbox) => {
      checkbox.checked = value && value.includes(checkbox.value);
    });
    if (oldValue !== void 0) {
      this._requestValidation();
    }
  }
  /** @private */
  __readonlyChanged(readonly, oldReadonly) {
    if (readonly || oldReadonly) {
      this.__checkboxes.forEach((checkbox) => {
        checkbox.readonly = readonly;
      });
    }
  }
  /**
   * Override method inherited from `FocusMixin`
   * to prevent removing the `focused` attribute
   * when focus moves between checkboxes inside the group.
   *
   * @param {!FocusEvent} event
   * @return {boolean}
   * @protected
   */
  _shouldRemoveFocus(event) {
    return !this.contains(event.relatedTarget);
  }
  /**
   * Override method inherited from `FocusMixin`
   * to run validation when the group loses focus.
   *
   * @param {boolean} focused
   * @override
   * @protected
   */
  _setFocused(focused) {
    super._setFocused(focused);
    if (!focused && document.hasFocus()) {
      this._requestValidation();
    }
  }
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class CheckboxGroup extends CheckboxGroupMixin(
  ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-checkbox-group";
  }
  static get styles() {
    return checkboxGroupStyles;
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-group-field-container">
        <div part="label">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true"></span>
        </div>

        <div part="group-field">
          <slot></slot>
        </div>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>
      </div>

      <slot name="tooltip"></slot>
    `;
  }
}
defineCustomElement(CheckboxGroup);
/**
 * @license
 * Copyright 2017 Google LLC
 * SPDX-License-Identifier: BSD-3-Clause
 */
const notifyChildrenConnectedChanged = (parent, isConnected) => {
  const children = parent._$disconnectableChildren;
  if (children === void 0) {
    return false;
  }
  for (const obj of children) {
    obj["_$notifyDirectiveConnectionChanged"]?.(isConnected, false);
    notifyChildrenConnectedChanged(obj, isConnected);
  }
  return true;
};
const removeDisconnectableFromParent = (obj) => {
  let parent, children;
  do {
    if ((parent = obj._$parent) === void 0) {
      break;
    }
    children = parent._$disconnectableChildren;
    children.delete(obj);
    obj = parent;
  } while (children?.size === 0);
};
const addDisconnectableToParent = (obj) => {
  for (let parent; parent = obj._$parent; obj = parent) {
    let children = parent._$disconnectableChildren;
    if (children === void 0) {
      parent._$disconnectableChildren = children = /* @__PURE__ */ new Set();
    } else if (children.has(obj)) {
      break;
    }
    children.add(obj);
    installDisconnectAPI(parent);
  }
};
function reparentDisconnectables(newParent) {
  if (this._$disconnectableChildren !== void 0) {
    removeDisconnectableFromParent(this);
    this._$parent = newParent;
    addDisconnectableToParent(this);
  } else {
    this._$parent = newParent;
  }
}
function notifyChildPartConnectedChanged(isConnected, isClearingValue = false, fromPartIndex = 0) {
  const value = this._$committedValue;
  const children = this._$disconnectableChildren;
  if (children === void 0 || children.size === 0) {
    return;
  }
  if (isClearingValue) {
    if (Array.isArray(value)) {
      for (let i = fromPartIndex; i < value.length; i++) {
        notifyChildrenConnectedChanged(value[i], false);
        removeDisconnectableFromParent(value[i]);
      }
    } else if (value != null) {
      notifyChildrenConnectedChanged(value, false);
      removeDisconnectableFromParent(value);
    }
  } else {
    notifyChildrenConnectedChanged(this, isConnected);
  }
}
const installDisconnectAPI = (obj) => {
  if (obj.type == PartType.CHILD) {
    obj._$notifyConnectionChanged ??= notifyChildPartConnectedChanged;
    obj._$reparentDisconnectables ??= reparentDisconnectables;
  }
};
class AsyncDirective extends Directive {
  constructor() {
    super(...arguments);
    this._$disconnectableChildren = void 0;
  }
  /**
   * Initialize the part with internal fields
   * @param part
   * @param parent
   * @param attributeIndex
   */
  _$initialize(part, parent, attributeIndex) {
    super._$initialize(part, parent, attributeIndex);
    addDisconnectableToParent(this);
    this.isConnected = part._$isConnected;
  }
  // This property needs to remain unminified.
  /**
   * Called from the core code when a directive is going away from a part (in
   * which case `shouldRemoveFromParent` should be true), and from the
   * `setChildrenConnected` helper function when recursively changing the
   * connection state of a tree (in which case `shouldRemoveFromParent` should
   * be false).
   *
   * @param isConnected
   * @param isClearingDirective - True when the directive itself is being
   *     removed; false when the tree is being disconnected
   * @internal
   */
  ["_$notifyDirectiveConnectionChanged"](isConnected, isClearingDirective = true) {
    if (isConnected !== this.isConnected) {
      this.isConnected = isConnected;
      if (isConnected) {
        this.reconnected?.();
      } else {
        this.disconnected?.();
      }
    }
    if (isClearingDirective) {
      notifyChildrenConnectedChanged(this, isConnected);
      removeDisconnectableFromParent(this);
    }
  }
  /**
   * Sets the value of the directive's Part outside the normal `update`/`render`
   * lifecycle of a directive.
   *
   * This method should not be called synchronously from a directive's `update`
   * or `render`.
   *
   * @param directive The directive to update
   * @param value The value to set
   */
  setValue(value) {
    if (isSingleExpression(this.__part)) {
      this.__part._$setValue(value, this);
    } else {
      if (this.__attributeIndex === void 0) {
        throw new Error(`Expected this.__attributeIndex to be a number`);
      }
      const newValues = [...this.__part._$committedValue];
      newValues[this.__attributeIndex] = value;
      this.__part._$setValue(newValues, this, 0);
    }
  }
  /**
   * User callbacks for implementing logic to release any resources/subscriptions
   * that may have been retained by this directive. Since directives may also be
   * re-connected, `reconnected` should also be implemented to restore the
   * working state of the directive prior to the next render.
   */
  disconnected() {
  }
  reconnected() {
  }
}
class FlowComponentDirective extends AsyncDirective {
  constructor(partInfo) {
    super(partInfo);
    if (partInfo.type !== PartType.CHILD) {
      throw new Error(`${this.constructor.directiveName}() can only be used in child bindings`);
    }
  }
  update(part, [appid, nodeid]) {
    this.updateContent(part, appid, nodeid);
    return noChange;
  }
  updateContent(part, appid, nodeid) {
    const { parentNode, startNode } = part;
    this.__parentNode = parentNode;
    const hasNewNodeId = nodeid !== void 0 && nodeid !== null;
    const newNode = hasNewNodeId ? this.getNewNode(appid, nodeid) : null;
    const oldNode = this.getOldNode(part);
    clearTimeout(this.__parentNode.__nodeRetryTimeout);
    if (hasNewNodeId && !newNode) {
      this.__parentNode.__nodeRetryTimeout = setTimeout(() => this.updateContent(part, appid, nodeid));
    } else if (oldNode === newNode) {
      return;
    } else if (oldNode && newNode) {
      parentNode.replaceChild(newNode, oldNode);
    } else if (oldNode) {
      parentNode.removeChild(oldNode);
    } else if (newNode) {
      startNode.after(newNode);
    }
  }
  getNewNode(appid, nodeid) {
    return window.Vaadin.Flow.clients[appid].getByNodeId(nodeid);
  }
  getOldNode(part) {
    const { startNode, endNode } = part;
    if (startNode.nextSibling === endNode) {
      return;
    }
    return startNode.nextSibling;
  }
  disconnected() {
    clearTimeout(this.__parentNode.__nodeRetryTimeout);
  }
}
const flowComponentDirective = directive(FlowComponentDirective);
function getNode(appid, nodeid) {
  return flowComponentDirective(appid, nodeid);
}
function setChildNodes(appid, nodeIds, root) {
  render$1(html`${nodeIds.map((id) => flowComponentDirective(appid, id))}`, root);
}
function patchVirtualContainer(container) {
  const originalInsertBefore = container.insertBefore;
  container.insertBefore = function(newNode, referenceNode) {
    if (referenceNode && referenceNode.parentNode === this) {
      return originalInsertBefore.call(this, newNode, referenceNode);
    } else {
      return originalInsertBefore.call(this, newNode, null);
    }
  };
}
window.Vaadin ||= {};
window.Vaadin.FlowComponentHost ||= { patchVirtualContainer, getNode, setChildNodes };
window.Vaadin.Flow.comboBoxConnector = {};
window.Vaadin.Flow.comboBoxConnector.initLazy = (comboBox) => {
  if (comboBox.$connector) {
    return;
  }
  comboBox.$connector = {};
  const pageCallbacks = {};
  let cache2 = {};
  let lastFilter = "";
  const placeHolder = new window.Vaadin.ComboBoxPlaceholder();
  const serverFacade = /* @__PURE__ */ (() => {
    let lastFilterSentToServer = "";
    let dataCommunicatorResetNeeded = false;
    const needsDataCommunicatorReset = () => dataCommunicatorResetNeeded = true;
    const getLastFilterSentToServer = () => lastFilterSentToServer;
    const requestData = (startIndex, endIndex, params2) => {
      const count = endIndex - startIndex;
      const filter = params2.filter;
      comboBox.$server.setViewportRange(startIndex, count, filter);
      lastFilterSentToServer = filter;
      if (dataCommunicatorResetNeeded) {
        comboBox.$server.resetDataCommunicator();
        dataCommunicatorResetNeeded = false;
      }
    };
    return {
      needsDataCommunicatorReset,
      getLastFilterSentToServer,
      requestData
    };
  })();
  const clearPageCallbacks = (pages = Object.keys(pageCallbacks)) => {
    pages.forEach((page) => {
      pageCallbacks[page]([], comboBox.size);
      delete pageCallbacks[page];
      const pageStart = parseInt(page) * comboBox.pageSize;
      const pageEnd = pageStart + comboBox.pageSize;
      const end = Math.min(pageEnd, comboBox.filteredItems.length);
      for (let i = pageStart; i < end; i++) {
        comboBox.filteredItems[i] = placeHolder;
      }
    });
  };
  comboBox.dataProvider = function(params2, callback) {
    if (params2.pageSize != comboBox.pageSize) {
      throw "Invalid pageSize";
    }
    if (comboBox._clientSideFilter) {
      if (cache2[0]) {
        performClientSideFilter(cache2[0], params2.filter, callback);
        return;
      } else {
        params2.filter = "";
      }
    }
    const filterChanged = params2.filter !== lastFilter;
    if (filterChanged) {
      cache2 = {};
      lastFilter = params2.filter;
      comboBox._filterDebouncer = Debouncer.debounce(
        comboBox._filterDebouncer,
        timeOut.after(comboBox._filterTimeout ?? 500),
        () => {
          if (serverFacade.getLastFilterSentToServer() === params2.filter) {
            serverFacade.needsDataCommunicatorReset();
          }
          if (params2.filter !== lastFilter) {
            throw new Error("Expected params.filter to be '" + lastFilter + "' but was '" + params2.filter + "'");
          }
          comboBox._filterDebouncer = void 0;
          clearPageCallbacks();
          comboBox.dataProvider(params2, callback);
        }
      );
      return;
    }
    if (comboBox._filterDebouncer) {
      pageCallbacks[params2.page] = callback;
      return;
    }
    if (cache2[params2.page]) {
      commitPage(params2.page, callback);
    } else {
      pageCallbacks[params2.page] = callback;
      const maxRangeCount = Math.max(params2.pageSize * 2, 500);
      const activePages = Object.keys(pageCallbacks).map((page) => parseInt(page));
      const rangeMin = Math.min(...activePages);
      const rangeMax = Math.max(...activePages);
      if (activePages.length * params2.pageSize > maxRangeCount) {
        if (params2.page === rangeMin) {
          clearPageCallbacks([String(rangeMax)]);
        } else {
          clearPageCallbacks([String(rangeMin)]);
        }
        comboBox.dataProvider(params2, callback);
      } else if (rangeMax - rangeMin + 1 !== activePages.length) {
        clearPageCallbacks();
      } else {
        const startIndex = params2.pageSize * rangeMin;
        const endIndex = params2.pageSize * (rangeMax + 1);
        serverFacade.requestData(startIndex, endIndex, params2);
      }
    }
  };
  comboBox.$connector.clear = (start2, length) => {
    const firstPageToClear = Math.floor(start2 / comboBox.pageSize);
    const numberOfPagesToClear = Math.ceil(length / comboBox.pageSize);
    for (let i = firstPageToClear; i < firstPageToClear + numberOfPagesToClear; i++) {
      delete cache2[i];
    }
  };
  comboBox.$connector.filter = (item, filter) => {
    filter = filter ? filter.toString().toLowerCase() : "";
    return comboBox._getItemLabel(item, comboBox.itemLabelPath).toString().toLowerCase().indexOf(filter) > -1;
  };
  comboBox.$connector.set = (index, items, filter) => {
    if (filter != serverFacade.getLastFilterSentToServer()) {
      return;
    }
    if (index % comboBox.pageSize != 0) {
      throw "Got new data to index " + index + " which is not aligned with the page size of " + comboBox.pageSize;
    }
    if (index === 0 && items.length === 0 && pageCallbacks[0]) {
      cache2[0] = [];
      return;
    }
    const firstPageToSet = index / comboBox.pageSize;
    const updatedPageCount = Math.ceil(items.length / comboBox.pageSize);
    for (let i = 0; i < updatedPageCount; i++) {
      let page = firstPageToSet + i;
      let slice = items.slice(i * comboBox.pageSize, (i + 1) * comboBox.pageSize);
      cache2[page] = slice;
    }
  };
  comboBox.$connector.updateData = (items) => {
    const itemsMap = new Map(items.map((item) => [item.key, item]));
    comboBox.filteredItems = comboBox.filteredItems.map((item) => {
      return itemsMap.get(item.key) || item;
    });
  };
  comboBox.$connector.updateSize = function(newSize) {
    if (!comboBox._clientSideFilter) {
      comboBox.size = newSize;
    }
  };
  comboBox.$connector.reset = function() {
    if (comboBox._filterDebouncer) {
      comboBox._filterDebouncer.cancel();
      comboBox._filterDebouncer = void 0;
    }
    clearPageCallbacks();
    cache2 = {};
    comboBox.clearCache();
  };
  comboBox.$connector.confirm = function(id, filter) {
    if (filter != serverFacade.getLastFilterSentToServer()) {
      return;
    }
    let activePages = Object.getOwnPropertyNames(pageCallbacks);
    for (let i = 0; i < activePages.length; i++) {
      let page = activePages[i];
      if (cache2[page]) {
        commitPage(page, pageCallbacks[page]);
      }
    }
    comboBox.$server.confirmUpdate(id);
  };
  const commitPage = function(page, callback) {
    let data = cache2[page];
    if (comboBox._clientSideFilter) {
      performClientSideFilter(data, comboBox.filter, callback);
    } else {
      delete cache2[page];
      callback(data, comboBox.size);
    }
  };
  const performClientSideFilter = function(page, filter, callback) {
    let filteredItems = page;
    if (filter) {
      filteredItems = page.filter((item) => comboBox.$connector.filter(item, filter));
    }
    callback(filteredItems, filteredItems.length);
  };
  comboBox.addEventListener("custom-value-set", (e) => e.preventDefault());
  comboBox.itemClassNameGenerator = function(item) {
    return item.className || "";
  };
};
window.Vaadin.ComboBoxPlaceholder = ComboBoxPlaceholder;
function getContainer(appId, nodeId) {
  try {
    return window.Vaadin.Flow.clients[appId].getByNodeId(nodeId);
  } catch (error2) {
    console.error("Could not get node %s from app %s", nodeId, appId);
    console.error(error2);
  }
}
function initLazy$1(contextMenu, appId) {
  if (contextMenu.$connector) {
    return;
  }
  contextMenu.$connector = {
    /**
     * Generates and assigns the items to the context menu.
     *
     * @param {number} nodeId
     */
    generateItems(nodeId) {
      const items = generateItemsTree(appId, nodeId);
      contextMenu.items = items;
    }
  };
}
function generateItemsTree(appId, nodeId) {
  const container = getContainer(appId, nodeId);
  if (!container) {
    return;
  }
  return Array.from(container.children).map((child) => {
    const item = {
      component: child,
      checked: child._checked,
      keepOpen: child._keepOpen,
      className: child.className,
      theme: child.__theme
    };
    if (child._hasVaadinItemMixin && child._containerNodeId) {
      item.children = generateItemsTree(appId, child._containerNodeId);
    }
    child._item = item;
    return item;
  });
}
function setChecked(component, checked) {
  if (component._item) {
    component._item.checked = checked;
    if (component._item.keepOpen) {
      component.toggleAttribute("menu-item-checked", checked);
    }
  }
}
function setKeepOpen(component, keepOpen) {
  if (component._item) {
    component._item.keepOpen = keepOpen;
  }
}
function setTheme(component, theme2) {
  if (component._item) {
    component._item.theme = theme2;
  }
}
window.Vaadin.Flow.contextMenuConnector = {
  initLazy: initLazy$1,
  generateItemsTree,
  setChecked,
  setKeepOpen,
  setTheme
};
function init$z(target) {
  if (target.$contextMenuTargetConnector) {
    return;
  }
  target.$contextMenuTargetConnector = {
    openOnHandler(e) {
      if (target.preventContextMenu && target.preventContextMenu(e)) {
        return;
      }
      e.preventDefault();
      e.stopPropagation();
      this.$contextMenuTargetConnector.openEvent = e;
      let detail = {};
      if (target.getContextMenuBeforeOpenDetail) {
        detail = target.getContextMenuBeforeOpenDetail(e);
      }
      target.dispatchEvent(
        new CustomEvent("vaadin-context-menu-before-open", {
          detail
        })
      );
    },
    updateOpenOn(eventType) {
      this.removeListener();
      this.openOnEventType = eventType;
      customElements.whenDefined("vaadin-context-menu").then(() => {
        if (gestures[eventType]) {
          addListener(target, eventType, this.openOnHandler);
        } else {
          target.addEventListener(eventType, this.openOnHandler);
        }
      });
    },
    removeListener() {
      if (this.openOnEventType) {
        if (gestures[this.openOnEventType]) {
          removeListener(target, this.openOnEventType, this.openOnHandler);
        } else {
          target.removeEventListener(this.openOnEventType, this.openOnHandler);
        }
      }
    },
    openMenu(contextMenu) {
      contextMenu.open(this.openEvent);
    },
    removeConnector() {
      this.removeListener();
      target.$contextMenuTargetConnector = void 0;
    }
  };
}
window.Vaadin.Flow.contextMenuTargetConnector = { init: init$z };
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const crudDialogOverlay = css$h`
  [part='header'] {
    color: var(--vaadin-dialog-title-color, var(--vaadin-text-color));
    font-size: var(--vaadin-dialog-title-font-size, 1em);
    font-weight: var(--vaadin-dialog-title-font-weight, 600);
    line-height: var(--vaadin-dialog-title-line-height, inherit);
    padding: var(--vaadin-crud-header-padding, var(--vaadin-dialog-padding, var(--vaadin-padding-l)));
  }

  ::slotted([slot='header']) {
    color: inherit !important;
    display: contents;
    font: inherit !important;
    overflow-wrap: anywhere;
  }

  :host(:is(*, #id)) [part='content'] {
    overflow: auto;
    overscroll-behavior: contain;
    padding: var(--vaadin-crud-form-padding, var(--vaadin-padding-l));
    padding-top: 0;
  }

  ::slotted([slot='form']) {
    --vaadin-crud-form-padding: 0;
  }

  [part='footer'] {
    justify-content: normal;
    background: var(--vaadin-crud-footer-background, transparent);
    border-top: var(--vaadin-crud-border-width, 1px) solid
      var(--vaadin-crud-border-color, var(--vaadin-border-color-secondary));
  }
`;
const crudDialogOverlayStyles = [...dialogOverlayStyles, crudDialogOverlay];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class CrudDialogOverlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-crud-dialog-overlay";
  }
  static get styles() {
    return crudDialogOverlayStyles;
  }
  /**
   * Override method from OverlayFocusMixin to use dialog as focus trap root
   * @protected
   * @override
   */
  get _focusTrapRoot() {
    return this.getRootNode().host;
  }
  /** @protected */
  render() {
    return html`
      <div part="backdrop" id="backdrop" ?hidden="${!this.withBackdrop}"></div>
      <div part="overlay" id="overlay">
        <section id="resizerContainer" class="resizer-container">
          <header part="header">
            <slot name="header"></slot>
          </header>
          <div part="content" id="content">
            <slot name="form"></slot>
          </div>
          <footer part="footer" role="toolbar">
            <slot name="save-button"></slot>
            <slot name="cancel-button"></slot>
            <slot name="delete-button"></slot>
          </footer>
        </section>
      </div>
    `;
  }
  /**
   * @protected
   * @override
   */
  ready() {
    super.ready();
    this.setAttribute("has-header", "");
    this.setAttribute("has-footer", "");
  }
}
defineCustomElement(CrudDialogOverlay);
class CrudDialog extends DialogBaseMixin(ThemePropertyMixin(PolylitMixin(LitElement))) {
  static get is() {
    return "vaadin-crud-dialog";
  }
  static get styles() {
    return css$h`
      :host([opened]),
      :host([opening]),
      :host([closing]) {
        display: block !important;
        position: fixed;
      }

      :host,
      :host([hidden]) {
        display: none !important;
      }

      :host(:focus-visible) ::part(overlay) {
        outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
      }
    `;
  }
  static get properties() {
    return {
      fullscreen: {
        type: Boolean
      },
      crudElement: {
        type: Object
      }
    };
  }
  /** @protected */
  render() {
    return html`
      <vaadin-crud-dialog-overlay
        id="overlay"
        .owner="${this.crudElement}"
        .opened="${this.opened}"
        @opened-changed="${this._onOverlayOpened}"
        @mousedown="${this._bringOverlayToFront}"
        @touchstart="${this._bringOverlayToFront}"
        @vaadin-overlay-outside-click="${this.__cancel}"
        @vaadin-overlay-escape-press="${this.__cancel}"
        theme="${ifDefined(this._theme)}"
        .modeless="${this.modeless}"
        .withBackdrop="${!this.modeless}"
        ?fullscreen="${this.fullscreen}"
        focus-trap
        exportparts="backdrop, overlay, header, content, footer"
      >
        <slot name="header" slot="header"></slot>
        <slot name="form" slot="form"></slot>
        <slot name="save-button" slot="save-button"></slot>
        <slot name="cancel-button" slot="cancel-button"></slot>
        <slot name="delete-button" slot="delete-button"></slot>
      </vaadin-crud-dialog-overlay>
    `;
  }
  /** @private **/
  __cancel() {
    this.dispatchEvent(new CustomEvent("cancel"));
  }
}
defineCustomElement(CrudDialog);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const GridColumnGroupMixin = (superClass) => class extends ColumnBaseMixin(superClass) {
  static get properties() {
    return {
      /** @private */
      _childColumns: {
        value() {
          return this._getChildColumns(this);
        }
      },
      /**
       * Flex grow ratio for the column group as the sum of the ratios of its child columns.
       * @attr {number} flex-grow
       */
      flexGrow: {
        type: Number,
        readOnly: true,
        sync: true
      },
      /**
       * Width of the column group as the sum of the widths of its child columns.
       */
      width: {
        type: String,
        readOnly: true,
        sync: true
      },
      /** @private */
      _visibleChildColumns: Array,
      /** @private */
      _colSpan: Number,
      /** @private */
      _rootColumns: Array
    };
  }
  static get observers() {
    return [
      "_groupFrozenChanged(frozen, _rootColumns)",
      "_groupFrozenToEndChanged(frozenToEnd, _rootColumns)",
      "_groupHiddenChanged(hidden)",
      "_colSpanChanged(_colSpan, _headerCell, _footerCell)",
      "_groupOrderChanged(_order, _rootColumns)",
      "_groupReorderStatusChanged(_reorderStatus, _rootColumns)",
      "_groupResizableChanged(resizable, _rootColumns)"
    ];
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this._addNodeObserver();
    this._updateFlexAndWidth();
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (this._observer) {
      this._observer.disconnect();
    }
  }
  /**
   * @param {string} path
   * @param {unknown=} value
   * @protected
   */
  _columnPropChanged(path, value) {
    if (path === "hidden") {
      this._preventHiddenSynchronization = true;
      this._updateVisibleChildColumns(this._childColumns);
      this._preventHiddenSynchronization = false;
    }
    if (/flexGrow|width|hidden|_childColumns/u.test(path)) {
      this._updateFlexAndWidth();
    }
    if (path === "frozen" && !this.frozen) {
      this.frozen = value;
    }
    if (path === "lastFrozen" && !this._lastFrozen) {
      this._lastFrozen = value;
    }
    if (path === "frozenToEnd" && !this.frozenToEnd) {
      this.frozenToEnd = value;
    }
    if (path === "firstFrozenToEnd" && !this._firstFrozenToEnd) {
      this._firstFrozenToEnd = value;
    }
  }
  /** @private */
  _groupOrderChanged(order, rootColumns) {
    if (rootColumns) {
      const _rootColumns = rootColumns.slice(0);
      if (!order) {
        _rootColumns.forEach((column2) => {
          column2._order = 0;
        });
        return;
      }
      const trailingZeros = /(0+)$/u.exec(order).pop().length;
      const childCountDigits = ~~(Math.log(rootColumns.length) / Math.LN10) + 1;
      const scope = 10 ** (trailingZeros - childCountDigits);
      if (_rootColumns[0] && _rootColumns[0]._order) {
        _rootColumns.sort((a, b) => a._order - b._order);
      }
      updateColumnOrders(_rootColumns, scope, order);
    }
  }
  /** @private */
  _groupReorderStatusChanged(reorderStatus, rootColumns) {
    if (reorderStatus === void 0 || rootColumns === void 0) {
      return;
    }
    rootColumns.forEach((column2) => {
      column2._reorderStatus = reorderStatus;
    });
  }
  /** @private */
  _groupResizableChanged(resizable, rootColumns) {
    if (resizable === void 0 || rootColumns === void 0) {
      return;
    }
    rootColumns.forEach((column2) => {
      column2.resizable = resizable;
    });
  }
  /** @private */
  _updateVisibleChildColumns(childColumns) {
    this._visibleChildColumns = Array.prototype.filter.call(childColumns, (col) => !col.hidden);
    this._colSpan = this._visibleChildColumns.length;
    this._updateAutoHidden();
  }
  /** @protected */
  _updateFlexAndWidth() {
    if (!this._visibleChildColumns) {
      return;
    }
    if (this._visibleChildColumns.length > 0) {
      const width = this._visibleChildColumns.reduce((prev, curr) => {
        prev += ` + ${(curr.width || "0px").replace("calc", "")}`;
        return prev;
      }, "").substring(3);
      this._setWidth(`calc(${width})`);
    } else {
      this._setWidth("0px");
    }
    this._setFlexGrow(
      Array.prototype.reduce.call(this._visibleChildColumns, (prev, curr) => prev + curr.flexGrow, 0)
    );
  }
  /**
   * This method is called before the group's frozen value is being propagated to the child columns.
   * In case some of the child columns are frozen, while others are not, the non-frozen ones
   * will get automatically frozen as well. As this may sometimes be unintended, this method
   * shows a warning in the console in such cases.
   * @private
   */
  __scheduleAutoFreezeWarning(columns, frozenProp) {
    if (this._grid) {
      const frozenAttr = frozenProp.replace(/([A-Z])/gu, "-$1").toLowerCase();
      const firstColumnFrozen = columns[0][frozenProp] || columns[0].hasAttribute(frozenAttr);
      const allSameFrozen = columns.every((column2) => {
        return (column2[frozenProp] || column2.hasAttribute(frozenAttr)) === firstColumnFrozen;
      });
      if (!allSameFrozen) {
        this._grid.__autoFreezeWarningDebouncer = Debouncer.debounce(
          this._grid.__autoFreezeWarningDebouncer,
          animationFrame,
          () => {
            console.warn(
              `WARNING: Joining ${frozenProp} and non-${frozenProp} Grid columns inside the same column group! This will automatically freeze all the joined columns to avoid rendering issues. If this was intentional, consider marking each joined column explicitly as ${frozenProp}. Otherwise, exclude the ${frozenProp} columns from the joined group.`
            );
          }
        );
      }
    }
  }
  /** @private */
  _groupFrozenChanged(frozen, rootColumns) {
    if (rootColumns === void 0 || frozen === void 0) {
      return;
    }
    if (frozen !== false) {
      this.__scheduleAutoFreezeWarning(rootColumns, "frozen");
      Array.from(rootColumns).forEach((col) => {
        col.frozen = frozen;
      });
    }
  }
  /** @private */
  _groupFrozenToEndChanged(frozenToEnd, rootColumns) {
    if (rootColumns === void 0 || frozenToEnd === void 0) {
      return;
    }
    if (frozenToEnd !== false) {
      this.__scheduleAutoFreezeWarning(rootColumns, "frozenToEnd");
      Array.from(rootColumns).forEach((col) => {
        col.frozenToEnd = frozenToEnd;
      });
    }
  }
  /** @private */
  _groupHiddenChanged(hidden) {
    if (hidden || this.__groupHiddenInitialized) {
      this._synchronizeHidden();
    }
    this.__groupHiddenInitialized = true;
  }
  /** @private */
  _updateAutoHidden() {
    const wasAutoHidden = this._autoHidden;
    this._autoHidden = (this._visibleChildColumns || []).length === 0;
    if (wasAutoHidden || this._autoHidden) {
      this.hidden = this._autoHidden;
    }
  }
  /** @private */
  _synchronizeHidden() {
    if (this._childColumns && !this._preventHiddenSynchronization) {
      this._childColumns.forEach((column2) => {
        column2.hidden = this.hidden;
      });
    }
  }
  /** @private */
  _colSpanChanged(colSpan, headerCell, footerCell) {
    if (headerCell) {
      headerCell.setAttribute("colspan", colSpan);
      if (this._grid) {
        this._grid.__a11yUpdateCellColspan(headerCell, colSpan);
      }
    }
    if (footerCell) {
      footerCell.setAttribute("colspan", colSpan);
      if (this._grid) {
        this._grid.__a11yUpdateCellColspan(footerCell, colSpan);
      }
    }
  }
  /**
   * @param {!GridColumnGroup} el
   * @return {!Array<!GridColumn>}
   * @protected
   */
  _getChildColumns(el) {
    return ColumnObserver.getColumns(el);
  }
  /** @private */
  _addNodeObserver() {
    this._observer = new ColumnObserver(this, () => {
      this._preventHiddenSynchronization = true;
      this._rootColumns = this._getChildColumns(this);
      this._childColumns = this._rootColumns;
      this._updateVisibleChildColumns(this._childColumns);
      this._preventHiddenSynchronization = false;
      if (this._grid && this._grid._debounceUpdateColumnTree) {
        this._grid._debounceUpdateColumnTree();
      }
    });
    this._observer.flush();
  }
  /**
   * @param {!Node} node
   * @return {boolean}
   * @protected
   */
  _isColumnElement(node) {
    return node.nodeType === Node.ELEMENT_NODE && /\bcolumn\b/u.test(node.localName);
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class GridColumnGroup extends GridColumnGroupMixin(PolylitMixin(LitElement)) {
  static get is() {
    return "vaadin-grid-column-group";
  }
}
defineCustomElement(GridColumnGroup);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const gridFilterStyles = css$h`
  :host {
    display: inline-flex;
    max-width: 100%;
  }

  ::slotted(*) {
    width: 100%;
    box-sizing: border-box;
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const GridFilterElementMixin = (superClass) => class extends superClass {
  static get properties() {
    return {
      /**
       * JS Path of the property in the item used for filtering the data.
       */
      path: {
        type: String,
        sync: true
      },
      /**
       * Current filter value.
       */
      value: {
        type: String,
        notify: true,
        sync: true
      },
      /** @private */
      _textField: {
        type: Object,
        sync: true
      }
    };
  }
  static get observers() {
    return ["_filterChanged(path, value, _textField)"];
  }
  /** @protected */
  ready() {
    super.ready();
    this._filterController = new SlotController(this, "", "vaadin-text-field", {
      initializer: (field2) => {
        field2.addEventListener("input", (e) => {
          this.value = e.target.value;
        });
        this._textField = field2;
      }
    });
    this.addController(this._filterController);
  }
  /** @private */
  _filterChanged(path, value, textField) {
    if (path === void 0 || value === void 0 || !textField) {
      return;
    }
    textField.value = value;
    this._debouncerFilterChanged = Debouncer.debounce(this._debouncerFilterChanged, timeOut.after(200), () => {
      this.dispatchEvent(new CustomEvent("filter-changed", { bubbles: true }));
    });
  }
  focus() {
    if (this._textField) {
      this._textField.focus();
    }
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class GridFilter extends GridFilterElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-grid-filter";
  }
  static get styles() {
    return gridFilterStyles;
  }
  /** @protected */
  render() {
    return html`<slot></slot>`;
  }
}
defineCustomElement(GridFilter);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const gridSorterStyles = css$h`
  :host {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    max-width: 100%;
    gap: var(--vaadin-gap-s);
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }

  [part='content'] {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  [part='indicators'] {
    position: relative;
    flex: none;
    height: 1lh;
    color: var(--vaadin-text-color-disabled);
  }

  [part='order'] {
    display: inline;
    vertical-align: super;
    font-size: 0.75em;
    line-height: 1;
    color: var(--vaadin-text-color-secondary);
  }

  [part='indicators']::before {
    content: '';
    display: inline-block;
    height: 12px;
    width: 8px;
    mask-image: var(--_vaadin-icon-sort);
    background: currentColor;
  }

  :host([direction]) [part='indicators']::before {
    padding-bottom: 6px;
    height: 6px;
    mask-clip: content-box;
  }

  :host([direction='desc']) [part='indicators']::before {
    padding-block: 6px 0;
  }

  :host([direction]) [part='indicators'] {
    color: var(--vaadin-text-color-secondary);
  }

  @media (any-hover: hover) {
    :host(:hover) [part='indicators'] {
      color: var(--vaadin-text-color);
    }
  }

  @media (forced-colors: active) {
    [part='indicators']::before {
      background: CanvasText;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const GridSorterMixin = (superClass) => class GridSorterMixinClass extends superClass {
  static get properties() {
    return {
      /**
       * JS Path of the property in the item used for sorting the data.
       */
      path: {
        type: String
      },
      /**
       * How to sort the data.
       * Possible values are `asc` to use an ascending algorithm, `desc` to sort the data in
       * descending direction, or `null` for not sorting the data.
       */
      direction: {
        type: String,
        reflectToAttribute: true,
        notify: true,
        value: null,
        sync: true
      },
      /**
       * @type {number | null}
       * @protected
       */
      _order: {
        type: Number,
        value: null,
        sync: true
      }
    };
  }
  static get observers() {
    return ["_pathOrDirectionChanged(path, direction)"];
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("click", this._onClick.bind(this));
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this._grid) {
      this._grid.__applySorters();
    } else {
      this.__dispatchSorterChangedEvenIfPossible();
    }
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (!this.parentNode && this._grid) {
      this._grid.__removeSorters([this]);
    } else if (this._grid) {
      this._grid.__applySorters();
    }
  }
  /** @private */
  _pathOrDirectionChanged() {
    this.__dispatchSorterChangedEvenIfPossible();
  }
  /** @private */
  __dispatchSorterChangedEvenIfPossible() {
    if (this.path === void 0 || this.direction === void 0 || !this.isConnected) {
      return;
    }
    this.dispatchEvent(
      new CustomEvent("sorter-changed", {
        detail: { shiftClick: Boolean(this._shiftClick), fromSorterClick: Boolean(this._fromSorterClick) },
        bubbles: true,
        composed: true
      })
    );
    this._fromSorterClick = false;
    this._shiftClick = false;
  }
  /** @private */
  _getDisplayOrder(order) {
    return order === null ? "" : order + 1;
  }
  /** @private */
  _onClick(e) {
    if (e.defaultPrevented) {
      return;
    }
    const activeElement = this.getRootNode().activeElement;
    if (this !== activeElement && this.contains(activeElement)) {
      return;
    }
    e.preventDefault();
    this._shiftClick = e.shiftKey;
    this._fromSorterClick = true;
    if (this.direction === "asc") {
      this.direction = "desc";
    } else if (this.direction === "desc") {
      this.direction = null;
    } else {
      this.direction = "asc";
    }
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class GridSorter extends GridSorterMixin(ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-grid-sorter";
  }
  static get styles() {
    return gridSorterStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="content">
        <slot></slot>
      </div>
      <div part="indicators">
        <span part="order">${this._getDisplayOrder(this._order)}</span>
      </div>
    `;
  }
}
defineCustomElement(GridSorter);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const crudEditStyles = css$h`
  [part='icon'] {
    background: currentColor;
    display: block;
    height: var(--vaadin-icon-size, 1lh);
    mask: var(--_vaadin-icon-pen) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
    width: var(--vaadin-icon-size, 1lh);
  }

  @media (forced-colors: active) {
    [part='icon'] {
      background: CanvasText;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class CrudEdit extends Button {
  static get is() {
    return "vaadin-crud-edit";
  }
  static get styles() {
    return [super.styles, crudEditStyles];
  }
  /** @protected */
  render() {
    return html`
      <div part="icon"></div>
      <slot name="tooltip"></slot>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("click", this.__onClick);
    this.setAttribute("aria-label", "Edit");
  }
  /** @private */
  __onClick(e) {
    const tr = e.target.parentElement.assignedSlot.parentElement.parentElement;
    tr.dispatchEvent(
      new CustomEvent("edit", { detail: { item: tr._item, index: tr.index }, bubbles: true, composed: true })
    );
  }
  /**
   * Fired when user on the icon.
   *
   * @event edit
   * @param {Object} detail.item the item to edit
   * @param {Object} detail.index the index of the item in the data set
   */
}
defineCustomElement(CrudEdit);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
function capitalize(path) {
  return path.toLowerCase().replace(/([^\w]+)/gu, " ").trim().replace(/^./u, (c) => c.toUpperCase());
}
function getProperty(path, obj) {
  return get$5(path, obj);
}
function setProperty(path, value, obj) {
  if (obj && path) {
    path.split(".").slice(0, -1).reduce((o, p) => {
      if (!o[p]) {
        o[p] = {};
      }
      return o[p];
    }, obj);
    set(path, value, obj);
  }
}
function isValidEditorPosition(editorPosition) {
  return ["bottom", "aside"].includes(editorPosition);
}
function editColumnDefaultRenderer(root, column2) {
  let edit = root.firstElementChild;
  if (!edit) {
    edit = document.createElement("vaadin-crud-edit");
    if (column2.hasAttribute("theme")) {
      edit.setAttribute("theme", column2.getAttribute("theme"));
    }
    root.appendChild(edit);
  }
  if (column2.ariaLabel) {
    edit.setAttribute("aria-label", column2.ariaLabel);
  } else {
    edit.removeAttribute("aria-label");
  }
}
function createField(crudForm, parent, path) {
  const field2 = document.createElement("vaadin-text-field");
  field2.label = capitalize(path);
  field2.path = path;
  field2.required = true;
  parent.appendChild(field2);
  crudForm._fields.push(field2);
  return field2;
}
function createFields(crudForm, parent, object, path) {
  Object.keys(object).forEach((prop) => {
    if (!crudForm.include && crudForm.exclude && crudForm.exclude.test(prop)) {
      return;
    }
    const newPath = (path ? `${path}.` : "") + prop;
    if (object[prop] && typeof object[prop] === "object") {
      createFields(crudForm, parent, object[prop], newPath);
    } else {
      createField(crudForm, parent, newPath);
    }
  });
  if (!crudForm._fields.length) {
    crudForm._fields = void 0;
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class CrudEditColumn extends GridColumn {
  static get is() {
    return "vaadin-crud-edit-column";
  }
  static get properties() {
    return {
      /**
       * Automatically sets the width of the column based on the column contents when this is set to `true`.
       * @private
       */
      autoWidth: {
        type: Boolean,
        value: true
      },
      /**
       * Flex grow ratio for the cell widths. When set to 0, cell width is fixed.
       * @private
       */
      flexGrow: {
        type: Number,
        value: 0
      },
      /**
       * The arial-label for the edit button
       */
      ariaLabel: {
        type: String
      }
    };
  }
  static get observers() {
    return ["_onRendererOrBindingChanged(_renderer, _cells, _bodyContentHidden, _cells.*, path, ariaLabel)"];
  }
  /**
   * Renders the crud edit element to the body cell.
   *
   * @override
   */
  _defaultRenderer(root, column2) {
    editColumnDefaultRenderer(root, column2);
  }
}
defineCustomElement(CrudEditColumn);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const crudGrid = css$h`
  #scroller {
    border-radius: inherit;
  }
`;
const crudGridStyles = [gridStyles, crudGrid];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const IncludedMixin = (superClass) => class IncludedMixin extends superClass {
  static get properties() {
    return {
      /**
       * A list of item fields that should not be mapped to form fields.
       *
       * When [`include`](#/elements/vaadin-crud-form#property-include) is defined, this property is ignored.
       *
       * Default is to exclude any private property.
       *
       * @type {string | RegExp}
       */
      exclude: {
        type: String,
        value: "^_",
        observer: "__onExcludeChange",
        sync: true
      },
      /**
       * A list of item properties that should be mapped to form fields.
       *
       * When it is defined [`exclude`](#/elements/vaadin-crud-form#property-exclude) is ignored.
       *
       * @type {string | !Array<string> | undefined}
       */
      include: {
        type: String,
        observer: "__onIncludeChange",
        sync: true
      }
    };
  }
  /** @private */
  __onExcludeChange(exclude) {
    if (typeof exclude === "string") {
      this.exclude = exclude ? RegExp(exclude.replace(/, */gu, "|"), "iu") : void 0;
    }
  }
  /** @private */
  __onIncludeChange(include) {
    if (typeof include === "string") {
      this.include = include ? include.split(/, */u) : void 0;
    } else if (!this._fields && Array.isArray(include)) {
      const item = {};
      this.include.forEach((path) => {
        setProperty(path, null, item);
      });
      this._configure(item);
    }
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const CrudGridMixin = (superClass) => class extends IncludedMixin(superClass) {
  static get properties() {
    return {
      /**
       * Disable filtering in the generated columns.
       * @attr {boolean} no-filter
       */
      noFilter: {
        type: Boolean
      },
      /**
       * Disable sorting in the generated columns.
       * @attr {boolean} no-sort
       */
      noSort: {
        type: Boolean
      },
      /**
       * Do not add headers to columns.
       * @attr {boolean} no-head
       */
      noHead: {
        type: Boolean
      },
      /**
       * Determines whether the edit column should be hidden.
       * @attr {boolean} hide-edit-column
       */
      hideEditColumn: {
        type: Boolean,
        sync: true
      }
    };
  }
  static get observers() {
    return ["__onItemsChange(items)", "__onHideEditColumnChange(hideEditColumn)"];
  }
  /** @private */
  __onItemsChange(items) {
    if ((!this.dataProvider || this.dataProvider === this._arrayDataProvider) && !this.include && items && items[0]) {
      this._configure(items[0]);
    }
  }
  /** @private */
  __onHideEditColumnChange() {
    if (this.firstChild) {
      this.__toggleEditColumn();
    }
  }
  /** @private */
  __toggleEditColumn() {
    let editColumn = this.querySelector("vaadin-crud-edit-column");
    if (this.hideEditColumn) {
      if (editColumn) {
        this.removeChild(editColumn);
      }
    } else if (!editColumn) {
      editColumn = document.createElement("vaadin-crud-edit-column");
      editColumn.frozenToEnd = true;
      this.appendChild(editColumn);
    }
  }
  /** @private */
  __dataProviderWrapper(params2, callback) {
    this.__dataProvider(params2, (items, size) => {
      if (this.innerHTML === "" && !this.include && items[0]) {
        this._configure(items[0]);
      }
      callback(items, size);
    });
  }
  /**
   * @override
   * @private
   */
  _dataProviderChanged(dataProvider, oldDataProvider) {
    if (this._arrayDataProvider === dataProvider) {
      super._dataProviderChanged(dataProvider, oldDataProvider);
    } else if (this.__dataProviderWrapper !== dataProvider) {
      this.innerHTML = "";
      this.__dataProvider = dataProvider;
      this.dataProvider = this.__dataProviderWrapper;
      super._dataProviderChanged(this.__dataProviderWrapper, oldDataProvider);
    }
  }
  /**
   * Auto-generate grid columns based on the JSON structure of the object provided.
   *
   * Method will be executed when items or dataProvider is assigned.
   * @private
   */
  _configure(item) {
    this.innerHTML = "";
    this.__createColumns(this, item, void 0, this.__getPropertyDepth(item));
    this.__toggleEditColumn();
  }
  /**
   * Return the deepest property depth of the object
   * @private
   */
  __getPropertyDepth(object) {
    if (!object || typeof object !== "object") {
      return 0;
    }
    return Object.keys(object).reduce((deepest, prop) => {
      if (this.exclude && this.exclude.test(prop)) {
        return deepest;
      }
      return Math.max(deepest, 1 + this.__getPropertyDepth(object[prop]));
    }, 0);
  }
  /**
   * Parse the camelCase column names into sentence case headers.
   * @param {string} path
   * @return {string}
   * @protected
   */
  _generateHeader(path) {
    return path.substr(path.lastIndexOf(".") + 1).replace(/([A-Z])/gu, "-$1").toLowerCase().replace(/-/gu, " ").replace(/^./u, (match2) => match2.toUpperCase());
  }
  /** @private */
  __createColumn(parent, path) {
    let col;
    if (!this.noFilter && !this.noSort && !parent.__sortColumnGroup) {
      col = this.__createGroup(parent);
      col.__sortColumnGroup = true;
      this.__createColumn(col, path);
    } else {
      col = document.createElement("vaadin-grid-column");
      parent.appendChild(col);
      col.renderer = (root, _column, model) => {
        root.textContent = path ? getProperty(path, model.item) : model.item;
      };
    }
    if (!this.noHead && path) {
      col.headerRenderer = (root) => {
        if (root.firstElementChild) {
          return;
        }
        const label = this._generateHeader(path);
        if (col.__sortColumnGroup || this.noFilter && !this.noSort) {
          const sorter = document.createElement("vaadin-grid-sorter");
          sorter.setAttribute("path", path);
          sorter.setAttribute("aria-label", `Sort by ${label}`);
          sorter.textContent = label;
          root.appendChild(sorter);
        } else if (!this.noFilter) {
          const filter = document.createElement("vaadin-grid-filter");
          filter.setAttribute("path", path);
          filter.setAttribute("aria-label", `Filter by ${label}`);
          filter.style.display = "flex";
          const textField = window.document.createElement("vaadin-text-field");
          textField.setAttribute("theme", "small");
          textField.setAttribute("focus-target", true);
          textField.style.width = "100%";
          if (this.noSort) {
            textField.placeholder = label;
          }
          textField.addEventListener("value-changed", (event) => {
            filter.value = event.detail.value;
          });
          filter.appendChild(textField);
          root.appendChild(filter);
        } else if (this.noSort && this.noFilter) {
          root.textContent = label;
        }
      };
    }
  }
  /**
   * Creates the column structure for the (sub)object.
   *
   * @param {HTMLElement} parent May be the crud-grid or a column group.
   * @param {Object} object The object to create the sub-columns for.
   * @param {string} path The property path from the root item to the object.
   * @param {number} depth The depth of the object in the object hierarchy.
   * @private
   */
  __createColumns(parent, object, path, depth) {
    if (object && typeof object === "object") {
      Object.keys(object).forEach((prop) => {
        if (!this.include && this.exclude && this.exclude.test(prop)) {
          return;
        }
        const subObject = object[prop];
        const subObjectPath = path ? `${path}.${prop}` : prop;
        let subObjectColumn = parent;
        if (!this.noHead && depth > 1) {
          const isSubObject = subObject && typeof subObject === "object";
          subObjectColumn = this.__createGroup(parent, isSubObject ? prop : void 0);
        }
        this.__createColumns(subObjectColumn, subObject, subObjectPath, depth - 1);
      });
    } else if (depth > 1) {
      this.__createColumns(this.__createGroup(parent), void 0, path, depth - 1);
    } else {
      this.__createColumn(parent, path);
    }
  }
  /** @private */
  __createGroup(parent, header) {
    const grp = document.createElement("vaadin-grid-column-group");
    if (header) {
      grp.header = capitalize(header);
    }
    parent.appendChild(grp);
    return grp;
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class CrudGrid extends CrudGridMixin(Grid) {
  static get is() {
    return "vaadin-crud-grid";
  }
  static get styles() {
    return crudGridStyles;
  }
}
defineCustomElement(CrudGrid);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
CSS.registerProperty({
  name: "--_min-width-labels-aside",
  syntax: "<length>",
  inherits: false,
  initialValue: "0px"
});
addGlobalStyles(
  "vaadin-form-layout-base",
  css$h`
    @layer vaadin.base {
      html {
        --vaadin-form-layout-label-spacing: var(--vaadin-gap-s);
        --vaadin-form-layout-label-width: 8em;
        --vaadin-form-layout-column-spacing: var(--vaadin-gap-l);
        --vaadin-form-layout-row-spacing: var(--vaadin-gap-l);
      }
    }
  `
);
const formLayoutStyles = css$h`
  :host {
    /* Default values */
    --_label-spacing: var(--vaadin-form-layout-label-spacing);
    --_label-width: var(--vaadin-form-layout-label-width);
    --_column-spacing: var(--vaadin-form-layout-column-spacing);
    --_row-spacing: var(--vaadin-form-layout-row-spacing);

    align-self: stretch;
    display: block;
    max-width: 100%;
  }

  :host([hidden]) {
    display: none !important;
  }

  :host(:not([auto-responsive])) {
    contain: layout;
  }

  :host(:not([auto-responsive])) #layout {
    align-items: baseline; /* default \`stretch\` is not appropriate */
    display: flex;
    flex-wrap: wrap; /* the items should wrap */
    /* Compensate for row spacing */
    margin-block: calc(-0.5 * var(--_row-spacing));
  }

  :host(:not([auto-responsive])) #layout ::slotted(*) {
    /* Items should neither grow nor shrink. */
    flex-grow: 0;
    flex-shrink: 0;

    /* Margins make spacing between the columns and rows */
    margin-inline: calc(0.5 * var(--_column-spacing));
    margin-block: calc(0.5 * var(--_row-spacing));
  }

  #layout ::slotted(br) {
    display: none;
  }

  :host([auto-responsive]) {
    /* Column width */
    --_column-width: var(--vaadin-field-default-width, 12em);
    --_column-width-labels-above: var(--_column-width);
    --_column-width-labels-aside: calc(var(--_column-width) + var(--_label-width) + var(--_label-spacing));

    /* Column gap */
    --_min-total-gap: calc((var(--_min-columns) - 1) * var(--_column-spacing));
    --_max-total-gap: calc((var(--_max-columns) - 1) * var(--_column-spacing));

    /* Minimum form layout width */
    --_min-width-labels-above: calc(var(--_min-columns) * var(--_column-width-labels-above) + var(--_min-total-gap));
    --_min-width-labels-aside: calc(var(--_min-columns) * var(--_column-width-labels-aside) + var(--_min-total-gap));
    --_min-width: var(--_min-width-labels-above);

    /* Maximum form layout width */
    --_max-width-labels-above: calc(var(--_max-columns) * var(--_column-width-labels-above) + var(--_max-total-gap));
    --_max-width-labels-aside: calc(var(--_max-columns) * var(--_column-width-labels-aside) + var(--_max-total-gap));
    --_max-width: var(--_max-width-labels-above);

    display: flex;
    min-width: var(--_min-width);
  }

  :host([auto-responsive]) #layout {
    /* By default, labels should be displayed above the fields */
    --_form-item-labels-above: initial; /* true */
    --_form-item-labels-aside: ' '; /* false */

    /* CSS grid related properties */
    --_grid-column-width: var(--_column-width-labels-above);
    --_grid-repeat: var(--_grid-column-width);

    display: grid;
    gap: var(--_row-spacing) var(--_column-spacing);

    /*
      Auto-columns can be created when an item's colspan exceeds the rendered column count.
      By setting auto-columns to 0, we exclude these columns from --_grid-rendered-column-count,
      which is then used to cap the colspan.
    */
    grid-auto-columns: 0;

    align-self: start;
    grid-template-columns: repeat(auto-fill, var(--_grid-repeat));
    place-items: baseline start;

    /*
      Firefox requires min-width on both :host and #layout to allow the layout
      to shrink below the value specified in the CSS width property above.
    */
    min-width: var(--_min-width);

    /*
      To prevent the layout from exceeding the column limit defined by --_max-columns,
      its width needs to be constrained:

      1. "width" is used instead of "max-width" because, together with the default "flex: 0 1 auto",
      it allows the layout to shrink to its minimum width inside <vaadin-horizontal-layout>, which
      wouldn't work otherwise.

      2. "width" is used instead of "flex-basis" to make the layout expand to the maximum
      number of columns inside <vaadin-overlay>, which creates a new stacking context
      without a predefined width.
    */
    width: var(--_max-width);
  }

  :host([auto-responsive]) #layout ::slotted(*) {
    /* Make form items inherit label position from the layout */
    --_form-item-labels-above: inherit;
    --_form-item-labels-aside: inherit;

    /* By default, place each child on a new row */
    grid-column: 1 / span min(var(--_grid-colspan, 1), var(--_grid-rendered-column-count));

    /* Form items do not need margins in auto-responsive mode */
    margin: 0;
  }

  :host([auto-responsive][auto-rows]) #layout ::slotted(*) {
    grid-column-start: var(--_grid-colstart, auto);
  }

  :host([auto-responsive][labels-aside]) {
    --_max-width: var(--_max-width-labels-aside);
  }

  :host([auto-responsive][labels-aside]) #layout[fits-labels-aside] {
    --_form-item-labels-above: ' '; /* false */
    --_form-item-labels-aside: initial; /* true */
    --_grid-column-width: var(--_column-width-labels-aside);
  }

  :host([auto-responsive][expand-columns]) #layout {
    /*
      The "min" value in minmax ensures that once "maxColumns" is reached, the grid stops adding
      new columns and instead expands the existing ones evenly to fill the available space.

      The "max" value in minmax allows CSS grid columns to grow and evenly distribute any space
      that remains when there isn't room for an additional column and "maxColumns" hasn't been
      reached yet.
    */
    --_grid-repeat: minmax(
      max(var(--_grid-column-width), calc((100% - var(--_max-total-gap)) / var(--_max-columns))),
      1fr
    );

    /* Allow the layout to take up full available width of the parent element. */
    flex-grow: 1;
  }
`;
const formLayoutSlotStyles = css$h`
  /* Using :where to ensure user styles always take precedence */
  :where(
    vaadin-form-layout[auto-responsive] > *,
    vaadin-form-layout[auto-responsive] vaadin-form-row > *,
    vaadin-form-layout[auto-responsive] vaadin-form-item > *
  ) {
    box-sizing: border-box;
    max-width: 100%;
  }

  :where(
    vaadin-form-layout[auto-responsive][expand-fields] > *,
    vaadin-form-layout[auto-responsive][expand-fields] vaadin-form-row > *,
    vaadin-form-layout[auto-responsive][expand-fields] vaadin-form-item > *
  ) {
    min-width: 100%;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class AbstractLayout {
  /**
   * @param {HTMLElement} host
   * @param {{ mutationObserverOptions: MutationObserverInit }} config
   */
  constructor(host, config2) {
    this.host = host;
    this.props = {};
    this.config = config2;
    this.isConnected = false;
    this.__resizeObserver = new ResizeObserver((entries) => setTimeout(() => this._onResize(entries)));
    this.__mutationObserver = new MutationObserver((records) => this._onMutation(records));
  }
  /**
   * Connects the layout to the host element.
   */
  connect() {
    if (this.isConnected) {
      return;
    }
    this.isConnected = true;
    this.__resizeObserver.observe(this.host);
    this.__mutationObserver.observe(this.host, this.config.mutationObserverOptions);
  }
  /**
   * Disconnects the layout from the host element.
   */
  disconnect() {
    if (!this.isConnected) {
      return;
    }
    this.isConnected = false;
    this.__resizeObserver.disconnect();
    this.__mutationObserver.disconnect();
  }
  /**
   * Sets the properties of the layout controller.
   */
  setProps(props) {
    this.props = props;
  }
  /**
   * Updates the layout based on the current properties.
   */
  updateLayout() {
  }
  /**
   * @param {ResizeObserverEntry[]} _entries
   * @protected
   */
  _onResize(_entries) {
  }
  /**
   * @param {MutationRecord[]} _records
   * @protected
   */
  _onMutation(_records) {
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function isBreakLine(el) {
  return el.localName === "br";
}
class AutoResponsiveLayout extends AbstractLayout {
  constructor(host) {
    super(host, {
      mutationObserverOptions: {
        subtree: true,
        childList: true,
        attributes: true,
        attributeFilter: ["colspan", "data-colspan", "hidden"]
      }
    });
  }
  /** @override */
  connect() {
    if (this.isConnected) {
      return;
    }
    super.connect();
    this.updateLayout();
  }
  /** @override */
  disconnect() {
    if (!this.isConnected) {
      return;
    }
    super.disconnect();
    const { host } = this;
    host.style.removeProperty("--_column-width");
    host.style.removeProperty("--_max-columns");
    host.$.layout.removeAttribute("fits-labels-aside");
    host.$.layout.style.removeProperty("--_grid-rendered-column-count");
    this.__children.forEach((child) => {
      child.style.removeProperty("--_grid-colstart");
      child.style.removeProperty("--_grid-colspan");
    });
  }
  /** @override */
  setProps(props) {
    super.setProps(props);
    if (this.isConnected) {
      this.updateLayout();
    }
  }
  /** @override */
  updateLayout() {
    const { host, props } = this;
    if (!this.isConnected || isElementHidden(host)) {
      return;
    }
    let columnCount = 0;
    let maxColumns = 0;
    const children = this.__children;
    children.filter((child) => isBreakLine(child) || !isElementHidden(child)).forEach((child, index, children2) => {
      const prevChild = children2[index - 1];
      if (isBreakLine(child)) {
        columnCount = 0;
        return;
      }
      if (prevChild && prevChild.parentElement !== child.parentElement || !props.autoRows && child.parentElement === host) {
        columnCount = 0;
      }
      if (props.autoRows && columnCount === 0) {
        child.style.setProperty("--_grid-colstart", 1);
      } else {
        child.style.removeProperty("--_grid-colstart");
      }
      const colspan = child.getAttribute("colspan") || child.getAttribute("data-colspan");
      if (colspan) {
        columnCount += parseInt(colspan);
        child.style.setProperty("--_grid-colspan", colspan);
      } else {
        columnCount += 1;
        child.style.removeProperty("--_grid-colspan");
      }
      maxColumns = Math.max(maxColumns, columnCount);
    });
    children.filter(isElementHidden).forEach((child) => {
      child.style.removeProperty("--_grid-colstart");
    });
    if (props.columnWidth) {
      host.style.setProperty("--_column-width", props.columnWidth);
    } else {
      host.style.removeProperty("--_column-width");
    }
    host.style.setProperty("--_min-columns", props.minColumns);
    host.style.setProperty("--_max-columns", Math.min(Math.max(props.minColumns, props.maxColumns), maxColumns));
    host.$.layout.toggleAttribute("fits-labels-aside", this.props.labelsAside && this.__fitsLabelsAside);
    host.$.layout.style.setProperty("--_grid-rendered-column-count", this.__renderedColumnCount);
  }
  /** @override */
  _onResize() {
    this.updateLayout();
  }
  /** @override */
  _onMutation(records) {
    const shouldUpdateLayout = records.some(({ target }) => {
      return target === this.host || target.parentElement === this.host || target.parentElement.localName === "vaadin-form-row";
    });
    if (shouldUpdateLayout) {
      this.updateLayout();
    }
  }
  /** @private */
  get __children() {
    return [...this.host.children].flatMap((child) => {
      return child.localName === "vaadin-form-row" ? [...child.children] : child;
    });
  }
  /** @private */
  get __renderedColumnCount() {
    const { gridTemplateColumns } = getComputedStyle(this.host.$.layout);
    return gridTemplateColumns.split(" ").filter((width) => width !== "0px").length;
  }
  /** @private */
  get __minWidthLabelsAside() {
    return parseFloat(getComputedStyle(this.host).getPropertyValue("--_min-width-labels-aside"));
  }
  /** @private */
  get __fitsLabelsAside() {
    return this.host.offsetWidth >= this.__minWidthLabelsAside;
  }
}
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function isValidCSSLength(value) {
  return CSS.supports("word-spacing", value) && !["inherit", "normal"].includes(value);
}
function naturalNumberOrOne(n) {
  if (typeof n === "number" && n >= 1 && n < Infinity) {
    return Math.floor(n);
  }
  return 1;
}
class ResponsiveStepsLayout extends AbstractLayout {
  constructor(host) {
    super(host, {
      mutationObserverOptions: {
        subtree: true,
        childList: true,
        attributes: true,
        attributeFilter: ["colspan", "data-colspan", "hidden"]
      }
    });
  }
  /** @override */
  connect() {
    if (this.isConnected) {
      return;
    }
    super.connect();
    this.__selectResponsiveStep();
    this.updateLayout();
    requestAnimationFrame(() => this.__selectResponsiveStep());
    requestAnimationFrame(() => this.updateLayout());
  }
  /** @override */
  disconnect() {
    if (!this.isConnected) {
      return;
    }
    super.disconnect();
    const { host } = this;
    host.$.layout.style.removeProperty("opacity");
    [...host.children].forEach((child) => {
      child.style.removeProperty("width");
      child.style.removeProperty("margin-left");
      child.style.removeProperty("margin-right");
      child.removeAttribute("label-position");
    });
  }
  /** @override */
  setProps(props) {
    const { responsiveSteps } = props;
    if (!Array.isArray(responsiveSteps)) {
      throw new Error('Invalid "responsiveSteps" type, an Array is required.');
    }
    if (responsiveSteps.length < 1) {
      throw new Error('Invalid empty "responsiveSteps" array, at least one item is required.');
    }
    responsiveSteps.forEach((step) => {
      if (naturalNumberOrOne(step.columns) !== step.columns) {
        throw new Error(`Invalid 'columns' value of ${step.columns}, a natural number is required.`);
      }
      if (step.minWidth !== void 0 && !isValidCSSLength(step.minWidth)) {
        throw new Error(`Invalid 'minWidth' value of ${step.minWidth}, a valid CSS length required.`);
      }
      if (step.labelsPosition !== void 0 && ["aside", "top"].indexOf(step.labelsPosition) === -1) {
        throw new Error(
          `Invalid 'labelsPosition' value of ${step.labelsPosition}, 'aside' or 'top' string is required.`
        );
      }
    });
    super.setProps(props);
    if (this.isConnected) {
      this.__selectResponsiveStep();
      this.updateLayout();
    }
  }
  /** @override */
  updateLayout() {
    const { host } = this;
    if (!this.isConnected || isElementHidden(host)) {
      return;
    }
    const style = getComputedStyle(host);
    const columnSpacing = style.getPropertyValue("--_column-spacing");
    const direction = style.direction;
    const marginStartProp = `margin-${direction === "ltr" ? "left" : "right"}`;
    const marginEndProp = `margin-${direction === "ltr" ? "right" : "left"}`;
    const containerWidth = host.offsetWidth;
    let col = 0;
    Array.from(host.children).filter((child) => child.localName === "br" || getComputedStyle(child).display !== "none").forEach((child, index, children) => {
      if (child.localName === "br") {
        col = 0;
        return;
      }
      const attrColspan = child.getAttribute("colspan") || child.getAttribute("data-colspan");
      let colspan;
      colspan = naturalNumberOrOne(parseFloat(attrColspan));
      colspan = Math.min(colspan, this.__columnCount);
      const childRatio = colspan / this.__columnCount;
      child.style.width = `calc(${childRatio * 100}% - ${1 - childRatio} * ${columnSpacing})`;
      if (col + colspan > this.__columnCount) {
        col = 0;
      }
      if (col === 0) {
        child.style.setProperty(marginStartProp, "0px");
      } else {
        child.style.removeProperty(marginStartProp);
      }
      const nextIndex = index + 1;
      const nextLineBreak = nextIndex < children.length && children[nextIndex].localName === "br";
      if (col + colspan === this.__columnCount) {
        child.style.setProperty(marginEndProp, "0px");
      } else if (nextLineBreak) {
        const colspanRatio = (this.__columnCount - col - colspan) / this.__columnCount;
        child.style.setProperty(
          marginEndProp,
          `calc(${colspanRatio * containerWidth}px + ${colspanRatio} * ${columnSpacing})`
        );
      } else {
        child.style.removeProperty(marginEndProp);
      }
      col = (col + colspan) % this.__columnCount;
      if (child.localName === "vaadin-form-item") {
        if (this.__labelsOnTop) {
          if (child.getAttribute("label-position") !== "top") {
            child.__useLayoutLabelPosition = true;
            child.setAttribute("label-position", "top");
          }
        } else if (child.__useLayoutLabelPosition) {
          delete child.__useLayoutLabelPosition;
          child.removeAttribute("label-position");
        }
      }
    });
  }
  /** @override */
  _onResize() {
    const { host } = this;
    if (isElementHidden(host)) {
      host.$.layout.style.opacity = "0";
      return;
    }
    this.__selectResponsiveStep();
    this.updateLayout();
    host.$.layout.style.opacity = "";
  }
  /** @override */
  _onMutation(records) {
    const shouldUpdateLayout = records.some(({ target }) => {
      return target === this.host || target.parentElement === this.host;
    });
    if (shouldUpdateLayout) {
      this.updateLayout();
    }
  }
  /** @private */
  __selectResponsiveStep() {
    if (!this.isConnected) {
      return;
    }
    const { host, props } = this;
    let selectedStep;
    const tmpStyleProp = "background-position";
    props.responsiveSteps.forEach((step) => {
      host.$.layout.style.setProperty(tmpStyleProp, step.minWidth);
      const stepMinWidthPx = parseFloat(getComputedStyle(host.$.layout).getPropertyValue(tmpStyleProp));
      if (stepMinWidthPx <= host.offsetWidth) {
        selectedStep = step;
      }
    });
    host.$.layout.style.removeProperty(tmpStyleProp);
    if (selectedStep) {
      this.__columnCount = selectedStep.columns;
      this.__labelsOnTop = selectedStep.labelsPosition === "top";
    }
  }
}
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const FormLayoutMixin = (superClass) => class extends SlotStylesMixin(superClass) {
  static get properties() {
    return {
      /**
       * @typedef FormLayoutResponsiveStep
       * @type {object}
       * @property {string} minWidth - The threshold value for this step in CSS length units.
       * @property {number} columns - Number of columns. Only natural numbers are valid.
       * @property {string} labelsPosition - Labels position option, valid values: `"aside"` (default), `"top"`.
       */
      /**
       * Allows specifying a responsive behavior with the number of columns
       * and the label position depending on the layout width.
       *
       * Format: array of objects, each object defines one responsive step
       * with `minWidth` CSS length, `columns` number, and optional
       * `labelsPosition` string of `"aside"` or `"top"`. At least one item is required.
       *
       * NOTE: Responsive steps are ignored in auto-responsive mode, which may be
       * enabled explicitly via the `autoResponsive` property or implicitly
       * if the following feature flag is set:
       *
       * ```js
       * window.Vaadin.featureFlags.defaultAutoResponsiveFormLayout = true
       * ```
       *
       * #### Examples
       *
       * ```javascript
       * formLayout.responsiveSteps = [{columns: 1}];
       * // The layout is always a single column, labels aside.
       * ```
       *
       * ```javascript
       * formLayout.responsiveSteps = [
       *   {minWidth: 0, columns: 1},
       *   {minWidth: '40em', columns: 2}
       * ];
       * // Sets two responsive steps:
       * // 1. When the layout width is < 40em, one column, labels aside.
       * // 2. Width >= 40em, two columns, labels aside.
       * ```
       *
       * ```javascript
       * formLayout.responsiveSteps = [
       *   {minWidth: 0, columns: 1, labelsPosition: 'top'},
       *   {minWidth: '20em', columns: 1},
       *   {minWidth: '40em', columns: 2}
       * ];
       * // Default value. Three responsive steps:
       * // 1. Width < 20em, one column, labels on top.
       * // 2. 20em <= width < 40em, one column, labels aside.
       * // 3. Width >= 40em, two columns, labels aside.
       * ```
       *
       * @type {!Array<!FormLayoutResponsiveStep>}
       */
      responsiveSteps: {
        type: Array,
        value() {
          return [
            { minWidth: 0, columns: 1, labelsPosition: "top" },
            { minWidth: "20em", columns: 1 },
            { minWidth: "40em", columns: 2 }
          ];
        },
        observer: "__responsiveStepsChanged",
        sync: true
      },
      /**
       * When set to `true`, the component automatically creates and adjusts columns based on
       * the container's width. Columns have a fixed width defined by `columnWidth` and their
       * number increases up to the limit set by `maxColumns`. The component dynamically adjusts
       * the number of columns as the container size changes. When this mode is enabled,
       * `responsiveSteps` are ignored.
       *
       * By default, each field is placed on a new row. To organize fields into rows, there are
       * two options:
       *
       * 1. Use `<vaadin-form-row>` to explicitly group fields into rows.
       *
       * 2. Enable the `autoRows` property to automatically arrange fields in available columns,
       *    wrapping to a new row when necessary. `<br>` elements can be used to force a new row.
       *
       * The auto-responsive mode is disabled by default. To enable it for an individual instance,
       * use this property. Alternatively, if you want it to be enabled for all instances by default,
       * enable the `defaultAutoResponsiveFormLayout` feature flag before `<vaadin-form-layout>`
       * elements are added to the DOM:
       *
       * ```js
       * window.Vaadin.featureFlags.defaultAutoResponsiveFormLayout = true;
       * ```
       *
       * @attr {boolean} auto-responsive
       */
      autoResponsive: {
        type: Boolean,
        sync: true,
        value: () => {
          if (window.Vaadin && window.Vaadin.featureFlags && window.Vaadin.featureFlags.defaultAutoResponsiveFormLayout) {
            return true;
          }
          return false;
        },
        reflectToAttribute: true
      },
      /**
       * When `autoResponsive` is enabled, defines the width of each column.
       * The value must be defined in CSS length units, e.g. `100px`.
       *
       * If the column width isn't explicitly set, it defaults to `12em`
       * or `--vaadin-field-default-width` if that CSS property is defined.
       *
       * @attr {string} column-width
       */
      columnWidth: {
        type: String,
        sync: true
      },
      /**
       * When `autoResponsive` is enabled, defines the maximum number of columns
       * that the layout can create. The layout will create columns up to this
       * limit based on the available container width.
       *
       * The default value is `10`.
       *
       * @attr {number} max-columns
       */
      maxColumns: {
        type: Number,
        sync: true,
        value: 10
      },
      /**
       * When `autoResponsive` is enabled, defines the minimum number of columns
       * that the layout can create. The layout will create columns at least up
       * to this limit.
       *
       * The default value is `1`.
       *
       * @attr {number} min-columns
       */
      minColumns: {
        type: Number,
        sync: true,
        value: 1
      },
      /**
       * When enabled with `autoResponsive`, distributes fields across columns
       * by placing each field in the next available column and wrapping to
       * the next row when the current row is full. `<br>` elements can be
       * used to force a new row.
       *
       * The default value is `false`.
       *
       * @attr {boolean} auto-rows
       */
      autoRows: {
        type: Boolean,
        sync: true,
        value: false,
        reflectToAttribute: true
      },
      /**
       * When enabled with `autoResponsive`, `<vaadin-form-item>` prefers positioning
       * labels beside the fields. If the layout is too narrow to fit a single column
       * with a side label, the component will automatically switch labels to their
       * default position above the fields.
       *
       * The default value is `false`.
       *
       * To customize the label width and the gap between the label and the field,
       * use the following CSS properties:
       *
       * - `--vaadin-form-layout-label-width`
       * - `--vaadin-form-layout-label-spacing`
       *
       * @attr {boolean} labels-aside
       */
      labelsAside: {
        type: Boolean,
        sync: true,
        value: false,
        reflectToAttribute: true
      },
      /**
       * When `autoResponsive` is enabled, specifies whether the columns should expand
       * in width to evenly fill any remaining space after all columns have been created.
       *
       * The default value is `false`.
       *
       * @attr {boolean} expand-columns
       */
      expandColumns: {
        type: Boolean,
        sync: true,
        value: false,
        reflectToAttribute: true
      },
      /**
       * When `autoResponsive` is enabled, specifies whether fields should stretch
       * to take up all available space within columns. This setting also applies
       * to fields inside `<vaadin-form-item>` elements.
       *
       * The default value is `false`.
       *
       * @attr {boolean} expand-fields
       */
      expandFields: {
        type: Boolean,
        sync: true,
        value: false,
        reflectToAttribute: true
      }
    };
  }
  static get observers() {
    return [
      "__autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, minColumns, autoRows, labelsAside, expandColumns, expandFields)",
      "__autoResponsiveChanged(autoResponsive)"
    ];
  }
  constructor() {
    super();
    this.__currentLayout;
    this.__autoResponsiveLayout = new AutoResponsiveLayout(this);
    this.__responsiveStepsLayout = new ResponsiveStepsLayout(this);
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this.__currentLayout.connect();
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    this.__currentLayout.disconnect();
  }
  /** @protected */
  get slotStyles() {
    return [`${formLayoutSlotStyles}`.replace("vaadin-form-layout", this.localName)];
  }
  /** @protected */
  _updateLayout() {
    this.__currentLayout.updateLayout();
  }
  /** @private */
  __responsiveStepsChanged(responsiveSteps, oldResponsiveSteps) {
    try {
      this.__responsiveStepsLayout.setProps({ responsiveSteps });
    } catch (e) {
      if (oldResponsiveSteps && oldResponsiveSteps !== responsiveSteps) {
        console.warn(`${e.message} Using previously set 'responsiveSteps' instead.`);
        this.responsiveSteps = oldResponsiveSteps;
      } else {
        console.warn(`${e.message} Using default 'responsiveSteps' instead.`);
        this.responsiveSteps = [
          { minWidth: 0, columns: 1, labelsPosition: "top" },
          { minWidth: "20em", columns: 1 },
          { minWidth: "40em", columns: 2 }
        ];
      }
    }
  }
  /** @private */
  // eslint-disable-next-line @typescript-eslint/max-params
  __autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, minColumns, autoRows, labelsAside, expandColumns, expandFields) {
    this.__autoResponsiveLayout.setProps({
      columnWidth,
      maxColumns,
      minColumns,
      autoRows,
      labelsAside,
      expandColumns,
      expandFields
    });
  }
  /** @private */
  __autoResponsiveChanged(autoResponsive) {
    if (this.__currentLayout) {
      this.__currentLayout.disconnect();
    }
    if (autoResponsive) {
      this.__currentLayout = this.__autoResponsiveLayout;
    } else {
      this.__currentLayout = this.__responsiveStepsLayout;
    }
    this.__currentLayout.connect();
  }
};
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class FormLayout extends FormLayoutMixin(ThemableMixin(ElementMixin(PolylitMixin(LitElement)))) {
  static get is() {
    return "vaadin-form-layout";
  }
  static get styles() {
    return formLayoutStyles;
  }
  /** @protected */
  render() {
    return html`
      <div id="layout">
        <slot id="slot"></slot>
      </div>
    `;
  }
}
defineCustomElement(FormLayout);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class CrudForm extends IncludedMixin(FormLayout) {
  static get is() {
    return "vaadin-crud-form";
  }
  static get properties() {
    return {
      /**
       * The item being edited.
       * @type {unknown}
       */
      item: {
        type: Object,
        sync: true
      }
    };
  }
  static get observers() {
    return ["__onItemChange(item)"];
  }
  /**
   * Auto-generate form fields based on the JSON structure of the object provided.
   *
   * If not called, the method will be executed the first time an item is assigned.
   * @param {unknown} object
   * @protected
   */
  _configure(object) {
    this.innerHTML = "";
    this._fields = [];
    this.__createFields(this, object);
    this._updateLayout();
  }
  /** @private */
  __onItemChange(item) {
    if (!this._fields) {
      this._configure(item);
    }
  }
  /** @private */
  __createField(parent, path) {
    return createField(this, parent, path);
  }
  /** @private */
  __createFields(parent, object, path) {
    return createFields(this, parent, object, path);
  }
}
defineCustomElement(CrudForm);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const crudStyles = css$h`
  :host {
    --vaadin-grid-border-width: 0px;
    --vaadin-grid-border-radius: var(--vaadin-crud-border-radius, var(--vaadin-radius-l));
    --vaadin-crud-editor-max-height: 40%;
    --vaadin-crud-editor-max-width: 40%;
    border: var(--vaadin-crud-border-width, 1px) solid
      var(--vaadin-crud-border-color, var(--vaadin-border-color-secondary));
    border-radius: var(--vaadin-crud-border-radius, var(--vaadin-radius-m));
    height: 400px;
    width: 100%;
    background: var(--vaadin-crud-background, var(--vaadin-background-color));
  }

  :host,
  #main {
    align-self: stretch;
    display: flex;
    flex-direction: column;
    position: relative;
  }

  #main {
    flex: 1 1 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
  }

  ::slotted(vaadin-crud-grid) {
    border-end-start-radius: 0;
    border-end-end-radius: 0;
  }

  :host([hidden]),
  [hidden] {
    display: none !important;
  }

  #container {
    display: flex;
    height: 100%;
  }

  :host([editor-position='bottom']) #container {
    flex-direction: column;
  }

  :host([editor-position='aside'][editor-opened]) #main {
    border-inline-end: var(--vaadin-crud-border-width, 1px) solid
      var(--vaadin-crud-border-color, var(--vaadin-border-color-secondary));
  }

  :host([editor-position='aside'][editor-opened]) ::slotted(vaadin-crud-grid) {
    border-start-end-radius: 0;
    border-end-end-radius: 0;
  }

  :host([editor-position='aside'][editor-opened]) :is(#container, [part='editor']) {
    border-start-end-radius: inherit;
    border-end-end-radius: inherit;
  }

  :host([editor-position='bottom'][editor-opened]) #main {
    border-bottom: var(--vaadin-crud-border-width, 1px) solid
      var(--vaadin-crud-border-color, var(--vaadin-border-color-secondary));
  }

  :host([editor-position='bottom'][editor-opened]) :is(#container, [part='editor']) {
    border-end-start-radius: inherit;
    border-end-end-radius: inherit;
  }

  [part='toolbar'] {
    align-items: baseline;
    background: var(--vaadin-crud-toolbar-background, transparent);
    border-top: var(--vaadin-crud-border-width, 1px) solid
      var(--vaadin-crud-border-color, var(--vaadin-border-color-secondary));
    display: flex;
    flex-shrink: 0;
    justify-content: flex-end;
    padding: var(--vaadin-crud-toolbar-padding, var(--vaadin-dialog-padding, var(--vaadin-padding-l)));
  }

  :host([no-toolbar]) [part='toolbar'] {
    display: none;
  }

  [part='editor'] {
    display: flex;
    flex-direction: column;
    height: 100%;
    z-index: 1;
  }

  [part='editor']:focus-visible {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }

  :host(:not([editor-position=''])[editor-opened]:not([fullscreen])) [part='editor'] {
    flex: 1 0 100%;
  }

  :host([editor-position='bottom'][editor-opened]:not([fullscreen])) [part='editor'] {
    max-height: var(--vaadin-crud-editor-max-height);
  }

  :host([editor-position='aside'][editor-opened]:not([fullscreen])) [part='editor'] {
    max-width: var(--vaadin-crud-editor-max-width);
    min-width: 300px;
  }

  [part='scroller'] {
    display: flex;
    flex: auto;
    flex-direction: column;
    overflow: auto;
  }

  [part='header'] {
    color: var(--vaadin-crud-header-color, var(--vaadin-dialog-title-color, var(--vaadin-text-color)));
    font-size: var(--vaadin-crud-header-font-size, var(--vaadin-dialog-title-font-size, 1em));
    font-weight: var(--vaadin-crud-header-font-weight, var(--vaadin-dialog-title-font-weight, 600));
    line-height: var(--vaadin-crud-header-line-height, var(--vaadin-dialog-title-line-height, inherit));
    padding: var(--vaadin-crud-header-padding, var(--vaadin-dialog-padding, var(--vaadin-padding-l)));
  }

  ::slotted([slot='header']) {
    color: inherit !important;
    display: contents;
    font: inherit !important;
    overflow-wrap: anywhere;
  }

  ::slotted([slot='form']) {
    padding: var(--vaadin-crud-form-padding, var(--vaadin-dialog-padding, var(--vaadin-padding-l)));
    padding-top: 0;
  }

  [part='footer'] {
    background: var(--vaadin-crud-footer-background, transparent);
    border-top: var(--vaadin-crud-border-width, 1px) solid
      var(--vaadin-crud-border-color, var(--vaadin-border-color-secondary));
    display: flex;
    flex: none;
    gap: var(--vaadin-crud-footer-gap, var(--vaadin-gap-s));
    padding: var(--vaadin-crud-footer-padding, var(--vaadin-dialog-padding, var(--vaadin-padding-l)));
  }

  ::slotted([slot='delete-button']) {
    margin-inline-start: auto;
  }

  :host([theme~='no-border']) {
    border: 0;
    border-radius: 0;
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class ButtonSlotController extends SlotController {
  constructor(host, type, theme2, noDefaultNode) {
    super(host, `${type}-button`, noDefaultNode ? null : "vaadin-button");
    this.type = type;
    this.theme = theme2;
  }
  /**
   * Override method inherited from `SlotController`
   * to mark custom slotted button as the default.
   *
   * @param {Node} node
   * @protected
   * @override
   */
  initNode(node) {
    if (!node) {
      return;
    }
    if (node._isDefault) {
      this.defaultNode = node;
    }
    if (node === this.defaultNode && this.theme && !node.hasAttribute("theme")) {
      node.setAttribute("theme", this.theme);
    }
    const { host, type } = this;
    const property = `_${type}Button`;
    const listener = `__${type}`;
    if (host[property] && host[property] !== node) {
      host[property].remove();
    }
    node.addEventListener("click", host[listener]);
    host[property] = node;
  }
}
class FormSlotController extends SlotController {
  constructor(host) {
    super(host, "form", "vaadin-crud-form");
  }
  /**
   * Override method inherited from `SlotController`
   * to move slotted form to the overlay if needed.
   *
   * @param {Node} node
   * @protected
   * @override
   */
  initNode(node) {
    this.host._form = node;
    if (this.host.editorOpened) {
      this.host.__ensureChildren();
    }
  }
}
class GridSlotController extends SlotController {
  constructor(host) {
    super(host, "grid", "vaadin-crud-grid");
  }
  /**
   * Override method inherited from `SlotController`
   * to initialize `active-item-changed` listener.
   *
   * @param {Node} node
   * @protected
   * @override
   */
  initNode(node) {
    const { host } = this;
    queueMicrotask(() => {
      host.__editOnClickChanged(false, host._grid);
      host._grid = node;
      host.__editOnClickChanged(host.editOnClick, host._grid);
    });
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const DEFAULT_I18N$9 = {
  newItem: "New item",
  editItem: "Edit item",
  saveItem: "Save",
  cancel: "Cancel",
  deleteItem: "Delete...",
  editLabel: "Edit",
  confirm: {
    delete: {
      title: "Delete item",
      content: "Are you sure you want to delete this item? This action cannot be undone.",
      button: {
        confirm: "Delete",
        dismiss: "Cancel"
      }
    },
    cancel: {
      title: "Discard changes",
      content: "There are unsaved changes to this item.",
      button: {
        confirm: "Discard",
        dismiss: "Cancel"
      }
    }
  }
};
const CrudMixin = (superClass) => class extends I18nMixin(DEFAULT_I18N$9, superClass) {
  static get properties() {
    return {
      /**
       * A reference to the grid used for displaying the item list
       * @private
       */
      _grid: {
        type: Object,
        observer: "__gridChanged"
      },
      /**
       * A reference to the editor component which will be teleported to the dialog
       * @private
       */
      _form: {
        type: Object,
        observer: "__formChanged"
      },
      /**
       * A reference to the save button which will be teleported to the dialog
       * @private
       */
      _saveButton: {
        type: Object
      },
      /**
       * A reference to the delete button which will be teleported to the dialog
       * @private
       */
      _deleteButton: {
        type: Object
      },
      /**
       * A reference to the cancel button which will be teleported to the dialog
       * @private
       */
      _cancelButton: {
        type: Object
      },
      /**
       * A reference to the default editor header element created by the CRUD
       * @private
       */
      _defaultHeader: {
        type: Object
      },
      /**
       * A reference to the "New item" button
       * @private
       */
      _newButton: {
        type: Object
      },
      /**
       * An array containing the items which will be stamped to the column template instances.
       */
      items: {
        type: Array,
        notify: true,
        observer: "__itemsChanged",
        sync: true
      },
      /**
       * The item being edited in the dialog.
       */
      editedItem: {
        type: Object,
        observer: "__editedItemChanged",
        notify: true,
        sync: true
      },
      /**
       * Sets how editor will be presented on desktop screen.
       *
       * Accepted values are:
       *   - `` (default) - form will open as overlay
       *   - `bottom` - form will open below the grid
       *   - `aside` - form will open on the grid side (_right_, if lft and _left_ if rtl)
       * @attr {bottom|aside} editor-position
       */
      editorPosition: {
        type: String,
        value: "",
        reflectToAttribute: true,
        observer: "__editorPositionChanged",
        sync: true
      },
      /**
       * Enables user to click on row to edit it.
       * Note: When enabled, auto-generated grid won't show the edit column.
       * @attr {boolean} edit-on-click
       */
      editOnClick: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * Function that provides items lazily. Receives arguments `params`, `callback`
       *
       * `params.page` Requested page index
       * `params.pageSize` Current page size
       * `params.filters` Currently applied filters
       * `params.sortOrders` Currently applied sorting orders
       *
       * `callback(items, size)` Callback function with arguments:
       *   - `items` Current page of items
       *   - `size` Total number of items
       * @type {CrudDataProvider | undefined}
       */
      dataProvider: {
        type: Function,
        observer: "__dataProviderChanged"
      },
      /**
       * Disable filtering when grid is autoconfigured.
       * @attr {boolean} no-filter
       */
      noFilter: {
        type: Boolean
      },
      /**
       * Disable sorting when grid is autoconfigured.
       * @attr {boolean} no-sort
       */
      noSort: {
        type: Boolean
      },
      /**
       * Remove grid headers when it is autoconfigured.
       * @attr {boolean} no-head
       */
      noHead: {
        type: Boolean
      },
      /**
       * A comma-separated list of fields to include in the generated grid and the generated editor.
       *
       * It can be used to explicitly define the field order.
       *
       * When it is defined [`exclude`](#/elements/vaadin-crud#property-exclude) is ignored.
       *
       * Default is undefined meaning that all properties in the object should be mapped to fields.
       */
      include: {
        type: String
      },
      /**
       * A comma-separated list of fields to be excluded from the generated grid and the generated editor.
       *
       * When [`include`](#/elements/vaadin-crud#property-include) is defined, this parameter is ignored.
       *
       * Default is to exclude all private fields (those properties starting with underscore)
       */
      exclude: {
        type: String
      },
      /**
       * Reflects the opened status of the editor.
       */
      editorOpened: {
        type: Boolean,
        reflectToAttribute: true,
        notify: true,
        observer: "__editorOpenedChanged",
        sync: true
      },
      /**
       * Number of items in the data set which is reported by the grid.
       * Typically it reflects the number of filtered items displayed in the grid.
       *
       * Note: As with `<vaadin-grid>`, this property updates automatically only
       * if `items` is used for data.
       */
      size: {
        type: Number,
        readOnly: true,
        notify: true
      },
      /**
       * Controls visibility state of toolbar.
       * When set to false toolbar is hidden and shown when set to true.
       * @attr {boolean} no-toolbar
       */
      noToolbar: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        sync: true
      },
      /** @private */
      __dialogAriaLabel: String,
      /** @private */
      __isDirty: {
        type: Boolean,
        sync: true
      },
      /** @private */
      __isNew: Boolean,
      /**
       * @protected
       */
      _fullscreen: {
        type: Boolean,
        observer: "__fullscreenChanged",
        sync: true
      },
      /**
       * @protected
       */
      _fullscreenMediaQuery: {
        value: "(max-width: 600px), (max-height: 600px)"
      }
    };
  }
  static get observers() {
    return [
      "__headerPropsChanged(_defaultHeader, __isNew, __effectiveI18n)",
      "__formPropsChanged(_form, _theme, include, exclude)",
      "__gridPropsChanged(_grid, _theme, include, exclude, noFilter, noHead, noSort, items)",
      "__i18nChanged(__effectiveI18n, _grid)",
      "__editOnClickChanged(editOnClick, _grid)",
      "__saveButtonPropsChanged(_saveButton, __effectiveI18n, __isDirty)",
      "__cancelButtonPropsChanged(_cancelButton, __effectiveI18n)",
      "__deleteButtonPropsChanged(_deleteButton, __effectiveI18n, __isNew)",
      "__newButtonPropsChanged(_newButton, __effectiveI18n)"
    ];
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure and default values:
   *
   * ```js
   * {
   *   newItem: 'New item',
   *   editItem: 'Edit item',
   *   saveItem: 'Save',
   *   cancel: 'Cancel',
   *   deleteItem: 'Delete...',
   *   editLabel: 'Edit',
   *   confirm: {
   *     delete: {
   *       title: 'Confirm delete',
   *       content: 'Are you sure you want to delete the selected item? This action cannot be undone.',
   *       button: {
   *         confirm: 'Delete',
   *         dismiss: 'Cancel'
   *       }
   *     },
   *     cancel: {
   *       title: 'Unsaved changes',
   *       content: 'There are unsaved modifications to the item.',
   *       button: {
   *         confirm: 'Discard',
   *         dismiss: 'Continue editing'
   *       }
   *     }
   *   }
   * }
   * ```
   * @type {!CrudI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  constructor() {
    super();
    this.__cancel = this.__cancel.bind(this);
    this.__delete = this.__delete.bind(this);
    this.__save = this.__save.bind(this);
    this.__new = this.__new.bind(this);
    this.__onFormChange = this.__onFormChange.bind(this);
    this.__onGridEdit = this.__onGridEdit.bind(this);
    this.__onGridSizeChanged = this.__onGridSizeChanged.bind(this);
    this.__onGridActiveItemChanged = this.__onGridActiveItemChanged.bind(this);
    this.__focusRestorationController = new FocusRestorationController();
  }
  /** @protected */
  get _headerNode() {
    return this._headerController && this._headerController.node;
  }
  /**
   * A reference to all fields inside the [`_form`](#/elements/vaadin-crud#property-_form) element
   * @return {!Array<!HTMLElement>}
   * @protected
   */
  get _fields() {
    if (!this.__fields || !this.__fields.length) {
      this.__fields = Array.from(this._form.querySelectorAll("*")).filter((e) => e.validate || e.checkValidity);
    }
    return this.__fields;
  }
  /** @private */
  get _editor() {
    return this.shadowRoot.querySelector("#editor");
  }
  /** @private */
  get _scroller() {
    return this.shadowRoot.querySelector("#scroller");
  }
  /** @private */
  get _dialogMode() {
    return this.editorPosition === "" || this._fullscreen;
  }
  /** @protected */
  ready() {
    super.ready();
    this._gridController = new GridSlotController(this);
    this.addController(this._gridController);
    this._newButtonController = new ButtonSlotController(this, "new", null, this._noDefaultButtons);
    this.addController(this._newButtonController);
    this._headerController = new SlotController(this, "header", "h3", {
      initializer: (node) => {
        this._defaultHeader = node;
      }
    });
    this.addController(this._headerController);
    this.addController(new FormSlotController(this));
    this._saveButtonController = new ButtonSlotController(this, "save", "primary", this._noDefaultButtons);
    this._cancelButtonController = new ButtonSlotController(this, "cancel", "tertiary", this._noDefaultButtons);
    this._deleteButtonController = new ButtonSlotController(this, "delete", "tertiary error", this._noDefaultButtons);
    this.addController(this._saveButtonController);
    this.addController(this._cancelButtonController);
    this.addController(this._deleteButtonController);
    this.addController(
      new MediaQueryController(this._fullscreenMediaQuery, (matches) => {
        this._fullscreen = matches;
      })
    );
    this.addController(this.__focusRestorationController);
    this._confirmCancelDialog = this.querySelector('vaadin-confirm-dialog[slot="confirm-cancel"]');
    this._confirmDeleteDialog = this.querySelector('vaadin-confirm-dialog[slot="confirm-delete"]');
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("_grid") || props.has("_newButton") || props.has("editorOpened") || props.has("editorPosition") || props.has("_fullscreen")) {
      const hide = this.editorOpened && this._dialogMode;
      this.__hideElement(this._grid, hide);
      this.__hideElement(this._newButton, hide);
    }
  }
  /**
   * @param {boolean} isDirty
   * @private
   */
  __isSaveBtnDisabled(isDirty) {
    return !isDirty;
  }
  /**
   * @param {HTMLElement | undefined} headerNode
   * @param {boolean} isNew
   * @param {CrudI18n} effectiveI18n
   * @private
   */
  __headerPropsChanged(headerNode, isNew, effectiveI18n) {
    if (headerNode) {
      headerNode.textContent = isNew ? effectiveI18n.newItem : effectiveI18n.editItem;
    }
  }
  /**
   * @param {CrudI18n} effectiveI18n
   * @param {CrudGrid | Grid} grid
   * @private
   */
  __i18nChanged(effectiveI18n, grid) {
    if (!grid) {
      return;
    }
    queueMicrotask(() => {
      Array.from(grid.querySelectorAll("vaadin-crud-edit-column")).forEach((column2) => {
        column2.ariaLabel = effectiveI18n.editLabel;
      });
    });
  }
  /** @private */
  __editorPositionChanged(editorPosition) {
    if (isValidEditorPosition(editorPosition)) {
      return;
    }
    this.editorPosition = "";
  }
  /** @private */
  __editorOpenedChanged(opened, oldOpened) {
    if (!opened && oldOpened) {
      this.__closeEditor();
    } else {
      this.__formChanged(this._form);
    }
    if (opened) {
      if (this._editor) {
        this._editor.focus();
      }
      setTimeout(() => {
        this.__dialogAriaLabel = this._headerNode.textContent.trim();
      });
    }
    this.__toggleToolbar();
    if (this._scroller) {
      this._scroller.scrollTop = 0;
    }
  }
  /** @private */
  __fullscreenChanged(fullscreen, oldFullscreen) {
    if (fullscreen || oldFullscreen) {
      this.__toggleToolbar();
      this.toggleAttribute("fullscreen", fullscreen);
    }
  }
  /** @private */
  __toggleToolbar() {
    if (this.editorPosition === "bottom" && !this._fullscreen) {
      this.$.toolbar.style.display = this.editorOpened ? "none" : "";
    }
  }
  /** @private */
  __onGridEdit(event) {
    event.stopPropagation();
    this.__confirmBeforeChangingEditedItem(event.detail.item);
  }
  /** @private */
  __onFormChange() {
    this.__isDirty = true;
  }
  /** @private */
  __onGridSizeChanged() {
    this._setSize(this._grid.size);
  }
  /**
   * @param {CrudGrid | Grid} grid
   * @param {CrudGrid | Grid | undefined} oldGrid
   * @private
   */
  __gridChanged(grid, oldGrid) {
    if (oldGrid) {
      oldGrid.removeEventListener("edit", this.__onGridEdit);
      oldGrid.removeEventListener("size-changed", this.__onGridSizeChanged);
    }
    if (this.dataProvider) {
      this.__dataProviderChanged(this.dataProvider);
    }
    if (this.editedItem) {
      this.__editedItemChanged(this.editedItem);
    }
    grid.addEventListener("edit", this.__onGridEdit);
    grid.addEventListener("size-changed", this.__onGridSizeChanged);
    this.__onGridSizeChanged();
  }
  /**
   * @param {HTMLElement | undefined | null} form
   * @param {HTMLElement | undefined | null} oldForm
   * @private
   */
  __formChanged(form, oldForm) {
    if (oldForm) {
      oldForm.removeEventListener("change", this.__onFormChange);
      oldForm.removeEventListener("input", this.__onFormChange);
    }
    if (!form) {
      return;
    }
    if (this.items) {
      this.__itemsChanged(this.items);
    }
    if (this.editedItem) {
      this.__editedItemChanged(this.editedItem);
    }
    form.addEventListener("change", this.__onFormChange);
    form.addEventListener("input", this.__onFormChange);
  }
  /**
   * @param {HTMLElement | undefined} form
   * @param {string} theme
   * @param {string | string[] | undefined} include
   * @param {string | RegExp} exclude
   * @private
   */
  __formPropsChanged(form, theme2, include, exclude) {
    if (form) {
      form.include = include;
      form.exclude = exclude;
      if (theme2) {
        form.setAttribute("theme", theme2);
      } else {
        form.removeAttribute("theme");
      }
    }
  }
  /**
   * @param {HTMLElement | undefined} grid
   * @param {string} theme
   * @param {string | string[] | undefined} include
   * @param {string | RegExp} exclude
   * @param {boolean} noFilter
   * @param {boolean} noHead
   * @param {boolean} noSort
   * @param {Array<unknown> | undefined} items
   * @private
   */
  // eslint-disable-next-line @typescript-eslint/max-params
  __gridPropsChanged(grid, theme2, include, exclude, noFilter, noHead, noSort, items) {
    if (!grid) {
      return;
    }
    if (grid === this._gridController.defaultNode) {
      grid.noFilter = noFilter;
      grid.noHead = noHead;
      grid.noSort = noSort;
      grid.include = include;
      grid.exclude = exclude;
      if (theme2) {
        grid.setAttribute("theme", theme2);
      } else {
        grid.removeAttribute("theme");
      }
    }
    grid.items = items;
  }
  /**
   * @param {HTMLElement | undefined} saveButton
   * @param {CrudI18n} effectiveI18n
   * @param {boolean} isDirty
   * @private
   */
  __saveButtonPropsChanged(saveButton, effectiveI18n, isDirty) {
    if (saveButton) {
      saveButton.toggleAttribute("disabled", this.__isSaveBtnDisabled(isDirty));
      if (saveButton === this._saveButtonController.defaultNode) {
        saveButton.textContent = effectiveI18n.saveItem;
      }
    }
  }
  /**
   * @param {HTMLElement | undefined} deleteButton
   * @param {CrudI18n} effectiveI18n
   * @param {boolean} isNew
   * @private
   */
  __deleteButtonPropsChanged(deleteButton, effectiveI18n, isNew) {
    if (deleteButton) {
      deleteButton.toggleAttribute("hidden", isNew);
      if (deleteButton === this._deleteButtonController.defaultNode) {
        deleteButton.textContent = effectiveI18n.deleteItem;
      }
    }
  }
  /**
   * @param {HTMLElement | undefined} cancelButton
   * @param {CrudI18n} effectiveI18n
   * @private
   */
  __cancelButtonPropsChanged(cancelButton, effectiveI18n) {
    if (cancelButton && cancelButton === this._cancelButtonController.defaultNode) {
      cancelButton.textContent = effectiveI18n.cancel;
    }
  }
  /**
   * @param {HTMLElement | undefined} newButton
   * @param {CrudI18n} effectiveI18n
   * @private
   */
  __newButtonPropsChanged(newButton, effectiveI18n) {
    if (newButton && newButton === this._newButtonController.defaultNode) {
      newButton.textContent = effectiveI18n.newItem;
    }
  }
  /** @private */
  __dataProviderChanged(dataProvider) {
    if (this._grid) {
      this._grid.dataProvider = this.__createDataProviderProxy(dataProvider);
    }
  }
  /** @private */
  __editOnClickChanged(editOnClick, grid) {
    if (!grid) {
      return;
    }
    grid.hideEditColumn = editOnClick;
    if (editOnClick) {
      grid.addEventListener("active-item-changed", this.__onGridActiveItemChanged);
    } else {
      grid.removeEventListener("active-item-changed", this.__onGridActiveItemChanged);
    }
  }
  /** @private */
  __onGridActiveItemChanged(event) {
    const item = event.detail.value;
    if (this.editorOpened && this.__isDirty) {
      this.__confirmBeforeChangingEditedItem(item);
      return;
    }
    if (item) {
      this.__edit(item);
    } else if (!this.__keepOpened) {
      this.__closeEditor();
    }
  }
  /** @private */
  __confirmBeforeChangingEditedItem(item, keepOpened) {
    if (this.editorOpened && // Editor opened
    this.__isDirty && // Form change has been made
    this.editedItem !== item) {
      this._confirmCancelDialog.opened = true;
      this.addEventListener(
        "cancel",
        (event) => {
          event.preventDefault();
          if (item || keepOpened) {
            this.__edit(item);
            this.__clearItemAndKeepEditorOpened(item, keepOpened);
          } else {
            this.__closeEditor();
          }
        },
        { once: true }
      );
    } else {
      this.__edit(item);
      this.__clearItemAndKeepEditorOpened(item, keepOpened);
    }
  }
  /** @private */
  __clearItemAndKeepEditorOpened(item, keepOpened) {
    if (!item) {
      setTimeout(() => {
        this.__keepOpened = keepOpened;
        this.editedItem = this._grid.activeItem = void 0;
      });
    }
  }
  /** @private */
  __createDataProviderProxy(dataProvider) {
    return (params2, callback) => {
      const callbackProxy = (chunk, size) => {
        if (chunk && chunk[0]) {
          this.__model = chunk[0];
        }
        callback(chunk, size);
      };
      dataProvider(params2, callbackProxy);
    };
  }
  /** @private */
  __itemsChanged(items) {
    if (this.items && this.items[0]) {
      this.__model = items[0];
    }
  }
  /** @private */
  __editedItemChanged(item) {
    if (!this._form) {
      return;
    }
    if (item) {
      if (!this._fields.length && this._form._configure) {
        if (this.__model) {
          this._form._configure(this.__model);
        } else {
          console.warn(
            "<vaadin-crud> Unable to autoconfigure form because the data structure is unknown. Either specify `include` or ensure at least one item is available beforehand."
          );
        }
      }
      this._form.item = item;
      this._fields.forEach((e) => {
        const path = e.path || e.getAttribute("path");
        if (path) {
          e.value = getProperty(path, item);
        }
      });
      this.__isNew = !!(this.__isNew || this.items && this.items.indexOf(item) < 0);
      this.editorOpened = true;
    }
  }
  /** @private */
  __validate() {
    return this._fields.every((e) => (e.validate || e.checkValidity).call(e));
  }
  /** @private */
  __setHighlightedItem(item) {
    if (this._grid === this._gridController.defaultNode) {
      this._grid.selectedItems = item ? [item] : [];
    }
  }
  /** @private */
  __closeEditor() {
    this.editorOpened = false;
    this.__isDirty = false;
    this.__setHighlightedItem(null);
    setTimeout(() => this.__clearItemAndKeepEditorOpened(null, false));
  }
  /** @private */
  __new() {
    this.__confirmBeforeChangingEditedItem(null, true);
  }
  /** @private */
  __edit(item) {
    if (this.editedItem === item) {
      return;
    }
    this.__setHighlightedItem(item);
    this.__openEditor(item);
  }
  /** @private */
  __fireEvent(type, item) {
    const event = new CustomEvent(type, { detail: { item }, cancelable: true });
    this.dispatchEvent(event);
    return event.defaultPrevented === false;
  }
  /** @private */
  __openEditor(item) {
    this.__focusRestorationController.saveFocus();
    this.__isDirty = false;
    this.__isNew = !item;
    const result = this.__fireEvent(this.__isNew ? "new" : "edit", item);
    if (result) {
      this.editedItem = item || {};
    } else {
      this.editorOpened = true;
    }
  }
  /** @private */
  __restoreFocusOnDelete() {
    if (this._grid._flatSize === 1) {
      this._newButton.focus();
    } else {
      this._grid._focusFirstVisibleRow();
    }
  }
  /** @private */
  __restoreFocusOnSaveOrCancel() {
    const focusNode = this.__focusRestorationController.focusNode;
    const row = this._grid._getRowContainingNode(focusNode);
    if (!row) {
      this.__focusRestorationController.restoreFocus();
      return;
    }
    if (this._grid._isItemAssignedToRow(this.editedItem, row) && this._grid._isInViewport(row)) {
      this.__focusRestorationController.restoreFocus();
    } else {
      this._grid._focusFirstVisibleRow();
    }
  }
  /** @private */
  __save() {
    if (!this.__validate()) {
      return;
    }
    const item = { ...this.editedItem };
    this._fields.forEach((e) => {
      const path = e.path || e.getAttribute("path");
      if (path) {
        setProperty(path, e.value, item);
      }
    });
    const result = this.__fireEvent("save", item);
    if (result) {
      if (this.__isNew && !this.dataProvider) {
        if (!this.items) {
          this.items = [item];
        } else {
          this.items.push(item);
        }
      } else {
        if (!this.editedItem) {
          this.editedItem = {};
        }
        Object.assign(this.editedItem, item);
      }
      this.__restoreFocusOnSaveOrCancel();
      this._grid.clearCache();
      this.__closeEditor();
    }
  }
  /** @private */
  __cancel() {
    if (this.__isDirty) {
      this._confirmCancelDialog.opened = true;
    } else {
      this.__confirmCancel();
    }
  }
  /** @private */
  __confirmCancel() {
    const result = this.__fireEvent("cancel", this.editedItem);
    if (result) {
      this.__restoreFocusOnSaveOrCancel();
      this.__closeEditor();
    }
  }
  /** @private */
  __delete() {
    this._confirmDeleteDialog.opened = true;
  }
  /** @private */
  __confirmDelete() {
    const result = this.__fireEvent("delete", this.editedItem);
    if (result) {
      if (this.items && this.items.indexOf(this.editedItem) >= 0) {
        this.items.splice(this.items.indexOf(this.editedItem), 1);
      }
      this.__restoreFocusOnDelete();
      this._grid.clearCache();
      this.__closeEditor();
    }
  }
  /** @private */
  __hideElement(element, value) {
    if (!element) return;
    if (value) {
      element.setAttribute("aria-hidden", "true");
    } else {
      element.removeAttribute("aria-hidden");
    }
  }
  /**
   * Fired when user wants to edit an existing item. If the default is prevented, then
   * a new item is not assigned to the form, giving that responsibility to the app, though
   * dialog is always opened.
   *
   * @event edit
   * @param {Object} detail.item the item to edit
   */
  /**
   * Fired when user wants to create a new item.
   *
   * @event new
   */
  /**
   * Fired when user wants to delete item. If the default is prevented, then
   * no action is performed, items array is not modified nor dialog closed
   *
   * @event delete
   * @param {Object} detail.item the item to delete
   */
  /**
   * Fired when user discards edition. If the default is prevented, then
   * no action is performed, user is responsible to close dialog and reset
   * item and grid.
   *
   * @event cancel
   * @param {Object} detail.item the item to delete
   */
  /**
   * Fired when user wants to save a new or an existing item. If the default is prevented, then
   * no action is performed, items array is not modified nor dialog closed
   *
   * @event save
   * @param {Object} detail.item the item to save
   * @param {Object} detail.new whether the item is a new one
   */
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class Crud extends CrudMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-crud";
  }
  static get cvdlName() {
    return "vaadin-crud";
  }
  static get styles() {
    return crudStyles;
  }
  /** @protected */
  render() {
    return html`
      <div id="container">
        <div id="main">
          <slot name="grid"></slot>

          <div id="toolbar" part="toolbar">
            <slot name="toolbar"></slot>
            <slot name="new-button"></slot>
          </div>
        </div>

        ${!this._dialogMode ? html`
              <div
                part="editor"
                id="editor"
                role="group"
                aria-labelledby="header"
                tabindex="0"
                ?hidden="${!this.editorOpened}"
              >
                <div part="scroller" id="scroller">
                  <div part="header" id="header">
                    <slot name="header"></slot>
                  </div>
                  <slot name="form"></slot>
                </div>

                <div part="footer" role="toolbar">
                  <slot name="save-button"></slot>
                  <slot name="cancel-button"></slot>
                  <slot name="delete-button"></slot>
                </div>
              </div>
            ` : nothing}
      </div>

      ${this._dialogMode ? html`
            <vaadin-crud-dialog
              id="dialog"
              aria-label="${ifDefined(this.__dialogAriaLabel)}"
              theme="${ifDefined(this._theme)}"
              exportparts="backdrop, overlay, header, content, footer"
              .crudElement="${this}"
              .opened="${this.editorOpened}"
              .fullscreen="${this._fullscreen}"
              .noCloseOnOutsideClick="${this.__isDirty}"
              .noCloseOnEsc="${this.__isDirty}"
              @cancel="${this.__cancel}"
            >
              <slot name="header" slot="header"></slot>
              <slot name="form" slot="form"></slot>
              <slot name="save-button" slot="save-button"></slot>
              <slot name="cancel-button" slot="cancel-button"></slot>
              <slot name="delete-button" slot="delete-button"></slot>
            </vaadin-crud-dialog>
          ` : nothing}

      <slot name="confirm-cancel"></slot>

      <slot name="confirm-delete"></slot>
    `;
  }
  /**
   * Override update to render slotted overlays into light DOM after rendering shadow DOM.
   * @param changedProperties
   * @protected
   */
  update(changedProperties) {
    super.update(changedProperties);
    this.__renderSlottedOverlays();
  }
  /** @private */
  __renderSlottedOverlays() {
    render$1(
      html`
        <vaadin-confirm-dialog
          theme="${ifDefined(this._theme)}"
          slot="confirm-cancel"
          @confirm="${this.__confirmCancel}"
          cancel-button-visible
          .confirmText="${this.__effectiveI18n.confirm.cancel.button.confirm}"
          .cancelText="${this.__effectiveI18n.confirm.cancel.button.dismiss}"
          .header="${this.__effectiveI18n.confirm.cancel.title}"
          .message="${this.__effectiveI18n.confirm.cancel.content}"
          confirm-theme="primary"
        ></vaadin-confirm-dialog>

        <vaadin-confirm-dialog
          theme="${ifDefined(this._theme)}"
          slot="confirm-delete"
          @confirm="${this.__confirmDelete}"
          cancel-button-visible
          .confirmText="${this.__effectiveI18n.confirm.delete.button.confirm}"
          .cancelText="${this.__effectiveI18n.confirm.delete.button.dismiss}"
          .header="${this.__effectiveI18n.confirm.delete.title}"
          .message="${this.__effectiveI18n.confirm.delete.content}"
          confirm-theme="primary error"
        ></vaadin-confirm-dialog>
      `,
      this,
      { host: this }
    );
  }
}
defineCustomElement(Crud);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const GridSelectionColumnBaseMixin = (superClass) => class GridSelectionColumnBaseMixin extends superClass {
  static get properties() {
    return {
      /**
       * Width of the cells for this column.
       */
      width: {
        type: String,
        value: "58px",
        sync: true
      },
      /**
       * Override `autoWidth` to enable auto-width
       */
      autoWidth: {
        type: Boolean,
        value: true
      },
      /**
       * Flex grow ratio for the cell widths. When set to 0, cell width is fixed.
       * @attr {number} flex-grow
       */
      flexGrow: {
        type: Number,
        value: 0,
        sync: true
      },
      /**
       * When true, all the items are selected.
       * @attr {boolean} select-all
       */
      selectAll: {
        type: Boolean,
        value: false,
        notify: true,
        sync: true
      },
      /**
       * When true, the active item gets automatically selected.
       * @attr {boolean} auto-select
       */
      autoSelect: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * When true, rows can be selected by dragging over the selection column.
       * @attr {boolean} drag-select
       */
      dragSelect: {
        type: Boolean,
        value: false,
        sync: true
      },
      /** @protected */
      _indeterminate: {
        type: Boolean,
        sync: true
      },
      /** @protected */
      _selectAllHidden: Boolean,
      /**
       * Indicates whether the shift key is currently pressed.
       *
       * @protected
       */
      _shiftKeyDown: {
        type: Boolean,
        value: false
      }
    };
  }
  static get observers() {
    return [
      "_onHeaderRendererOrBindingChanged(_headerRenderer, _headerCell, path, header, selectAll, _indeterminate, _selectAllHidden)"
    ];
  }
  constructor() {
    super();
    this.__onCellTrack = this.__onCellTrack.bind(this);
    this.__onCellClick = this.__onCellClick.bind(this);
    this.__onCellMouseDown = this.__onCellMouseDown.bind(this);
    this.__onGridInteraction = this.__onGridInteraction.bind(this);
    this.__onActiveItemChanged = this.__onActiveItemChanged.bind(this);
    this.__onTouchStart = this.__onTouchStart.bind(this);
    this.__onSelectRowCheckboxChange = this.__onSelectRowCheckboxChange.bind(this);
    this.__onSelectAllCheckboxChange = this.__onSelectAllCheckboxChange.bind(this);
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this._grid) {
      this._grid.addEventListener("keyup", this.__onGridInteraction);
      this._grid.addEventListener("keydown", this.__onGridInteraction, { capture: true });
      this._grid.addEventListener("mousedown", this.__onGridInteraction);
      this._grid.addEventListener("active-item-changed", this.__onActiveItemChanged);
      this._grid.addEventListener("touchstart", this.__onTouchStart);
    }
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (this._grid) {
      this._grid.removeEventListener("keyup", this.__onGridInteraction);
      this._grid.removeEventListener("keydown", this.__onGridInteraction, { capture: true });
      this._grid.removeEventListener("mousedown", this.__onGridInteraction);
      this._grid.removeEventListener("active-item-changed", this.__onActiveItemChanged);
      this._grid.removeEventListener("touchstart", this.__onTouchStart);
    }
  }
  /**
   * Renders the Select All checkbox to the header cell.
   *
   * @override
   */
  _defaultHeaderRenderer(root, _column) {
    let checkbox = root.firstElementChild;
    if (!checkbox) {
      checkbox = document.createElement("vaadin-checkbox");
      checkbox.accessibleName = "Select All";
      checkbox.classList.add("vaadin-grid-select-all-checkbox");
      checkbox.addEventListener("change", this.__onSelectAllCheckboxChange);
      root.appendChild(checkbox);
    }
    const checked = this.__isChecked(this.selectAll, this._indeterminate);
    checkbox.checked = checked;
    checkbox.indeterminate = this._indeterminate;
    checkbox.style.visibility = this._selectAllHidden ? "hidden" : "";
  }
  /**
   * Renders the Select Row checkbox to the body cell.
   *
   * @override
   */
  _defaultRenderer(root, _column, { item, selected }) {
    let checkbox = root.firstElementChild;
    if (!checkbox) {
      checkbox = document.createElement("vaadin-checkbox");
      checkbox.accessibleName = "Select Row";
      checkbox.addEventListener("change", this.__onSelectRowCheckboxChange);
      root.appendChild(checkbox);
      addListener(root, "track", this.__onCellTrack);
      setTouchAction(root, "pinch-zoom");
      root.addEventListener("mousedown", this.__onCellMouseDown);
      root.addEventListener("click", this.__onCellClick);
    }
    checkbox.__item = item;
    checkbox.checked = selected;
    const isSelectable = this._grid.__isItemSelectable(item);
    checkbox.readonly = !isSelectable;
    const isHidden = !isSelectable && !selected;
    checkbox.style.visibility = isHidden ? "hidden" : "";
  }
  /**
   * Updates the select all state when the Select All checkbox is switched.
   * The listener handles only user-fired events.
   *
   * @private
   */
  __onSelectAllCheckboxChange(e) {
    if (this._indeterminate || e.currentTarget.checked) {
      this._selectAll();
    } else {
      this._deselectAll();
    }
  }
  /** @private */
  __onGridInteraction(e) {
    this._shiftKeyDown = e.shiftKey;
    if (this.autoSelect) {
      this._grid.$.scroller.toggleAttribute("range-selecting", this._shiftKeyDown);
    }
  }
  /**
   * Selects or deselects the row when the Select Row checkbox is switched.
   * The listener handles only user-fired events.
   *
   * @private
   */
  __onSelectRowCheckboxChange(e) {
    this.__toggleItem(e.currentTarget.__item, e.currentTarget.checked);
  }
  /** @private */
  __onCellTrack(event) {
    if (!this.dragSelect) {
      return;
    }
    this.__dragCurrentY = event.detail.y;
    this.__dragDy = event.detail.dy;
    if (event.detail.state === "start") {
      if (this.__multiTouchActive) {
        return;
      }
      const renderedRows = this._grid._getRenderedRows();
      const dragStartRow = renderedRows.find((row) => row.contains(event.currentTarget.assignedSlot));
      this.__selectOnDrag = !this._grid._isSelected(dragStartRow._item);
      this.__dragStartIndex = dragStartRow.index;
      this.__dragStartItem = dragStartRow._item;
      this.__dragAutoScroller();
    } else if (event.detail.state === "end") {
      if (this.__dragStartItem) {
        this.__toggleItem(this.__dragStartItem, this.__selectOnDrag);
      }
      setTimeout(() => {
        this.__dragStartIndex = void 0;
      });
    }
  }
  /** @private */
  __onCellMouseDown(e) {
    if (this.dragSelect) {
      e.preventDefault();
    }
  }
  /** @private */
  __onTouchStart(e) {
    if (e.touches.length > 1) {
      this.__multiTouchActive = true;
      this.__dragStartIndex = void 0;
      this.__dragStartItem = void 0;
    } else {
      this.__multiTouchActive = false;
    }
  }
  /** @private */
  __onCellClick(e) {
    if (this.__dragStartIndex !== void 0) {
      e.preventDefault();
    }
  }
  /** @private */
  _onCellKeyDown(e) {
    const target = e.composedPath()[0];
    if (e.keyCode !== 32) {
      return;
    }
    if (target === this._headerCell) {
      if (this.selectAll) {
        this._deselectAll();
      } else {
        this._selectAll();
      }
    } else if (this._cells.includes(target) && !this.autoSelect) {
      const checkbox = target._content.firstElementChild;
      this.__toggleItem(checkbox.__item);
    }
  }
  /** @private */
  __onActiveItemChanged(e) {
    const activeItem = e.detail.value;
    if (this.autoSelect) {
      const item = activeItem || this.__previousActiveItem;
      if (item) {
        this.__toggleItem(item);
      }
    }
    this.__previousActiveItem = activeItem;
  }
  /** @private */
  __dragAutoScroller() {
    if (this.__dragStartIndex === void 0) {
      return;
    }
    const renderedRows = this._grid._getRenderedRows();
    const hoveredRow = renderedRows.find((row) => {
      const rowRect = row.getBoundingClientRect();
      return this.__dragCurrentY >= rowRect.top && this.__dragCurrentY <= rowRect.bottom;
    });
    let hoveredIndex = hoveredRow ? hoveredRow.index : void 0;
    const scrollableArea = this.__getScrollableArea();
    if (this.__dragCurrentY < scrollableArea.top) {
      hoveredIndex = this._grid._firstVisibleIndex;
    } else if (this.__dragCurrentY > scrollableArea.bottom) {
      hoveredIndex = this._grid._lastVisibleIndex;
    }
    if (hoveredIndex !== void 0) {
      renderedRows.forEach((row) => {
        if (hoveredIndex > this.__dragStartIndex && row.index >= this.__dragStartIndex && row.index <= hoveredIndex || hoveredIndex < this.__dragStartIndex && row.index <= this.__dragStartIndex && row.index >= hoveredIndex) {
          this.__toggleItem(row._item, this.__selectOnDrag);
          this.__dragStartItem = void 0;
        }
      });
    }
    const scrollTriggerArea = scrollableArea.height * 0.15;
    const maxScrollAmount = 10;
    if (this.__dragDy < 0 && this.__dragCurrentY < scrollableArea.top + scrollTriggerArea) {
      const dy = scrollableArea.top + scrollTriggerArea - this.__dragCurrentY;
      const percentage = Math.min(1, dy / scrollTriggerArea);
      this._grid.$.table.scrollTop -= percentage * maxScrollAmount;
    }
    if (this.__dragDy > 0 && this.__dragCurrentY > scrollableArea.bottom - scrollTriggerArea) {
      const dy = this.__dragCurrentY - (scrollableArea.bottom - scrollTriggerArea);
      const percentage = Math.min(1, dy / scrollTriggerArea);
      this._grid.$.table.scrollTop += percentage * maxScrollAmount;
    }
    setTimeout(() => this.__dragAutoScroller(), 10);
  }
  /**
   * Gets the scrollable area of the grid as a bounding client rect. The
   * scrollable area is the bounding rect of the grid minus the header and
   * footer.
   *
   * @private
   */
  __getScrollableArea() {
    const gridRect = this._grid.$.table.getBoundingClientRect();
    const headerRect = this._grid.$.header.getBoundingClientRect();
    const footerRect = this._grid.$.footer.getBoundingClientRect();
    return {
      top: gridRect.top + headerRect.height,
      bottom: gridRect.bottom - footerRect.height,
      left: gridRect.left,
      right: gridRect.right,
      height: gridRect.height - headerRect.height - footerRect.height,
      width: gridRect.width
    };
  }
  /**
   * Override to handle the user selecting all items.
   * @protected
   */
  _selectAll() {
  }
  /**
   * Override to handle the user deselecting all items.
   * @protected
   */
  _deselectAll() {
  }
  /**
   * Override to handle the user selecting an item.
   * @param {Object} item the item to select
   * @protected
   */
  _selectItem(_item) {
  }
  /**
   * Override to handle the user deselecting an item.
   * @param {Object} item the item to deselect
   * @protected
   */
  _deselectItem(_item) {
  }
  /**
   * Toggles the selected state of the given item.
   *
   * @param item the item to toggle
   * @param {boolean} [selected] whether to select or deselect the item
   * @private
   */
  __toggleItem(item, selected = !this._grid._isSelected(item)) {
    if (selected === this._grid._isSelected(item)) {
      return;
    }
    if (selected) {
      this._selectItem(item);
    } else {
      this._deselectItem(item);
    }
  }
  /**
   * IOS needs indeterminate + checked at the same time
   * @private
   */
  __isChecked(selectAll, indeterminate) {
    return indeterminate || selectAll;
  }
};
class GridFlowSelectionColumn extends GridSelectionColumnBaseMixin(GridColumn) {
  static get is() {
    return "vaadin-grid-flow-selection-column";
  }
  static get properties() {
    return {
      /**
       * Override property to enable auto-width
       */
      autoWidth: {
        type: Boolean,
        value: true
      },
      /**
       * Override property to set custom width
       */
      width: {
        type: String,
        value: "56px"
      }
    };
  }
  /**
   * Override method from `GridSelectionColumnBaseMixin` to add ID to select all
   * checkbox
   *
   * @override
   */
  _defaultHeaderRenderer(root, _column) {
    super._defaultHeaderRenderer(root, _column);
    const checkbox = root.firstElementChild;
    if (checkbox) {
      checkbox.id = "selectAllCheckbox";
    }
  }
  /**
   * Override a method from `GridSelectionColumnBaseMixin` to handle the user
   * selecting all items.
   *
   * @protected
   * @override
   */
  _selectAll() {
    this.selectAll = true;
    this.$server.selectAll();
  }
  /**
   * Override a method from `GridSelectionColumnBaseMixin` to handle the user
   * deselecting all items.
   *
   * @protected
   * @override
   */
  _deselectAll() {
    this.selectAll = false;
    this.$server.deselectAll();
  }
  /**
   * Override a method from `GridSelectionColumnBaseMixin` to handle the user
   * selecting an item.
   *
   * @param {Object} item the item to select
   * @protected
   * @override
   */
  _selectItem(item) {
    this.$server.setShiftKeyDown(this._shiftKeyDown);
    this._grid.$connector.doSelection([item], true);
  }
  /**
   * Override a method from `GridSelectionColumnBaseMixin` to handle the user
   * deselecting an item.
   *
   * @param {Object} item the item to deselect
   * @protected
   * @override
   */
  _deselectItem(item) {
    this.$server.setShiftKeyDown(this._shiftKeyDown);
    this._grid.$connector.doDeselection([item], true);
    this.selectAll = false;
  }
}
customElements.define(GridFlowSelectionColumn.is, GridFlowSelectionColumn);
window.Vaadin.Flow.gridConnector = {};
window.Vaadin.Flow.gridConnector.initLazy = (grid) => {
  if (grid.$connector) {
    return;
  }
  const dataProviderController = grid._dataProviderController;
  let cache2 = {};
  const rootRequestDelay = 150;
  let rootRequestDebouncer;
  let lastRequestedRange = [0, 0];
  const validSelectionModes = ["SINGLE", "NONE", "MULTI"];
  let selectedKeys = {};
  let selectionMode = "SINGLE";
  let sorterDirectionsSetFromServer = false;
  grid.size = 0;
  grid.itemIdPath = "key";
  grid.$connector = {};
  grid.$connector.hasRootRequestQueue = () => {
    const { pendingRequests } = dataProviderController.rootCache;
    return Object.keys(pendingRequests).length > 0 || !!rootRequestDebouncer?.isActive();
  };
  grid.$connector.doSelection = function(items, userOriginated) {
    if (selectionMode === "NONE" || !items.length || userOriginated && grid.hasAttribute("disabled")) {
      return;
    }
    if (selectionMode === "SINGLE") {
      selectedKeys = {};
    }
    let selectedItemsChanged = false;
    items.forEach((item) => {
      const selectable = !userOriginated || grid.isItemSelectable(item);
      selectedItemsChanged = selectedItemsChanged || selectable;
      if (item && selectable) {
        selectedKeys[item.key] = item;
        item.selected = true;
        if (userOriginated) {
          grid.$server.select(item.key);
        }
      }
      const isSelectedItemDifferentOrNull = !grid.activeItem || !item || item.key != grid.activeItem.key;
      if (!userOriginated && selectionMode === "SINGLE" && isSelectedItemDifferentOrNull) {
        grid.activeItem = item;
      }
    });
    if (selectedItemsChanged) {
      grid.selectedItems = Object.values(selectedKeys);
    }
  };
  grid.$connector.doDeselection = function(items, userOriginated) {
    if (selectionMode === "NONE" || !items.length || userOriginated && grid.hasAttribute("disabled")) {
      return;
    }
    const updatedSelectedItems = grid.selectedItems.slice();
    while (items.length) {
      const itemToDeselect = items.shift();
      const selectable = !userOriginated || grid.isItemSelectable(itemToDeselect);
      if (!selectable) {
        continue;
      }
      for (let i = 0; i < updatedSelectedItems.length; i++) {
        const selectedItem = updatedSelectedItems[i];
        if (itemToDeselect?.key === selectedItem.key) {
          updatedSelectedItems.splice(i, 1);
          break;
        }
      }
      if (itemToDeselect) {
        delete selectedKeys[itemToDeselect.key];
        delete itemToDeselect.selected;
        if (userOriginated) {
          grid.$server.deselect(itemToDeselect.key);
        }
      }
    }
    grid.selectedItems = updatedSelectedItems;
  };
  grid.__activeItemChanged = function(newVal, oldVal) {
    if (selectionMode != "SINGLE") {
      return;
    }
    if (!newVal) {
      if (oldVal && selectedKeys[oldVal.key]) {
        if (grid.__deselectDisallowed) {
          grid.activeItem = oldVal;
        } else {
          oldVal = dataProviderController.getItemContext(oldVal).item;
          grid.$connector.doDeselection([oldVal], true);
        }
      }
    } else if (!selectedKeys[newVal.key]) {
      grid.$connector.doSelection([newVal], true);
    }
  };
  grid._createPropertyObserver("activeItem", "__activeItemChanged", true);
  grid.__activeItemChangedDetails = function(newVal, oldVal) {
    if (grid.__disallowDetailsOnClick) {
      return;
    }
    if (newVal == null && oldVal === void 0) {
      return;
    }
    if (newVal && !newVal.detailsOpened) {
      grid.$server.setDetailsVisible(newVal.key);
    } else {
      grid.$server.setDetailsVisible(null);
    }
  };
  grid._createPropertyObserver("activeItem", "__activeItemChangedDetails", true);
  grid.$connector.debounceRootRequest = function(page) {
    const delay = grid._hasData ? rootRequestDelay : 0;
    rootRequestDebouncer = Debouncer.debounce(rootRequestDebouncer, timeOut.after(delay), () => {
      grid.$connector.fetchPage((firstIndex, size) => grid.$server.setViewportRange(firstIndex, size), page);
    });
  };
  grid.$connector.fetchPage = function(fetch, page) {
    page = Math.min(page, Math.floor((grid.size - 1) / grid.pageSize));
    const visibleRows = grid._getRenderedRows();
    let start2 = visibleRows.length > 0 ? visibleRows[0].index : 0;
    let end = visibleRows.length > 0 ? visibleRows[visibleRows.length - 1].index : 0;
    let buffer2 = end - start2;
    start2 = Math.max(0, start2 - buffer2);
    end = Math.min(end + buffer2, grid.size);
    let pageRange = [Math.floor(start2 / grid.pageSize), Math.floor(end / grid.pageSize)];
    if (page < pageRange[0] || page > pageRange[1]) {
      pageRange = [page, page];
    }
    if (lastRequestedRange[0] != pageRange[0] || lastRequestedRange[1] != pageRange[1]) {
      lastRequestedRange = pageRange;
      let pageCount = pageRange[1] - pageRange[0] + 1;
      fetch(pageRange[0] * grid.pageSize, pageCount * grid.pageSize);
    }
  };
  grid.dataProvider = function(params2, callback) {
    if (params2.pageSize != grid.pageSize) {
      throw "Invalid pageSize";
    }
    let page = params2.page;
    if (grid.size === 0) {
      callback([], 0);
      return;
    }
    if (cache2[page]) {
      callback(cache2[page]);
    } else {
      grid.$connector.debounceRootRequest(page);
    }
  };
  grid.$connector.setSorterDirections = function(directions) {
    sorterDirectionsSetFromServer = true;
    setTimeout(() => {
      try {
        const sorters = Array.from(grid.querySelectorAll("vaadin-grid-sorter"));
        grid._sorters.forEach((sorter) => {
          if (!sorters.includes(sorter)) {
            sorters.push(sorter);
          }
        });
        sorters.forEach((sorter) => {
          sorter.direction = null;
        });
        if (grid.multiSortPriority !== "append") {
          directions = directions.reverse();
        }
        directions.forEach(({ column: column2, direction }) => {
          sorters.forEach((sorter) => {
            if (sorter.getAttribute("path") === column2) {
              sorter.direction = direction;
            }
          });
        });
        grid.__applySorters();
      } finally {
        sorterDirectionsSetFromServer = false;
      }
    });
  };
  let preventUpdateVisibleRowsActive = 0;
  function preventUpdateVisibleRows(callback) {
    try {
      preventUpdateVisibleRowsActive++;
      callback();
    } finally {
      preventUpdateVisibleRowsActive--;
    }
  }
  grid.__updateVisibleRows = function(...args) {
    if (preventUpdateVisibleRowsActive === 0) {
      Object.getPrototypeOf(this).__updateVisibleRows.call(this, ...args);
    }
  };
  grid.__updateRow = function(row, ...args) {
    Object.getPrototypeOf(this).__updateRow.call(this, row, ...args);
    if (selectionMode === validSelectionModes[1]) {
      row.removeAttribute("aria-selected");
      Array.from(row.children).forEach((cell) => cell.removeAttribute("aria-selected"));
    }
  };
  const itemsUpdated = function(items) {
    if (!items || !Array.isArray(items)) {
      throw "Attempted to call itemsUpdated with an invalid value: " + JSON.stringify(items);
    }
    let detailsOpenedItems = Array.from(grid.detailsOpenedItems);
    for (let i = 0; i < items.length; ++i) {
      const item = items[i];
      if (!item) {
        continue;
      }
      if (item.detailsOpened) {
        if (grid._getItemIndexInArray(item, detailsOpenedItems) < 0) {
          detailsOpenedItems.push(item);
        }
      } else if (grid._getItemIndexInArray(item, detailsOpenedItems) >= 0) {
        detailsOpenedItems.splice(grid._getItemIndexInArray(item, detailsOpenedItems), 1);
      }
    }
    grid.detailsOpenedItems = detailsOpenedItems;
  };
  const updateGridCache = function(page) {
    const { rootCache } = dataProviderController;
    if (cache2[page] && rootCache.pendingRequests[page]) {
      return;
    }
    for (let i = 0; i < grid.pageSize; i++) {
      const index = page * grid.pageSize + i;
      const item = cache2[page]?.[i];
      rootCache.items[index] = item;
    }
  };
  grid.$connector.set = function(startIndex, items) {
    items.forEach((item, i) => {
      const index = startIndex + i;
      const page = Math.floor(index / grid.pageSize);
      cache2[page] ??= [];
      cache2[page][index % grid.pageSize] = item;
    });
    const firstPage = Math.floor(startIndex / grid.pageSize);
    const updatedPageCount = Math.ceil(items.length / grid.pageSize);
    for (let i = 0; i < updatedPageCount; i++) {
      updateGridCache(firstPage + i);
    }
    preventUpdateVisibleRows(() => {
      grid.$connector.doSelection(items.filter((item) => item.selected));
      grid.$connector.doDeselection(items.filter((item) => !item.selected && selectedKeys[item.key]));
      itemsUpdated(items);
    });
    grid.__updateVisibleRows(startIndex, startIndex + items.length - 1);
  };
  const itemToCacheLocation = function(item) {
    for (let page in cache2) {
      for (let index in cache2[page]) {
        if (grid.getItemId(cache2[page][index]) === grid.getItemId(item)) {
          return { page, index };
        }
      }
    }
    return null;
  };
  grid.$connector.updateFlatData = function(updatedItems) {
    const updatedIndexes = [];
    for (let i = 0; i < updatedItems.length; i++) {
      let cacheLocation = itemToCacheLocation(updatedItems[i]);
      if (cacheLocation) {
        cache2[cacheLocation.page][cacheLocation.index] = updatedItems[i];
        const index = parseInt(cacheLocation.page) * grid.pageSize + parseInt(cacheLocation.index);
        const { rootCache } = dataProviderController;
        if (rootCache.items[index]) {
          rootCache.items[index] = updatedItems[i];
        }
        updatedIndexes.push(index);
      }
    }
    preventUpdateVisibleRows(() => {
      itemsUpdated(updatedItems);
    });
    updatedIndexes.forEach((index) => grid.__updateVisibleRows(index, index));
  };
  grid.$connector.clear = function(index, length) {
    if (!cache2 || Object.keys(cache2).length === 0) {
      return;
    }
    if (index % grid.pageSize != 0) {
      throw "Got cleared data for index " + index + " which is not aligned with the page size of " + grid.pageSize;
    }
    let firstPage = Math.floor(index / grid.pageSize);
    let updatedPageCount = Math.ceil(length / grid.pageSize);
    for (let i = 0; i < updatedPageCount; i++) {
      let page = firstPage + i;
      let items = cache2[page];
      if (items) {
        preventUpdateVisibleRows(() => {
          grid.$connector.doDeselection(items.filter((item) => selectedKeys[item.key]));
          items.forEach((item) => grid.closeItemDetails(item));
        });
        delete cache2[page];
        updateGridCache(page);
      }
    }
    grid.__updateVisibleRows(index, index + length - 1);
  };
  grid.$connector.reset = function() {
    cache2 = {};
    dataProviderController.clearCache();
    lastRequestedRange = [-1, -1];
    rootRequestDebouncer?.cancel();
    grid.__updateVisibleRows();
  };
  grid.$connector.updateSize = (newSize) => grid.size = newSize;
  grid.$connector.updateUniqueItemIdPath = (path) => grid.itemIdPath = path;
  grid.$connector.confirm = function(id) {
    const { pendingRequests } = dataProviderController.rootCache;
    Object.entries(pendingRequests).forEach(([page, callback]) => {
      const lastAvailablePage = grid.size ? Math.ceil(grid.size / grid.pageSize) - 1 : 0;
      const lastRequestedRangeEnd = Math.min(lastRequestedRange[1], lastAvailablePage);
      if (cache2[page]) {
        callback(cache2[page]);
      } else if (page < lastRequestedRange[0] || +page > lastRequestedRangeEnd) {
        callback(new Array(grid.pageSize));
        grid.requestContentUpdate();
      } else if (callback && grid.size === 0) {
        callback([]);
      }
    });
    if (Object.keys(pendingRequests).length === 0) {
      rootRequestDebouncer?.cancel();
      lastRequestedRange = [-1, -1];
    }
    grid.$server.confirmUpdate(id);
  };
  grid.$connector.setSelectionMode = function(mode2) {
    if ((typeof mode2 === "string" || mode2 instanceof String) && validSelectionModes.indexOf(mode2) >= 0) {
      selectionMode = mode2;
      selectedKeys = {};
      grid.selectedItems = [];
      grid.$connector.updateMultiSelectable();
    } else {
      throw "Attempted to set an invalid selection mode";
    }
  };
  grid.$connector.updateMultiSelectable = function() {
    if (!grid.$) {
      return;
    }
    if (selectionMode === validSelectionModes[0]) {
      grid.$.table.setAttribute("aria-multiselectable", false);
    } else if (selectionMode === validSelectionModes[1]) {
      grid.$.table.removeAttribute("aria-multiselectable");
    } else {
      grid.$.table.setAttribute("aria-multiselectable", true);
    }
  };
  grid._createPropertyObserver("isAttached", () => grid.$connector.updateMultiSelectable());
  const singleTimeRenderer = (renderer) => {
    return (root) => {
      if (renderer) {
        renderer(root);
        renderer = null;
      }
    };
  };
  grid.$connector.setHeaderRenderer = function(column2, options2) {
    const { content: content2, showSorter, sorterPath } = options2;
    if (content2 === null) {
      column2.headerRenderer = null;
      return;
    }
    column2.headerRenderer = singleTimeRenderer((root) => {
      root.innerHTML = "";
      let contentRoot = root;
      if (showSorter) {
        const sorter = document.createElement("vaadin-grid-sorter");
        sorter.setAttribute("path", sorterPath);
        const ariaLabel = content2 instanceof Node ? content2.textContent : content2;
        if (ariaLabel) {
          sorter.setAttribute("aria-label", `Sort by ${ariaLabel}`);
        }
        root.appendChild(sorter);
        contentRoot = sorter;
      }
      if (content2 instanceof Node) {
        contentRoot.appendChild(content2);
      } else {
        contentRoot.textContent = content2;
      }
    });
  };
  grid._getActiveSorters = function() {
    return this._sorters.filter((sorter) => sorter.direction);
  };
  grid.__applySorters = function(...args) {
    const sorters = grid._mapSorters();
    const sortersChanged = JSON.stringify(grid._previousSorters) !== JSON.stringify(sorters);
    grid._previousSorters = sorters;
    Object.getPrototypeOf(this).__applySorters.call(this, ...args);
    if (sortersChanged && !sorterDirectionsSetFromServer) {
      grid.$server.sortersChanged(sorters);
    }
  };
  grid.$connector.setFooterRenderer = function(column2, options2) {
    const { content: content2 } = options2;
    if (content2 === null) {
      column2.footerRenderer = null;
      return;
    }
    column2.footerRenderer = singleTimeRenderer((root) => {
      root.innerHTML = "";
      if (content2 instanceof Node) {
        root.appendChild(content2);
      } else {
        root.textContent = content2;
      }
    });
  };
  grid.addEventListener("vaadin-context-menu-before-open", function(e) {
    const { key: key2, columnId } = e.detail;
    grid.$server.updateContextMenuTargetItem(key2, columnId);
  });
  grid.getContextMenuBeforeOpenDetail = function(event) {
    const sourceEvent = event.detail.sourceEvent || event;
    const eventContext = grid.getEventContext(sourceEvent);
    const key2 = eventContext.item?.key || "";
    const columnId = eventContext.column?.id || "";
    return { key: key2, columnId };
  };
  grid.preventContextMenu = function(event) {
    const isLeftClick = event.type === "click";
    const { column: column2 } = grid.getEventContext(event);
    return isLeftClick && column2 instanceof GridFlowSelectionColumn;
  };
  grid.addEventListener("click", (e) => _fireClickEvent(e, "item-click"));
  grid.addEventListener("dblclick", (e) => _fireClickEvent(e, "item-double-click"));
  grid.addEventListener("column-resize", (e) => {
    const cols = grid._getColumnsInOrder().filter((col) => !col.hidden);
    cols.forEach((col) => {
      col.dispatchEvent(new CustomEvent("column-drag-resize"));
    });
    grid.dispatchEvent(
      new CustomEvent("column-drag-resize", {
        detail: {
          resizedColumnKey: e.detail.resizedColumn._flowId
        }
      })
    );
  });
  grid.addEventListener("column-reorder", (e) => {
    const columns = grid._columnTree.slice(0).pop().filter((c) => c._flowId).sort((b, a) => b._order - a._order).map((c) => c._flowId);
    grid.dispatchEvent(
      new CustomEvent("column-reorder-all-columns", {
        detail: { columns }
      })
    );
  });
  grid.addEventListener("cell-focus", (e) => {
    const eventContext = grid.getEventContext(e);
    const expectedSectionValues = ["header", "body", "footer"];
    if (expectedSectionValues.indexOf(eventContext.section) === -1) {
      return;
    }
    grid.dispatchEvent(
      new CustomEvent("grid-cell-focus", {
        detail: {
          itemKey: eventContext.item ? eventContext.item.key : null,
          internalColumnId: eventContext.column ? eventContext.column._flowId : null,
          section: eventContext.section
        }
      })
    );
  });
  function _fireClickEvent(event, eventName) {
    if (event.defaultPrevented) {
      return;
    }
    const path = event.composedPath();
    const idx = path.findIndex((node) => node.localName === "td" || node.localName === "th");
    const cell = path[idx];
    const content2 = path.slice(0, idx);
    if (content2.some((node) => {
      const focusable = cell?._focusButton !== node && isFocusable(node);
      return focusable || node instanceof HTMLLabelElement;
    })) {
      return;
    }
    const eventContext = grid.getEventContext(event);
    const section = eventContext.section;
    if (eventContext.item && section !== "details") {
      event.itemKey = eventContext.item.key;
      if (eventContext.column) {
        event.internalColumnId = eventContext.column._flowId;
      }
      grid.dispatchEvent(new CustomEvent(eventName, { detail: event }));
    }
  }
  grid.cellPartNameGenerator = function(column2, rowData) {
    const part = rowData.item.part;
    if (!part) {
      return;
    }
    return (part.row || "") + " " + (column2 && part[column2._flowId] || "");
  };
  grid.dropFilter = (rowData) => rowData.item && !rowData.item.dropDisabled;
  grid.dragFilter = (rowData) => rowData.item && !rowData.item.dragDisabled;
  grid.addEventListener("grid-dragstart", (e) => {
    if (grid._isSelected(e.detail.draggedItems[0])) {
      if (grid.__selectionDragData) {
        Object.keys(grid.__selectionDragData).forEach((type) => {
          e.detail.setDragData(type, grid.__selectionDragData[type]);
        });
      } else {
        (grid.__dragDataTypes || []).forEach((type) => {
          e.detail.setDragData(type, e.detail.draggedItems.map((item) => item.dragData[type]).join("\n"));
        });
      }
      if (grid.__selectionDraggedItemsCount > 1) {
        e.detail.setDraggedItemsCount(grid.__selectionDraggedItemsCount);
      }
    } else {
      (grid.__dragDataTypes || []).forEach((type) => {
        e.detail.setDragData(type, e.detail.draggedItems[0].dragData[type]);
      });
    }
  });
  grid.isItemSelectable = (item) => {
    return item?.selectable === void 0 || item.selectable;
  };
  function isRowFullyInViewport(row) {
    const rowRect = row.getBoundingClientRect();
    const tableRect = grid.$.table.getBoundingClientRect();
    const headerRect = grid.$.header.getBoundingClientRect();
    const footerRect = grid.$.footer.getBoundingClientRect();
    return rowRect.top >= tableRect.top + headerRect.height && rowRect.bottom <= tableRect.bottom - footerRect.height;
  }
  grid.$connector.scrollToItem = function(itemKey, ...args) {
    const targetRow = grid._getRenderedRows().find((row) => {
      const { item } = grid.__getRowModel(row);
      return grid.getItemId(item) === itemKey;
    });
    if (targetRow && isRowFullyInViewport(targetRow)) {
      return;
    }
    grid.scrollToIndex(...args);
  };
};
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const defaultParseValue = (value) => {
  return value.split("	");
};
const defaultFormatValue = (inputValues) => {
  return inputValues.join("	");
};
const CustomFieldMixin = (superClass) => class CustomFieldMixin extends FieldMixin(FocusMixin(KeyboardMixin(superClass))) {
  static get properties() {
    return {
      /**
       * The name of the control, which is submitted with the form data.
       */
      name: {
        type: String
      },
      /**
       * The value of the field. When wrapping several inputs, it will contain `\t`
       * (Tab character) as a delimiter indicating parts intended to be used as the
       * corresponding inputs values.
       * Use the [`formatValue`](#/elements/vaadin-custom-field#property-formatValue)
       * and [`parseValue`](#/elements/vaadin-custom-field#property-parseValue)
       * properties to customize this behavior.
       */
      value: {
        type: String,
        observer: "__valueChanged",
        notify: true,
        sync: true
      },
      /**
       * Array of available input nodes
       * @type {!Array<!HTMLElement> | undefined}
       */
      inputs: {
        type: Array,
        readOnly: true,
        observer: "__inputsChanged"
      },
      /**
       * A function to format the values of the individual fields contained by
       * the custom field into a single component value. The function receives
       * an array of all values of the individual fields in the order of their
       * presence in the DOM, and must return a single component value.
       * This function is called each time a value of an internal field is
       * changed.
       *
       * Example:
       * ```js
       * customField.formatValue = (fieldValues) => {
       *   return fieldValues.join("-");
       * }
       * ```
       * @type {!CustomFieldFormatValueFn | undefined}
       */
      formatValue: {
        type: Function
      },
      /**
       * A function to parse the component value into values for the individual
       * fields contained by the custom field. The function receives the
       * component value, and must return an array of values for the individual
       * fields in the order of their presence in the DOM.
       * The function is called each time the value of the component changes.
       *
       * Example:
       * ```js
       * customField.parseValue = (componentValue) => {
       *   return componentValue.split("-");
       * }
       * ```
       * @type {!CustomFieldParseValueFn | undefined}
       */
      parseValue: {
        type: Function
      }
    };
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("role", "group");
    this.ariaTarget = this;
    this.__childrenObserver = new MutationObserver(() => {
      this.__setInputsFromSlot();
    });
    this.__setInputsFromSlot();
    this.$.slot.addEventListener("slotchange", () => {
      this.__setInputsFromSlot();
      getFlattenedElements(this.$.slot).filter((el) => !this.__isInput(el)).forEach((el) => {
        this.__childrenObserver.observe(el, { childList: true });
      });
    });
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
    this._tooltipController.setShouldShow((target) => {
      const inputs = target.inputs || [];
      return !inputs.some((el) => el.opened);
    });
  }
  /**
   * @param {FocusOptions=} options
   * @protected
   * @override
   */
  focus(options2) {
    if (this.inputs && this.inputs[0]) {
      this.inputs[0].focus(options2);
    }
  }
  /**
   * Override method inherited from `FocusMixin` to validate on blur.
   * @param {boolean} focused
   * @protected
   */
  _setFocused(focused) {
    super._setFocused(focused);
    if (!focused) {
      this._requestValidation();
    }
  }
  /**
   * Override method inherited from `FocusMixin` to not remove focused
   * state when focus moves to another input in the custom field.
   * @param {FocusEvent} event
   * @return {boolean}
   * @protected
   */
  _shouldRemoveFocus(event) {
    const { relatedTarget } = event;
    return !this.inputs || !this.inputs.some((el) => relatedTarget === (el.focusElement || el));
  }
  /**
   * Returns true if the current inputs values satisfy all constraints (if any).
   *
   * @return {boolean}
   */
  checkValidity() {
    const hasInvalidFields = this.inputs && this.inputs.some((input) => !(input.validate || input.checkValidity).call(input));
    if (hasInvalidFields || this.required && !(this.value && this.value.trim())) {
      return false;
    }
    return true;
  }
  /**
   * Override an observer from `FieldMixin`
   * to validate when required is removed.
   *
   * @protected
   * @override
   */
  _requiredChanged(required) {
    super._requiredChanged(required);
    if (required === false) {
      this._requestValidation();
    }
  }
  /**
   * @param {KeyboardEvent} e
   * @protected
   * @override
   */
  _onKeyDown(e) {
    if (e.key === "Tab") {
      const inputs = this.inputs || [];
      if (inputs.indexOf(e.target) < inputs.length - 1 && !e.shiftKey || inputs.indexOf(e.target) > 0 && e.shiftKey) {
        return;
      }
      this.__setValue();
    }
  }
  /** @protected */
  _onInputChange(event) {
    event.stopPropagation();
    this.__setValue();
    this._requestValidation();
    this.dispatchEvent(
      new CustomEvent("change", {
        bubbles: true,
        cancelable: false,
        detail: {
          value: this.value
        }
      })
    );
  }
  /** @private */
  __setValue() {
    this.__settingValue = true;
    const formatFn = this.formatValue || defaultFormatValue;
    this.value = formatFn.apply(this, [this.inputs.map((input) => input.value)]);
    this.__settingValue = false;
  }
  /** @private */
  __isInput(node) {
    const isSlottedInput = node.getAttribute("slot") === "input" || node.getAttribute("slot") === "textarea";
    return !isSlottedInput && (node.validate || node.checkValidity);
  }
  /** @private */
  __getInputsFromSlot() {
    return getFlattenedElements(this.$.slot).filter((node) => this.__isInput(node));
  }
  /** @private */
  __setInputsFromSlot() {
    this._setInputs(this.__getInputsFromSlot());
  }
  /** @private */
  __inputsChanged(inputs, oldInputs) {
    if (inputs.length === 0) {
      if (oldInputs && oldInputs.length > 0) {
        this.__setValue();
      }
      return;
    }
    if (this.value && this.value !== "	" && (!oldInputs || oldInputs.length === 0)) {
      this.__applyInputsValue(this.value);
    } else {
      this.__setValue();
    }
  }
  /** @private */
  __toggleHasValue(value) {
    this.toggleAttribute("has-value", value !== null && value.trim() !== "");
  }
  /** @private */
  __valueChanged(value, oldValue) {
    this.__toggleHasValue(value);
    if (this.__settingValue || !this.inputs) {
      return;
    }
    this.__applyInputsValue(value || "	");
    if (oldValue !== void 0) {
      this._requestValidation();
    }
  }
  /** @private */
  __applyInputsValue(value) {
    const parseFn = this.parseValue || defaultParseValue;
    const valuesArray = parseFn.apply(this, [value]);
    if (!valuesArray || valuesArray.length === 0) {
      console.warn("Value parser has not provided values array");
      return;
    }
    this.inputs.forEach((input, idx) => {
      input.value = valuesArray[idx];
    });
  }
};
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class CustomField extends CustomFieldMixin(ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-custom-field";
  }
  static get styles() {
    return field;
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-custom-field-container">
        <div part="label" @click="${this.focus}">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true"></span>
        </div>

        <div class="inputs-wrapper" part="input-fields" @change="${this._onInputChange}">
          <slot id="slot"></slot>
        </div>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>
      </div>

      <slot name="tooltip"></slot>
    `;
  }
  /**
   * Fired when the user commits a value change for any of the internal inputs.
   *
   * @event change
   */
}
defineCustomElement(CustomField);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const dashboardWidgetAndSectionStyles = css$h`
  :host {
    box-sizing: border-box;
    --_widget-background: var(--vaadin-dashboard-widget-background, var(--vaadin-background-color));
    --_widget-border-radius: var(--vaadin-dashboard-widget-border-radius, var(--vaadin-radius-m));
    --_widget-border-width: var(--vaadin-dashboard-widget-border-width, 1px);
    --_widget-border-color: var(--vaadin-dashboard-widget-border-color, var(--vaadin-border-color-secondary));
    --_widget-shadow: var(--vaadin-dashboard-widget-shadow, 0 0 0 0 transparent);
    --_widget-editable-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3);
    --_widget-selected-shadow: 0 3px 12px -1px rgba(0, 0, 0, 0.3);
    --_drop-target-background: var(--vaadin-dashboard-drop-target-background, var(--vaadin-background-container));
    --_drop-target-border-color: var(--vaadin-dashboard-drop-target-border-color, var(--vaadin-border-color-secondary));
    --_focus-ring-color: var(--vaadin-focus-ring-color);
    --_focus-ring-width: var(--vaadin-focus-ring-width);
  }

  :host([focused]) {
    z-index: 1;
    outline: var(--_focus-ring-width) solid var(--_focus-ring-color);
    outline-offset: calc(var(--_widget-border-width) * -1);
  }

  :host([dragging]) {
    box-shadow: none;
    background: var(--_drop-target-background);
    border-color: var(--_drop-target-border-color);
  }

  :host([dragging]) * {
    visibility: hidden;
  }

  :host(:not([editable])) [part~='move-button'],
  :host(:not([editable])) [part~='remove-button'],
  :host(:not([editable])) #focus-button,
  :host(:not([editable])) #focus-button-wrapper,
  :host(:not([editable])) .mode-controls {
    display: none;
  }

  #focustrap {
    display: contents;
  }

  header {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    justify-content: space-between;
    gap: var(--vaadin-dashboard-widget-header-gap, var(--vaadin-gap-s));
  }

  [part='title'] {
    flex: 1;
    color: var(--vaadin-dashboard-widget-title-color, var(--vaadin-text-color));
    font-size: var(--vaadin-dashboard-widget-title-font-size, 1em);
    font-weight: var(--vaadin-dashboard-widget-title-font-weight, 500);
    line-height: var(--vaadin-dashboard-widget-title-line-height, inherit);
    white-space: var(--vaadin-dashboard-widget-title-wrap, wrap);
    text-overflow: ellipsis;
    overflow: hidden;
    align-self: safe center;
  }

  vaadin-dashboard-button {
    z-index: 1;
  }

  vaadin-dashboard-button .icon::before {
    display: block;
    content: '';
    height: var(--vaadin-icon-size, 1lh);
    width: var(--vaadin-icon-size, 1lh);
    background: currentColor;
    mask: var(--icon) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
  }

  #focus-button-wrapper,
  #focus-button {
    position: absolute;
    inset: 0;
    opacity: 0;
  }

  #focus-button {
    pointer-events: none;
    padding: 0;
    border: none;
  }

  .mode-controls {
    position: absolute;
    inset: 0;
    z-index: 2;
  }

  .mode-controls[hidden] {
    display: none;
  }

  /* Drag handle */
  [part~='move-button'] {
    cursor: move;
    --icon: var(--_vaadin-icon-drag);
  }

  /* Remove button */
  [part~='remove-button'] {
    cursor: pointer;
    --icon: var(--_vaadin-icon-cross);
  }

  /* Move-mode buttons */
  [part~='move-backward-button'],
  [part~='move-forward-button'],
  [part~='move-apply-button'] {
    position: absolute;
    top: 50%;
  }

  [part~='move-backward-button'] {
    inset-inline-start: 0;
    transform: translateY(-50%);
    --icon: var(--_vaadin-icon-chevron-down);
  }

  [part~='move-forward-button'] {
    inset-inline-end: 0;
    transform: translateY(-50%);
    --icon: var(--_vaadin-icon-chevron-down);
  }

  [part~='move-apply-button'] {
    left: 50%;
    transform: translate(-50%, -50%);
    --icon: var(--_vaadin-icon-checkmark);
  }

  :host([first-child]) [part~='move-backward-button'],
  :host([last-child]) [part~='move-forward-button'] {
    display: none;
  }

  :host(:not([dir='rtl'])) [part~='move-backward-button'],
  :host([dir='rtl']) [part~='move-forward-button'] {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }

  :host(:not([dir='rtl'])) [part~='move-forward-button'],
  :host([dir='rtl']) [part~='move-backward-button'] {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }

  :host(:not([dir='rtl'])) [part~='move-backward-button'] .icon,
  :host([dir='rtl']) [part~='move-forward-button'] .icon {
    rotate: 90deg;
  }

  :host(:not([dir='rtl'])) [part~='move-forward-button'] .icon,
  :host([dir='rtl']) [part~='move-backward-button'] .icon {
    rotate: -90deg;
  }

  /* Resize-mode buttons */
  [part~='resize-shrink-width-button'],
  [part~='resize-shrink-height-button'],
  [part~='resize-grow-width-button'],
  [part~='resize-grow-height-button'],
  [part~='resize-apply-button'] {
    position: absolute;
  }

  [part~='resize-shrink-width-button'] {
    inset-inline-end: 0;
    top: 50%;
  }

  :host(:not([dir='rtl'])) [part~='resize-shrink-width-button'] {
    transform: translateY(-50%) translateX(-100%);
  }

  :host([dir='rtl']) [part~='resize-shrink-width-button'] {
    transform: translateY(-50%) translateX(100%);
  }

  .mode-controls:has([part~='resize-grow-width-button'][hidden]) [part~='resize-shrink-width-button'] {
    transform: translateY(-50%);
  }

  [part~='resize-grow-width-button'] {
    inset-inline-start: 100%;
    top: 50%;
  }

  :host(:not([dir='rtl'])) [part~='resize-grow-width-button'] {
    transform: translateY(-50%) translateX(-100%);
  }

  :host([dir='rtl']) [part~='resize-grow-width-button'] {
    transform: translateY(-50%) translateX(100%);
  }

  [part~='resize-shrink-height-button'] {
    bottom: 0;
    left: 50%;
    transform: translateX(-50%) translateY(-100%);
  }

  [part~='resize-grow-height-button'] {
    top: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(-100%);
  }

  [part~='resize-grow-height-button'],
  [part~='resize-grow-width-button'] {
    --icon: var(--_vaadin-icon-plus);
  }

  [part~='resize-shrink-height-button'],
  [part~='resize-shrink-width-button'] {
    --icon: var(--_vaadin-icon-minus);
  }

  [part~='resize-apply-button'] {
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    --icon: var(--_vaadin-icon-checkmark);
  }

  [part~='resize-shrink-width-button'] + [part~='resize-grow-width-button'] {
    margin-left: 1px;
  }

  [part~='resize-grow-height-button'],
  [part~='resize-shrink-height-button'] {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }

  [part~='resize-shrink-height-button']:not([hidden]) + [part~='resize-grow-height-button'] {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }

  [part~='resize-shrink-height-button'] + [part~='resize-grow-height-button'] {
    margin-top: 1px;
  }

  :host(:not([dir='rtl'])) [part~='resize-grow-width-button'],
  :host(:not([dir='rtl'])) [part~='resize-shrink-width-button'] {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }

  :host([dir='rtl']) [part~='resize-grow-width-button'],
  :host([dir='rtl']) [part~='resize-shrink-width-button'] {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }

  :host(:not([dir='rtl'])) [part~='resize-shrink-width-button']:not([hidden]) + [part~='resize-grow-width-button'] {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }

  :host([dir='rtl']) [part~='resize-shrink-width-button']:not([hidden]) + [part~='resize-grow-width-button'] {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }

  @media (forced-colors: active) {
    vaadin-dashboard-button .icon::before {
      background: currentColor;
      forced-color-adjust: none;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const widgetStyles = css$h`
  :host {
    display: flex;
    flex-direction: column;
    grid-column: var(--_item-column);
    grid-row: var(--_item-row);
    position: relative;
    background: var(--_widget-background);
    border-radius: var(--_widget-border-radius);
    box-shadow: var(--_widget-shadow);
    border-color: var(--_widget-border-color);
  }

  :host::before {
    content: '';
    position: absolute;
    inset: 0;
    border-color: inherit;
    border-width: var(--_widget-border-width);
    border-style: solid;
    border-radius: inherit;
    pointer-events: none;
  }

  :host([hidden]) {
    display: none !important;
  }

  :host(:not([editable])) [part~='resize-button'] {
    display: none;
  }

  [part~='content'] {
    flex: 1;
    overflow: hidden;
    min-height: 1em;
  }

  [part~='resize-button'] {
    position: absolute;
    bottom: 0;
    inset-inline-end: 0;
    z-index: 1;
    overflow: hidden;
    touch-action: none;
    cursor: nwse-resize;
    --icon: var(--_vaadin-icon-resize);
  }

  :host([dir='rtl']) [part~='resize-button'] {
    cursor: sw-resize;
  }

  :host([dir='rtl']) [part~='resize-button'] .icon::before {
    transform: scaleX(-1);
  }

  /* Widget states */

  :host([editable]) {
    --vaadin-dashboard-widget-shadow: var(--_widget-editable-shadow);
  }

  :host([selected]) {
    --vaadin-dashboard-widget-shadow: var(--_widget-selected-shadow);
  }

  :host([resizing])::after {
    content: '';
    z-index: 2;
    position: absolute;
    top: 0;
    width: var(--_widget-resizer-width, 0);
    height: var(--_widget-resizer-height, 0);
    background: color-mix(in srgb, currentColor 5%, var(--_widget-background) 70%);
    border-color: color-mix(in srgb, currentColor 10%, transparent);
    border-width: var(--_widget-border-width);
    border-style: solid;
    border-radius: inherit;
  }

  /* Widget parts */
  header {
    padding: var(
      --vaadin-dashboard-widget-header-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
  }

  :host([editable]) header {
    padding: var(--vaadin-dashboard-widget-header-padding, var(--vaadin-padding-s));
  }

  header:has([part~='title'][hidden]) {
    padding: 0;
  }
`;
const dashboardWidgetStyles = [widgetStyles, dashboardWidgetAndSectionStyles];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const WRAPPER_LOCAL_NAME = "vaadin-dashboard-widget-wrapper";
const SYNCHRONIZED_ATTRIBUTES = ["editable", "dragging", "first-child", "last-child"];
function itemsEqual(a, b) {
  if (a === b) {
    return true;
  }
  if (a.id !== void 0 && b.id !== void 0) {
    return a.id === b.id;
  }
  return false;
}
function getItemsArrayOfItem(item, items) {
  if (items.some((i) => itemsEqual(i, item))) {
    return items;
  }
  const parentItem = items.find((i) => i.items && getItemsArrayOfItem(item, i.items));
  return parentItem ? parentItem.items : null;
}
function getElementItem(element) {
  const wrapper = element.closest(WRAPPER_LOCAL_NAME);
  return wrapper && wrapper.__item;
}
function fireMove(element, delta) {
  element.dispatchEvent(
    new CustomEvent("item-move", {
      bubbles: true,
      detail: { delta }
    })
  );
}
function fireResize(element, colspanDelta, rowspanDelta) {
  element.dispatchEvent(
    new CustomEvent("item-resize", {
      bubbles: true,
      detail: {
        colspanDelta,
        rowspanDelta
      }
    })
  );
  if ("requestUpdate" in element) {
    element.requestUpdate();
  }
}
function fireRemove(element) {
  element.dispatchEvent(new CustomEvent("item-remove", { bubbles: true }));
}
function findFilteredAncestorInstance(node, elementFilter) {
  while (node) {
    if (elementFilter(node)) {
      return node;
    }
    if (node instanceof ShadowRoot) {
      node = node.host;
    } else {
      const rootNode = node.getRootNode();
      if (rootNode instanceof ShadowRoot) {
        node = rootNode.host;
      } else if (node.parentNode) {
        node = node.parentNode;
      } else {
        node = null;
      }
    }
  }
  return null;
}
function findAncestorInstance(node, baseClass) {
  return findFilteredAncestorInstance(node, (el) => {
    return el instanceof baseClass;
  });
}
function getParentLayout(node) {
  return findFilteredAncestorInstance(node, (el) => el.__hasVaadinDashboardLayoutMixin);
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const dashboardButton = css$h`
  :host {
    padding: 4px;
  }

  :host([theme~='tertiary']) {
    color: var(--vaadin-dashboard-button-text-color, var(--vaadin-text-color-secondary));
  }
`;
const dashboardButtonStyles = [buttonStyles, dashboardButton];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class DashboardButton extends ButtonMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-dashboard-button";
  }
  static get styles() {
    return dashboardButtonStyles;
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-button-container">
        <span part="prefix" aria-hidden="true">
          <slot name="prefix"></slot>
        </span>
        <span part="label">
          <slot></slot>
        </span>
        <span part="suffix" aria-hidden="true">
          <slot name="suffix"></slot>
        </span>
      </div>
      <slot name="tooltip"></slot>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
  }
}
defineCustomElement(DashboardButton);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class KeyboardController {
  constructor(host) {
    this.host = host;
    host.addEventListener("focusout", (e) => this.__focusout(e));
    host.addEventListener("keydown", (e) => this.__keydown(e));
  }
  /** @private */
  __focusout(e) {
    const focusOutElement = e.composedPath()[0];
    const isHostVisible = !!this.host.offsetHeight;
    const isFocusButtonHidden = getComputedStyle(focusOutElement).display === "none";
    if (isHostVisible && isFocusButtonHidden && this.host.hasAttribute("editable")) {
      this.host.__focusApply();
    } else {
      this.host.__exitMode();
      this.host.__focused = false;
      this.host.__selected = false;
    }
  }
  /** @private */
  __keydown(e) {
    if (e.metaKey || e.ctrlKey || !this.host.__selected) {
      return;
    }
    if (e.key === "Backspace" || e.key === "Delete") {
      this.__delete(e);
    } else if (e.key === "Escape") {
      this.__escape(e);
    } else if (e.shiftKey && e.key.startsWith("Arrow")) {
      this.__resize(e);
    } else if (e.key.startsWith("Arrow")) {
      this.__move(e);
    }
  }
  /** @private */
  __delete(e) {
    e.preventDefault();
    fireRemove(this.host);
  }
  /** @private */
  __escape(e) {
    e.preventDefault();
    if (this.host.__moveMode || this.host.__resizeMode) {
      this.host.__exitMode(true);
    } else {
      this.host.__selected = false;
      this.host.focus();
    }
  }
  /** @private */
  __resize(e) {
    const resizeMap = {
      ArrowRight: [document.dir === "rtl" ? -1 : 1, 0],
      ArrowLeft: [document.dir === "rtl" ? 1 : -1, 0],
      ArrowDown: [0, 1],
      ArrowUp: [0, -1]
    };
    if (resizeMap[e.key]) {
      e.preventDefault();
      fireResize(this.host, ...resizeMap[e.key]);
    }
  }
  /** @private */
  __move(e) {
    const moveMap = {
      ArrowRight: document.dir === "rtl" ? -1 : 1,
      ArrowLeft: document.dir === "rtl" ? 1 : -1,
      ArrowDown: 1,
      ArrowUp: -1
    };
    if (moveMap[e.key]) {
      e.preventDefault();
      fireMove(this.host, moveMap[e.key]);
    }
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const DEFAULT_I18N$8 = {
  selectWidget: "Select widget for editing",
  selectSection: "Select section for editing",
  remove: "Remove",
  move: "Move",
  moveApply: "Apply",
  moveForward: "Move Forward",
  moveBackward: "Move Backward",
  resize: "Resize",
  resizeApply: "Apply",
  resizeShrinkWidth: "Shrink width",
  resizeGrowWidth: "Grow width",
  resizeShrinkHeight: "Shrink height",
  resizeGrowHeight: "Grow height"
};
function getDefaultI18n() {
  return { ...DEFAULT_I18N$8 };
}
const DashboardItemMixin = (superClass) => class DashboardItemMixinClass extends ResizeMixin(superClass) {
  static get properties() {
    return {
      /** @protected */
      __i18n: {
        type: Object
      },
      /** @protected */
      _rootHeadingLevel: {
        type: Number
      },
      /** @private */
      __selected: {
        type: Boolean,
        reflectToAttribute: true,
        attribute: "selected",
        observer: "__selectedChanged"
      },
      /** @private */
      __focused: {
        type: Boolean,
        reflectToAttribute: true,
        attribute: "focused"
      },
      /** @private */
      __moveMode: {
        type: Boolean,
        reflectToAttribute: true,
        attribute: "move-mode",
        observer: "__moveModeChanged"
      },
      /** @private */
      __resizeMode: {
        type: Boolean,
        reflectToAttribute: true,
        attribute: "resize-mode",
        observer: "__resizeModeChanged"
      }
    };
  }
  /** @private */
  __renderDragHandle() {
    return html`<vaadin-dashboard-button
        id="drag-handle"
        draggable="true"
        class="drag-handle"
        part="button move-button"
        theme="icon tertiary"
        aria-label="${this.__i18n.move}"
        title="${this.__i18n.move}"
        tabindex="${this.__selected ? 0 : -1}"
        @click="${() => this.__enterMoveMode()}"
      >
        <div class="icon"></div>
      </vaadin-dashboard-button>`;
  }
  /** @private */
  __renderRemoveButton() {
    return html`<vaadin-dashboard-button
        aria-label="${this.__i18n.remove}"
        title="${this.__i18n.remove}"
        id="remove-button"
        part="button remove-button"
        theme="icon tertiary"
        tabindex="${this.__selected ? 0 : -1}"
        @click="${() => fireRemove(this)}"
      >
        <div class="icon"></div>
      </vaadin-dashboard-button>`;
  }
  /** @private */
  __renderFocusButton(i18nSelectTitleForEditingProperty) {
    return html`<label draggable="true" class="drag-handle" id="focus-button-wrapper">
        <button
          id="focus-button"
          aria-label=${this.__i18n[i18nSelectTitleForEditingProperty]}
          aria-describedby="title"
          aria-pressed="${!!this.__selected}"
          @focus="${() => {
      this.__focused = true;
    }}"
          @blur="${() => {
      this.__focused = false;
    }}"
          @click="${() => {
      const wasSelected = this.__selected;
      this.__selected = !wasSelected;
      this.__focused = wasSelected;
      if (this.__selected) {
        this.$["drag-handle"].focus();
      }
    }}"
        ></button>
      </label>`;
  }
  /** @private */
  __renderResizeHandle() {
    return html`<vaadin-dashboard-button
        aria-label="${this.__i18n.resize}"
        title="${this.__i18n.resize}"
        id="resize-handle"
        part="button resize-button"
        class="resize-handle"
        theme="icon tertiary"
        tabindex="${this.__selected ? 0 : -1}"
        @click="${() => this.__enterResizeMode()}"
      >
        <div class="icon"></div>
      </vaadin-dashboard-button>`;
  }
  /** @private */
  __renderMoveControls() {
    return html`<div
        id="move-controls"
        class="mode-controls"
        .hidden="${!this.__moveMode}"
        @pointerdown="${(e) => e.preventDefault()}"
      >
        <vaadin-dashboard-button
          theme="primary icon"
          aria-label="${this.__i18n.moveBackward}"
          title="${this.__i18n.moveBackward}"
          @click="${() => fireMove(this, -1)}"
          id="move-backward"
          part="button move-backward-button"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
        <vaadin-dashboard-button
          theme="primary icon large"
          aria-label="${this.__i18n.moveApply}"
          title="${this.__i18n.moveApply}"
          @click="${() => this.__exitMode(true)}"
          id="move-apply"
          part="button move-apply-button"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
        <vaadin-dashboard-button
          theme="primary icon"
          aria-label="${this.__i18n.moveForward}"
          title="${this.__i18n.moveForward}"
          @click="${() => fireMove(this, 1)}"
          id="move-forward"
          part="button move-forward-button"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
      </div>`;
  }
  /** @private */
  __renderResizeControls() {
    const style = getComputedStyle(this);
    const hasMinRowHeight = style.getPropertyValue("--_row-min-height") !== "auto";
    const effectiveColCount = style.getPropertyValue("--_col-count");
    const maxColCount = style.getPropertyValue("--_col-max-count");
    const colCount = Math.min(effectiveColCount, maxColCount);
    const colspan = style.getPropertyValue("--vaadin-dashboard-widget-colspan") || 1;
    const rowspan = style.getPropertyValue("--vaadin-dashboard-widget-rowspan") || 1;
    const canShrinkWidth = colspan > 1;
    const canShrinkHeight = rowspan > 1;
    const canGrowWidth = colspan < colCount;
    return html`<div
        id="resize-controls"
        class="mode-controls"
        .hidden="${!this.__resizeMode}"
        @pointerdown="${(e) => e.preventDefault()}"
      >
        <vaadin-dashboard-button
          theme="primary icon large"
          aria-label="${this.__i18n.resizeApply}"
          title="${this.__i18n.resizeApply}"
          @click="${() => this.__exitMode(true)}"
          id="resize-apply"
          part="button resize-apply-button"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
        <vaadin-dashboard-button
          theme="primary icon"
          aria-label="${this.__i18n.resizeShrinkWidth}"
          title="${this.__i18n.resizeShrinkWidth}"
          @click="${() => fireResize(this, -1, 0)}"
          .hidden="${!canShrinkWidth}"
          id="resize-shrink-width"
          part="button resize-shrink-width-button"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
        <vaadin-dashboard-button
          theme="primary icon"
          aria-label="${this.__i18n.resizeGrowWidth}"
          title="${this.__i18n.resizeGrowWidth}"
          @click="${() => fireResize(this, 1, 0)}"
          .hidden="${!canGrowWidth}"
          id="resize-grow-width"
          part="button resize-grow-width-button"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
        <vaadin-dashboard-button
          theme="primary icon"
          aria-label="${this.__i18n.resizeShrinkHeight}"
          title="${this.__i18n.resizeShrinkHeight}"
          @click="${() => fireResize(this, 0, -1)}"
          id="resize-shrink-height"
          part="button resize-shrink-height-button"
          .hidden="${!hasMinRowHeight || !canShrinkHeight}"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
        <vaadin-dashboard-button
          theme="primary icon"
          aria-label="${this.__i18n.resizeGrowHeight}"
          title="${this.__i18n.resizeGrowHeight}"
          @click="${() => fireResize(this, 0, 1)}"
          id="resize-grow-height"
          part="button resize-grow-height-button"
          .hidden="${!hasMinRowHeight}"
        >
          <div class="icon"></div>
        </vaadin-dashboard-button>
      </div>`;
  }
  constructor() {
    super();
    this.__keyboardController = new KeyboardController(this);
    this.__focusTrapController = new FocusTrapController(this);
    this.__boundRootHeadingLevelChangedListener = this.__updateRootHeadingLevel.bind(this);
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(this.__keyboardController);
    this.addController(this.__focusTrapController);
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this.__updateRootHeadingLevel();
    this.__addHeadingLevelListener();
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    this.__removeHeadingLevelListener();
  }
  /** @private */
  __selectedChanged(selected, oldSelected) {
    if (!!selected === !!oldSelected) {
      return;
    }
    this.dispatchEvent(new CustomEvent("item-selected-changed", { bubbles: true, detail: { value: selected } }));
    if (selected) {
      this.__focusTrapController.trapFocus(this.$.focustrap);
    } else {
      this.__focusTrapController.releaseFocus();
    }
  }
  /**
   * @param {FocusOptions=} options
   * @protected
   * @override
   */
  focus(options2) {
    if (this.hasAttribute("editable")) {
      this.$["focus-button"].focus(options2);
    } else {
      super.focus(options2);
    }
  }
  /** @private */
  __exitMode(focus2) {
    if (this.__moveMode) {
      this.__moveMode = false;
      if (focus2) {
        this.$["drag-handle"].focus();
        this.__focusTrapController.trapFocus(this.$.focustrap);
      }
    } else if (this.__resizeMode) {
      this.__resizeMode = false;
      if (focus2) {
        this.$["resize-handle"].focus();
        this.__focusTrapController.trapFocus(this.$.focustrap);
      }
    }
  }
  /** @private */
  __focusApply() {
    if (this.__moveMode) {
      this.$["move-apply"].focus();
    } else if (this.__resizeMode) {
      this.$["resize-apply"].focus();
    }
  }
  /** @private */
  __enterMoveMode() {
    this.__selected = true;
    this.__moveMode = true;
    requestAnimationFrame(() => {
      this.__focusTrapController.trapFocus(this.$["move-controls"]);
    });
  }
  /** @private */
  __enterResizeMode() {
    this.__selected = true;
    this.__resizeMode = true;
    requestAnimationFrame(() => {
      this.__focusTrapController.trapFocus(this.$["resize-controls"]);
    });
  }
  /** @private */
  __moveModeChanged(moveMode, oldMoveMode) {
    if (!!moveMode === !!oldMoveMode) {
      return;
    }
    this.dispatchEvent(new CustomEvent("item-move-mode-changed", { bubbles: true, detail: { value: moveMode } }));
  }
  /** @private */
  __resizeModeChanged(resizeMode, oldResizeMode) {
    if (!!resizeMode === !!oldResizeMode) {
      return;
    }
    this.dispatchEvent(new CustomEvent("item-resize-mode-changed", { bubbles: true, detail: { value: resizeMode } }));
  }
  /** @private */
  __addHeadingLevelListener() {
    this.__removeHeadingLevelListener();
    const parentLayout = getParentLayout(this);
    if (parentLayout) {
      this.__rootHeadingLevelListenerTarget = parentLayout;
      parentLayout.addEventListener(
        "dashboard-root-heading-level-changed",
        this.__boundRootHeadingLevelChangedListener
      );
    }
  }
  /** @private */
  __removeHeadingLevelListener() {
    if (this.__rootHeadingLevelListenerTarget) {
      this.__rootHeadingLevelListenerTarget.removeEventListener(
        "dashboard-root-heading-level-changed",
        this.__boundRootHeadingLevelChangedListener
      );
      this.__rootHeadingLevelListenerTarget = null;
    }
  }
  /** @private */
  __updateRootHeadingLevel() {
    const parentLayout = getParentLayout(this);
    if (parentLayout) {
      this._rootHeadingLevel = parentLayout.rootHeadingLevel;
    }
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const sectionStyles = css$h`
  :host {
    display: grid;
    position: relative;
    grid-template-columns: subgrid;
    --_section-column: 1 / calc(var(--_effective-col-count) + 1);
    grid-column: var(--_section-column) !important;
    gap: var(--_gap);
    /* Dashboard section header height */
    grid-template-rows: minmax(0, auto) repeat(auto-fill, var(--_row-height));
    grid-auto-rows: var(--_row-height);
    border: var(--_widget-border-width) solid var(--_widget-border-color);
    border-radius: var(--vaadin-dashboard-section-border-radius, var(--vaadin-radius-l));
    padding: calc(var(--_gap) - var(--_widget-border-width));
    margin-inline: calc(var(--_gap) * -1);
    margin-block: var(--_gap);
  }

  :host([hidden]) {
    display: none !important;
  }

  ::slotted(*) {
    --_item-column: span min(var(--vaadin-dashboard-widget-colspan, 1), var(--_effective-col-count, var(--_col-count)));

    grid-column: var(--_item-column);
    --_item-row: span var(--vaadin-dashboard-widget-rowspan, 1);
    grid-row: var(--_item-row);
  }

  header {
    grid-column: var(--_section-column);
  }

  :host::before {
    z-index: 2 !important;
  }

  ::slotted(vaadin-dashboard-widget-wrapper) {
    display: contents;
  }

  /* Section states */

  :host(:not([editable])) {
    --_widget-border-width: 0px;
  }
`;
const dashboardSectionStyles = [sectionStyles, dashboardWidgetAndSectionStyles];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class DashboardSection extends DashboardItemMixin(
  ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-dashboard-section";
  }
  static get styles() {
    return dashboardSectionStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  static get properties() {
    return {
      /**
       * The object used to localize this component.
       *
       * To change the default localization, replace the entire
       * `i18n` object with a custom one.
       *
       * The object has the following structure and default values:
       * ```js
       * {
       *   selectSection: 'Select section for editing',
       *   remove: 'Remove',
       *   move: 'Move',
       *   moveApply: 'Apply',
       *   moveForward: 'Move Forward',
       *   moveBackward: 'Move Backward',
       * }
       * ```
       * @private
       */
      __i18n: {
        type: Object,
        value: () => {
          return getDefaultI18n();
        }
      },
      /**
       * The title of the section
       *
       * @attr {string} section-title
       */
      sectionTitle: {
        type: String,
        value: ""
      },
      /** @private */
      __childCount: {
        type: Number,
        value: 0
      }
    };
  }
  /** @protected */
  render() {
    return html`
      ${this.__renderMoveControls()}

      <div id="focustrap">
        ${this.__renderFocusButton("selectSection")}

        <header part="header">
          ${this.__renderDragHandle()}
          <div id="title" role="heading" aria-level=${this._rootHeadingLevel || 2} part="title"
            >${this.sectionTitle}</div
          >
          ${this.__renderRemoveButton()}
        </header>
      </div>

      <!-- Default slot is used by <vaadin-dashboard-layout> -->
      <slot></slot>
      <!-- Named slots are used by <vaadin-dashboard> -->
      ${[...Array(this.__childCount)].map((_2, index) => html`<slot name="slot-${index}"></slot>`)}
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "region");
    }
  }
}
defineCustomElement(DashboardSection);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class DashboardWidget extends DashboardItemMixin(
  ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-dashboard-widget";
  }
  static get styles() {
    return dashboardWidgetStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  static get properties() {
    return {
      /**
       * The object used to localize this component.
       *
       * To change the default localization, replace the entire
       * `i18n` object with a custom one.
       *
       * The object has the following structure and default values:
       * ```js
       * {
       *   selectWidget: 'Select widget for editing',
       *   remove: 'Remove',
       *   resize: 'Resize',
       *   resizeApply: 'Apply',
       *   resizeShrinkWidth: 'Shrink width',
       *   resizeGrowWidth: 'Grow width',
       *   resizeShrinkHeight: 'Shrink height',
       *   resizeGrowHeight: 'Grow height',
       *   move: 'Move',
       *   moveApply: 'Apply',
       *   moveForward: 'Move Forward',
       *   moveBackward: 'Move Backward',
       * }
       * ```
       * @private
       */
      __i18n: {
        type: Object,
        value: () => {
          return getDefaultI18n();
        }
      },
      /**
       * The title of the widget.
       *
       * @attr {string} widget-title
       */
      widgetTitle: {
        type: String,
        value: ""
      },
      /* @private */
      __isNestedWidget: {
        type: Boolean,
        value: false
      }
    };
  }
  /** @protected */
  render() {
    return html`
      ${this.__renderMoveControls()} ${this.__renderResizeControls()}

      <div id="focustrap">
        ${this.__renderFocusButton("selectWidget")}

        <header part="header">
          ${this.__renderDragHandle()} ${this.__renderWidgetTitle()}
          <slot name="header-content"></slot>
          ${this.__renderRemoveButton()}
        </header>

        ${this.__renderResizeHandle()}
      </div>

      <div id="content" part="content">
        <slot></slot>
      </div>
    `;
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    const wrapper = this.closest(WRAPPER_LOCAL_NAME);
    if (wrapper) {
      SYNCHRONIZED_ATTRIBUTES.forEach((attr2) => {
        this.toggleAttribute(attr2, !!wrapper[attr2]);
      });
      this.__i18n = wrapper.i18n;
    }
    this.__updateNestedState();
    const undefinedAncestor = this.closest("*:not(:defined)");
    if (undefinedAncestor) {
      customElements.whenDefined(undefinedAncestor.localName).then(() => {
        queueMicrotask(() => this.__updateNestedState());
      });
    }
  }
  /** @protected */
  ready() {
    super.ready();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "article");
    }
  }
  /** @private */
  __renderWidgetTitle() {
    let effectiveHeadingLevel = this._rootHeadingLevel;
    if (effectiveHeadingLevel == null) {
      effectiveHeadingLevel = 2;
    }
    if (this.__isNestedWidget) {
      effectiveHeadingLevel += 1;
    }
    return html`<div
      id="title"
      part="title"
      role="heading"
      aria-level=${effectiveHeadingLevel}
      .hidden=${!this.widgetTitle}
      >${this.widgetTitle}</div
    >`;
  }
  /** @private */
  __updateNestedState() {
    this.__isNestedWidget = !!findAncestorInstance(this, DashboardSection);
  }
}
defineCustomElement(DashboardWidget);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const dashboardLayoutStyles = css$h`
  :host {
    display: block;
    overflow: auto;
    box-sizing: border-box;
    width: 100%;
  }

  :host([hidden]) {
    display: none !important;
  }

  :host([dense-layout]) #grid {
    grid-auto-flow: dense;
  }

  #grid {
    box-sizing: border-box;

    /* Padding around dashboard edges */
    --_default-padding: var(--vaadin-padding-l);
    --_padding: max(0px, var(--vaadin-dashboard-padding, var(--_default-padding)));
    padding: var(--_padding);

    /* Gap between widgets */
    --_default-gap: var(--vaadin-gap-s);
    --_gap: max(0px, var(--vaadin-dashboard-gap, var(--_default-gap)));
    gap: var(--_gap);

    /* Default min and max column widths */
    --_default-col-min-width: 25em;
    --_default-col-max-width: 1fr;

    /* Effective min and max column widths */
    --_col-min-width: var(--vaadin-dashboard-col-min-width, var(--_default-col-min-width));
    --_col-max-width: var(--vaadin-dashboard-col-max-width, var(--_default-col-max-width));

    /* Effective max column count */
    --_col-max-count: var(--vaadin-dashboard-col-max-count, var(--_col-count));

    /* Effective column count */
    --_effective-col-count: min(var(--_col-count), var(--_col-max-count));

    /* Default row min height */
    --_default-row-min-height: 12em;
    /* Effective row min height */
    --_row-min-height: var(--vaadin-dashboard-row-min-height, var(--_default-row-min-height));
    /* Effective row height */
    --_row-height: minmax(var(--_row-min-height, auto), auto);

    display: grid;
    overflow: hidden;
    min-width: calc(var(--_col-min-width) + var(--_padding) * 2);

    grid-template-columns: repeat(
      var(--_effective-col-count, auto-fill),
      minmax(var(--_col-min-width), var(--_col-max-width))
    );

    grid-auto-rows: var(--_row-height);
  }

  ::slotted(*) {
    /* The grid-column value applied to children */
    --_item-column: span min(var(--vaadin-dashboard-widget-colspan, 1), var(--_effective-col-count, var(--_col-count)));

    grid-column: var(--_item-column);

    /* The grid-row value applied to children */
    --_item-row: span var(--vaadin-dashboard-widget-rowspan, 1);
    grid-row: var(--_item-row);
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const dashboard = css$h`
  #grid[item-resizing] {
    -webkit-user-select: none;
    user-select: none;
  }

  ::slotted(vaadin-dashboard-widget-wrapper) {
    display: contents;
  }
`;
const dashboardStyles = [dashboardLayoutStyles, dashboard];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const DashboardLayoutMixin = (superClass) => class DashboardLayoutMixinClass extends ResizeMixin(superClass) {
  static get properties() {
    return {
      /**
       * Whether the dashboard layout is dense.
       *
       * @attr {boolean} dense-layout
       */
      denseLayout: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * Root heading level for sections and widgets. Defaults to 2.
       *
       * If changed to e.g. 1:
       * - sections will have the attribute `aria-level` with value 1
       * - non-nested widgets will have the attribute `aria-level` with value 1
       * - nested widgets will have the attribute `aria-level` with value 2
       *
       * @attr {number} root-heading-level
       */
      rootHeadingLevel: {
        type: Number,
        value: 2,
        sync: true,
        reflectToAttribute: true,
        observer: "__rootHeadingLevelChanged"
      }
    };
  }
  constructor() {
    super();
    this.__hasVaadinDashboardLayoutMixin = true;
  }
  /** @protected */
  ready() {
    super.ready();
    this._onResize();
  }
  /**
   * @protected
   * @override
   */
  _onResize() {
    this.$.grid.style.width = `${this.offsetWidth}px`;
    this.__updateColumnCount();
  }
  /**
   * @private
   */
  __updateColumnCount() {
    this.$.grid.style.removeProperty("--_col-count");
    const columnCount = getComputedStyle(this.$.grid).gridTemplateColumns.split(" ").length;
    this.$.grid.style.setProperty("--_col-count", columnCount);
  }
  /** @private */
  __rootHeadingLevelChanged(rootHeadingLevel) {
    this.dispatchEvent(
      new CustomEvent("dashboard-root-heading-level-changed", { detail: { value: rootHeadingLevel } })
    );
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const REORDER_EVENT_TIMEOUT = 200;
const REORDER_MOVE_THRESHOLD = 10;
class WidgetReorderController {
  constructor(host) {
    this.host = host;
    this.draggedElementRemoveObserver = new MutationObserver(() => this.__restoreDraggedElement());
    host.addEventListener("dragstart", (e) => this.__dragStart(e));
    host.addEventListener("dragend", (e) => this.__dragEnd(e));
    host.addEventListener("dragover", (e) => this.__dragOver(e));
    host.addEventListener("drop", (e) => this.__drop(e));
    host.addEventListener("item-move", (e) => this.__itemMove(e));
  }
  /** @private */
  __dragStart(e) {
    const handle = [...e.composedPath()].find((el) => el.classList && el.classList.contains("drag-handle"));
    if (!handle) {
      return;
    }
    this.__draggedElement = e.target;
    this.__draggedElement.__exitMode();
    this.__draggedElement.__focused = false;
    this.__draggedElement.__selected = false;
    this.draggedItem = getElementItem(this.__draggedElement);
    const { left, top } = this.__draggedElement.getBoundingClientRect();
    e.dataTransfer.setDragImage(this.__draggedElement, e.clientX - left, e.clientY - top);
    e.dataTransfer.setData("text/plain", "item");
    this.draggedElementRemoveObserver.observe(this.host, { childList: true, subtree: true });
    requestAnimationFrame(() => {
      this.host.items = [...this.host.items];
    });
  }
  /** @private */
  __dragOver(e) {
    if (!this.draggedItem) {
      return;
    }
    this.__startX ||= e.clientX;
    this.__startY ||= e.clientY;
    const currentDx = e.clientX - (this.__previousX || e.clientX);
    const currentDy = e.clientY - (this.__previousY || e.clientY);
    this.__previousX = e.clientX;
    this.__previousY = e.clientY;
    if (currentDx && this.__dx && Math.sign(currentDx) !== Math.sign(this.__dx)) {
      this.__startX = e.clientX;
    }
    if (currentDy && this.__dy && Math.sign(currentDy) !== Math.sign(this.__dy)) {
      this.__startY = e.clientY;
    }
    this.__dx = e.clientX - this.__startX;
    this.__dy = e.clientY - this.__startY;
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    const dragContextElements = this.__getDragContextElements(this.__draggedElement);
    const draggedElement = dragContextElements.find((element) => getElementItem(element) === this.draggedItem);
    if (!draggedElement) {
      return;
    }
    const otherElements = dragContextElements.filter((element) => element !== draggedElement);
    if (otherElements.length === 0) {
      return;
    }
    let targetElement = otherElements.find((other) => other.contains(e.target));
    if (!targetElement) {
      targetElement = this.__getClosestElement(otherElements, e.clientX, e.clientY);
    }
    if (!this.__reordering && this.__isDraggedOver(draggedElement, targetElement, {
      x: e.clientX,
      y: e.clientY,
      dx: this.__dx,
      dy: this.__dy
    })) {
      this.__reordering = true;
      setTimeout(() => {
        this.__reordering = false;
      }, REORDER_EVENT_TIMEOUT);
      const targetItem = getElementItem(targetElement);
      const targetItems = getItemsArrayOfItem(targetItem, this.host.items);
      const targetIndex = targetItems.indexOf(targetItem);
      this.__reorderItems(this.draggedItem, targetIndex);
    }
  }
  /** @private */
  __dragEnd() {
    if (!this.draggedItem) {
      return;
    }
    this.__previousX = null;
    this.__previousY = null;
    this.__startX = null;
    this.__startY = null;
    this.__dx = null;
    this.__dy = null;
    if (this.__draggedElement.parentElement === this.host) {
      this.__draggedElement.remove();
    }
    this.__fireItemMovedEvent(this.draggedItem);
    this.__draggedElement = null;
    this.draggedItem = null;
    this.host.items = [...this.host.items];
    this.draggedElementRemoveObserver.disconnect();
  }
  /** @private */
  __fireItemMovedEvent(item) {
    const section = this.host.items.find((hostItem) => hostItem.items && hostItem.items.includes(item));
    this.host.dispatchEvent(
      new CustomEvent("dashboard-item-moved", {
        detail: { item, items: this.host.items, section }
      })
    );
  }
  /** @private */
  __drop(e) {
    if (!this.draggedItem) {
      return;
    }
    e.preventDefault();
  }
  /**
   * Returns the element closest to the given coordinates.
   * @private
   */
  __getClosestElement(elements, x, y) {
    return elements.reduce(
      (closest, element) => {
        const { left, top, width, height } = element.getBoundingClientRect();
        const centerX = left + width / 2;
        const centerY = top + height / 2;
        const distance = Math.hypot(centerX - x, centerY - y);
        return distance < closest.distance ? { element, distance } : closest;
      },
      { element: null, distance: Number.MAX_VALUE }
    ).element;
  }
  /**
   * Returns true if the dragged element is dragged enough over the target element in
   * the direction relative to their positions where x and y are the coordinates
   * of the drag event.
   * @private
   */
  __isDraggedOver(draggedElement, targetElement, { x, y, dx, dy }) {
    const draggedPos = draggedElement.getBoundingClientRect();
    const targetPos = targetElement.getBoundingClientRect();
    if (draggedPos.top >= targetPos.bottom) {
      return y < targetPos.bottom && dy < -REORDER_MOVE_THRESHOLD;
    } else if (draggedPos.bottom <= targetPos.top) {
      return y > targetPos.top && dy > REORDER_MOVE_THRESHOLD;
    } else if (draggedPos.left >= targetPos.right) {
      return x < targetPos.right && dx < -REORDER_MOVE_THRESHOLD;
    } else if (draggedPos.right <= targetPos.left) {
      return x > targetPos.left && dx > REORDER_MOVE_THRESHOLD;
    }
  }
  /**
   * Returns the elements (widgets or sections) that are candidates for reordering with the
   * currently dragged item. Effectively, this is the list of child widgets or sections inside
   * the same parent container (host or a section) as the dragged item.
   * @private
   */
  __getDragContextElements() {
    const draggedItemWrapper = [...this.host.querySelectorAll(WRAPPER_LOCAL_NAME)].find(
      (el) => itemsEqual(el.__item, this.draggedItem)
    );
    if (!draggedItemWrapper) {
      return [];
    }
    return [...draggedItemWrapper.parentElement.children].filter((el) => el.localName === WRAPPER_LOCAL_NAME && el.firstElementChild).map((el) => el.firstElementChild);
  }
  /** @private */
  __reorderItems(draggedItem, targetIndex) {
    if (targetIndex < 0 || targetIndex >= getItemsArrayOfItem(draggedItem, this.host.items).length) {
      return;
    }
    const items = getItemsArrayOfItem(draggedItem, this.host.items);
    const draggedIndex = items.indexOf(draggedItem);
    items.splice(draggedIndex, 1);
    items.splice(targetIndex, 0, draggedItem);
    this.host.items = [...this.host.items];
  }
  /**
   * The dragged element might be removed from the DOM during the drag operation if
   * the widgets get re-rendered. This method restores the dragged element if it's not
   * present in the DOM to ensure the dragend event is fired.
   * @private
   */
  __restoreDraggedElement() {
    if (!this.host.contains(this.__draggedElement)) {
      this.__draggedElement.style.display = "none";
      this.host.appendChild(this.__draggedElement);
    }
  }
  /**
   * Handle the item-move event dispatched by a widget / section.
   * @private
   */
  __itemMove(e) {
    e.stopImmediatePropagation();
    const item = getElementItem(e.target);
    const items = getItemsArrayOfItem(item, this.host.items);
    this.__reorderItems(item, items.indexOf(item) + e.detail.delta);
    this.__fireItemMovedEvent(item);
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class WidgetResizeController {
  constructor(host) {
    this.host = host;
    this.__resizedElementRemoveObserver = new MutationObserver(() => this.__restoreResizedElement());
    this.__touchMoveCancelListener = (e) => e.preventDefault();
    addListener(host, "track", (e) => this.__onTrack(e));
    setTouchAction(host, "");
    host.addEventListener("item-resize", (e) => this.__itemResize(e));
  }
  /** @private */
  __onTrack(e) {
    if (e.detail.state === "start") {
      this.__onResizeStart(e);
    } else if (e.detail.state === "track") {
      this.__onResize(e);
    } else if (e.detail.state === "end") {
      this.__onResizeEnd(e);
    }
  }
  /** @private */
  __onResizeStart(e) {
    const handle = [...e.composedPath()].find((el) => el.classList && el.classList.contains("resize-handle"));
    if (!handle) {
      return;
    }
    this.host.$.grid.toggleAttribute("item-resizing", true);
    this.resizedItem = getElementItem(e.target);
    this.__resizeStartWidth = e.target.offsetWidth;
    this.__resizeStartHeight = e.target.offsetHeight;
    this.__resizeWidth = this.__resizeStartWidth + e.detail.dx;
    this.__resizeHeight = this.__resizeStartHeight + e.detail.dy;
    this.__updateWidgetStyles();
    this.__resizedElement = e.target;
    this.__resizedElementRemoveObserver.observe(this.host, { childList: true, subtree: true });
    document.addEventListener("touchmove", this.__touchMoveCancelListener, { passive: false });
  }
  /** @private */
  __onResize(e) {
    if (!this.resizedItem) {
      return;
    }
    this.__resizeWidth = this.__resizeStartWidth + (document.dir === "rtl" ? -e.detail.dx : e.detail.dx);
    this.__resizeHeight = this.__resizeStartHeight + e.detail.dy;
    this.__updateWidgetStyles();
    const itemWrapper = this.__getItemWrapper(this.resizedItem);
    if (!itemWrapper.firstElementChild) {
      return;
    }
    const gridStyle = getComputedStyle(this.host.$.grid);
    const gapSize = parseFloat(gridStyle.gap || 0);
    const currentElementWidth = itemWrapper.firstElementChild.offsetWidth;
    const columns = gridStyle.gridTemplateColumns.split(" ");
    const columnWidth = parseFloat(columns[0]);
    if (this.__resizeWidth > currentElementWidth + gapSize + columnWidth / 2) {
      this.__updateResizedItem(1, 0);
    } else if (this.__resizeWidth < currentElementWidth - columnWidth / 2) {
      this.__updateResizedItem(-1, 0);
    }
    const currentElementHeight = itemWrapper.firstElementChild.offsetHeight;
    const rowMinHeight = Math.min(...gridStyle.gridTemplateRows.split(" ").map((height) => parseFloat(height)));
    if (e.detail.ddy > 0 && this.__resizeHeight > currentElementHeight + gapSize + rowMinHeight / 2) {
      this.__updateResizedItem(0, 1);
    } else if (e.detail.ddy < 0 && this.__resizeHeight < currentElementHeight - rowMinHeight / 2) {
      this.__updateResizedItem(0, -1);
    }
  }
  /** @private */
  __onResizeEnd() {
    if (!this.resizedItem) {
      return;
    }
    if (this.__resizedElement.parentElement === this.host) {
      this.__resizedElement.remove();
    }
    const itemWrapper = this.__getItemWrapper(this.resizedItem);
    itemWrapper.style.removeProperty("--_widget-resizer-width");
    itemWrapper.style.removeProperty("--_widget-resizer-height");
    if (itemWrapper.firstElementChild) {
      itemWrapper.firstElementChild.toggleAttribute("resizing", false);
    }
    this.host.$.grid.toggleAttribute("item-resizing", false);
    this.__resizedElementRemoveObserver.disconnect();
    document.removeEventListener("touchmove", this.__touchMoveCancelListener);
    this.__fireItemResizedEvent(this.resizedItem);
    this.resizedItem = null;
  }
  /** @private */
  __fireItemResizedEvent(item) {
    this.host.dispatchEvent(
      new CustomEvent("dashboard-item-resized", {
        detail: { item, items: this.host.items }
      })
    );
  }
  /** @private */
  __getItemWrapper(item) {
    return [...this.host.querySelectorAll(WRAPPER_LOCAL_NAME)].find((el) => itemsEqual(el.__item, item));
  }
  /** @private */
  __updateResizedItem(colspanDelta, rowspanDelta) {
    this.__resizeItem(this.resizedItem, colspanDelta, rowspanDelta);
    requestAnimationFrame(() => this.__updateWidgetStyles());
  }
  /** @private */
  __resizeItem(item, colspanDelta, rowspanDelta) {
    if (item.items) {
      return;
    }
    const gridStyle = getComputedStyle(this.host.$.grid);
    if (rowspanDelta && gridStyle.getPropertyValue("--_row-min-height") === "auto") {
      return;
    }
    const columns = gridStyle.gridTemplateColumns.split(" ");
    const currentColspan = item.colspan || 1;
    const currentRowspan = item.rowspan || 1;
    const newColspan = Math.min(Math.max(currentColspan + colspanDelta, 1), columns.length);
    const newRowspan = Math.max(currentRowspan + rowspanDelta, 1);
    if ((item.colspan || 1) === newColspan && (item.rowspan || 1) === newRowspan) {
      return;
    }
    item.colspan = newColspan;
    item.rowspan = newRowspan;
    this.host.items = [...this.host.items];
  }
  /** @private */
  __updateWidgetStyles() {
    const itemWrapper = this.__getItemWrapper(this.resizedItem);
    itemWrapper.style.setProperty("--_widget-resizer-width", `${this.__resizeWidth}px`);
    itemWrapper.style.setProperty("--_widget-resizer-height", `${this.__resizeHeight}px`);
    if (itemWrapper.firstElementChild) {
      itemWrapper.firstElementChild.toggleAttribute("resizing", true);
    }
  }
  /** @private */
  __restoreResizedElement() {
    if (!this.host.contains(this.__resizedElement)) {
      this.__resizedElement.style.display = "none";
      this.host.appendChild(this.__resizedElement);
    }
  }
  /**
   * Handle the item-resize event dispatched by a widget / section.
   * @private
   */
  __itemResize(e) {
    e.stopImmediatePropagation();
    const item = getElementItem(e.target);
    this.__resizeItem(item, e.detail.colspanDelta, e.detail.rowspanDelta);
    this.__fireItemResizedEvent(item);
  }
  hostDisconnected() {
    document.removeEventListener("touchmove", this.__touchMoveCancelListener);
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const DEFAULT_I18N$7 = getDefaultI18n();
class Dashboard extends DashboardLayoutMixin(
  I18nMixin(DEFAULT_I18N$7, ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-dashboard";
  }
  static get cvdlName() {
    return "vaadin-dashboard";
  }
  static get styles() {
    return dashboardStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  static get properties() {
    return {
      /**
       * An array containing the items of the dashboard
       * @type {!Array<!DashboardItem> | null | undefined}
       */
      items: {
        type: Array
      },
      /**
       * Custom function for rendering a widget for each dashboard item.
       * Placing something else than a widget in the wrapper is not supported.
       * Receives three arguments:
       *
       * - `root` The container for the widget.
       * - `dashboard` The reference to the `<vaadin-dashboard>` element.
       * - `model` The object with the properties related with the rendered
       *   item, contains:
       *   - `model.item` The item.
       *
       * @type {DashboardRenderer | null | undefined}
       */
      renderer: {
        type: Function
      },
      /**
       * Whether the dashboard is editable.
       */
      editable: {
        type: Boolean
      },
      /** @private */
      __childCount: {
        type: Number,
        value: 0
      }
    };
  }
  static get observers() {
    return ["__itemsOrRendererChanged(items, renderer, editable, __effectiveI18n)"];
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following structure and default values:
   * ```js
   * {
   *   selectSection: 'Select section for editing',
   *   selectWidget: 'Select widget for editing',
   *   remove: 'Remove',
   *   resize: 'Resize',
   *   resizeApply: 'Apply',
   *   resizeShrinkWidth: 'Shrink width',
   *   resizeGrowWidth: 'Grow width',
   *   resizeShrinkHeight: 'Shrink height',
   *   resizeGrowHeight: 'Grow height',
   *   move: 'Move',
   *   moveApply: 'Apply',
   *   moveForward: 'Move Forward',
   *   moveBackward: 'Move Backward',
   * }
   * ```
   * @type {!DashboardI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  constructor() {
    super();
    this.__widgetReorderController = new WidgetReorderController(this);
    this.__widgetResizeController = new WidgetResizeController(this);
    this.addEventListener("item-remove", (e) => this.__itemRemove(e));
    this.addEventListener("item-selected-changed", (e) => this.__itemSelectedChanged(e));
    this.addEventListener("item-move-mode-changed", (e) => this.__itemMoveModeChanged(e));
    this.addEventListener("item-resize-mode-changed", (e) => this.__itemResizeModeChanged(e));
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(this.__widgetReorderController);
    this.addController(this.__widgetResizeController);
  }
  /** @protected */
  render() {
    return html`<div id="grid">
      ${[...Array(this.__childCount)].map((_2, index) => html`<slot name="slot-${index}"></slot>`)}
    </div>`;
  }
  /** @private */
  __itemsOrRendererChanged(items, renderer) {
    this.__childCount = items ? items.length : 0;
    this.__renderItemWrappers(items || []);
    this.querySelectorAll(WRAPPER_LOCAL_NAME).forEach((wrapper) => {
      if (wrapper.firstElementChild && wrapper.firstElementChild.localName === "vaadin-dashboard-section") {
        return;
      }
      const item = getElementItem(wrapper);
      if (item.component instanceof HTMLElement) {
        if (item.component.parentElement !== wrapper) {
          wrapper.textContent = "";
          wrapper.appendChild(item.component);
        }
      } else if (renderer) {
        renderer(wrapper, this, { item });
      } else {
        wrapper.innerHTML = "";
      }
      if (wrapper.firstElementChild) {
        SYNCHRONIZED_ATTRIBUTES.forEach((attr2) => {
          wrapper.firstElementChild.toggleAttribute(attr2, !!wrapper[attr2]);
        });
        wrapper.firstElementChild.__i18n = this.__effectiveI18n;
      }
    });
  }
  /** @private */
  __renderItemWrappers(items, hostElement = this) {
    let wrappers = [...hostElement.children].filter((el) => el.localName === WRAPPER_LOCAL_NAME);
    const focusedWrapper = wrappers.find((wrapper) => wrapper.querySelector(":focus"));
    const focusedWrapperWillBeRemoved = focusedWrapper && !this.__isActiveWrapper(focusedWrapper);
    const wrapperClosestToRemovedFocused = focusedWrapperWillBeRemoved && this.__getClosestActiveWrapper(focusedWrapper);
    items.forEach((item, index) => {
      const wrapper = wrappers.find((el) => itemsEqual(getElementItem(el), item)) || this.__createWrapper(item);
      wrappers = wrappers.filter((el) => el !== wrapper);
      if (!wrapper.isConnected) {
        hostElement.appendChild(wrapper);
      }
      this.__updateWrapper(wrapper, item);
      wrapper.slot = `slot-${index}`;
      if (item.items) {
        let section = wrapper.firstElementChild;
        const isComponentSection = item.component instanceof DashboardSection;
        if (!(section instanceof DashboardSection)) {
          section = isComponentSection ? item.component : document.createElement("vaadin-dashboard-section");
          wrapper.appendChild(section);
        }
        if (!isComponentSection) {
          section.sectionTitle = item.title;
        }
        SYNCHRONIZED_ATTRIBUTES.forEach((attr2) => section.toggleAttribute(attr2, !!wrapper[attr2]));
        section.__i18n = this.__effectiveI18n;
        section.__childCount = item.items.length;
        this.__renderItemWrappers(item.items, section);
      }
    });
    wrappers.forEach((wrapper) => wrapper.remove());
    requestAnimationFrame(() => {
      if (focusedWrapperWillBeRemoved) {
        this.__focusWrapperContent(wrapperClosestToRemovedFocused || this.querySelector(WRAPPER_LOCAL_NAME));
      }
      const focusedItem = this.querySelector(":focus");
      if (focusedItem && this.__outsideViewport(focusedItem)) {
        focusedItem.scrollIntoView();
      }
    });
  }
  /** @private */
  __outsideViewport(element) {
    const rect2 = element.getBoundingClientRect();
    const viewportHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
    const viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
    if (rect2.bottom < 0 || rect2.right < 0 || rect2.top > viewportHeight || rect2.left > viewportWidth) {
      return true;
    }
    const dashboardRect = this.getBoundingClientRect();
    if (rect2.bottom < dashboardRect.top || rect2.right < dashboardRect.left || rect2.top > dashboardRect.bottom || rect2.left > dashboardRect.right) {
      return true;
    }
    return false;
  }
  /** @private */
  __focusWrapperContent(wrapper) {
    if (wrapper && wrapper.firstElementChild) {
      wrapper.firstElementChild.focus();
    }
  }
  /**
   * Checks if the wrapper represents an item that is part of the dashboard's items array
   * @private
   */
  __isActiveWrapper(wrapper) {
    if (!wrapper || wrapper.localName !== WRAPPER_LOCAL_NAME) {
      return false;
    }
    return getItemsArrayOfItem(getElementItem(wrapper), this.items);
  }
  /**
   * Parses the slot name to get the index of the item in the dashboard
   * For example, slot name "slot-12" will return 12
   * @private
   */
  __parseSlotIndex(slotName) {
    return parseInt(slotName.split("-")[1]);
  }
  /** @private */
  __getClosestActiveWrapper(wrapper) {
    if (!wrapper || this.__isActiveWrapper(wrapper)) {
      return wrapper;
    }
    const siblingWrappers = [...wrapper.parentElement.children].sort((a, b) => {
      return this.__parseSlotIndex(a.slot) - this.__parseSlotIndex(b.slot);
    });
    const findSiblingWrapper = (wrapper2, dir) => {
      while (wrapper2) {
        if (this.__isActiveWrapper(wrapper2)) {
          return wrapper2;
        }
        const currentIndex = siblingWrappers.indexOf(wrapper2);
        wrapper2 = dir === 1 ? siblingWrappers[currentIndex + 1] : siblingWrappers[currentIndex - 1];
      }
    };
    return findSiblingWrapper(wrapper, 1) || findSiblingWrapper(wrapper, -1) || this.__getClosestActiveWrapper(wrapper.parentElement.closest(WRAPPER_LOCAL_NAME));
  }
  /** @private */
  __createWrapper(item) {
    const wrapper = document.createElement(WRAPPER_LOCAL_NAME);
    wrapper.__item = item;
    return wrapper;
  }
  /** @private */
  __updateWrapper(wrapper, item) {
    const style = `
      ${item.colspan ? `--vaadin-dashboard-widget-colspan: ${item.colspan};` : ""}
      ${item.rowspan ? `--vaadin-dashboard-widget-rowspan: ${item.rowspan};` : ""}
    `.trim();
    wrapper.__item = item;
    wrapper.setAttribute("style", style);
    wrapper.editable = this.editable;
    wrapper.dragging = this.__widgetReorderController.draggedItem === item;
    wrapper["first-child"] = item === getItemsArrayOfItem(item, this.items)[0];
    wrapper["last-child"] = item === getItemsArrayOfItem(item, this.items).slice(-1)[0];
    wrapper.i18n = this.__effectiveI18n;
  }
  /** @private */
  __itemRemove(e) {
    e.stopImmediatePropagation();
    const item = getElementItem(e.target);
    const items = getItemsArrayOfItem(item, this.items);
    const section = this.items.find((i) => i.items && i.items.includes(item));
    const beforeRemoveEvent = new CustomEvent("dashboard-item-before-remove", {
      cancelable: true,
      detail: { item, items: this.items, section }
    });
    this.dispatchEvent(beforeRemoveEvent);
    if (beforeRemoveEvent.defaultPrevented) {
      return;
    }
    items.splice(items.indexOf(item), 1);
    this.items = [...this.items];
    this.toggleAttribute("item-selected", false);
    this.dispatchEvent(new CustomEvent("dashboard-item-removed", { detail: { item, items: this.items, section } }));
  }
  /** @private */
  __dispatchCustomEvent(eventName, item, value) {
    if (!item) {
      return;
    }
    this.dispatchEvent(
      new CustomEvent(eventName, {
        detail: {
          item,
          value
        }
      })
    );
  }
  /** @private */
  __itemSelectedChanged(e) {
    e.stopImmediatePropagation();
    this.__dispatchCustomEvent("dashboard-item-selected-changed", getElementItem(e.target), e.detail.value);
    this.toggleAttribute("item-selected", e.detail.value);
  }
  /** @private */
  __itemMoveModeChanged(e) {
    e.stopImmediatePropagation();
    this.__dispatchCustomEvent("dashboard-item-move-mode-changed", getElementItem(e.target), e.detail.value);
  }
  /** @private */
  __itemResizeModeChanged(e) {
    e.stopImmediatePropagation();
    this.__dispatchCustomEvent("dashboard-item-resize-mode-changed", getElementItem(e.target), e.detail.value);
  }
  /**
   * @private
   */
  __updateColumnCount() {
    const previousColumnCount = this.$.grid.style.getPropertyValue("--_col-count");
    super.__updateColumnCount();
    if (previousColumnCount !== this.$.grid.style.getPropertyValue("--_col-count")) {
      this.querySelectorAll(WRAPPER_LOCAL_NAME).forEach((wrapper) => {
        if (wrapper.firstElementChild && "requestUpdate" in wrapper.firstElementChild) {
          wrapper.firstElementChild.requestUpdate();
        }
      });
    }
  }
  /**
   * Fired when an item selected state changed
   *
   * @event dashboard-item-selected-changed
   */
  /**
   * Fired when an item move mode changed
   *
   * @event dashboard-item-move-mode-changed
   */
  /**
   * Fired when an item resize mode changed
   *
   * @event dashboard-item-resize-mode-changed
   */
  /**
   * Fired when an item was moved
   *
   * @event dashboard-item-moved
   */
  /**
   * Fired when an item was resized
   *
   * @event dashboard-item-resized
   */
  /**
   * Fired before an item is removed
   *
   * @event dashboard-item-before-remove
   */
  /**
   * Fired when an item was removed
   *
   * @event dashboard-item-removed
   */
}
defineCustomElement(Dashboard);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const datePickerOverlayStyles = css$h`
  [part='overlay'] {
    display: flex;
    flex: auto;
    max-height: var(--vaadin-date-picker-overlay-max-height, 30rem);
    box-sizing: content-box;
    width: var(
      --vaadin-date-picker-overlay-width,
      calc(
        var(--vaadin-date-picker-date-width, 2rem) * 7 +
          var(--vaadin-date-picker-month-padding, var(--vaadin-padding-s)) * 2 +
          var(--vaadin-date-picker-year-scroller-width, 3rem)
      )
    );
    cursor: default;
  }

  :host([fullscreen]) {
    --vaadin-date-picker-date-width: calc(100% / 7);
  }

  :host([fullscreen]) [part='backdrop'] {
    display: block;
  }

  :host([fullscreen]) [part='overlay'] {
    border: none;
    border-radius: 0;
    max-height: 75vh;
    width: 100%;
  }

  [part~='content'] {
    flex: auto;
  }

  @media (max-width: 450px), (max-height: 450px) {
    :host {
      inset: auto 0 0 !important;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2015 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DatePickerOverlayMixin = (superClass) => class DatePickerOverlayMixin extends PositionMixin(OverlayMixin(superClass)) {
  /**
   * Override method inherited from `OverlayMixin` to not close on input click.
   * Needed to ignore date-picker's own input in the mousedown listener below.
   *
   * @param {Event} event
   * @return {boolean}
   * @protected
   */
  _shouldCloseOnOutsideClick(event) {
    const eventPath = event.composedPath();
    return !eventPath.includes(this.positionTarget);
  }
  /**
   * @protected
   * @override
   */
  _mouseDownListener(event) {
    super._mouseDownListener(event);
    if (this._shouldCloseOnOutsideClick(event) && !isElementFocusable(event.composedPath()[0])) {
      event.preventDefault();
    }
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DatePickerOverlay extends DatePickerOverlayMixin(
  DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-date-picker-overlay";
  }
  static get styles() {
    return [overlayStyles, datePickerOverlayStyles];
  }
  /** @protected */
  render() {
    return html`
      <div id="backdrop" part="backdrop" ?hidden="${!this.withBackdrop}"></div>
      <div part="overlay" id="overlay">
        <div part="content" id="content">
          <slot></slot>
        </div>
      </div>
    `;
  }
  /**
   * Override method from `OverlayFocusMixin` to specify content root
   * used to detect whether focus should be restored on overlay close.
   *
   * @protected
   * @override
   */
  get _contentRoot() {
    return this.owner._overlayContent;
  }
}
defineCustomElement(DatePickerOverlay);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function getISOWeekNumber(date) {
  let dayOfWeek = date.getDay();
  if (dayOfWeek === 0) {
    dayOfWeek = 7;
  }
  const nearestThursdayDiff = 4 - dayOfWeek;
  const nearestThursday = new Date(date.getTime() + nearestThursdayDiff * 24 * 3600 * 1e3);
  const firstOfJanuary = new Date(0, 0);
  firstOfJanuary.setFullYear(nearestThursday.getFullYear());
  const timeDiff = nearestThursday.getTime() - firstOfJanuary.getTime();
  const daysSinceFirstOfJanuary = Math.round(timeDiff / (24 * 3600 * 1e3));
  return Math.floor(daysSinceFirstOfJanuary / 7 + 1);
}
function normalizeDate(date) {
  const normalizedDate = new Date(date);
  normalizedDate.setHours(0, 0, 0, 0);
  return normalizedDate;
}
function normalizeUTCDate(date) {
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0, 0));
}
function dateEquals(date1, date2, normalizer = normalizeDate) {
  return date1 instanceof Date && date2 instanceof Date && normalizer(date1).getTime() === normalizer(date2).getTime();
}
function extractDateParts(date) {
  return {
    day: date.getDate(),
    month: date.getMonth(),
    year: date.getFullYear()
  };
}
function dateAllowed(date, min2, max2, isDateDisabled) {
  let dateIsDisabled = false;
  if (typeof isDateDisabled === "function" && !!date) {
    const dateToCheck = extractDateParts(date);
    dateIsDisabled = isDateDisabled(dateToCheck);
  }
  return (!min2 || date >= min2) && (!max2 || date <= max2) && !dateIsDisabled;
}
function getClosestDate(date, dates) {
  return dates.filter((date2) => date2 !== void 0).reduce((closestDate, candidate) => {
    if (!candidate) {
      return closestDate;
    }
    if (!closestDate) {
      return candidate;
    }
    const candidateDiff = Math.abs(date.getTime() - candidate.getTime());
    const closestDateDiff = Math.abs(closestDate.getTime() - date.getTime());
    return candidateDiff < closestDateDiff ? candidate : closestDate;
  });
}
function dateAfterXMonths(months) {
  const today = /* @__PURE__ */ new Date();
  const result = new Date(today);
  result.setDate(1);
  result.setMonth(parseInt(months) + today.getMonth());
  return result;
}
function getAdjustedYear(referenceDate, year, month = 0, day = 1) {
  if (year > 99) {
    throw new Error("The provided year cannot have more than 2 digits.");
  }
  if (year < 0) {
    throw new Error("The provided year cannot be negative.");
  }
  let adjustedYear = year + Math.floor(referenceDate.getFullYear() / 100) * 100;
  if (referenceDate < new Date(adjustedYear - 50, month, day)) {
    adjustedYear -= 100;
  } else if (referenceDate > new Date(adjustedYear + 50, month, day)) {
    adjustedYear += 100;
  }
  return adjustedYear;
}
function parseDate(str) {
  const parts = /^([-+]\d{1}|\d{2,4}|[-+]\d{6})-(\d{1,2})-(\d{1,2})$/u.exec(str);
  if (!parts) {
    return void 0;
  }
  const date = new Date(0, 0);
  date.setFullYear(parseInt(parts[1], 10));
  date.setMonth(parseInt(parts[2], 10) - 1);
  date.setDate(parseInt(parts[3], 10));
  return date;
}
function parseUTCDate(str) {
  const parts = /^([-+]\d{1}|\d{2,4}|[-+]\d{6})-(\d{1,2})-(\d{1,2})$/u.exec(str);
  if (!parts) {
    return void 0;
  }
  const date = new Date(Date.UTC(0, 0));
  date.setUTCFullYear(parseInt(parts[1], 10));
  date.setUTCMonth(parseInt(parts[2], 10) - 1);
  date.setUTCDate(parseInt(parts[3], 10));
  return date;
}
function formatISODateBase(dateParts) {
  const pad2 = (num, fmt = "00") => (fmt + num).substr((fmt + num).length - fmt.length);
  let yearSign = "";
  let yearFmt = "0000";
  let yearAbs = dateParts.year;
  if (yearAbs < 0) {
    yearAbs = -yearAbs;
    yearSign = "-";
    yearFmt = "000000";
  } else if (dateParts.year >= 1e4) {
    yearSign = "+";
    yearFmt = "000000";
  }
  const year = yearSign + pad2(yearAbs, yearFmt);
  const month = pad2(dateParts.month + 1);
  const day = pad2(dateParts.day);
  return [year, month, day].join("-");
}
function formatISODate(date) {
  if (!(date instanceof Date)) {
    return "";
  }
  return formatISODateBase({
    year: date.getFullYear(),
    month: date.getMonth(),
    day: date.getDate()
  });
}
function formatUTCISODate(date) {
  if (!(date instanceof Date)) {
    return "";
  }
  return formatISODateBase({
    year: date.getUTCFullYear(),
    month: date.getUTCMonth(),
    day: date.getUTCDate()
  });
}
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const template$2 = document.createElement("template");
template$2.innerHTML = `
  <style>
    :host {
      display: block;
      overflow: hidden;
      height: 500px;
    }

    #scroller {
      position: relative;
      height: 100%;
      overflow: auto;
      outline: none;
      overflow-x: hidden;
      scrollbar-width: none;
    }

    #scroller::-webkit-scrollbar {
      display: none;
    }

    .buffer {
      position: absolute;
      width: var(--vaadin-infinite-scroller-buffer-width, 100%);
      box-sizing: border-box;
      top: var(--vaadin-infinite-scroller-buffer-offset, 0);
    }
  </style>

  <div id="scroller" tabindex="-1">
    <div class="buffer"></div>
    <div class="buffer"></div>
    <div id="fullHeight"></div>
  </div>
`;
class InfiniteScroller extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: "open" });
    root.appendChild(template$2.content.cloneNode(true));
    this.bufferSize = 20;
    this._initialScroll = 5e5;
    this._initialIndex = 0;
    this._activated = false;
  }
  /**
   * @return {boolean}
   */
  get active() {
    return this._activated;
  }
  set active(active) {
    if (active && !this._activated) {
      this._createPool();
      this._activated = true;
    }
  }
  /**
   * @return {number}
   */
  get bufferOffset() {
    return this._buffers[0].offsetTop;
  }
  /**
   * @return {number}
   */
  get itemHeight() {
    if (!this._itemHeightVal) {
      const itemHeight = getComputedStyle(this).getPropertyValue("--vaadin-infinite-scroller-item-height");
      const tmpStyleProp = "background-position";
      this.$.fullHeight.style.setProperty(tmpStyleProp, itemHeight);
      const itemHeightPx = getComputedStyle(this.$.fullHeight).getPropertyValue(tmpStyleProp);
      this.$.fullHeight.style.removeProperty(tmpStyleProp);
      this._itemHeightVal = parseFloat(itemHeightPx);
    }
    return this._itemHeightVal;
  }
  /** @private */
  get _bufferHeight() {
    return this.itemHeight * this.bufferSize;
  }
  /**
   * @return {number}
   */
  get position() {
    return (this.$.scroller.scrollTop - this._buffers[0].translateY) / this.itemHeight + this._firstIndex;
  }
  /**
   * Current scroller position as index. Can be a fractional number.
   *
   * @type {number}
   */
  set position(index) {
    this._preventScrollEvent = true;
    if (index > this._firstIndex && index < this._firstIndex + this.bufferSize * 2) {
      this.$.scroller.scrollTop = this.itemHeight * (index - this._firstIndex) + this._buffers[0].translateY;
    } else {
      this._initialIndex = ~~index;
      this._reset();
      this._scrollDisabled = true;
      this.$.scroller.scrollTop += index % 1 * this.itemHeight;
      this._scrollDisabled = false;
    }
  }
  /** @protected */
  connectedCallback() {
    if (!this._ready) {
      this._ready = true;
      this.$ = {};
      this.shadowRoot.querySelectorAll("[id]").forEach((node) => {
        this.$[node.id] = node;
      });
      this.$.scroller.addEventListener("scroll", () => this._scroll());
      this._buffers = [...this.shadowRoot.querySelectorAll(".buffer")];
      this.$.fullHeight.style.height = `${this._initialScroll * 2}px`;
    }
  }
  /** @protected */
  disconnectedCallback() {
    if (this._debouncerScrollFinish) {
      this._debouncerScrollFinish.cancel();
    }
    if (this._debouncerUpdateClones) {
      this._debouncerUpdateClones.cancel();
    }
    if (this.__pendingFinishInit) {
      cancelAnimationFrame(this.__pendingFinishInit);
    }
  }
  /**
   * Force the scroller to update clones after a reset, without
   * waiting for the debouncer to resolve.
   */
  forceUpdate() {
    if (this._debouncerScrollFinish) {
      this._debouncerScrollFinish.flush();
    }
    if (this._debouncerUpdateClones) {
      this._buffers[0].updated = this._buffers[1].updated = false;
      this._updateClones();
      this._debouncerUpdateClones.cancel();
    }
  }
  /**
   * @protected
   * @override
   */
  _createElement() {
  }
  /**
   * @param {HTMLElement} _element
   * @param {number} _index
   * @protected
   * @override
   */
  _updateElement(_element, _index) {
  }
  /** @private */
  _finishInit() {
    if (!this._initDone) {
      this._buffers.forEach((buffer2) => {
        [...buffer2.children].forEach((slot) => {
          this._ensureStampedInstance(slot._itemWrapper);
        });
      });
      if (!this._buffers[0].translateY) {
        this._reset();
      }
      this._initDone = true;
      this.dispatchEvent(new CustomEvent("init-done"));
    }
  }
  /** @private */
  _translateBuffer(up) {
    const index = up ? 1 : 0;
    this._buffers[index].translateY = this._buffers[index ? 0 : 1].translateY + this._bufferHeight * (index ? -1 : 1);
    this._buffers[index].style.transform = `translate3d(0, ${this._buffers[index].translateY}px, 0)`;
    this._buffers[index].updated = false;
    this._buffers.reverse();
  }
  /** @private */
  _scroll() {
    if (this._scrollDisabled) {
      return;
    }
    const scrollTop = this.$.scroller.scrollTop;
    if (scrollTop < this._bufferHeight || scrollTop > this._initialScroll * 2 - this._bufferHeight) {
      this._initialIndex = ~~this.position;
      this._reset();
    }
    const offset2 = this.itemHeight + this.bufferOffset;
    const upperThresholdReached = scrollTop > this._buffers[1].translateY + offset2;
    const lowerThresholdReached = scrollTop < this._buffers[0].translateY + offset2;
    if (upperThresholdReached || lowerThresholdReached) {
      this._translateBuffer(lowerThresholdReached);
      this._updateClones();
    }
    if (!this._preventScrollEvent) {
      this.dispatchEvent(new CustomEvent("custom-scroll", { bubbles: false, composed: true }));
    }
    this._preventScrollEvent = false;
    this._debouncerScrollFinish = Debouncer.debounce(this._debouncerScrollFinish, timeOut.after(200), () => {
      const scrollerRect = this.$.scroller.getBoundingClientRect();
      if (!this._isVisible(this._buffers[0], scrollerRect) && !this._isVisible(this._buffers[1], scrollerRect)) {
        this.position = this.position;
      }
    });
  }
  /** @private */
  _reset() {
    this._scrollDisabled = true;
    this.$.scroller.scrollTop = this._initialScroll;
    this._buffers[0].translateY = this._initialScroll - this._bufferHeight;
    this._buffers[1].translateY = this._initialScroll;
    this._buffers.forEach((buffer2) => {
      buffer2.style.transform = `translate3d(0, ${buffer2.translateY}px, 0)`;
    });
    this._buffers[0].updated = this._buffers[1].updated = false;
    this._updateClones(true);
    this._debouncerUpdateClones = Debouncer.debounce(this._debouncerUpdateClones, timeOut.after(200), () => {
      this._buffers[0].updated = this._buffers[1].updated = false;
      this._updateClones();
    });
    this._scrollDisabled = false;
  }
  /** @private */
  _createPool() {
    const viewportHeight = this.innerHeight;
    this._buffers.forEach((buffer2) => {
      for (let i = 0; i < this.bufferSize; i++) {
        const itemWrapper = document.createElement("div");
        itemWrapper.style.height = `${this.itemHeight}px`;
        itemWrapper.instance = {};
        const slotName = `vaadin-infinite-scroller-item-content-${generateUniqueId()}`;
        const slot = document.createElement("slot");
        slot.setAttribute("name", slotName);
        slot._itemWrapper = itemWrapper;
        buffer2.appendChild(slot);
        itemWrapper.setAttribute("slot", slotName);
        this.appendChild(itemWrapper);
        if (this.itemHeight * i <= viewportHeight) {
          this._ensureStampedInstance(itemWrapper);
        }
      }
    });
    this.__pendingFinishInit = requestAnimationFrame(() => {
      this._finishInit();
      this.__pendingFinishInit = null;
    });
  }
  /** @private */
  _ensureStampedInstance(itemWrapper) {
    if (itemWrapper.firstElementChild) {
      return;
    }
    const tmpInstance = itemWrapper.instance;
    itemWrapper.instance = this._createElement();
    itemWrapper.appendChild(itemWrapper.instance);
    Object.keys(tmpInstance).forEach((prop) => {
      itemWrapper.instance[prop] = tmpInstance[prop];
    });
  }
  /** @private */
  _updateClones(viewPortOnly) {
    this._firstIndex = Math.round((this._buffers[0].translateY - this._initialScroll) / this.itemHeight) + this._initialIndex;
    const scrollerRect = viewPortOnly ? this.$.scroller.getBoundingClientRect() : void 0;
    this._buffers.forEach((buffer2, bufferIndex) => {
      if (!buffer2.updated) {
        const firstIndex = this._firstIndex + this.bufferSize * bufferIndex;
        [...buffer2.children].forEach((slot, index) => {
          const itemWrapper = slot._itemWrapper;
          if (!viewPortOnly || this._isVisible(itemWrapper, scrollerRect)) {
            this._updateElement(itemWrapper.instance, firstIndex + index);
          }
        });
        buffer2.updated = true;
      }
    });
  }
  /** @private */
  _isVisible(element, container) {
    const rect2 = element.getBoundingClientRect();
    return rect2.bottom > container.top && rect2.top < container.bottom;
  }
}
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const stylesTemplate$1 = document.createElement("template");
stylesTemplate$1.innerHTML = `
  <style>
    :host {
      --vaadin-infinite-scroller-item-height: 270px;
      grid-area: months;
      height: auto;
    }
  </style>
`;
class DatePickerMonthScroller extends InfiniteScroller {
  static get is() {
    return "vaadin-date-picker-month-scroller";
  }
  constructor() {
    super();
    this.bufferSize = 3;
    this.shadowRoot.appendChild(stylesTemplate$1.content.cloneNode(true));
  }
  /**
   * @protected
   * @override
   */
  _createElement() {
    return document.createElement("vaadin-month-calendar");
  }
  /**
   * @param {HTMLElement} element
   * @param {number} index
   * @protected
   * @override
   */
  _updateElement(element, index) {
    element.month = dateAfterXMonths(index);
  }
}
defineCustomElement(DatePickerMonthScroller);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const stylesTemplate = document.createElement("template");
stylesTemplate.innerHTML = `
  <style>
    :host {
      --vaadin-infinite-scroller-item-height: 80px;
      width: 50px;
      display: block;
      position: relative;
      grid-area: years;
      height: auto;
      -webkit-tap-highlight-color: transparent;
      -webkit-user-select: none;
      user-select: none;
      /* Center the year scroller position. */
      --vaadin-infinite-scroller-buffer-offset: 50%;
    }

    :host::before {
      content: '';
      display: block;
      background: transparent;
      width: 0;
      height: 0;
      position: absolute;
      left: 0;
      top: 50%;
      transform: translateY(-50%);
      border-width: 6px;
      border-style: solid;
      border-color: transparent;
      border-left-color: #000;
    }
  </style>
`;
class DatePickerYearScroller extends InfiniteScroller {
  static get is() {
    return "vaadin-date-picker-year-scroller";
  }
  constructor() {
    super();
    this.bufferSize = 12;
    this.shadowRoot.appendChild(stylesTemplate.content.cloneNode(true));
  }
  /**
   * @protected
   * @override
   */
  _createElement() {
    return document.createElement("vaadin-date-picker-year");
  }
  /**
   * @param {HTMLElement} element
   * @param {number} index
   * @protected
   * @override
   */
  _updateElement(element, index) {
    element.year = this._yearAfterXYears(index);
  }
  /** @private */
  _yearAfterXYears(index) {
    const today = /* @__PURE__ */ new Date();
    const result = new Date(today);
    result.setFullYear(parseInt(index) + today.getFullYear());
    return result.getFullYear();
  }
}
defineCustomElement(DatePickerYearScroller);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const datePickerYearStyles = css$h`
  :host {
    display: block;
    height: 100%;
  }

  [part='year-number'] {
    align-items: center;
    display: flex;
    height: 50%;
    justify-content: center;
    transform: translateY(-50%);
    color: var(--vaadin-text-color-secondary);
  }

  :host([current]) [part='year-number'] {
    color: var(--vaadin-date-picker-year-scroller-current-year-color, var(--vaadin-text-color));
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DatePickerYear extends ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))) {
  static get is() {
    return "vaadin-date-picker-year";
  }
  static get styles() {
    return datePickerYearStyles;
  }
  static get properties() {
    return {
      year: {
        type: String,
        sync: true
      },
      selectedDate: {
        type: Object,
        sync: true
      }
    };
  }
  /** @protected */
  render() {
    return html`
      <div part="year-number">${this.year}</div>
      <div part="year-separator" aria-hidden="true"></div>
    `;
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("year")) {
      this.toggleAttribute("current", this.year === (/* @__PURE__ */ new Date()).getFullYear());
    }
    if (props.has("year") || props.has("selectedDate")) {
      this.toggleAttribute("selected", this.selectedDate && this.selectedDate.getFullYear() === this.year);
    }
  }
}
defineCustomElement(DatePickerYear);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const monthCalendarStyles = css$h`
  :host {
    display: block;
    padding: var(--vaadin-date-picker-month-padding, var(--vaadin-padding-s));
  }

  [part='month-header'] {
    color: var(--vaadin-date-picker-month-header-color, var(--vaadin-text-color));
    font-size: var(--vaadin-date-picker-month-header-font-size, 0.9375rem);
    font-weight: var(--vaadin-date-picker-month-header-font-weight, 500);
    line-height: inherit;
    margin-bottom: 0.75rem;
    text-align: center;
  }

  table {
    border-collapse: collapse;
    display: flex;
    flex-direction: column;
  }

  tr {
    display: flex;
    flex-wrap: wrap;
  }

  [part~='weekday'] {
    color: var(--vaadin-date-picker-weekday-color, var(--vaadin-text-color-secondary));
    font-size: var(--vaadin-date-picker-weekday-font-size, 0.75rem);
    font-weight: var(--vaadin-date-picker-weekday-font-weight, 500);
    margin-bottom: 0.375rem;
    width: var(--vaadin-date-picker-date-width, 2rem);
  }

  /* Week numbers are on a separate row, don't reserve space on weekday row. */
  [part~='weekday']:empty {
    display: none;
  }

  [part~='week-number'] {
    color: var(--vaadin-date-picker-week-number-color, var(--vaadin-text-color-secondary));
    font-size: var(--vaadin-date-picker-week-number-font-size, 0.7rem);
    line-height: 1;
    width: 100%;
    margin-top: 0.125em;
    margin-bottom: 0.125em;
    gap: 0.25em;
  }

  [part~='week-number']::after {
    content: '';
    height: 1px;
    flex: 1;
    background: var(
      --vaadin-date-picker-week-divider-color,
      var(--vaadin-divider-color, var(--vaadin-border-color-secondary))
    );
  }

  [part~='weekday'],
  [part~='week-number'],
  [part~='date'] {
    align-items: center;
    display: flex;
    justify-content: center;
    padding: 0;
  }

  [part~='date'] {
    border-radius: var(--vaadin-date-picker-date-border-radius, var(--vaadin-radius-m));
    position: relative;
    width: var(--vaadin-date-picker-date-width, 2rem);
    height: var(--vaadin-date-picker-date-height, 2rem);
    cursor: var(--vaadin-clickable-cursor);
    outline: none;
  }

  [part~='date']::after {
    border-radius: inherit;
    content: '';
    position: absolute;
    z-index: -1;
    height: inherit;
    aspect-ratio: 1;
  }

  :where([part~='date']:focus)::after {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
    outline-offset: calc(var(--vaadin-focus-ring-width) * -1);
  }

  [part~='today'] {
    color: var(--vaadin-date-picker-date-today-color, var(--vaadin-text-color));
  }

  [part~='selected'] {
    color: var(--vaadin-date-picker-date-selected-color, var(--vaadin-background-color));
  }

  [part~='selected']::after {
    background: var(--vaadin-date-picker-date-selected-background, var(--vaadin-text-color));
    outline-offset: 1px;
  }

  [disabled] {
    cursor: var(--vaadin-disabled-cursor);
    color: var(--vaadin-date-picker-date-disabled-color, var(--vaadin-text-color-disabled));
    opacity: 0.7;
  }

  [hidden] {
    display: none;
  }

  @media (forced-colors: active) {
    [part~='week-number']::after {
      background: CanvasText;
    }

    [part~='today'] {
      font-weight: 600;
    }

    [part~='selected'] {
      forced-color-adjust: none;
      --vaadin-date-picker-date-selected-color: SelectedItemText;
      color: SelectedItemText !important;
      --vaadin-date-picker-date-selected-background: SelectedItem;
    }

    [disabled] {
      color: GrayText !important;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const MonthCalendarMixin = (superClass) => class MonthCalendarMixinClass extends FocusMixin(superClass) {
  static get properties() {
    return {
      /**
       * A `Date` object defining the month to be displayed. Only year and
       * month properties are actually used.
       */
      month: {
        type: Object,
        value: /* @__PURE__ */ new Date(),
        sync: true
      },
      /**
       * A `Date` object for the currently selected date.
       */
      selectedDate: {
        type: Object,
        notify: true,
        sync: true
      },
      /**
       * A `Date` object for the currently focused date.
       */
      focusedDate: {
        type: Object
      },
      /**
       * Set true to display ISO-8601 week numbers in the calendar. Notice that
       * displaying week numbers is only supported when `i18n.firstDayOfWeek`
       * is 1 (Monday).
       */
      showWeekNumbers: {
        type: Boolean,
        value: false
      },
      i18n: {
        type: Object
      },
      /**
       * Flag stating whether taps on the component should be ignored.
       */
      ignoreTaps: {
        type: Boolean
      },
      /**
       * The earliest date that can be selected. All earlier dates will be disabled.
       */
      minDate: {
        type: Date,
        value: null,
        sync: true
      },
      /**
       * The latest date that can be selected. All later dates will be disabled.
       */
      maxDate: {
        type: Date,
        value: null,
        sync: true
      },
      /**
       * A function to be used to determine whether the user can select a given date.
       * Receives a `DatePickerDate` object of the date to be selected and should return a
       * boolean.
       * @type {Function | undefined}
       */
      isDateDisabled: {
        type: Function,
        value: () => false
      },
      enteredDate: {
        type: Date
      },
      disabled: {
        type: Boolean,
        reflectToAttribute: true,
        computed: "__computeDisabled(month, minDate, maxDate)"
      },
      /** @protected */
      _days: {
        type: Array,
        computed: "__computeDays(month, i18n, minDate, maxDate, isDateDisabled)"
      },
      /** @protected */
      _weeks: {
        type: Array,
        computed: "__computeWeeks(_days)"
      },
      /** @private */
      _notTapping: {
        type: Boolean
      },
      /** @private */
      __hasFocus: {
        type: Boolean
      }
    };
  }
  static get observers() {
    return ["__focusedDateChanged(focusedDate, _days)", "_showWeekNumbersChanged(showWeekNumbers, i18n)"];
  }
  get focusableDateElement() {
    return [...this.shadowRoot.querySelectorAll("[part~=date]")].find((datePart) => {
      return dateEquals(datePart.date, this.focusedDate);
    });
  }
  /** @protected */
  ready() {
    super.ready();
    addListener(this.$.monthGrid, "tap", this._handleTap.bind(this));
  }
  /** @override */
  _setFocused(focused) {
    super._setFocused(focused);
    this.__hasFocus = focused;
  }
  /**
   * Returns true if all the dates in the month are out of the allowed range
   * @protected
   */
  __computeDisabled(month, minDate, maxDate) {
    const firstDate = new Date(0, 0);
    firstDate.setFullYear(month.getFullYear());
    firstDate.setMonth(month.getMonth());
    firstDate.setDate(1);
    const lastDate = new Date(0, 0);
    lastDate.setFullYear(month.getFullYear());
    lastDate.setMonth(month.getMonth() + 1);
    lastDate.setDate(0);
    if (minDate && maxDate && minDate.getMonth() === maxDate.getMonth() && minDate.getMonth() === month.getMonth() && maxDate.getDate() - minDate.getDate() >= 0) {
      return false;
    }
    return !dateAllowed(firstDate, minDate, maxDate) && !dateAllowed(lastDate, minDate, maxDate);
  }
  /** @protected */
  _getTitle(month, i18n) {
    if (month === void 0 || i18n === void 0) {
      return;
    }
    return i18n.formatTitle(i18n.monthNames[month.getMonth()], month.getFullYear());
  }
  /** @protected */
  _onMonthGridTouchStart() {
    this._notTapping = false;
    setTimeout(() => {
      this._notTapping = true;
    }, 300);
  }
  /** @private */
  _dateAdd(date, delta) {
    date.setDate(date.getDate() + delta);
  }
  /** @private */
  _applyFirstDayOfWeek(weekDayNames, firstDayOfWeek) {
    if (weekDayNames === void 0 || firstDayOfWeek === void 0) {
      return;
    }
    return weekDayNames.slice(firstDayOfWeek).concat(weekDayNames.slice(0, firstDayOfWeek));
  }
  /** @protected */
  __computeWeekDayNames(i18n, showWeekNumbers) {
    if (i18n === void 0 || showWeekNumbers === void 0) {
      return [];
    }
    const { weekdays, weekdaysShort, firstDayOfWeek } = i18n;
    const weekDayNamesShort = this._applyFirstDayOfWeek(weekdaysShort, firstDayOfWeek);
    const weekDayNames = this._applyFirstDayOfWeek(weekdays, firstDayOfWeek);
    return weekDayNames.map((day, index) => {
      return {
        weekDay: day,
        weekDayShort: weekDayNamesShort[index]
      };
    }).slice(0, 7);
  }
  /** @private */
  __focusedDateChanged(focusedDate, days) {
    if (Array.isArray(days) && days.some((date) => dateEquals(date, focusedDate))) {
      this.removeAttribute("aria-hidden");
    } else {
      this.setAttribute("aria-hidden", "true");
    }
  }
  /** @protected */
  _getDate(date) {
    return date ? date.getDate() : "";
  }
  /** @protected */
  __computeShowWeekSeparator(showWeekNumbers, i18n) {
    return showWeekNumbers && i18n && i18n.firstDayOfWeek === 1;
  }
  /** @protected */
  _isToday(date) {
    return dateEquals(/* @__PURE__ */ new Date(), date);
  }
  /** @protected */
  __computeDays(month, i18n) {
    if (month === void 0 || i18n === void 0) {
      return [];
    }
    const date = new Date(0, 0);
    date.setFullYear(month.getFullYear());
    date.setMonth(month.getMonth());
    date.setDate(1);
    while (date.getDay() !== i18n.firstDayOfWeek) {
      this._dateAdd(date, -1);
    }
    const days = [];
    const startMonth = date.getMonth();
    const targetMonth = month.getMonth();
    while (date.getMonth() === targetMonth || date.getMonth() === startMonth) {
      days.push(date.getMonth() === targetMonth ? new Date(date.getTime()) : null);
      this._dateAdd(date, 1);
    }
    return days;
  }
  /** @protected */
  __computeWeeks(days) {
    return days.reduce((acc, day, i) => {
      if (i % 7 === 0) {
        acc.push([]);
      }
      acc[acc.length - 1].push(day);
      return acc;
    }, []);
  }
  /** @protected */
  _handleTap(e) {
    if (!this.ignoreTaps && !this._notTapping && e.target.date && !e.target.hasAttribute("disabled")) {
      this.selectedDate = e.target.date;
      this.dispatchEvent(
        new CustomEvent("date-tap", { detail: { date: e.target.date }, bubbles: true, composed: true })
      );
    }
  }
  /** @protected */
  _preventDefault(e) {
    e.preventDefault();
  }
  /** @protected */
  __computeWeekNumber(days) {
    const date = days.reduce((acc, d) => {
      return !acc && d ? d : acc;
    });
    return getISOWeekNumber(date);
  }
  /** @protected */
  __computeDayAriaLabel(date) {
    if (!date) {
      return "";
    }
    let ariaLabel = `${this._getDate(date)} ${this.i18n.monthNames[date.getMonth()]} ${date.getFullYear()}, ${this.i18n.weekdays[date.getDay()]}`;
    if (this._isToday(date)) {
      ariaLabel += `, ${this.i18n.today}`;
    }
    return ariaLabel;
  }
  /** @private */
  _showWeekNumbersChanged(showWeekNumbers, i18n) {
    if (this.__computeShowWeekSeparator(showWeekNumbers, i18n)) {
      this.setAttribute("week-numbers", "");
    } else {
      this.removeAttribute("week-numbers");
    }
  }
  // eslint-disable-next-line @typescript-eslint/max-params
  __computeDatePart(date, focusedDate, selectedDate, minDate, maxDate, isDateDisabled, enteredDate, hasFocus) {
    const result = ["date"];
    if (this.__isDayDisabled(date, minDate, maxDate, isDateDisabled)) {
      result.push("disabled");
    }
    if (dateEquals(date, focusedDate) && (hasFocus || dateEquals(date, enteredDate))) {
      result.push("focused");
    }
    if (this.__isDaySelected(date, selectedDate)) {
      result.push("selected");
    }
    if (this._isToday(date)) {
      result.push("today");
    }
    if (date < normalizeDate(/* @__PURE__ */ new Date())) {
      result.push("past");
    }
    if (date > normalizeDate(/* @__PURE__ */ new Date())) {
      result.push("future");
    }
    return result.join(" ");
  }
  /** @private */
  __isDaySelected(date, selectedDate) {
    return dateEquals(date, selectedDate);
  }
  /** @private */
  __computeDayAriaSelected(date, selectedDate) {
    return String(this.__isDaySelected(date, selectedDate));
  }
  /** @private */
  __isDayDisabled(date, minDate, maxDate, isDateDisabled) {
    return !dateAllowed(date, minDate, maxDate, isDateDisabled);
  }
  /** @private */
  __computeDayAriaDisabled(date, min2, max2, isDateDisabled) {
    if (date === void 0 || min2 === void 0 && max2 === void 0 && isDateDisabled === void 0) {
      return "false";
    }
    return String(this.__isDayDisabled(date, min2, max2, isDateDisabled));
  }
  /** @private */
  __computeDayTabIndex(date, focusedDate) {
    return dateEquals(date, focusedDate) ? "0" : "-1";
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class MonthCalendar extends MonthCalendarMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-month-calendar";
  }
  static get styles() {
    return monthCalendarStyles;
  }
  /** @protected */
  render() {
    const weekDayNames = this.__computeWeekDayNames(this.i18n, this.showWeekNumbers);
    const weeks = this._weeks;
    const hideWeekSeparator = !this.__computeShowWeekSeparator(this.showWeekNumbers, this.i18n);
    return html`
      <div part="month-header" id="month-header" aria-hidden="true">${this._getTitle(this.month, this.i18n)}</div>
      <table
        id="monthGrid"
        role="grid"
        aria-labelledby="month-header"
        @touchend="${this._preventDefault}"
        @touchstart="${this._onMonthGridTouchStart}"
      >
        <thead id="weekdays-container">
          <tr role="row" part="weekdays">
            <th part="weekday" aria-hidden="true" ?hidden="${hideWeekSeparator}"></th>
            ${weekDayNames.map(
      (item) => html`
                <th role="columnheader" part="weekday" scope="col" abbr="${item.weekDay}" aria-hidden="true">
                  ${item.weekDayShort}
                </th>
              `
    )}
          </tr>
        </thead>
        <tbody id="days-container">
          ${weeks.map(
      (week) => html`
              <tr role="row">
                <td part="week-number" aria-hidden="true" ?hidden="${hideWeekSeparator}">
                  ${this.__computeWeekNumber(week)}
                </td>
                ${week.map((date) => {
        return html`
                    <td
                      role="gridcell"
                      part="${this.__computeDatePart(
          date,
          this.focusedDate,
          this.selectedDate,
          this.minDate,
          this.maxDate,
          this.isDateDisabled,
          this.enteredDate,
          this.__hasFocus
        )}"
                      .date="${date}"
                      ?disabled="${this.__isDayDisabled(date, this.minDate, this.maxDate, this.isDateDisabled)}"
                      tabindex="${this.__computeDayTabIndex(date, this.focusedDate)}"
                      aria-selected="${this.__computeDayAriaSelected(date, this.selectedDate)}"
                      aria-disabled="${this.__computeDayAriaDisabled(
          date,
          this.minDate,
          this.maxDate,
          this.isDateDisabled
        )}"
                      aria-label="${this.__computeDayAriaLabel(date)}"
                      >${this._getDate(date)}</td
                    >
                  `;
      })}
              </tr>
            `
    )}
        </tbody>
      </table>
    `;
  }
}
defineCustomElement(MonthCalendar);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const overlayContentStyles = css$h`
  :host {
    display: grid;
    grid-template-areas:
      'header header'
      'months years'
      'toolbar years';
    grid-template-columns: minmax(0, 1fr) 0;
    height: 100%;
    outline: none;
    overflow: hidden;
  }

  :host([desktop]) {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  :host([fullscreen][years-visible]) {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  [part='years-toggle-button'] {
    display: inline-flex;
    align-items: center;
    border-radius: var(--vaadin-button-border-radius, var(--vaadin-radius-m));
    color: var(--vaadin-text-color);
    font-size: var(--vaadin-button-font-size, inherit);
    font-weight: var(--vaadin-button-font-weight, 500);
    height: var(--vaadin-button-height, auto);
    line-height: var(--vaadin-button-line-height, inherit);
    padding: var(--vaadin-button-padding, var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container));
    cursor: var(--vaadin-clickable-cursor);
  }

  :host([years-visible]) [part='years-toggle-button'] {
    background: var(--vaadin-text-color);
    color: var(--vaadin-background-color);
  }

  [hidden] {
    display: none !important;
  }

  ::slotted([slot='months']) {
    --vaadin-infinite-scroller-item-height: calc(
      16.5rem + var(--_vaadin-date-picker-week-numbers-visible, 0) *
        (var(--vaadin-date-picker-week-number-font-size, 0.7rem) * 1.25 * 6)
    );
  }

  :host([desktop]) ::slotted([slot='months']) {
    border-bottom: 1px solid var(--vaadin-border-color-secondary);
  }

  ::slotted([slot='years']) {
    visibility: hidden;
    background: var(--vaadin-date-picker-year-scroller-background, var(--vaadin-background-container));
    width: var(--vaadin-date-picker-year-scroller-width, 3rem);
    box-sizing: border-box;
    border-inline-start: 1px solid
      var(--vaadin-date-picker-year-scroller-border-color, var(--vaadin-border-color-secondary));
    overflow: visible;
    min-height: 0;
    clip-path: inset(0);
  }

  ::slotted([slot='years'])::before {
    background: var(--vaadin-overlay-background, var(--vaadin-background-color));
    border: 1px solid var(--vaadin-date-picker-year-scroller-border-color, var(--vaadin-border-color-secondary));
    width: 16px;
    height: 16px;
    position: absolute;
    left: auto;
    z-index: 1;
    rotate: 45deg;
    translate: calc(-50% - 1px) -50%;
    transform: none;
  }

  :host([dir='rtl']) ::slotted([slot='years'])::before {
    translate: calc(50% + 1px) -50%;
  }

  :host([desktop]) ::slotted([slot='years']),
  :host([years-visible]) ::slotted([slot='years']) {
    visibility: visible;
  }

  [part='toolbar'] {
    display: flex;
    grid-area: toolbar;
    justify-content: space-between;
    padding: var(--vaadin-date-picker-toolbar-padding, var(--vaadin-padding-s));
  }

  :host([fullscreen]) [part='toolbar'] {
    grid-area: header;
    border-bottom: 1px solid var(--vaadin-border-color-secondary);
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DatePickerOverlayContentMixin = (superClass) => class DatePickerOverlayContentMixin extends superClass {
  static get properties() {
    return {
      scrollDuration: {
        type: Number,
        value: 300
      },
      /**
       * The value for this element.
       */
      selectedDate: {
        type: Object,
        value: null,
        sync: true
      },
      /**
       * Date value which is focused using keyboard.
       */
      focusedDate: {
        type: Object,
        notify: true,
        observer: "_focusedDateChanged",
        sync: true
      },
      _focusedMonthDate: Number,
      /**
       * Date which should be visible when there is no value selected.
       */
      initialPosition: {
        type: Object,
        observer: "_initialPositionChanged",
        sync: true
      },
      _originDate: {
        type: Object,
        value: /* @__PURE__ */ new Date()
      },
      _visibleMonthIndex: Number,
      _desktopMode: {
        type: Boolean,
        observer: "_desktopModeChanged"
      },
      _desktopMediaQuery: {
        type: String,
        value: "(min-width: 375px)"
      },
      i18n: {
        type: Object
      },
      showWeekNumbers: {
        type: Boolean,
        value: false
      },
      _ignoreTaps: Boolean,
      _notTapping: Boolean,
      /**
       * The earliest date that can be selected. All earlier dates will be disabled.
       */
      minDate: {
        type: Object,
        sync: true
      },
      /**
       * The latest date that can be selected. All later dates will be disabled.
       */
      maxDate: {
        type: Object,
        sync: true
      },
      /**
       * A function to be used to determine whether the user can select a given date.
       * Receives a `DatePickerDate` object of the date to be selected and should return a
       * boolean.
       *
       * @type {function(DatePickerDate): boolean | undefined}
       */
      isDateDisabled: {
        type: Function
      },
      enteredDate: {
        type: Date,
        sync: true
      },
      /**
       * Input label
       */
      label: String,
      _cancelButton: {
        type: Object
      },
      _todayButton: {
        type: Object
      },
      calendars: {
        type: Array,
        value: () => []
      },
      years: {
        type: Array,
        value: () => []
      }
    };
  }
  static get observers() {
    return [
      "__updateCalendars(calendars, i18n, minDate, maxDate, selectedDate, focusedDate, showWeekNumbers, _ignoreTaps, _theme, isDateDisabled, enteredDate)",
      "__updateCancelButton(_cancelButton, i18n)",
      "__updateTodayButton(_todayButton, i18n, minDate, maxDate, isDateDisabled)",
      "__updateYears(years, selectedDate, _theme)"
    ];
  }
  /**
   * Whether to scroll to a sub-month position when scrolling to a date.
   * This is active if the month scroller is not large enough to fit a
   * full month. In that case we want to scroll to a position between
   * two months in order to have the focused date in the visible area.
   * @returns {boolean} whether to use sub-month scrolling
   * @private
   */
  get __useSubMonthScrolling() {
    return this._monthScroller.clientHeight < this._monthScroller.itemHeight + this._monthScroller.bufferOffset;
  }
  get focusableDateElement() {
    return this.calendars.map((calendar) => calendar.focusableDateElement).find(Boolean);
  }
  /** @protected */
  _initControllers() {
    this.addController(
      new MediaQueryController(this._desktopMediaQuery, (matches) => {
        this._desktopMode = matches;
      })
    );
    this.addController(
      new SlotController(this, "today-button", "vaadin-button", {
        observe: false,
        initializer: (btn) => {
          btn.setAttribute("theme", "tertiary");
          btn.addEventListener("keydown", (e) => this.__onTodayButtonKeyDown(e));
          btn.addEventListener("click", this._onTodayTap.bind(this));
          this._todayButton = btn;
        }
      })
    );
    this.addController(
      new SlotController(this, "cancel-button", "vaadin-button", {
        observe: false,
        initializer: (btn) => {
          btn.setAttribute("theme", "tertiary");
          btn.addEventListener("keydown", (e) => this.__onCancelButtonKeyDown(e));
          btn.addEventListener("click", this._cancel.bind(this));
          this._cancelButton = btn;
        }
      })
    );
    this.__initMonthScroller();
    this.__initYearScroller();
  }
  reset() {
    this._closeYearScroller();
  }
  /**
   * Focuses the cancel button
   */
  focusCancel() {
    this._cancelButton.focus();
  }
  /**
   * Scrolls the list to the given Date.
   */
  scrollToDate(date, animate2) {
    const offset2 = this.__useSubMonthScrolling ? this._calculateWeekScrollOffset(date) : 0;
    this._scrollToPosition(this._differenceInMonths(date, this._originDate) + offset2, animate2);
    this._monthScroller.forceUpdate();
  }
  /** @private */
  __initMonthScroller() {
    this.addController(
      new SlotController(this, "months", "vaadin-date-picker-month-scroller", {
        observe: false,
        initializer: (scroller) => {
          scroller.addEventListener("custom-scroll", () => {
            this._onMonthScroll();
          });
          scroller.addEventListener("touchstart", () => {
            this._onMonthScrollTouchStart();
          });
          scroller.addEventListener("keydown", (e) => {
            this.__onMonthCalendarKeyDown(e);
          });
          scroller.addEventListener("init-done", () => {
            const calendars = [...this.querySelectorAll("vaadin-month-calendar")];
            calendars.forEach((calendar) => {
              calendar.addEventListener("selected-date-changed", (e) => {
                this.selectedDate = e.detail.value;
              });
            });
            this.calendars = calendars;
          });
          this._monthScroller = scroller;
        }
      })
    );
  }
  /** @private */
  __initYearScroller() {
    this.addController(
      new SlotController(this, "years", "vaadin-date-picker-year-scroller", {
        observe: false,
        initializer: (scroller) => {
          scroller.setAttribute("aria-hidden", "true");
          addListener(scroller, "tap", (e) => {
            this._onYearTap(e);
          });
          scroller.addEventListener("custom-scroll", () => {
            this._onYearScroll();
          });
          scroller.addEventListener("touchstart", () => {
            this._onYearScrollTouchStart();
          });
          scroller.addEventListener("init-done", () => {
            this.years = [...this.querySelectorAll("vaadin-date-picker-year")];
          });
          this._yearScroller = scroller;
        }
      })
    );
  }
  /** @private */
  __updateCancelButton(cancelButton, i18n) {
    if (cancelButton) {
      cancelButton.textContent = i18n && i18n.cancel;
    }
  }
  /** @private */
  __updateTodayButton(todayButton, i18n, minDate, maxDate, isDateDisabled) {
    if (todayButton) {
      todayButton.textContent = i18n && i18n.today;
      todayButton.disabled = !this._isTodayAllowed(minDate, maxDate, isDateDisabled);
    }
  }
  // eslint-disable-next-line @typescript-eslint/max-params
  __updateCalendars(calendars, i18n, minDate, maxDate, selectedDate, focusedDate, showWeekNumbers, ignoreTaps, theme2, isDateDisabled, enteredDate) {
    if (calendars && calendars.length) {
      calendars.forEach((calendar) => {
        calendar.i18n = i18n;
        calendar.minDate = minDate;
        calendar.maxDate = maxDate;
        calendar.isDateDisabled = isDateDisabled;
        calendar.focusedDate = focusedDate;
        calendar.selectedDate = selectedDate;
        calendar.showWeekNumbers = showWeekNumbers;
        calendar.ignoreTaps = ignoreTaps;
        calendar.enteredDate = enteredDate;
        if (theme2) {
          calendar.setAttribute("theme", theme2);
        } else {
          calendar.removeAttribute("theme");
        }
      });
    }
  }
  /** @private */
  __updateYears(years, selectedDate, theme2) {
    if (years && years.length) {
      years.forEach((year) => {
        year.selectedDate = selectedDate;
        if (theme2) {
          year.setAttribute("theme", theme2);
        } else {
          year.removeAttribute("theme");
        }
      });
    }
  }
  /**
   * Select a date and fire event indicating user interaction.
   * @protected
   */
  _selectDate(dateToSelect) {
    if (!this._dateAllowed(dateToSelect)) {
      return false;
    }
    this.selectedDate = dateToSelect;
    this.dispatchEvent(
      new CustomEvent("date-selected", { detail: { date: dateToSelect }, bubbles: true, composed: true })
    );
    return true;
  }
  /** @private */
  _desktopModeChanged(desktopMode) {
    this.toggleAttribute("desktop", desktopMode);
  }
  /** @private */
  _focusedDateChanged(focusedDate) {
    this.revealDate(focusedDate);
  }
  /**
   * Scrolls the month and year scrollers enough to reveal the given date.
   */
  revealDate(date, animate2 = true) {
    if (!date) {
      return;
    }
    const diff = this._differenceInMonths(date, this._originDate);
    if (this.__useSubMonthScrolling) {
      const offset2 = this._calculateWeekScrollOffset(date);
      this._scrollToPosition(diff + offset2, animate2);
      return;
    }
    const scrolledAboveViewport = this._monthScroller.position > diff;
    const visibleArea = Math.max(
      this._monthScroller.itemHeight,
      this._monthScroller.clientHeight - this._monthScroller.bufferOffset * 2
    );
    const visibleItems = visibleArea / this._monthScroller.itemHeight;
    const scrolledBelowViewport = this._monthScroller.position + visibleItems - 1 < diff;
    if (scrolledAboveViewport) {
      this._scrollToPosition(diff, animate2);
    } else if (scrolledBelowViewport) {
      this._scrollToPosition(diff - visibleItems + 1, animate2);
    }
  }
  /**
   * Calculates an offset to be added to the month scroll position
   * when using sub-month scrolling, in order ensure that the week
   * that the date is in is visible even for small scroll areas.
   * As the month scroller uses a month as minimal scroll unit
   * (a value of `1` equals one month), we can not exactly identify
   * the position of a specific week. This is a best effort
   * implementation based on manual testing.
   * @param date the date for which to calculate the offset
   * @returns {number} the offset
   * @private
   */
  _calculateWeekScrollOffset(date) {
    const temp = new Date(0, 0);
    temp.setFullYear(date.getFullYear());
    temp.setMonth(date.getMonth());
    temp.setDate(1);
    let week = 0;
    while (temp.getDate() < date.getDate()) {
      temp.setDate(temp.getDate() + 1);
      if (temp.getDay() === this.i18n.firstDayOfWeek) {
        week += 1;
      }
    }
    return week / 6;
  }
  /** @private */
  _initialPositionChanged(initialPosition) {
    if (this._monthScroller && this._yearScroller) {
      this._monthScroller.active = true;
      this._yearScroller.active = true;
    }
    this.scrollToDate(initialPosition);
  }
  /** @private */
  _repositionYearScroller() {
    const monthPosition = this._monthScroller.position;
    this._visibleMonthIndex = Math.floor(monthPosition);
    this._yearScroller.position = (monthPosition + this._originDate.getMonth()) / 12;
  }
  /** @private */
  _repositionMonthScroller() {
    this._monthScroller.position = this._yearScroller.position * 12 - this._originDate.getMonth();
    this._visibleMonthIndex = Math.floor(this._monthScroller.position);
  }
  /** @private */
  _onMonthScroll() {
    this._repositionYearScroller();
    this._doIgnoreTaps();
  }
  /** @private */
  _onYearScroll() {
    this._repositionMonthScroller();
    this._doIgnoreTaps();
  }
  /** @private */
  _onYearScrollTouchStart() {
    this._notTapping = false;
    setTimeout(() => {
      this._notTapping = true;
    }, 300);
    this._repositionMonthScroller();
  }
  /** @private */
  _onMonthScrollTouchStart() {
    this._repositionYearScroller();
  }
  /** @private */
  _doIgnoreTaps() {
    this._ignoreTaps = true;
    this._debouncer = Debouncer.debounce(this._debouncer, timeOut.after(300), () => {
      this._ignoreTaps = false;
    });
  }
  /** @private */
  _onTodayTap() {
    const today = this._getTodayMidnight();
    if (Math.abs(this._monthScroller.position - this._differenceInMonths(today, this._originDate)) < 1e-3) {
      this._selectDate(today);
      this._close();
    } else {
      this._scrollToCurrentMonth();
    }
  }
  /** @private */
  _scrollToCurrentMonth() {
    if (this.focusedDate) {
      this.focusedDate = /* @__PURE__ */ new Date();
    }
    this.scrollToDate(/* @__PURE__ */ new Date(), true);
  }
  /** @private */
  _onYearTap(e) {
    if (!this._ignoreTaps && !this._notTapping) {
      const scrollDelta = e.detail.y - (this._yearScroller.getBoundingClientRect().top + this._yearScroller.clientHeight / 2);
      const yearDelta = scrollDelta / this._yearScroller.itemHeight;
      this._scrollToPosition(this._monthScroller.position + yearDelta * 12, true);
    }
  }
  /** @private */
  _scrollToPosition(targetPosition, animate2) {
    if (this._targetPosition !== void 0) {
      this._targetPosition = targetPosition;
      return;
    }
    if (!animate2) {
      this._monthScroller.position = targetPosition;
      this._monthScroller.forceUpdate();
      this._targetPosition = void 0;
      this._repositionYearScroller();
      this.__tryFocusDate();
      return;
    }
    this._targetPosition = targetPosition;
    let revealResolve;
    this._revealPromise = new Promise((resolve) => {
      revealResolve = resolve;
    });
    const easingFunction = (t, b, c, d) => {
      t /= d / 2;
      if (t < 1) {
        return c / 2 * t * t + b;
      }
      t -= 1;
      return -c / 2 * (t * (t - 2) - 1) + b;
    };
    let start2 = 0;
    const initialPosition = this._monthScroller.position;
    const smoothScroll = (timestamp) => {
      if (!start2) {
        start2 = timestamp;
      }
      const currentTime = timestamp - start2;
      if (currentTime < this.scrollDuration) {
        const currentPos = easingFunction(
          currentTime,
          initialPosition,
          this._targetPosition - initialPosition,
          this.scrollDuration
        );
        this._monthScroller.position = currentPos;
        window.requestAnimationFrame(smoothScroll);
      } else {
        this.dispatchEvent(
          new CustomEvent("scroll-animation-finished", {
            bubbles: true,
            composed: true,
            detail: {
              position: this._targetPosition,
              oldPosition: initialPosition
            }
          })
        );
        this._monthScroller.position = this._targetPosition;
        this._monthScroller.forceUpdate();
        this._targetPosition = void 0;
        revealResolve();
        this._revealPromise = void 0;
      }
      setTimeout(this._repositionYearScroller.bind(this), 1);
    };
    window.requestAnimationFrame(smoothScroll);
  }
  /** @private */
  _toggleYearScroller() {
    this.toggleAttribute("years-visible");
  }
  /** @private */
  _closeYearScroller() {
    this.removeAttribute("years-visible");
  }
  /** @private */
  _yearAfterXMonths(months) {
    return dateAfterXMonths(months).getFullYear();
  }
  /** @private */
  _differenceInMonths(date1, date2) {
    const months = (date1.getFullYear() - date2.getFullYear()) * 12;
    return months - date2.getMonth() + date1.getMonth();
  }
  /** @private */
  _clear() {
    this._selectDate("");
  }
  /** @private */
  _close() {
    this.dispatchEvent(new CustomEvent("close", { bubbles: true, composed: true }));
  }
  /** @private */
  _cancel() {
    this.focusedDate = this.selectedDate;
    this._close();
  }
  /** @private */
  __toggleDate(date) {
    if (dateEquals(date, this.selectedDate)) {
      this._clear();
      this.focusedDate = date;
    } else {
      this._selectDate(date);
    }
  }
  /** @private */
  __onMonthCalendarKeyDown(event) {
    let handled = false;
    switch (event.key) {
      case "ArrowDown":
        this._moveFocusByDays(7);
        handled = true;
        break;
      case "ArrowUp":
        this._moveFocusByDays(-7);
        handled = true;
        break;
      case "ArrowRight":
        this._moveFocusByDays(this.__isRTL ? -1 : 1);
        handled = true;
        break;
      case "ArrowLeft":
        this._moveFocusByDays(this.__isRTL ? 1 : -1);
        handled = true;
        break;
      case "Enter":
        if (this._selectDate(this.focusedDate)) {
          this._close();
          handled = true;
        }
        break;
      case " ":
        this.__toggleDate(this.focusedDate);
        handled = true;
        break;
      case "Home":
        this._moveFocusInsideMonth(this.focusedDate, "minDate");
        handled = true;
        break;
      case "End":
        this._moveFocusInsideMonth(this.focusedDate, "maxDate");
        handled = true;
        break;
      case "PageDown":
        this._moveFocusByMonths(event.shiftKey ? 12 : 1);
        handled = true;
        break;
      case "PageUp":
        this._moveFocusByMonths(event.shiftKey ? -12 : -1);
        handled = true;
        break;
      case "Tab":
        this._onTabKeyDown(event, "calendar");
        break;
    }
    if (handled) {
      event.preventDefault();
      event.stopPropagation();
    }
  }
  /** @private */
  _onTabKeyDown(event, section) {
    event.stopPropagation();
    switch (section) {
      case "calendar":
        if (event.shiftKey) {
          event.preventDefault();
          if (this.hasAttribute("fullscreen")) {
            this.focusCancel();
          } else {
            this.__focusInput();
          }
        }
        break;
      case "today":
        if (event.shiftKey) {
          event.preventDefault();
          this.focusDateElement();
        }
        break;
      case "cancel":
        if (!event.shiftKey) {
          event.preventDefault();
          if (this.hasAttribute("fullscreen")) {
            this.focusDateElement();
          } else {
            this.__focusInput();
          }
        }
        break;
    }
  }
  /** @private */
  __onTodayButtonKeyDown(event) {
    if (event.key === "Tab") {
      this._onTabKeyDown(event, "today");
    }
  }
  /** @private */
  __onCancelButtonKeyDown(event) {
    if (event.key === "Tab") {
      this._onTabKeyDown(event, "cancel");
    }
  }
  /** @private */
  __focusInput() {
    this.dispatchEvent(new CustomEvent("focus-input", { bubbles: true, composed: true }));
  }
  /** @private */
  __tryFocusDate() {
    const dateToFocus = this.__pendingDateFocus;
    if (dateToFocus) {
      const dateElement = this.focusableDateElement;
      if (dateElement && dateEquals(dateElement.date, this.__pendingDateFocus)) {
        delete this.__pendingDateFocus;
        dateElement.focus();
      }
    }
  }
  async focusDate(date, keepMonth) {
    const dateToFocus = date || this.selectedDate || this.initialPosition || /* @__PURE__ */ new Date();
    this.focusedDate = dateToFocus;
    if (!keepMonth) {
      this._focusedMonthDate = dateToFocus.getDate();
    }
    await this.focusDateElement(false);
  }
  async focusDateElement(reveal = true) {
    this.__pendingDateFocus = this.focusedDate;
    if (!this.calendars.length) {
      await new Promise((resolve) => {
        requestAnimationFrame(() => {
          setTimeout(() => {
            resolve();
          });
        });
      });
    }
    if (reveal) {
      this.revealDate(this.focusedDate);
    }
    if (this._revealPromise) {
      await this._revealPromise;
    }
    this.__tryFocusDate();
  }
  /** @private */
  _focusClosestDate(focus2) {
    this.focusDate(getClosestDate(focus2, [this.minDate, this.maxDate]));
  }
  /** @private */
  _focusAllowedDate(dateToFocus, diff, keepMonth) {
    if (this._dateAllowed(dateToFocus, void 0, void 0, () => false)) {
      this.focusDate(dateToFocus, keepMonth);
    } else if (this._dateAllowed(this.focusedDate)) {
      if (diff > 0) {
        this.focusDate(this.maxDate);
      } else {
        this.focusDate(this.minDate);
      }
    } else {
      this._focusClosestDate(this.focusedDate);
    }
  }
  /** @private */
  _getDateDiff(months, days) {
    const date = new Date(0, 0);
    date.setFullYear(this.focusedDate.getFullYear());
    date.setMonth(this.focusedDate.getMonth() + months);
    if (days) {
      date.setDate(this.focusedDate.getDate() + days);
    }
    return date;
  }
  /** @private */
  _moveFocusByDays(days) {
    const dateToFocus = this._getDateDiff(0, days);
    this._focusAllowedDate(dateToFocus, days, false);
  }
  /** @private */
  _moveFocusByMonths(months) {
    const dateToFocus = this._getDateDiff(months);
    const targetMonth = dateToFocus.getMonth();
    if (!this._focusedMonthDate) {
      this._focusedMonthDate = this.focusedDate.getDate();
    }
    dateToFocus.setDate(this._focusedMonthDate);
    if (dateToFocus.getMonth() !== targetMonth) {
      dateToFocus.setDate(0);
    }
    this._focusAllowedDate(dateToFocus, months, true);
  }
  /** @private */
  _moveFocusInsideMonth(focusedDate, property) {
    const dateToFocus = new Date(0, 0);
    dateToFocus.setFullYear(focusedDate.getFullYear());
    if (property === "minDate") {
      dateToFocus.setMonth(focusedDate.getMonth());
      dateToFocus.setDate(1);
    } else {
      dateToFocus.setMonth(focusedDate.getMonth() + 1);
      dateToFocus.setDate(0);
    }
    if (this._dateAllowed(dateToFocus)) {
      this.focusDate(dateToFocus);
    } else if (this._dateAllowed(focusedDate)) {
      this.focusDate(this[property]);
    } else {
      this._focusClosestDate(focusedDate);
    }
  }
  /** @private */
  _dateAllowed(date, min2 = this.minDate, max2 = this.maxDate, isDateDisabled = this.isDateDisabled) {
    return dateAllowed(date, min2, max2, isDateDisabled);
  }
  /** @private */
  _isTodayAllowed(min2, max2, isDateDisabled) {
    return this._dateAllowed(this._getTodayMidnight(), min2, max2, isDateDisabled);
  }
  /** @private */
  _getTodayMidnight() {
    const today = /* @__PURE__ */ new Date();
    const todayMidnight = new Date(0, 0);
    todayMidnight.setFullYear(today.getFullYear());
    todayMidnight.setMonth(today.getMonth());
    todayMidnight.setDate(today.getDate());
    return todayMidnight;
  }
  /**
   * Fired when the scroller reaches the target scrolling position.
   * @event scroll-animation-finished
   * @param {Number} detail.position new position
   * @param {Number} detail.oldPosition old position
   */
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DatePickerOverlayContent extends DatePickerOverlayContentMixin(
  ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-date-picker-overlay-content";
  }
  static get styles() {
    return overlayContentStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <slot name="months"></slot>
      <slot name="years"></slot>

      <div role="toolbar" part="toolbar">
        <slot name="today-button"></slot>
        <div
          part="years-toggle-button"
          ?hidden="${this._desktopMode}"
          aria-hidden="true"
          @click="${this._toggleYearScroller}"
        >
          ${this._yearAfterXMonths(this._visibleMonthIndex)}
        </div>
        <slot name="cancel-button"></slot>
      </div>
    `;
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    this.setAttribute("role", "dialog");
    this._initControllers();
  }
}
defineCustomElement(DatePickerOverlayContent);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const datePickerStyles = css$h`
  :host([opened]) {
    pointer-events: auto;
  }

  :host([week-numbers]) {
    --_vaadin-date-picker-week-numbers-visible: 1;
  }

  :host([dir='rtl']) [part='input-field'] {
    direction: ltr;
  }

  :host([dir='rtl']) [part='input-field'] ::slotted(input)::placeholder {
    direction: rtl;
    text-align: left;
  }

  [part~='toggle-button']::before {
    mask-image: var(--_vaadin-icon-calendar);
  }

  :host([readonly]) [part~='toggle-button'] {
    display: none;
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const datePickerI18nDefaults = Object.freeze({
  monthNames: [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ],
  weekdays: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
  weekdaysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
  firstDayOfWeek: 0,
  today: "Today",
  cancel: "Cancel",
  referenceDate: "",
  formatDate(d) {
    const yearStr = String(d.year).replace(/\d+/u, (y) => "0000".substr(y.length) + y);
    return [d.month + 1, d.day, yearStr].join("/");
  },
  parseDate(text) {
    const parts = text.split("/");
    const today = /* @__PURE__ */ new Date();
    let date, month = today.getMonth(), year = today.getFullYear();
    if (parts.length === 3) {
      month = parseInt(parts[0]) - 1;
      date = parseInt(parts[1]);
      year = parseInt(parts[2]);
      if (parts[2].length < 3 && year >= 0) {
        const usedReferenceDate = this.referenceDate ? parseDate(this.referenceDate) : /* @__PURE__ */ new Date();
        year = getAdjustedYear(usedReferenceDate, year, month, date);
      }
    } else if (parts.length === 2) {
      month = parseInt(parts[0]) - 1;
      date = parseInt(parts[1]);
    } else if (parts.length === 1) {
      date = parseInt(parts[0]);
    }
    if (date !== void 0) {
      return { day: date, month, year };
    }
  },
  formatTitle: (monthName, fullYear) => {
    return `${monthName} ${fullYear}`;
  }
});
const DatePickerMixin = (subclass) => class DatePickerMixinClass extends I18nMixin(
  datePickerI18nDefaults,
  DelegateFocusMixin(InputConstraintsMixin(KeyboardMixin(subclass)))
) {
  static get properties() {
    return {
      /**
       * The current selected date.
       * @type {Date | undefined}
       * @protected
       */
      _selectedDate: {
        type: Object,
        sync: true
      },
      /**
       * @type {Date | undefined}
       * @protected
       */
      _focusedDate: {
        type: Object,
        sync: true
      },
      /**
       * Selected date.
       *
       * Supported date formats:
       * - ISO 8601 `"YYYY-MM-DD"` (default)
       * - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
       */
      value: {
        type: String,
        notify: true,
        value: "",
        sync: true
      },
      /**
       * Date which should be visible when there is no value selected.
       *
       * The same date formats as for the `value` property are supported.
       * @attr {string} initial-position
       */
      initialPosition: {
        type: String
      },
      /**
       * Set true to open the date selector overlay.
       */
      opened: {
        type: Boolean,
        reflectToAttribute: true,
        notify: true,
        observer: "_openedChanged",
        sync: true
      },
      /**
       * Set true to prevent the overlay from opening automatically.
       * @attr {boolean} auto-open-disabled
       */
      autoOpenDisabled: {
        type: Boolean,
        sync: true
      },
      /**
       * Set true to display ISO-8601 week numbers in the calendar. Notice that
       * displaying week numbers is only supported when `i18n.firstDayOfWeek`
       * is 1 (Monday).
       * @attr {boolean} show-week-numbers
       */
      showWeekNumbers: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * @protected
       */
      _fullscreen: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * @protected
       */
      _fullscreenMediaQuery: {
        value: "(max-width: 450px), (max-height: 450px)"
      },
      /**
       * The earliest date that can be selected. All earlier dates will be disabled.
       *
       * Supported date formats:
       * - ISO 8601 `"YYYY-MM-DD"` (default)
       * - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
       */
      min: {
        type: String,
        sync: true
      },
      /**
       * The latest date that can be selected. All later dates will be disabled.
       *
       * Supported date formats:
       * - ISO 8601 `"YYYY-MM-DD"` (default)
       * - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
       */
      max: {
        type: String,
        sync: true
      },
      /**
       * A function to be used to determine whether the user can select a given date.
       * Receives a `DatePickerDate` object of the date to be selected and should return a
       * boolean.
       *
       * @type {function(DatePickerDate): boolean | undefined}
       */
      isDateDisabled: {
        type: Function
      },
      /**
       * The earliest date that can be selected. All earlier dates will be disabled.
       * @type {Date | undefined}
       * @protected
       */
      _minDate: {
        type: Date,
        computed: "__computeMinOrMaxDate(min)"
      },
      /**
       * The latest date that can be selected. All later dates will be disabled.
       * @type {Date | undefined}
       * @protected
       */
      _maxDate: {
        type: Date,
        computed: "__computeMinOrMaxDate(max)"
      },
      /** @private */
      _noInput: {
        type: Boolean,
        computed: "_isNoInput(inputElement, _fullscreen, _ios, __effectiveI18n, opened, autoOpenDisabled)"
      },
      /** @private */
      _ios: {
        type: Boolean,
        value: isIOS
      },
      /** @private */
      _focusOverlayOnOpen: Boolean,
      /** @private */
      _overlayContent: {
        type: Object,
        sync: true
      },
      /** @private */
      __enteredDate: {
        type: Date,
        sync: true
      }
    };
  }
  static get observers() {
    return [
      "_selectedDateChanged(_selectedDate, __effectiveI18n)",
      "_focusedDateChanged(_focusedDate, __effectiveI18n)",
      "__updateOverlayContent(_overlayContent, __effectiveI18n, label, _minDate, _maxDate, _focusedDate, _selectedDate, showWeekNumbers, isDateDisabled, __enteredDate)",
      "__updateOverlayContentTheme(_overlayContent, _theme)",
      "__updateOverlayContentFullScreen(_overlayContent, _fullscreen)"
    ];
  }
  static get constraints() {
    return [...super.constraints, "min", "max"];
  }
  constructor() {
    super();
    this._boundOnClick = this._onClick.bind(this);
    this._boundOnScroll = this._onScroll.bind(this);
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure and default values:
   *
   * ```js
   * {
   *   // An array with the full names of months starting
   *   // with January.
   *   monthNames: [
   *     'January', 'February', 'March', 'April', 'May',
   *     'June', 'July', 'August', 'September',
   *     'October', 'November', 'December'
   *   ],
   *
   *   // An array of weekday names starting with Sunday. Used
   *   // in screen reader announcements.
   *   weekdays: [
   *     'Sunday', 'Monday', 'Tuesday', 'Wednesday',
   *     'Thursday', 'Friday', 'Saturday'
   *   ],
   *
   *   // An array of short weekday names starting with Sunday.
   *   // Displayed in the calendar.
   *   weekdaysShort: [
   *     'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'
   *   ],
   *
   *   // An integer indicating the first day of the week
   *   // (0 = Sunday, 1 = Monday, etc.).
   *   firstDayOfWeek: 0,
   *
   *   // Translation of the Today shortcut button text.
   *   today: 'Today',
   *
   *   // Translation of the Cancel button text.
   *   cancel: 'Cancel',
   *
   *   // Used for adjusting the year value when parsing dates with short years.
   *   // The year values between 0 and 99 are evaluated and adjusted.
   *   // Example: for a referenceDate of 1970-10-30;
   *   //   dateToBeParsed: 40-10-30, result: 1940-10-30
   *   //   dateToBeParsed: 80-10-30, result: 1980-10-30
   *   //   dateToBeParsed: 10-10-30, result: 2010-10-30
   *   // Supported date format: ISO 8601 `"YYYY-MM-DD"` (default)
   *   // The default value is the current date.
   *   referenceDate: '',
   *
   *   // A function to format given `Object` as
   *   // date string. Object is in the format `{ day: ..., month: ..., year: ... }`
   *   // Note: The argument month is 0-based. This means that January = 0 and December = 11.
   *   formatDate: d => {
   *     // returns a string representation of the given
   *     // object in 'MM/DD/YYYY' -format
   *   },
   *
   *   // A function to parse the given text to an `Object` in the format `{ day: ..., month: ..., year: ... }`.
   *   // Must properly parse (at least) text formatted by `formatDate`.
   *   // Setting the property to null will disable keyboard input feature.
   *   // Note: The argument month is 0-based. This means that January = 0 and December = 11.
   *   parseDate: text => {
   *     // Parses a string in 'MM/DD/YY', 'MM/DD' or 'DD' -format to
   *     // an `Object` in the format `{ day: ..., month: ..., year: ... }`.
   *   }
   *
   *   // A function to format given `monthName` and
   *   // `fullYear` integer as calendar title string.
   *   formatTitle: (monthName, fullYear) => {
   *     return monthName + ' ' + fullYear;
   *   }
   * }
   * ```
   * @type {!DatePickerI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @override */
  get _inputElementValue() {
    return super._inputElementValue;
  }
  /** @override */
  set _inputElementValue(value) {
    super._inputElementValue = value;
    const parsedDate = this.__parseDate(value);
    this.__setEnteredDate(parsedDate);
  }
  /**
   * The input element's value when it cannot be parsed as a date, and an empty string otherwise.
   *
   * @return {string}
   * @private
   */
  get __unparsableValue() {
    if (!this._inputElementValue || this.__parseDate(this._inputElementValue)) {
      return "";
    }
    return this._inputElementValue;
  }
  /**
   * Override an event listener from `DelegateFocusMixin`
   * @protected
   */
  _onFocus(event) {
    super._onFocus(event);
    if (this._noInput && !isKeyboardActive()) {
      event.target.blur();
    }
  }
  /**
   * Override an event listener from `DelegateFocusMixin`
   * @protected
   */
  _onBlur(event) {
    super._onBlur(event);
    if (!this.opened) {
      this.__commitParsedOrFocusedDate();
      if (document.hasFocus()) {
        this._requestValidation();
      }
    }
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("click", this._boundOnClick);
    this.addController(
      new MediaQueryController(this._fullscreenMediaQuery, (matches) => {
        this._fullscreen = matches;
      })
    );
    this.addController(new VirtualKeyboardController(this));
    this._overlayElement = this.$.overlay;
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("showWeekNumbers") || props.has("__effectiveI18n")) {
      this.toggleAttribute("week-numbers", this.showWeekNumbers && this.__effectiveI18n.firstDayOfWeek === 1);
    }
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    this.opened = false;
  }
  /**
   * @param {FocusOptions=} options
   * @protected
   * @override
   */
  focus(options2) {
    if (this._noInput && !isKeyboardActive()) {
      this.open();
    } else {
      super.focus(options2);
    }
  }
  /**
   * Opens the dropdown.
   */
  open() {
    if (!this.disabled && !this.readonly) {
      this.opened = true;
    }
  }
  /**
   * Closes the dropdown.
   */
  close() {
    this.$.overlay.close();
  }
  /** @private */
  __ensureContent() {
    if (this._overlayContent) {
      return;
    }
    const content2 = document.createElement("vaadin-date-picker-overlay-content");
    content2.setAttribute("slot", "overlay");
    this.appendChild(content2);
    this._overlayContent = content2;
    content2.addEventListener("close", () => {
      this._close();
    });
    content2.addEventListener("focus-input", this._focusAndSelect.bind(this));
    content2.addEventListener("date-tap", (e) => {
      this.__commitDate(e.detail.date);
      this._close();
    });
    content2.addEventListener("date-selected", (e) => {
      this.__commitDate(e.detail.date);
    });
    content2.addEventListener("focusin", () => {
      if (this._keyboardActive) {
        this._setFocused(true);
      }
    });
    content2.addEventListener("focusout", (event) => {
      if (this._shouldRemoveFocus(event)) {
        this._setFocused(false);
      }
    });
    content2.addEventListener("focused-date-changed", (e) => {
      this._focusedDate = e.detail.value;
    });
    content2.addEventListener("click", (e) => e.stopPropagation());
  }
  /**
   * @param {string} dateString
   * @private
   */
  __parseDate(dateString) {
    if (!this.__effectiveI18n.parseDate) {
      return;
    }
    let dateObject = this.__effectiveI18n.parseDate(dateString);
    if (dateObject) {
      dateObject = parseDate(`${dateObject.year}-${dateObject.month + 1}-${dateObject.day}`);
    }
    if (dateObject && !isNaN(dateObject.getTime())) {
      return dateObject;
    }
  }
  /**
   * @param {Date} dateObject
   * @private
   */
  __formatDate(dateObject) {
    if (this.__effectiveI18n.formatDate) {
      return this.__effectiveI18n.formatDate(extractDateParts(dateObject));
    }
  }
  /**
   * Returns true if the current input value satisfies all constraints (if any)
   *
   * Override the `checkValidity` method for custom validations.
   *
   * @return {boolean} True if the value is valid
   */
  checkValidity() {
    const inputValue = this._inputElementValue;
    const inputValid = !inputValue || !!this._selectedDate && inputValue === this.__formatDate(this._selectedDate);
    const isDateValid = !this._selectedDate || dateAllowed(this._selectedDate, this._minDate, this._maxDate, this.isDateDisabled);
    let inputValidity = true;
    if (this.inputElement && this.inputElement.checkValidity) {
      inputValidity = this.inputElement.checkValidity();
    }
    return inputValid && isDateValid && inputValidity;
  }
  /**
   * Override method inherited from `FocusMixin`
   * to not call `_setFocused(true)` when focus
   * is restored after closing overlay on click,
   * and to avoid removing `focus-ring` attribute.
   *
   * @param {!FocusEvent} _event
   * @return {boolean}
   * @protected
   * @override
   */
  _shouldSetFocus(_event) {
    return !this._shouldKeepFocusRing;
  }
  /**
   * Override method inherited from `ClearButtonMixin`
   * to not blur on clear button mousedown when opened
   * so that focus remains in the input field.
   *
   * @return {boolean}
   * @protected
   * @override
   */
  _shouldKeepFocusOnClearMousedown() {
    if (this.opened) {
      return true;
    }
    return super._shouldKeepFocusOnClearMousedown();
  }
  /**
   * Override method inherited from `FocusMixin`
   * to prevent removing the `focused` attribute:
   * - when moving focus to the overlay content,
   * - when closing on date click / outside click.
   *
   * @param {FocusEvent} event
   * @return {boolean}
   * @protected
   * @override
   */
  _shouldRemoveFocus(event) {
    const { relatedTarget } = event;
    if (this.opened && relatedTarget !== null && relatedTarget !== document.body && !this.contains(relatedTarget) && !this._overlayContent.contains(relatedTarget)) {
      return true;
    }
    return !this.opened;
  }
  /**
   * Override method inherited from `FocusMixin`
   * to store the `focus-ring` state to restore
   * it later when closing on outside click.
   *
   * @param {boolean} focused
   * @protected
   * @override
   */
  _setFocused(focused) {
    super._setFocused(focused);
    this._shouldKeepFocusRing = focused && this._keyboardActive;
  }
  /**
   * Depending on the nature of the value change that has occurred since
   * the last commit attempt, triggers validation and fires an event:
   *
   * Value change             | Event
   * :------------------------|:------------------
   * empty => parsable        | change
   * empty => unparsable      | unparsable-change
   * parsable => empty        | change
   * parsable => parsable     | change
   * parsable => unparsable   | change
   * unparsable => empty      | unparsable-change
   * unparsable => parsable   | change
   * unparsable => unparsable | unparsable-change
   *
   * @private
   */
  __commitValueChange() {
    const unparsableValue = this.__unparsableValue;
    if (this.__committedValue !== this.value) {
      this._requestValidation();
      this.dispatchEvent(new CustomEvent("change", { bubbles: true }));
    } else if (this.__committedUnparsableValue !== unparsableValue) {
      this._requestValidation();
      this.dispatchEvent(new CustomEvent("unparsable-change"));
    }
    this.__committedValue = this.value;
    this.__committedUnparsableValue = unparsableValue;
  }
  /**
   * Sets the given date as the value and commits it.
   *
   * @param {Date} date
   * @private
   */
  __commitDate(date) {
    this.__keepCommittedValue = true;
    this._selectedDate = date;
    this.__keepCommittedValue = false;
    this.__commitValueChange();
  }
  /** @private */
  _close() {
    this._focus();
    this.close();
  }
  /** @private */
  // eslint-disable-next-line @typescript-eslint/max-params
  _isNoInput(inputElement, fullscreen, ios, effectiveI18n, opened, autoOpenDisabled) {
    const noInputOnFullscreenMode = fullscreen && (!autoOpenDisabled || opened);
    const noInputOnIos = ios && opened;
    return !inputElement || noInputOnFullscreenMode || noInputOnIos || !effectiveI18n.parseDate;
  }
  /** @private */
  _formatISO(date) {
    return formatISODate(date);
  }
  /** @protected */
  _inputElementChanged(input) {
    super._inputElementChanged(input);
    if (input) {
      input.autocomplete = "off";
      input.setAttribute("role", "combobox");
      input.setAttribute("aria-haspopup", "dialog");
      input.setAttribute("aria-expanded", !!this.opened);
      this._applyInputValue(this._selectedDate);
    }
  }
  /** @protected */
  _openedChanged(opened) {
    if (opened) {
      this.__ensureContent();
    }
    if (this.inputElement) {
      this.inputElement.setAttribute("aria-expanded", opened);
    }
  }
  /** @private */
  _selectedDateChanged(selectedDate, effectiveI18n) {
    if (selectedDate === void 0 || effectiveI18n === void 0) {
      return;
    }
    if (!this.__keepInputValue) {
      this._applyInputValue(selectedDate);
    }
    this.value = this._formatISO(selectedDate);
    this._ignoreFocusedDateChange = true;
    this._focusedDate = selectedDate;
    this._ignoreFocusedDateChange = false;
  }
  /** @private */
  _focusedDateChanged(focusedDate, effectiveI18n) {
    if (focusedDate === void 0 || effectiveI18n === void 0) {
      return;
    }
    if (!this._ignoreFocusedDateChange && !this._noInput) {
      this._applyInputValue(focusedDate);
    }
  }
  /**
   * Override the value observer from `InputMixin` to implement custom
   * handling of the `value` property. The date-picker doesn't forward
   * the value directly to the input like the default implementation of `InputMixin`.
   * Instead, it parses the value into a date, puts it in `_selectedDate` which
   * is then displayed in the input with respect to the specified date format.
   *
   * @param {string | undefined} value
   * @param {string | undefined} oldValue
   * @protected
   * @override
   */
  _valueChanged(value, oldValue) {
    const newDate = parseDate(value);
    if (value && !newDate) {
      this.value = oldValue;
      return;
    }
    if (value) {
      if (!dateEquals(this._selectedDate, newDate)) {
        this._selectedDate = newDate;
        if (oldValue !== void 0) {
          this._requestValidation();
        }
      }
    } else {
      this._selectedDate = null;
    }
    if (!this.__keepCommittedValue) {
      this.__committedValue = this.value;
      this.__committedUnparsableValue = "";
    }
    this._toggleHasValue(this._hasValue);
  }
  /** @private */
  // eslint-disable-next-line @typescript-eslint/max-params
  __updateOverlayContent(overlayContent, effectiveI18n, label, minDate, maxDate, focusedDate, selectedDate, showWeekNumbers, isDateDisabled, enteredDate) {
    if (overlayContent) {
      overlayContent.i18n = effectiveI18n;
      overlayContent.label = label;
      overlayContent.minDate = minDate;
      overlayContent.maxDate = maxDate;
      overlayContent.focusedDate = focusedDate;
      overlayContent.selectedDate = selectedDate;
      overlayContent.showWeekNumbers = showWeekNumbers;
      overlayContent.isDateDisabled = isDateDisabled;
      overlayContent.enteredDate = enteredDate;
    }
  }
  /** @private */
  __updateOverlayContentTheme(overlayContent, theme2) {
    if (overlayContent) {
      if (theme2) {
        overlayContent.setAttribute("theme", theme2);
      } else {
        overlayContent.removeAttribute("theme");
      }
    }
  }
  /** @private */
  __updateOverlayContentFullScreen(overlayContent, fullscreen) {
    if (overlayContent) {
      overlayContent.toggleAttribute("fullscreen", fullscreen);
    }
  }
  /** @protected */
  _onOverlayEscapePress(event) {
    event.stopPropagation();
    this._focusedDate = this._selectedDate;
    this._applyInputValue(this._selectedDate);
    this._close();
  }
  /** @protected */
  _onOverlayOpened() {
    const content2 = this._overlayContent;
    content2.reset();
    const initialPosition = this._getInitialPosition();
    content2.initialPosition = initialPosition;
    const scrollFocusDate = content2.focusedDate || initialPosition;
    content2.scrollToDate(scrollFocusDate);
    this._ignoreFocusedDateChange = true;
    content2.focusedDate = scrollFocusDate;
    this._ignoreFocusedDateChange = false;
    window.addEventListener("scroll", this._boundOnScroll, true);
    if (this._focusOverlayOnOpen) {
      content2.focusDateElement();
      this._focusOverlayOnOpen = false;
    } else {
      this._focus();
    }
    const input = this.inputElement;
    if (this._noInput && input) {
      input.blur();
      this._overlayContent.focusDateElement();
    }
    const focusables = this._noInput ? content2 : this;
    this.__showOthers = hideOthers(focusables);
  }
  /** @private */
  _getInitialPosition() {
    const parsedInitialPosition = parseDate(this.initialPosition);
    const initialPosition = this._selectedDate || this._overlayContent.initialPosition || parsedInitialPosition || /* @__PURE__ */ new Date();
    return parsedInitialPosition || dateAllowed(initialPosition, this._minDate, this._maxDate, this.isDateDisabled) ? initialPosition : this._minDate || this._maxDate ? getClosestDate(initialPosition, [this._minDate, this._maxDate]) : /* @__PURE__ */ new Date();
  }
  /**
   * Tries to parse the input element's value as a date. If the input value
   * is parsable, commits the resulting date as the value. Otherwise, commits
   * an empty string as the value. If no i18n parser is provided, commits
   * the focused date as the value.
   *
   * @private
   */
  __commitParsedOrFocusedDate() {
    this._ignoreFocusedDateChange = true;
    if (this.__effectiveI18n.parseDate) {
      const inputValue = this._inputElementValue || "";
      const parsedDate = this.__parseDate(inputValue);
      if (parsedDate) {
        this.__commitDate(parsedDate);
      } else {
        this.__keepInputValue = true;
        this.__commitDate(null);
        this.__keepInputValue = false;
      }
    } else if (this._focusedDate) {
      this.__commitDate(this._focusedDate);
    }
    this._ignoreFocusedDateChange = false;
  }
  /** @protected */
  _onOverlayClosed() {
    if (this.__showOthers) {
      this.__showOthers();
      this.__showOthers = null;
    }
    window.removeEventListener("scroll", this._boundOnScroll, true);
    this.__commitParsedOrFocusedDate();
    if (this.inputElement && this.inputElement.selectionStart) {
      this.inputElement.selectionStart = this.inputElement.selectionEnd;
    }
    if (!this.value && !this._keyboardActive) {
      this._requestValidation();
    }
  }
  /** @private */
  _onScroll(e) {
    if (e.target === window || !this._overlayContent.contains(e.target)) {
      this._overlayContent._repositionYearScroller();
    }
  }
  /** @protected */
  _focus() {
    if (!this._noInput) {
      this.inputElement.focus();
    }
  }
  /** @private */
  _focusAndSelect() {
    this._focus();
    this._setSelectionRange(0, this._inputElementValue.length);
  }
  /** @private */
  _applyInputValue(date) {
    this._inputElementValue = date ? this.__formatDate(date) : "";
  }
  /** @private */
  _setSelectionRange(a, b) {
    if (this.inputElement) {
      this.inputElement.setSelectionRange(a, b);
    }
  }
  /**
   * Override an event listener from `InputConstraintsMixin`
   * to have date-picker fully control when to fire a change event
   * and trigger validation.
   *
   * @protected
   */
  _onChange(event) {
    event.stopPropagation();
  }
  /**
   * @param {Event} event
   * @private
   */
  _onClick(event) {
    if (event.composedPath().includes(this._overlayElement)) {
      return;
    }
    if (!this._isClearButton(event)) {
      this._onHostClick(event);
    }
  }
  /**
   * @param {Event} event
   * @private
   */
  _onHostClick(event) {
    if (!this.autoOpenDisabled || this._noInput) {
      event.preventDefault();
      this.open();
    }
  }
  /**
   * Override an event listener from `InputControlMixin`
   * to validate and dispatch change on clear.
   * @protected
   */
  _onClearButtonClick(event) {
    event.preventDefault();
    this.__commitDate(null);
  }
  /**
   * Override an event listener from `KeyboardMixin`.
   * @param {KeyboardEvent} e
   * @protected
   * @override
   */
  _onKeyDown(e) {
    super._onKeyDown(e);
    if (this._noInput) {
      const allowedKeys = ["Tab", "Escape"];
      if (allowedKeys.indexOf(e.key) === -1) {
        e.preventDefault();
      }
    }
    switch (e.key) {
      case "ArrowDown":
      case "ArrowUp":
        e.preventDefault();
        if (this.opened) {
          this._overlayContent.focusDateElement();
        } else {
          this._focusOverlayOnOpen = true;
          this.open();
        }
        break;
      case "Tab":
        if (this.opened) {
          e.preventDefault();
          e.stopPropagation();
          this._setSelectionRange(0, 0);
          if (e.shiftKey) {
            this._overlayContent.focusCancel();
          } else {
            this._overlayContent.focusDateElement();
          }
        }
        break;
    }
  }
  /**
   * Override an event listener from `KeyboardMixin`.
   *
   * @param {!KeyboardEvent} event
   * @protected
   * @override
   */
  _onEnter(event) {
    if (event.composedPath().includes(this._overlayContent)) {
      return;
    }
    if (this.opened) {
      this.close();
    } else {
      this.__commitParsedOrFocusedDate();
    }
  }
  /**
   * Override an event listener from `KeyboardMixin`.
   * Do not call `super` in order to override clear
   * button logic defined in `InputControlMixin`.
   *
   * @param {!KeyboardEvent} event
   * @protected
   * @override
   */
  _onEscape(event) {
    if (this.opened) {
      this._onOverlayEscapePress(event);
      return;
    }
    if (this.clearButtonVisible && !!this.value && !this.readonly) {
      event.stopPropagation();
      this._onClearButtonClick(event);
      return;
    }
    if (this.inputElement.value === "") {
      this.__commitDate(null);
    } else {
      this._applyInputValue(this._selectedDate);
    }
  }
  /** @protected */
  _isClearButton(event) {
    return event.composedPath()[0] === this.clearElement;
  }
  /**
   * Override an event listener from `InputMixin`
   * @protected
   */
  _onInput() {
    if (!this.opened && this._inputElementValue && !this.autoOpenDisabled) {
      this.open();
    }
    const parsedDate = this.__parseDate(this._inputElementValue || "");
    if (parsedDate) {
      this._ignoreFocusedDateChange = true;
      if (!dateEquals(parsedDate, this._focusedDate)) {
        this._focusedDate = parsedDate;
      }
      this._ignoreFocusedDateChange = false;
    }
    this.__setEnteredDate(parsedDate);
  }
  /**
   * @param {Date} date
   * @private
   */
  __setEnteredDate(date) {
    if (date) {
      if (!dateEquals(this.__enteredDate, date)) {
        this.__enteredDate = date;
      }
    } else {
      this.__enteredDate = null;
    }
  }
  /** @private */
  __computeMinOrMaxDate(dateString) {
    return parseDate(dateString);
  }
  /**
   * Fired when the user commits a value change.
   *
   * @event change
   */
  /**
   * Fired when `value` property value changes.
   *
   * @event value-changed
   */
  /**
   * Fired when `opened` property value changes.
   *
   * @event opened-changed
   */
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DatePicker extends DatePickerMixin(
  InputControlMixin(ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-date-picker";
  }
  static get styles() {
    return [inputFieldShared, datePickerStyles];
  }
  static get properties() {
    return {
      /** @private */
      _positionTarget: {
        type: Object,
        sync: true
      }
    };
  }
  /**
   * Used by `InputControlMixin` as a reference to the clear button element.
   * @protected
   * @return {!HTMLElement}
   */
  get clearElement() {
    return this.$.clearButton;
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-date-picker-container">
        <div part="label">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true" @click="${this.focus}"></span>
        </div>

        <vaadin-input-container
          part="input-field"
          .readonly="${this.readonly}"
          .disabled="${this.disabled}"
          .invalid="${this.invalid}"
          theme="${ifDefined(this._theme)}"
        >
          <slot name="prefix" slot="prefix"></slot>
          <slot name="input"></slot>
          <div id="clearButton" part="field-button clear-button" slot="suffix" aria-hidden="true"></div>
          <div part="field-button toggle-button" slot="suffix" aria-hidden="true" @click="${this._toggle}"></div>
        </vaadin-input-container>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>

        <slot name="tooltip"></slot>
      </div>

      <vaadin-date-picker-overlay
        id="overlay"
        .owner="${this}"
        ?fullscreen="${this._fullscreen}"
        theme="${ifDefined(this._theme)}"
        .opened="${this.opened}"
        @opened-changed="${this._onOpenedChanged}"
        @vaadin-overlay-open="${this._onOverlayOpened}"
        @vaadin-overlay-close="${this._onVaadinOverlayClose}"
        @vaadin-overlay-closing="${this._onOverlayClosed}"
        restore-focus-on-close
        no-vertical-overlap
        exportparts="backdrop, overlay, content"
        .restoreFocusNode="${this.inputElement}"
        .positionTarget="${this._positionTarget}"
      >
        <slot name="overlay"></slot>
      </vaadin-date-picker-overlay>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(
      new InputController(
        this,
        (input) => {
          this._setInputElement(input);
          this._setFocusElement(input);
          this.stateTarget = input;
          this.ariaTarget = input;
        },
        {
          // The "search" word is a trick to prevent Safari from enabling AutoFill,
          // which is causing click issues:
          // https://github.com/vaadin/web-components/issues/6817#issuecomment-2268229567
          uniqueIdPrefix: "search-input"
        }
      )
    );
    this.addController(new LabelledInputController(this.inputElement, this._labelController));
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
    this._tooltipController.setPosition("top");
    this._tooltipController.setAriaTarget(this.inputElement);
    this._tooltipController.setShouldShow((target) => !target.opened);
    this._positionTarget = this.shadowRoot.querySelector('[part="input-field"]');
    const toggleButton = this.shadowRoot.querySelector('[part="field-button toggle-button"]');
    toggleButton.addEventListener("mousedown", (e) => e.preventDefault());
  }
  /** @private */
  _onOpenedChanged(event) {
    this.opened = event.detail.value;
  }
  /** @private */
  _onVaadinOverlayClose(e) {
    const event = e.detail.sourceEvent;
    if (event && event.composedPath().includes(this) && !event.composedPath().includes(this._overlayElement)) {
      e.preventDefault();
    }
  }
  /** @private */
  _toggle(e) {
    e.stopPropagation();
    if (this.$.overlay.opened) {
      this.close();
    } else {
      this.open();
    }
  }
}
defineCustomElement(DatePicker);
const formatDistanceLocale = {
  lessThanXSeconds: {
    one: "less than a second",
    other: "less than {{count}} seconds"
  },
  xSeconds: {
    one: "1 second",
    other: "{{count}} seconds"
  },
  halfAMinute: "half a minute",
  lessThanXMinutes: {
    one: "less than a minute",
    other: "less than {{count}} minutes"
  },
  xMinutes: {
    one: "1 minute",
    other: "{{count}} minutes"
  },
  aboutXHours: {
    one: "about 1 hour",
    other: "about {{count}} hours"
  },
  xHours: {
    one: "1 hour",
    other: "{{count}} hours"
  },
  xDays: {
    one: "1 day",
    other: "{{count}} days"
  },
  aboutXWeeks: {
    one: "about 1 week",
    other: "about {{count}} weeks"
  },
  xWeeks: {
    one: "1 week",
    other: "{{count}} weeks"
  },
  aboutXMonths: {
    one: "about 1 month",
    other: "about {{count}} months"
  },
  xMonths: {
    one: "1 month",
    other: "{{count}} months"
  },
  aboutXYears: {
    one: "about 1 year",
    other: "about {{count}} years"
  },
  xYears: {
    one: "1 year",
    other: "{{count}} years"
  },
  overXYears: {
    one: "over 1 year",
    other: "over {{count}} years"
  },
  almostXYears: {
    one: "almost 1 year",
    other: "almost {{count}} years"
  }
};
const formatDistance = (token, count, options2) => {
  let result;
  const tokenValue = formatDistanceLocale[token];
  if (typeof tokenValue === "string") {
    result = tokenValue;
  } else if (count === 1) {
    result = tokenValue.one;
  } else {
    result = tokenValue.other.replace("{{count}}", count.toString());
  }
  if (options2?.addSuffix) {
    if (options2.comparison && options2.comparison > 0) {
      return "in " + result;
    } else {
      return result + " ago";
    }
  }
  return result;
};
function buildFormatLongFn(args) {
  return (options2 = {}) => {
    const width = options2.width ? String(options2.width) : args.defaultWidth;
    const format2 = args.formats[width] || args.formats[args.defaultWidth];
    return format2;
  };
}
const dateFormats = {
  full: "EEEE, MMMM do, y",
  long: "MMMM do, y",
  medium: "MMM d, y",
  short: "MM/dd/yyyy"
};
const timeFormats = {
  full: "h:mm:ss a zzzz",
  long: "h:mm:ss a z",
  medium: "h:mm:ss a",
  short: "h:mm a"
};
const dateTimeFormats = {
  full: "{{date}} 'at' {{time}}",
  long: "{{date}} 'at' {{time}}",
  medium: "{{date}}, {{time}}",
  short: "{{date}}, {{time}}"
};
const formatLong = {
  date: buildFormatLongFn({
    formats: dateFormats,
    defaultWidth: "full"
  }),
  time: buildFormatLongFn({
    formats: timeFormats,
    defaultWidth: "full"
  }),
  dateTime: buildFormatLongFn({
    formats: dateTimeFormats,
    defaultWidth: "full"
  })
};
const formatRelativeLocale = {
  lastWeek: "'last' eeee 'at' p",
  yesterday: "'yesterday at' p",
  today: "'today at' p",
  tomorrow: "'tomorrow at' p",
  nextWeek: "eeee 'at' p",
  other: "P"
};
const formatRelative = (token, _date, _baseDate, _options) => formatRelativeLocale[token];
function buildLocalizeFn(args) {
  return (value, options2) => {
    const context = options2?.context ? String(options2.context) : "standalone";
    let valuesArray;
    if (context === "formatting" && args.formattingValues) {
      const defaultWidth = args.defaultFormattingWidth || args.defaultWidth;
      const width = options2?.width ? String(options2.width) : defaultWidth;
      valuesArray = args.formattingValues[width] || args.formattingValues[defaultWidth];
    } else {
      const defaultWidth = args.defaultWidth;
      const width = options2?.width ? String(options2.width) : args.defaultWidth;
      valuesArray = args.values[width] || args.values[defaultWidth];
    }
    const index = args.argumentCallback ? args.argumentCallback(value) : value;
    return valuesArray[index];
  };
}
const eraValues = {
  narrow: ["B", "A"],
  abbreviated: ["BC", "AD"],
  wide: ["Before Christ", "Anno Domini"]
};
const quarterValues = {
  narrow: ["1", "2", "3", "4"],
  abbreviated: ["Q1", "Q2", "Q3", "Q4"],
  wide: ["1st quarter", "2nd quarter", "3rd quarter", "4th quarter"]
};
const monthValues = {
  narrow: ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
  abbreviated: [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
  ],
  wide: [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ]
};
const dayValues = {
  narrow: ["S", "M", "T", "W", "T", "F", "S"],
  short: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
  abbreviated: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
  wide: [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
  ]
};
const dayPeriodValues = {
  narrow: {
    am: "a",
    pm: "p",
    midnight: "mi",
    noon: "n",
    morning: "morning",
    afternoon: "afternoon",
    evening: "evening",
    night: "night"
  },
  abbreviated: {
    am: "AM",
    pm: "PM",
    midnight: "midnight",
    noon: "noon",
    morning: "morning",
    afternoon: "afternoon",
    evening: "evening",
    night: "night"
  },
  wide: {
    am: "a.m.",
    pm: "p.m.",
    midnight: "midnight",
    noon: "noon",
    morning: "morning",
    afternoon: "afternoon",
    evening: "evening",
    night: "night"
  }
};
const formattingDayPeriodValues = {
  narrow: {
    am: "a",
    pm: "p",
    midnight: "mi",
    noon: "n",
    morning: "in the morning",
    afternoon: "in the afternoon",
    evening: "in the evening",
    night: "at night"
  },
  abbreviated: {
    am: "AM",
    pm: "PM",
    midnight: "midnight",
    noon: "noon",
    morning: "in the morning",
    afternoon: "in the afternoon",
    evening: "in the evening",
    night: "at night"
  },
  wide: {
    am: "a.m.",
    pm: "p.m.",
    midnight: "midnight",
    noon: "noon",
    morning: "in the morning",
    afternoon: "in the afternoon",
    evening: "in the evening",
    night: "at night"
  }
};
const ordinalNumber = (dirtyNumber, _options) => {
  const number = Number(dirtyNumber);
  const rem100 = number % 100;
  if (rem100 > 20 || rem100 < 10) {
    switch (rem100 % 10) {
      case 1:
        return number + "st";
      case 2:
        return number + "nd";
      case 3:
        return number + "rd";
    }
  }
  return number + "th";
};
const localize = {
  ordinalNumber,
  era: buildLocalizeFn({
    values: eraValues,
    defaultWidth: "wide"
  }),
  quarter: buildLocalizeFn({
    values: quarterValues,
    defaultWidth: "wide",
    argumentCallback: (quarter) => quarter - 1
  }),
  month: buildLocalizeFn({
    values: monthValues,
    defaultWidth: "wide"
  }),
  day: buildLocalizeFn({
    values: dayValues,
    defaultWidth: "wide"
  }),
  dayPeriod: buildLocalizeFn({
    values: dayPeriodValues,
    defaultWidth: "wide",
    formattingValues: formattingDayPeriodValues,
    defaultFormattingWidth: "wide"
  })
};
function buildMatchFn(args) {
  return (string, options2 = {}) => {
    const width = options2.width;
    const matchPattern = width && args.matchPatterns[width] || args.matchPatterns[args.defaultMatchWidth];
    const matchResult = string.match(matchPattern);
    if (!matchResult) {
      return null;
    }
    const matchedString = matchResult[0];
    const parsePatterns = width && args.parsePatterns[width] || args.parsePatterns[args.defaultParseWidth];
    const key2 = Array.isArray(parsePatterns) ? findIndex(parsePatterns, (pattern) => pattern.test(matchedString)) : (
      // [TODO] -- I challenge you to fix the type
      findKey(parsePatterns, (pattern) => pattern.test(matchedString))
    );
    let value;
    value = args.valueCallback ? args.valueCallback(key2) : key2;
    value = options2.valueCallback ? (
      // [TODO] -- I challenge you to fix the type
      options2.valueCallback(value)
    ) : value;
    const rest = string.slice(matchedString.length);
    return { value, rest };
  };
}
function findKey(object, predicate) {
  for (const key2 in object) {
    if (Object.prototype.hasOwnProperty.call(object, key2) && predicate(object[key2])) {
      return key2;
    }
  }
  return void 0;
}
function findIndex(array, predicate) {
  for (let key2 = 0; key2 < array.length; key2++) {
    if (predicate(array[key2])) {
      return key2;
    }
  }
  return void 0;
}
function buildMatchPatternFn(args) {
  return (string, options2 = {}) => {
    const matchResult = string.match(args.matchPattern);
    if (!matchResult) return null;
    const matchedString = matchResult[0];
    const parseResult = string.match(args.parsePattern);
    if (!parseResult) return null;
    let value = args.valueCallback ? args.valueCallback(parseResult[0]) : parseResult[0];
    value = options2.valueCallback ? options2.valueCallback(value) : value;
    const rest = string.slice(matchedString.length);
    return { value, rest };
  };
}
const matchOrdinalNumberPattern = /^(\d+)(th|st|nd|rd)?/i;
const parseOrdinalNumberPattern = /\d+/i;
const matchEraPatterns = {
  narrow: /^(b|a)/i,
  abbreviated: /^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,
  wide: /^(before christ|before common era|anno domini|common era)/i
};
const parseEraPatterns = {
  any: [/^b/i, /^(a|c)/i]
};
const matchQuarterPatterns = {
  narrow: /^[1234]/i,
  abbreviated: /^q[1234]/i,
  wide: /^[1234](th|st|nd|rd)? quarter/i
};
const parseQuarterPatterns = {
  any: [/1/i, /2/i, /3/i, /4/i]
};
const matchMonthPatterns = {
  narrow: /^[jfmasond]/i,
  abbreviated: /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,
  wide: /^(january|february|march|april|may|june|july|august|september|october|november|december)/i
};
const parseMonthPatterns = {
  narrow: [
    /^j/i,
    /^f/i,
    /^m/i,
    /^a/i,
    /^m/i,
    /^j/i,
    /^j/i,
    /^a/i,
    /^s/i,
    /^o/i,
    /^n/i,
    /^d/i
  ],
  any: [
    /^ja/i,
    /^f/i,
    /^mar/i,
    /^ap/i,
    /^may/i,
    /^jun/i,
    /^jul/i,
    /^au/i,
    /^s/i,
    /^o/i,
    /^n/i,
    /^d/i
  ]
};
const matchDayPatterns = {
  narrow: /^[smtwf]/i,
  short: /^(su|mo|tu|we|th|fr|sa)/i,
  abbreviated: /^(sun|mon|tue|wed|thu|fri|sat)/i,
  wide: /^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i
};
const parseDayPatterns = {
  narrow: [/^s/i, /^m/i, /^t/i, /^w/i, /^t/i, /^f/i, /^s/i],
  any: [/^su/i, /^m/i, /^tu/i, /^w/i, /^th/i, /^f/i, /^sa/i]
};
const matchDayPeriodPatterns = {
  narrow: /^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,
  any: /^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i
};
const parseDayPeriodPatterns = {
  any: {
    am: /^a/i,
    pm: /^p/i,
    midnight: /^mi/i,
    noon: /^no/i,
    morning: /morning/i,
    afternoon: /afternoon/i,
    evening: /evening/i,
    night: /night/i
  }
};
const match$1 = {
  ordinalNumber: buildMatchPatternFn({
    matchPattern: matchOrdinalNumberPattern,
    parsePattern: parseOrdinalNumberPattern,
    valueCallback: (value) => parseInt(value, 10)
  }),
  era: buildMatchFn({
    matchPatterns: matchEraPatterns,
    defaultMatchWidth: "wide",
    parsePatterns: parseEraPatterns,
    defaultParseWidth: "any"
  }),
  quarter: buildMatchFn({
    matchPatterns: matchQuarterPatterns,
    defaultMatchWidth: "wide",
    parsePatterns: parseQuarterPatterns,
    defaultParseWidth: "any",
    valueCallback: (index) => index + 1
  }),
  month: buildMatchFn({
    matchPatterns: matchMonthPatterns,
    defaultMatchWidth: "wide",
    parsePatterns: parseMonthPatterns,
    defaultParseWidth: "any"
  }),
  day: buildMatchFn({
    matchPatterns: matchDayPatterns,
    defaultMatchWidth: "wide",
    parsePatterns: parseDayPatterns,
    defaultParseWidth: "any"
  }),
  dayPeriod: buildMatchFn({
    matchPatterns: matchDayPeriodPatterns,
    defaultMatchWidth: "any",
    parsePatterns: parseDayPeriodPatterns,
    defaultParseWidth: "any"
  })
};
const enUS = {
  code: "en-US",
  formatDistance,
  formatLong,
  formatRelative,
  localize,
  match: match$1,
  options: {
    weekStartsOn: 0,
    firstWeekContainsDate: 1
  }
};
let defaultOptions = {};
function getDefaultOptions$1() {
  return defaultOptions;
}
const millisecondsInWeek = 6048e5;
const millisecondsInDay = 864e5;
const millisecondsInMinute = 6e4;
const millisecondsInHour = 36e5;
const millisecondsInSecond = 1e3;
const constructFromSymbol = /* @__PURE__ */ Symbol.for("constructDateFrom");
function constructFrom(date, value) {
  if (typeof date === "function") return date(value);
  if (date && typeof date === "object" && constructFromSymbol in date)
    return date[constructFromSymbol](value);
  if (date instanceof Date) return new date.constructor(value);
  return new Date(value);
}
function toDate(argument, context) {
  return constructFrom(context || argument, argument);
}
function getTimezoneOffsetInMilliseconds(date) {
  const _date = toDate(date);
  const utcDate = new Date(
    Date.UTC(
      _date.getFullYear(),
      _date.getMonth(),
      _date.getDate(),
      _date.getHours(),
      _date.getMinutes(),
      _date.getSeconds(),
      _date.getMilliseconds()
    )
  );
  utcDate.setUTCFullYear(_date.getFullYear());
  return +date - +utcDate;
}
function normalizeDates(context, ...dates) {
  const normalize = constructFrom.bind(
    null,
    dates.find((date) => typeof date === "object")
  );
  return dates.map(normalize);
}
function startOfDay(date, options2) {
  const _date = toDate(date, options2?.in);
  _date.setHours(0, 0, 0, 0);
  return _date;
}
function differenceInCalendarDays(laterDate, earlierDate, options2) {
  const [laterDate_, earlierDate_] = normalizeDates(
    options2?.in,
    laterDate,
    earlierDate
  );
  const laterStartOfDay = startOfDay(laterDate_);
  const earlierStartOfDay = startOfDay(earlierDate_);
  const laterTimestamp = +laterStartOfDay - getTimezoneOffsetInMilliseconds(laterStartOfDay);
  const earlierTimestamp = +earlierStartOfDay - getTimezoneOffsetInMilliseconds(earlierStartOfDay);
  return Math.round((laterTimestamp - earlierTimestamp) / millisecondsInDay);
}
function startOfYear(date, options2) {
  const date_ = toDate(date, options2?.in);
  date_.setFullYear(date_.getFullYear(), 0, 1);
  date_.setHours(0, 0, 0, 0);
  return date_;
}
function getDayOfYear(date, options2) {
  const _date = toDate(date, options2?.in);
  const diff = differenceInCalendarDays(_date, startOfYear(_date));
  const dayOfYear = diff + 1;
  return dayOfYear;
}
function startOfWeek(date, options2) {
  const defaultOptions2 = getDefaultOptions$1();
  const weekStartsOn = options2?.weekStartsOn ?? options2?.locale?.options?.weekStartsOn ?? defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
  const _date = toDate(date, options2?.in);
  const day = _date.getDay();
  const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
  _date.setDate(_date.getDate() - diff);
  _date.setHours(0, 0, 0, 0);
  return _date;
}
function startOfISOWeek(date, options2) {
  return startOfWeek(date, { ...options2, weekStartsOn: 1 });
}
function getISOWeekYear(date, options2) {
  const _date = toDate(date, options2?.in);
  const year = _date.getFullYear();
  const fourthOfJanuaryOfNextYear = constructFrom(_date, 0);
  fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4);
  fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0);
  const startOfNextYear = startOfISOWeek(fourthOfJanuaryOfNextYear);
  const fourthOfJanuaryOfThisYear = constructFrom(_date, 0);
  fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4);
  fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0);
  const startOfThisYear = startOfISOWeek(fourthOfJanuaryOfThisYear);
  if (_date.getTime() >= startOfNextYear.getTime()) {
    return year + 1;
  } else if (_date.getTime() >= startOfThisYear.getTime()) {
    return year;
  } else {
    return year - 1;
  }
}
function startOfISOWeekYear(date, options2) {
  const year = getISOWeekYear(date, options2);
  const fourthOfJanuary = constructFrom(date, 0);
  fourthOfJanuary.setFullYear(year, 0, 4);
  fourthOfJanuary.setHours(0, 0, 0, 0);
  return startOfISOWeek(fourthOfJanuary);
}
function getISOWeek(date, options2) {
  const _date = toDate(date, options2?.in);
  const diff = +startOfISOWeek(_date) - +startOfISOWeekYear(_date);
  return Math.round(diff / millisecondsInWeek) + 1;
}
function getWeekYear(date, options2) {
  const _date = toDate(date, options2?.in);
  const year = _date.getFullYear();
  const defaultOptions2 = getDefaultOptions$1();
  const firstWeekContainsDate = options2?.firstWeekContainsDate ?? options2?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
  const firstWeekOfNextYear = constructFrom(options2?.in || date, 0);
  firstWeekOfNextYear.setFullYear(year + 1, 0, firstWeekContainsDate);
  firstWeekOfNextYear.setHours(0, 0, 0, 0);
  const startOfNextYear = startOfWeek(firstWeekOfNextYear, options2);
  const firstWeekOfThisYear = constructFrom(options2?.in || date, 0);
  firstWeekOfThisYear.setFullYear(year, 0, firstWeekContainsDate);
  firstWeekOfThisYear.setHours(0, 0, 0, 0);
  const startOfThisYear = startOfWeek(firstWeekOfThisYear, options2);
  if (+_date >= +startOfNextYear) {
    return year + 1;
  } else if (+_date >= +startOfThisYear) {
    return year;
  } else {
    return year - 1;
  }
}
function startOfWeekYear(date, options2) {
  const defaultOptions2 = getDefaultOptions$1();
  const firstWeekContainsDate = options2?.firstWeekContainsDate ?? options2?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
  const year = getWeekYear(date, options2);
  const firstWeek = constructFrom(options2?.in || date, 0);
  firstWeek.setFullYear(year, 0, firstWeekContainsDate);
  firstWeek.setHours(0, 0, 0, 0);
  const _date = startOfWeek(firstWeek, options2);
  return _date;
}
function getWeek(date, options2) {
  const _date = toDate(date, options2?.in);
  const diff = +startOfWeek(_date, options2) - +startOfWeekYear(_date, options2);
  return Math.round(diff / millisecondsInWeek) + 1;
}
function addLeadingZeros(number, targetLength) {
  const sign2 = number < 0 ? "-" : "";
  const output = Math.abs(number).toString().padStart(targetLength, "0");
  return sign2 + output;
}
const lightFormatters = {
  // Year
  y(date, token) {
    const signedYear = date.getFullYear();
    const year = signedYear > 0 ? signedYear : 1 - signedYear;
    return addLeadingZeros(token === "yy" ? year % 100 : year, token.length);
  },
  // Month
  M(date, token) {
    const month = date.getMonth();
    return token === "M" ? String(month + 1) : addLeadingZeros(month + 1, 2);
  },
  // Day of the month
  d(date, token) {
    return addLeadingZeros(date.getDate(), token.length);
  },
  // AM or PM
  a(date, token) {
    const dayPeriodEnumValue = date.getHours() / 12 >= 1 ? "pm" : "am";
    switch (token) {
      case "a":
      case "aa":
        return dayPeriodEnumValue.toUpperCase();
      case "aaa":
        return dayPeriodEnumValue;
      case "aaaaa":
        return dayPeriodEnumValue[0];
      case "aaaa":
      default:
        return dayPeriodEnumValue === "am" ? "a.m." : "p.m.";
    }
  },
  // Hour [1-12]
  h(date, token) {
    return addLeadingZeros(date.getHours() % 12 || 12, token.length);
  },
  // Hour [0-23]
  H(date, token) {
    return addLeadingZeros(date.getHours(), token.length);
  },
  // Minute
  m(date, token) {
    return addLeadingZeros(date.getMinutes(), token.length);
  },
  // Second
  s(date, token) {
    return addLeadingZeros(date.getSeconds(), token.length);
  },
  // Fraction of second
  S(date, token) {
    const numberOfDigits = token.length;
    const milliseconds = date.getMilliseconds();
    const fractionalSeconds = Math.trunc(
      milliseconds * Math.pow(10, numberOfDigits - 3)
    );
    return addLeadingZeros(fractionalSeconds, token.length);
  }
};
const dayPeriodEnum = {
  midnight: "midnight",
  noon: "noon",
  morning: "morning",
  afternoon: "afternoon",
  evening: "evening",
  night: "night"
};
const formatters = {
  // Era
  G: function(date, token, localize2) {
    const era = date.getFullYear() > 0 ? 1 : 0;
    switch (token) {
      // AD, BC
      case "G":
      case "GG":
      case "GGG":
        return localize2.era(era, { width: "abbreviated" });
      // A, B
      case "GGGGG":
        return localize2.era(era, { width: "narrow" });
      // Anno Domini, Before Christ
      case "GGGG":
      default:
        return localize2.era(era, { width: "wide" });
    }
  },
  // Year
  y: function(date, token, localize2) {
    if (token === "yo") {
      const signedYear = date.getFullYear();
      const year = signedYear > 0 ? signedYear : 1 - signedYear;
      return localize2.ordinalNumber(year, { unit: "year" });
    }
    return lightFormatters.y(date, token);
  },
  // Local week-numbering year
  Y: function(date, token, localize2, options2) {
    const signedWeekYear = getWeekYear(date, options2);
    const weekYear = signedWeekYear > 0 ? signedWeekYear : 1 - signedWeekYear;
    if (token === "YY") {
      const twoDigitYear = weekYear % 100;
      return addLeadingZeros(twoDigitYear, 2);
    }
    if (token === "Yo") {
      return localize2.ordinalNumber(weekYear, { unit: "year" });
    }
    return addLeadingZeros(weekYear, token.length);
  },
  // ISO week-numbering year
  R: function(date, token) {
    const isoWeekYear = getISOWeekYear(date);
    return addLeadingZeros(isoWeekYear, token.length);
  },
  // Extended year. This is a single number designating the year of this calendar system.
  // The main difference between `y` and `u` localizers are B.C. years:
  // | Year | `y` | `u` |
  // |------|-----|-----|
  // | AC 1 |   1 |   1 |
  // | BC 1 |   1 |   0 |
  // | BC 2 |   2 |  -1 |
  // Also `yy` always returns the last two digits of a year,
  // while `uu` pads single digit years to 2 characters and returns other years unchanged.
  u: function(date, token) {
    const year = date.getFullYear();
    return addLeadingZeros(year, token.length);
  },
  // Quarter
  Q: function(date, token, localize2) {
    const quarter = Math.ceil((date.getMonth() + 1) / 3);
    switch (token) {
      // 1, 2, 3, 4
      case "Q":
        return String(quarter);
      // 01, 02, 03, 04
      case "QQ":
        return addLeadingZeros(quarter, 2);
      // 1st, 2nd, 3rd, 4th
      case "Qo":
        return localize2.ordinalNumber(quarter, { unit: "quarter" });
      // Q1, Q2, Q3, Q4
      case "QQQ":
        return localize2.quarter(quarter, {
          width: "abbreviated",
          context: "formatting"
        });
      // 1, 2, 3, 4 (narrow quarter; could be not numerical)
      case "QQQQQ":
        return localize2.quarter(quarter, {
          width: "narrow",
          context: "formatting"
        });
      // 1st quarter, 2nd quarter, ...
      case "QQQQ":
      default:
        return localize2.quarter(quarter, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // Stand-alone quarter
  q: function(date, token, localize2) {
    const quarter = Math.ceil((date.getMonth() + 1) / 3);
    switch (token) {
      // 1, 2, 3, 4
      case "q":
        return String(quarter);
      // 01, 02, 03, 04
      case "qq":
        return addLeadingZeros(quarter, 2);
      // 1st, 2nd, 3rd, 4th
      case "qo":
        return localize2.ordinalNumber(quarter, { unit: "quarter" });
      // Q1, Q2, Q3, Q4
      case "qqq":
        return localize2.quarter(quarter, {
          width: "abbreviated",
          context: "standalone"
        });
      // 1, 2, 3, 4 (narrow quarter; could be not numerical)
      case "qqqqq":
        return localize2.quarter(quarter, {
          width: "narrow",
          context: "standalone"
        });
      // 1st quarter, 2nd quarter, ...
      case "qqqq":
      default:
        return localize2.quarter(quarter, {
          width: "wide",
          context: "standalone"
        });
    }
  },
  // Month
  M: function(date, token, localize2) {
    const month = date.getMonth();
    switch (token) {
      case "M":
      case "MM":
        return lightFormatters.M(date, token);
      // 1st, 2nd, ..., 12th
      case "Mo":
        return localize2.ordinalNumber(month + 1, { unit: "month" });
      // Jan, Feb, ..., Dec
      case "MMM":
        return localize2.month(month, {
          width: "abbreviated",
          context: "formatting"
        });
      // J, F, ..., D
      case "MMMMM":
        return localize2.month(month, {
          width: "narrow",
          context: "formatting"
        });
      // January, February, ..., December
      case "MMMM":
      default:
        return localize2.month(month, { width: "wide", context: "formatting" });
    }
  },
  // Stand-alone month
  L: function(date, token, localize2) {
    const month = date.getMonth();
    switch (token) {
      // 1, 2, ..., 12
      case "L":
        return String(month + 1);
      // 01, 02, ..., 12
      case "LL":
        return addLeadingZeros(month + 1, 2);
      // 1st, 2nd, ..., 12th
      case "Lo":
        return localize2.ordinalNumber(month + 1, { unit: "month" });
      // Jan, Feb, ..., Dec
      case "LLL":
        return localize2.month(month, {
          width: "abbreviated",
          context: "standalone"
        });
      // J, F, ..., D
      case "LLLLL":
        return localize2.month(month, {
          width: "narrow",
          context: "standalone"
        });
      // January, February, ..., December
      case "LLLL":
      default:
        return localize2.month(month, { width: "wide", context: "standalone" });
    }
  },
  // Local week of year
  w: function(date, token, localize2, options2) {
    const week = getWeek(date, options2);
    if (token === "wo") {
      return localize2.ordinalNumber(week, { unit: "week" });
    }
    return addLeadingZeros(week, token.length);
  },
  // ISO week of year
  I: function(date, token, localize2) {
    const isoWeek = getISOWeek(date);
    if (token === "Io") {
      return localize2.ordinalNumber(isoWeek, { unit: "week" });
    }
    return addLeadingZeros(isoWeek, token.length);
  },
  // Day of the month
  d: function(date, token, localize2) {
    if (token === "do") {
      return localize2.ordinalNumber(date.getDate(), { unit: "date" });
    }
    return lightFormatters.d(date, token);
  },
  // Day of year
  D: function(date, token, localize2) {
    const dayOfYear = getDayOfYear(date);
    if (token === "Do") {
      return localize2.ordinalNumber(dayOfYear, { unit: "dayOfYear" });
    }
    return addLeadingZeros(dayOfYear, token.length);
  },
  // Day of week
  E: function(date, token, localize2) {
    const dayOfWeek = date.getDay();
    switch (token) {
      // Tue
      case "E":
      case "EE":
      case "EEE":
        return localize2.day(dayOfWeek, {
          width: "abbreviated",
          context: "formatting"
        });
      // T
      case "EEEEE":
        return localize2.day(dayOfWeek, {
          width: "narrow",
          context: "formatting"
        });
      // Tu
      case "EEEEEE":
        return localize2.day(dayOfWeek, {
          width: "short",
          context: "formatting"
        });
      // Tuesday
      case "EEEE":
      default:
        return localize2.day(dayOfWeek, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // Local day of week
  e: function(date, token, localize2, options2) {
    const dayOfWeek = date.getDay();
    const localDayOfWeek = (dayOfWeek - options2.weekStartsOn + 8) % 7 || 7;
    switch (token) {
      // Numerical value (Nth day of week with current locale or weekStartsOn)
      case "e":
        return String(localDayOfWeek);
      // Padded numerical value
      case "ee":
        return addLeadingZeros(localDayOfWeek, 2);
      // 1st, 2nd, ..., 7th
      case "eo":
        return localize2.ordinalNumber(localDayOfWeek, { unit: "day" });
      case "eee":
        return localize2.day(dayOfWeek, {
          width: "abbreviated",
          context: "formatting"
        });
      // T
      case "eeeee":
        return localize2.day(dayOfWeek, {
          width: "narrow",
          context: "formatting"
        });
      // Tu
      case "eeeeee":
        return localize2.day(dayOfWeek, {
          width: "short",
          context: "formatting"
        });
      // Tuesday
      case "eeee":
      default:
        return localize2.day(dayOfWeek, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // Stand-alone local day of week
  c: function(date, token, localize2, options2) {
    const dayOfWeek = date.getDay();
    const localDayOfWeek = (dayOfWeek - options2.weekStartsOn + 8) % 7 || 7;
    switch (token) {
      // Numerical value (same as in `e`)
      case "c":
        return String(localDayOfWeek);
      // Padded numerical value
      case "cc":
        return addLeadingZeros(localDayOfWeek, token.length);
      // 1st, 2nd, ..., 7th
      case "co":
        return localize2.ordinalNumber(localDayOfWeek, { unit: "day" });
      case "ccc":
        return localize2.day(dayOfWeek, {
          width: "abbreviated",
          context: "standalone"
        });
      // T
      case "ccccc":
        return localize2.day(dayOfWeek, {
          width: "narrow",
          context: "standalone"
        });
      // Tu
      case "cccccc":
        return localize2.day(dayOfWeek, {
          width: "short",
          context: "standalone"
        });
      // Tuesday
      case "cccc":
      default:
        return localize2.day(dayOfWeek, {
          width: "wide",
          context: "standalone"
        });
    }
  },
  // ISO day of week
  i: function(date, token, localize2) {
    const dayOfWeek = date.getDay();
    const isoDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek;
    switch (token) {
      // 2
      case "i":
        return String(isoDayOfWeek);
      // 02
      case "ii":
        return addLeadingZeros(isoDayOfWeek, token.length);
      // 2nd
      case "io":
        return localize2.ordinalNumber(isoDayOfWeek, { unit: "day" });
      // Tue
      case "iii":
        return localize2.day(dayOfWeek, {
          width: "abbreviated",
          context: "formatting"
        });
      // T
      case "iiiii":
        return localize2.day(dayOfWeek, {
          width: "narrow",
          context: "formatting"
        });
      // Tu
      case "iiiiii":
        return localize2.day(dayOfWeek, {
          width: "short",
          context: "formatting"
        });
      // Tuesday
      case "iiii":
      default:
        return localize2.day(dayOfWeek, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // AM or PM
  a: function(date, token, localize2) {
    const hours = date.getHours();
    const dayPeriodEnumValue = hours / 12 >= 1 ? "pm" : "am";
    switch (token) {
      case "a":
      case "aa":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "abbreviated",
          context: "formatting"
        });
      case "aaa":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "abbreviated",
          context: "formatting"
        }).toLowerCase();
      case "aaaaa":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "narrow",
          context: "formatting"
        });
      case "aaaa":
      default:
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // AM, PM, midnight, noon
  b: function(date, token, localize2) {
    const hours = date.getHours();
    let dayPeriodEnumValue;
    if (hours === 12) {
      dayPeriodEnumValue = dayPeriodEnum.noon;
    } else if (hours === 0) {
      dayPeriodEnumValue = dayPeriodEnum.midnight;
    } else {
      dayPeriodEnumValue = hours / 12 >= 1 ? "pm" : "am";
    }
    switch (token) {
      case "b":
      case "bb":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "abbreviated",
          context: "formatting"
        });
      case "bbb":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "abbreviated",
          context: "formatting"
        }).toLowerCase();
      case "bbbbb":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "narrow",
          context: "formatting"
        });
      case "bbbb":
      default:
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // in the morning, in the afternoon, in the evening, at night
  B: function(date, token, localize2) {
    const hours = date.getHours();
    let dayPeriodEnumValue;
    if (hours >= 17) {
      dayPeriodEnumValue = dayPeriodEnum.evening;
    } else if (hours >= 12) {
      dayPeriodEnumValue = dayPeriodEnum.afternoon;
    } else if (hours >= 4) {
      dayPeriodEnumValue = dayPeriodEnum.morning;
    } else {
      dayPeriodEnumValue = dayPeriodEnum.night;
    }
    switch (token) {
      case "B":
      case "BB":
      case "BBB":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "abbreviated",
          context: "formatting"
        });
      case "BBBBB":
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "narrow",
          context: "formatting"
        });
      case "BBBB":
      default:
        return localize2.dayPeriod(dayPeriodEnumValue, {
          width: "wide",
          context: "formatting"
        });
    }
  },
  // Hour [1-12]
  h: function(date, token, localize2) {
    if (token === "ho") {
      let hours = date.getHours() % 12;
      if (hours === 0) hours = 12;
      return localize2.ordinalNumber(hours, { unit: "hour" });
    }
    return lightFormatters.h(date, token);
  },
  // Hour [0-23]
  H: function(date, token, localize2) {
    if (token === "Ho") {
      return localize2.ordinalNumber(date.getHours(), { unit: "hour" });
    }
    return lightFormatters.H(date, token);
  },
  // Hour [0-11]
  K: function(date, token, localize2) {
    const hours = date.getHours() % 12;
    if (token === "Ko") {
      return localize2.ordinalNumber(hours, { unit: "hour" });
    }
    return addLeadingZeros(hours, token.length);
  },
  // Hour [1-24]
  k: function(date, token, localize2) {
    let hours = date.getHours();
    if (hours === 0) hours = 24;
    if (token === "ko") {
      return localize2.ordinalNumber(hours, { unit: "hour" });
    }
    return addLeadingZeros(hours, token.length);
  },
  // Minute
  m: function(date, token, localize2) {
    if (token === "mo") {
      return localize2.ordinalNumber(date.getMinutes(), { unit: "minute" });
    }
    return lightFormatters.m(date, token);
  },
  // Second
  s: function(date, token, localize2) {
    if (token === "so") {
      return localize2.ordinalNumber(date.getSeconds(), { unit: "second" });
    }
    return lightFormatters.s(date, token);
  },
  // Fraction of second
  S: function(date, token) {
    return lightFormatters.S(date, token);
  },
  // Timezone (ISO-8601. If offset is 0, output is always `'Z'`)
  X: function(date, token, _localize) {
    const timezoneOffset = date.getTimezoneOffset();
    if (timezoneOffset === 0) {
      return "Z";
    }
    switch (token) {
      // Hours and optional minutes
      case "X":
        return formatTimezoneWithOptionalMinutes(timezoneOffset);
      // Hours, minutes and optional seconds without `:` delimiter
      // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
      // so this token always has the same output as `XX`
      case "XXXX":
      case "XX":
        return formatTimezone(timezoneOffset);
      // Hours, minutes and optional seconds with `:` delimiter
      // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
      // so this token always has the same output as `XXX`
      case "XXXXX":
      case "XXX":
      // Hours and minutes with `:` delimiter
      default:
        return formatTimezone(timezoneOffset, ":");
    }
  },
  // Timezone (ISO-8601. If offset is 0, output is `'+00:00'` or equivalent)
  x: function(date, token, _localize) {
    const timezoneOffset = date.getTimezoneOffset();
    switch (token) {
      // Hours and optional minutes
      case "x":
        return formatTimezoneWithOptionalMinutes(timezoneOffset);
      // Hours, minutes and optional seconds without `:` delimiter
      // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
      // so this token always has the same output as `xx`
      case "xxxx":
      case "xx":
        return formatTimezone(timezoneOffset);
      // Hours, minutes and optional seconds with `:` delimiter
      // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
      // so this token always has the same output as `xxx`
      case "xxxxx":
      case "xxx":
      // Hours and minutes with `:` delimiter
      default:
        return formatTimezone(timezoneOffset, ":");
    }
  },
  // Timezone (GMT)
  O: function(date, token, _localize) {
    const timezoneOffset = date.getTimezoneOffset();
    switch (token) {
      // Short
      case "O":
      case "OO":
      case "OOO":
        return "GMT" + formatTimezoneShort(timezoneOffset, ":");
      // Long
      case "OOOO":
      default:
        return "GMT" + formatTimezone(timezoneOffset, ":");
    }
  },
  // Timezone (specific non-location)
  z: function(date, token, _localize) {
    const timezoneOffset = date.getTimezoneOffset();
    switch (token) {
      // Short
      case "z":
      case "zz":
      case "zzz":
        return "GMT" + formatTimezoneShort(timezoneOffset, ":");
      // Long
      case "zzzz":
      default:
        return "GMT" + formatTimezone(timezoneOffset, ":");
    }
  },
  // Seconds timestamp
  t: function(date, token, _localize) {
    const timestamp = Math.trunc(+date / 1e3);
    return addLeadingZeros(timestamp, token.length);
  },
  // Milliseconds timestamp
  T: function(date, token, _localize) {
    return addLeadingZeros(+date, token.length);
  }
};
function formatTimezoneShort(offset2, delimiter = "") {
  const sign2 = offset2 > 0 ? "-" : "+";
  const absOffset = Math.abs(offset2);
  const hours = Math.trunc(absOffset / 60);
  const minutes = absOffset % 60;
  if (minutes === 0) {
    return sign2 + String(hours);
  }
  return sign2 + String(hours) + delimiter + addLeadingZeros(minutes, 2);
}
function formatTimezoneWithOptionalMinutes(offset2, delimiter) {
  if (offset2 % 60 === 0) {
    const sign2 = offset2 > 0 ? "-" : "+";
    return sign2 + addLeadingZeros(Math.abs(offset2) / 60, 2);
  }
  return formatTimezone(offset2, delimiter);
}
function formatTimezone(offset2, delimiter = "") {
  const sign2 = offset2 > 0 ? "-" : "+";
  const absOffset = Math.abs(offset2);
  const hours = addLeadingZeros(Math.trunc(absOffset / 60), 2);
  const minutes = addLeadingZeros(absOffset % 60, 2);
  return sign2 + hours + delimiter + minutes;
}
const dateLongFormatter = (pattern, formatLong2) => {
  switch (pattern) {
    case "P":
      return formatLong2.date({ width: "short" });
    case "PP":
      return formatLong2.date({ width: "medium" });
    case "PPP":
      return formatLong2.date({ width: "long" });
    case "PPPP":
    default:
      return formatLong2.date({ width: "full" });
  }
};
const timeLongFormatter = (pattern, formatLong2) => {
  switch (pattern) {
    case "p":
      return formatLong2.time({ width: "short" });
    case "pp":
      return formatLong2.time({ width: "medium" });
    case "ppp":
      return formatLong2.time({ width: "long" });
    case "pppp":
    default:
      return formatLong2.time({ width: "full" });
  }
};
const dateTimeLongFormatter = (pattern, formatLong2) => {
  const matchResult = pattern.match(/(P+)(p+)?/) || [];
  const datePattern = matchResult[1];
  const timePattern = matchResult[2];
  if (!timePattern) {
    return dateLongFormatter(pattern, formatLong2);
  }
  let dateTimeFormat;
  switch (datePattern) {
    case "P":
      dateTimeFormat = formatLong2.dateTime({ width: "short" });
      break;
    case "PP":
      dateTimeFormat = formatLong2.dateTime({ width: "medium" });
      break;
    case "PPP":
      dateTimeFormat = formatLong2.dateTime({ width: "long" });
      break;
    case "PPPP":
    default:
      dateTimeFormat = formatLong2.dateTime({ width: "full" });
      break;
  }
  return dateTimeFormat.replace("{{date}}", dateLongFormatter(datePattern, formatLong2)).replace("{{time}}", timeLongFormatter(timePattern, formatLong2));
};
const longFormatters = {
  p: timeLongFormatter,
  P: dateTimeLongFormatter
};
const dayOfYearTokenRE = /^D+$/;
const weekYearTokenRE = /^Y+$/;
const throwTokens = ["D", "DD", "YY", "YYYY"];
function isProtectedDayOfYearToken(token) {
  return dayOfYearTokenRE.test(token);
}
function isProtectedWeekYearToken(token) {
  return weekYearTokenRE.test(token);
}
function warnOrThrowProtectedError(token, format2, input) {
  const _message = message(token, format2, input);
  console.warn(_message);
  if (throwTokens.includes(token)) throw new RangeError(_message);
}
function message(token, format2, input) {
  const subject = token[0] === "Y" ? "years" : "days of the month";
  return `Use \`${token.toLowerCase()}\` instead of \`${token}\` (in \`${format2}\`) for formatting ${subject} to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`;
}
function isDate(value) {
  return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
}
function isValid(date) {
  return !(!isDate(date) && typeof date !== "number" || isNaN(+toDate(date)));
}
const formattingTokensRegExp$1 = /[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g;
const longFormattingTokensRegExp$1 = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g;
const escapedStringRegExp$1 = /^'([^]*?)'?$/;
const doubleQuoteRegExp$1 = /''/g;
const unescapedLatinCharacterRegExp$1 = /[a-zA-Z]/;
function format(date, formatStr, options2) {
  const defaultOptions2 = getDefaultOptions$1();
  const locale = defaultOptions2.locale ?? enUS;
  const firstWeekContainsDate = defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
  const weekStartsOn = defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
  const originalDate = toDate(date, options2?.in);
  if (!isValid(originalDate)) {
    throw new RangeError("Invalid time value");
  }
  let parts = formatStr.match(longFormattingTokensRegExp$1).map((substring) => {
    const firstCharacter = substring[0];
    if (firstCharacter === "p" || firstCharacter === "P") {
      const longFormatter = longFormatters[firstCharacter];
      return longFormatter(substring, locale.formatLong);
    }
    return substring;
  }).join("").match(formattingTokensRegExp$1).map((substring) => {
    if (substring === "''") {
      return { isToken: false, value: "'" };
    }
    const firstCharacter = substring[0];
    if (firstCharacter === "'") {
      return { isToken: false, value: cleanEscapedString$1(substring) };
    }
    if (formatters[firstCharacter]) {
      return { isToken: true, value: substring };
    }
    if (firstCharacter.match(unescapedLatinCharacterRegExp$1)) {
      throw new RangeError(
        "Format string contains an unescaped latin alphabet character `" + firstCharacter + "`"
      );
    }
    return { isToken: false, value: substring };
  });
  if (locale.localize.preprocessor) {
    parts = locale.localize.preprocessor(originalDate, parts);
  }
  const formatterOptions = {
    firstWeekContainsDate,
    weekStartsOn,
    locale
  };
  return parts.map((part) => {
    if (!part.isToken) return part.value;
    const token = part.value;
    if (isProtectedWeekYearToken(token) || isProtectedDayOfYearToken(token)) {
      warnOrThrowProtectedError(token, formatStr, String(date));
    }
    const formatter = formatters[token[0]];
    return formatter(originalDate, token, locale.localize, formatterOptions);
  }).join("");
}
function cleanEscapedString$1(input) {
  const matched = input.match(escapedStringRegExp$1);
  if (!matched) {
    return input;
  }
  return matched[1].replace(doubleQuoteRegExp$1, "'");
}
function getDefaultOptions() {
  return Object.assign({}, getDefaultOptions$1());
}
function transpose(date, constructor) {
  const date_ = isConstructor(constructor) ? new constructor(0) : constructFrom(constructor, 0);
  date_.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
  date_.setHours(
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds()
  );
  return date_;
}
function isConstructor(constructor) {
  return typeof constructor === "function" && constructor.prototype?.constructor === constructor;
}
const TIMEZONE_UNIT_PRIORITY = 10;
class Setter {
  subPriority = 0;
  validate(_utcDate, _options) {
    return true;
  }
}
class ValueSetter extends Setter {
  constructor(value, validateValue, setValue, priority, subPriority) {
    super();
    this.value = value;
    this.validateValue = validateValue;
    this.setValue = setValue;
    this.priority = priority;
    if (subPriority) {
      this.subPriority = subPriority;
    }
  }
  validate(date, options2) {
    return this.validateValue(date, this.value, options2);
  }
  set(date, flags2, options2) {
    return this.setValue(date, flags2, this.value, options2);
  }
}
class DateTimezoneSetter extends Setter {
  priority = TIMEZONE_UNIT_PRIORITY;
  subPriority = -1;
  constructor(context, reference) {
    super();
    this.context = context || ((date) => constructFrom(reference, date));
  }
  set(date, flags2) {
    if (flags2.timestampIsSet) return date;
    return constructFrom(date, transpose(date, this.context));
  }
}
let Parser$1 = class Parser2 {
  run(dateString, token, match2, options2) {
    const result = this.parse(dateString, token, match2, options2);
    if (!result) {
      return null;
    }
    return {
      setter: new ValueSetter(
        result.value,
        this.validate,
        this.set,
        this.priority,
        this.subPriority
      ),
      rest: result.rest
    };
  }
  validate(_utcDate, _value, _options) {
    return true;
  }
};
class EraParser extends Parser$1 {
  priority = 140;
  parse(dateString, token, match2) {
    switch (token) {
      // AD, BC
      case "G":
      case "GG":
      case "GGG":
        return match2.era(dateString, { width: "abbreviated" }) || match2.era(dateString, { width: "narrow" });
      // A, B
      case "GGGGG":
        return match2.era(dateString, { width: "narrow" });
      // Anno Domini, Before Christ
      case "GGGG":
      default:
        return match2.era(dateString, { width: "wide" }) || match2.era(dateString, { width: "abbreviated" }) || match2.era(dateString, { width: "narrow" });
    }
  }
  set(date, flags2, value) {
    flags2.era = value;
    date.setFullYear(value, 0, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["R", "u", "t", "T"];
}
const numericPatterns = {
  month: /^(1[0-2]|0?\d)/,
  // 0 to 12
  date: /^(3[0-1]|[0-2]?\d)/,
  // 0 to 31
  dayOfYear: /^(36[0-6]|3[0-5]\d|[0-2]?\d?\d)/,
  // 0 to 366
  week: /^(5[0-3]|[0-4]?\d)/,
  // 0 to 53
  hour23h: /^(2[0-3]|[0-1]?\d)/,
  // 0 to 23
  hour24h: /^(2[0-4]|[0-1]?\d)/,
  // 0 to 24
  hour11h: /^(1[0-1]|0?\d)/,
  // 0 to 11
  hour12h: /^(1[0-2]|0?\d)/,
  // 0 to 12
  minute: /^[0-5]?\d/,
  // 0 to 59
  second: /^[0-5]?\d/,
  // 0 to 59
  singleDigit: /^\d/,
  // 0 to 9
  twoDigits: /^\d{1,2}/,
  // 0 to 99
  threeDigits: /^\d{1,3}/,
  // 0 to 999
  fourDigits: /^\d{1,4}/,
  // 0 to 9999
  anyDigitsSigned: /^-?\d+/,
  singleDigitSigned: /^-?\d/,
  // 0 to 9, -0 to -9
  twoDigitsSigned: /^-?\d{1,2}/,
  // 0 to 99, -0 to -99
  threeDigitsSigned: /^-?\d{1,3}/,
  // 0 to 999, -0 to -999
  fourDigitsSigned: /^-?\d{1,4}/
  // 0 to 9999, -0 to -9999
};
const timezonePatterns = {
  basicOptionalMinutes: /^([+-])(\d{2})(\d{2})?|Z/,
  basic: /^([+-])(\d{2})(\d{2})|Z/,
  basicOptionalSeconds: /^([+-])(\d{2})(\d{2})((\d{2}))?|Z/,
  extended: /^([+-])(\d{2}):(\d{2})|Z/,
  extendedOptionalSeconds: /^([+-])(\d{2}):(\d{2})(:(\d{2}))?|Z/
};
function mapValue(parseFnResult, mapFn) {
  if (!parseFnResult) {
    return parseFnResult;
  }
  return {
    value: mapFn(parseFnResult.value),
    rest: parseFnResult.rest
  };
}
function parseNumericPattern(pattern, dateString) {
  const matchResult = dateString.match(pattern);
  if (!matchResult) {
    return null;
  }
  return {
    value: parseInt(matchResult[0], 10),
    rest: dateString.slice(matchResult[0].length)
  };
}
function parseTimezonePattern(pattern, dateString) {
  const matchResult = dateString.match(pattern);
  if (!matchResult) {
    return null;
  }
  if (matchResult[0] === "Z") {
    return {
      value: 0,
      rest: dateString.slice(1)
    };
  }
  const sign2 = matchResult[1] === "+" ? 1 : -1;
  const hours = matchResult[2] ? parseInt(matchResult[2], 10) : 0;
  const minutes = matchResult[3] ? parseInt(matchResult[3], 10) : 0;
  const seconds = matchResult[5] ? parseInt(matchResult[5], 10) : 0;
  return {
    value: sign2 * (hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * millisecondsInSecond),
    rest: dateString.slice(matchResult[0].length)
  };
}
function parseAnyDigitsSigned(dateString) {
  return parseNumericPattern(numericPatterns.anyDigitsSigned, dateString);
}
function parseNDigits(n, dateString) {
  switch (n) {
    case 1:
      return parseNumericPattern(numericPatterns.singleDigit, dateString);
    case 2:
      return parseNumericPattern(numericPatterns.twoDigits, dateString);
    case 3:
      return parseNumericPattern(numericPatterns.threeDigits, dateString);
    case 4:
      return parseNumericPattern(numericPatterns.fourDigits, dateString);
    default:
      return parseNumericPattern(new RegExp("^\\d{1," + n + "}"), dateString);
  }
}
function parseNDigitsSigned(n, dateString) {
  switch (n) {
    case 1:
      return parseNumericPattern(numericPatterns.singleDigitSigned, dateString);
    case 2:
      return parseNumericPattern(numericPatterns.twoDigitsSigned, dateString);
    case 3:
      return parseNumericPattern(numericPatterns.threeDigitsSigned, dateString);
    case 4:
      return parseNumericPattern(numericPatterns.fourDigitsSigned, dateString);
    default:
      return parseNumericPattern(new RegExp("^-?\\d{1," + n + "}"), dateString);
  }
}
function dayPeriodEnumToHours(dayPeriod) {
  switch (dayPeriod) {
    case "morning":
      return 4;
    case "evening":
      return 17;
    case "pm":
    case "noon":
    case "afternoon":
      return 12;
    case "am":
    case "midnight":
    case "night":
    default:
      return 0;
  }
}
function normalizeTwoDigitYear(twoDigitYear, currentYear) {
  const isCommonEra = currentYear > 0;
  const absCurrentYear = isCommonEra ? currentYear : 1 - currentYear;
  let result;
  if (absCurrentYear <= 50) {
    result = twoDigitYear || 100;
  } else {
    const rangeEnd = absCurrentYear + 50;
    const rangeEndCentury = Math.trunc(rangeEnd / 100) * 100;
    const isPreviousCentury = twoDigitYear >= rangeEnd % 100;
    result = twoDigitYear + rangeEndCentury - (isPreviousCentury ? 100 : 0);
  }
  return isCommonEra ? result : 1 - result;
}
function isLeapYearIndex(year) {
  return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
}
class YearParser extends Parser$1 {
  priority = 130;
  incompatibleTokens = ["Y", "R", "u", "w", "I", "i", "e", "c", "t", "T"];
  parse(dateString, token, match2) {
    const valueCallback = (year) => ({
      year,
      isTwoDigitYear: token === "yy"
    });
    switch (token) {
      case "y":
        return mapValue(parseNDigits(4, dateString), valueCallback);
      case "yo":
        return mapValue(
          match2.ordinalNumber(dateString, {
            unit: "year"
          }),
          valueCallback
        );
      default:
        return mapValue(parseNDigits(token.length, dateString), valueCallback);
    }
  }
  validate(_date, value) {
    return value.isTwoDigitYear || value.year > 0;
  }
  set(date, flags2, value) {
    const currentYear = date.getFullYear();
    if (value.isTwoDigitYear) {
      const normalizedTwoDigitYear = normalizeTwoDigitYear(
        value.year,
        currentYear
      );
      date.setFullYear(normalizedTwoDigitYear, 0, 1);
      date.setHours(0, 0, 0, 0);
      return date;
    }
    const year = !("era" in flags2) || flags2.era === 1 ? value.year : 1 - value.year;
    date.setFullYear(year, 0, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
}
class LocalWeekYearParser extends Parser$1 {
  priority = 130;
  parse(dateString, token, match2) {
    const valueCallback = (year) => ({
      year,
      isTwoDigitYear: token === "YY"
    });
    switch (token) {
      case "Y":
        return mapValue(parseNDigits(4, dateString), valueCallback);
      case "Yo":
        return mapValue(
          match2.ordinalNumber(dateString, {
            unit: "year"
          }),
          valueCallback
        );
      default:
        return mapValue(parseNDigits(token.length, dateString), valueCallback);
    }
  }
  validate(_date, value) {
    return value.isTwoDigitYear || value.year > 0;
  }
  set(date, flags2, value, options2) {
    const currentYear = getWeekYear(date, options2);
    if (value.isTwoDigitYear) {
      const normalizedTwoDigitYear = normalizeTwoDigitYear(
        value.year,
        currentYear
      );
      date.setFullYear(
        normalizedTwoDigitYear,
        0,
        options2.firstWeekContainsDate
      );
      date.setHours(0, 0, 0, 0);
      return startOfWeek(date, options2);
    }
    const year = !("era" in flags2) || flags2.era === 1 ? value.year : 1 - value.year;
    date.setFullYear(year, 0, options2.firstWeekContainsDate);
    date.setHours(0, 0, 0, 0);
    return startOfWeek(date, options2);
  }
  incompatibleTokens = [
    "y",
    "R",
    "u",
    "Q",
    "q",
    "M",
    "L",
    "I",
    "d",
    "D",
    "i",
    "t",
    "T"
  ];
}
class ISOWeekYearParser extends Parser$1 {
  priority = 130;
  parse(dateString, token) {
    if (token === "R") {
      return parseNDigitsSigned(4, dateString);
    }
    return parseNDigitsSigned(token.length, dateString);
  }
  set(date, _flags, value) {
    const firstWeekOfYear = constructFrom(date, 0);
    firstWeekOfYear.setFullYear(value, 0, 4);
    firstWeekOfYear.setHours(0, 0, 0, 0);
    return startOfISOWeek(firstWeekOfYear);
  }
  incompatibleTokens = [
    "G",
    "y",
    "Y",
    "u",
    "Q",
    "q",
    "M",
    "L",
    "w",
    "d",
    "D",
    "e",
    "c",
    "t",
    "T"
  ];
}
class ExtendedYearParser extends Parser$1 {
  priority = 130;
  parse(dateString, token) {
    if (token === "u") {
      return parseNDigitsSigned(4, dateString);
    }
    return parseNDigitsSigned(token.length, dateString);
  }
  set(date, _flags, value) {
    date.setFullYear(value, 0, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["G", "y", "Y", "R", "w", "I", "i", "e", "c", "t", "T"];
}
class QuarterParser extends Parser$1 {
  priority = 120;
  parse(dateString, token, match2) {
    switch (token) {
      // 1, 2, 3, 4
      case "Q":
      case "QQ":
        return parseNDigits(token.length, dateString);
      // 1st, 2nd, 3rd, 4th
      case "Qo":
        return match2.ordinalNumber(dateString, { unit: "quarter" });
      // Q1, Q2, Q3, Q4
      case "QQQ":
        return match2.quarter(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.quarter(dateString, {
          width: "narrow",
          context: "formatting"
        });
      // 1, 2, 3, 4 (narrow quarter; could be not numerical)
      case "QQQQQ":
        return match2.quarter(dateString, {
          width: "narrow",
          context: "formatting"
        });
      // 1st quarter, 2nd quarter, ...
      case "QQQQ":
      default:
        return match2.quarter(dateString, {
          width: "wide",
          context: "formatting"
        }) || match2.quarter(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.quarter(dateString, {
          width: "narrow",
          context: "formatting"
        });
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 4;
  }
  set(date, _flags, value) {
    date.setMonth((value - 1) * 3, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "Y",
    "R",
    "q",
    "M",
    "L",
    "w",
    "I",
    "d",
    "D",
    "i",
    "e",
    "c",
    "t",
    "T"
  ];
}
class StandAloneQuarterParser extends Parser$1 {
  priority = 120;
  parse(dateString, token, match2) {
    switch (token) {
      // 1, 2, 3, 4
      case "q":
      case "qq":
        return parseNDigits(token.length, dateString);
      // 1st, 2nd, 3rd, 4th
      case "qo":
        return match2.ordinalNumber(dateString, { unit: "quarter" });
      // Q1, Q2, Q3, Q4
      case "qqq":
        return match2.quarter(dateString, {
          width: "abbreviated",
          context: "standalone"
        }) || match2.quarter(dateString, {
          width: "narrow",
          context: "standalone"
        });
      // 1, 2, 3, 4 (narrow quarter; could be not numerical)
      case "qqqqq":
        return match2.quarter(dateString, {
          width: "narrow",
          context: "standalone"
        });
      // 1st quarter, 2nd quarter, ...
      case "qqqq":
      default:
        return match2.quarter(dateString, {
          width: "wide",
          context: "standalone"
        }) || match2.quarter(dateString, {
          width: "abbreviated",
          context: "standalone"
        }) || match2.quarter(dateString, {
          width: "narrow",
          context: "standalone"
        });
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 4;
  }
  set(date, _flags, value) {
    date.setMonth((value - 1) * 3, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "Y",
    "R",
    "Q",
    "M",
    "L",
    "w",
    "I",
    "d",
    "D",
    "i",
    "e",
    "c",
    "t",
    "T"
  ];
}
class MonthParser extends Parser$1 {
  incompatibleTokens = [
    "Y",
    "R",
    "q",
    "Q",
    "L",
    "w",
    "I",
    "D",
    "i",
    "e",
    "c",
    "t",
    "T"
  ];
  priority = 110;
  parse(dateString, token, match2) {
    const valueCallback = (value) => value - 1;
    switch (token) {
      // 1, 2, ..., 12
      case "M":
        return mapValue(
          parseNumericPattern(numericPatterns.month, dateString),
          valueCallback
        );
      // 01, 02, ..., 12
      case "MM":
        return mapValue(parseNDigits(2, dateString), valueCallback);
      // 1st, 2nd, ..., 12th
      case "Mo":
        return mapValue(
          match2.ordinalNumber(dateString, {
            unit: "month"
          }),
          valueCallback
        );
      // Jan, Feb, ..., Dec
      case "MMM":
        return match2.month(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.month(dateString, { width: "narrow", context: "formatting" });
      // J, F, ..., D
      case "MMMMM":
        return match2.month(dateString, {
          width: "narrow",
          context: "formatting"
        });
      // January, February, ..., December
      case "MMMM":
      default:
        return match2.month(dateString, { width: "wide", context: "formatting" }) || match2.month(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.month(dateString, { width: "narrow", context: "formatting" });
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 11;
  }
  set(date, _flags, value) {
    date.setMonth(value, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
}
class StandAloneMonthParser extends Parser$1 {
  priority = 110;
  parse(dateString, token, match2) {
    const valueCallback = (value) => value - 1;
    switch (token) {
      // 1, 2, ..., 12
      case "L":
        return mapValue(
          parseNumericPattern(numericPatterns.month, dateString),
          valueCallback
        );
      // 01, 02, ..., 12
      case "LL":
        return mapValue(parseNDigits(2, dateString), valueCallback);
      // 1st, 2nd, ..., 12th
      case "Lo":
        return mapValue(
          match2.ordinalNumber(dateString, {
            unit: "month"
          }),
          valueCallback
        );
      // Jan, Feb, ..., Dec
      case "LLL":
        return match2.month(dateString, {
          width: "abbreviated",
          context: "standalone"
        }) || match2.month(dateString, { width: "narrow", context: "standalone" });
      // J, F, ..., D
      case "LLLLL":
        return match2.month(dateString, {
          width: "narrow",
          context: "standalone"
        });
      // January, February, ..., December
      case "LLLL":
      default:
        return match2.month(dateString, { width: "wide", context: "standalone" }) || match2.month(dateString, {
          width: "abbreviated",
          context: "standalone"
        }) || match2.month(dateString, { width: "narrow", context: "standalone" });
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 11;
  }
  set(date, _flags, value) {
    date.setMonth(value, 1);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "Y",
    "R",
    "q",
    "Q",
    "M",
    "w",
    "I",
    "D",
    "i",
    "e",
    "c",
    "t",
    "T"
  ];
}
function setWeek(date, week, options2) {
  const date_ = toDate(date, options2?.in);
  const diff = getWeek(date_, options2) - week;
  date_.setDate(date_.getDate() - diff * 7);
  return toDate(date_, options2?.in);
}
class LocalWeekParser extends Parser$1 {
  priority = 100;
  parse(dateString, token, match2) {
    switch (token) {
      case "w":
        return parseNumericPattern(numericPatterns.week, dateString);
      case "wo":
        return match2.ordinalNumber(dateString, { unit: "week" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 53;
  }
  set(date, _flags, value, options2) {
    return startOfWeek(setWeek(date, value, options2), options2);
  }
  incompatibleTokens = [
    "y",
    "R",
    "u",
    "q",
    "Q",
    "M",
    "L",
    "I",
    "d",
    "D",
    "i",
    "t",
    "T"
  ];
}
function setISOWeek(date, week, options2) {
  const _date = toDate(date, options2?.in);
  const diff = getISOWeek(_date, options2) - week;
  _date.setDate(_date.getDate() - diff * 7);
  return _date;
}
class ISOWeekParser extends Parser$1 {
  priority = 100;
  parse(dateString, token, match2) {
    switch (token) {
      case "I":
        return parseNumericPattern(numericPatterns.week, dateString);
      case "Io":
        return match2.ordinalNumber(dateString, { unit: "week" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 53;
  }
  set(date, _flags, value) {
    return startOfISOWeek(setISOWeek(date, value));
  }
  incompatibleTokens = [
    "y",
    "Y",
    "u",
    "q",
    "Q",
    "M",
    "L",
    "w",
    "d",
    "D",
    "e",
    "c",
    "t",
    "T"
  ];
}
const DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const DAYS_IN_MONTH_LEAP_YEAR = [
  31,
  29,
  31,
  30,
  31,
  30,
  31,
  31,
  30,
  31,
  30,
  31
];
class DateParser extends Parser$1 {
  priority = 90;
  subPriority = 1;
  parse(dateString, token, match2) {
    switch (token) {
      case "d":
        return parseNumericPattern(numericPatterns.date, dateString);
      case "do":
        return match2.ordinalNumber(dateString, { unit: "date" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(date, value) {
    const year = date.getFullYear();
    const isLeapYear = isLeapYearIndex(year);
    const month = date.getMonth();
    if (isLeapYear) {
      return value >= 1 && value <= DAYS_IN_MONTH_LEAP_YEAR[month];
    } else {
      return value >= 1 && value <= DAYS_IN_MONTH[month];
    }
  }
  set(date, _flags, value) {
    date.setDate(value);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "Y",
    "R",
    "q",
    "Q",
    "w",
    "I",
    "D",
    "i",
    "e",
    "c",
    "t",
    "T"
  ];
}
class DayOfYearParser extends Parser$1 {
  priority = 90;
  subpriority = 1;
  parse(dateString, token, match2) {
    switch (token) {
      case "D":
      case "DD":
        return parseNumericPattern(numericPatterns.dayOfYear, dateString);
      case "Do":
        return match2.ordinalNumber(dateString, { unit: "date" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(date, value) {
    const year = date.getFullYear();
    const isLeapYear = isLeapYearIndex(year);
    if (isLeapYear) {
      return value >= 1 && value <= 366;
    } else {
      return value >= 1 && value <= 365;
    }
  }
  set(date, _flags, value) {
    date.setMonth(0, value);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "Y",
    "R",
    "q",
    "Q",
    "M",
    "L",
    "w",
    "I",
    "d",
    "E",
    "i",
    "e",
    "c",
    "t",
    "T"
  ];
}
function addDays(date, amount, options2) {
  const _date = toDate(date, options2?.in);
  if (isNaN(amount)) return constructFrom(options2?.in || date, NaN);
  if (!amount) return _date;
  _date.setDate(_date.getDate() + amount);
  return _date;
}
function setDay(date, day, options2) {
  const defaultOptions2 = getDefaultOptions$1();
  const weekStartsOn = options2?.weekStartsOn ?? options2?.locale?.options?.weekStartsOn ?? defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
  const date_ = toDate(date, options2?.in);
  const currentDay = date_.getDay();
  const remainder = day % 7;
  const dayIndex = (remainder + 7) % 7;
  const delta = 7 - weekStartsOn;
  const diff = day < 0 || day > 6 ? day - (currentDay + delta) % 7 : (dayIndex + delta) % 7 - (currentDay + delta) % 7;
  return addDays(date_, diff, options2);
}
class DayParser extends Parser$1 {
  priority = 90;
  parse(dateString, token, match2) {
    switch (token) {
      // Tue
      case "E":
      case "EE":
      case "EEE":
        return match2.day(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.day(dateString, { width: "short", context: "formatting" }) || match2.day(dateString, { width: "narrow", context: "formatting" });
      // T
      case "EEEEE":
        return match2.day(dateString, {
          width: "narrow",
          context: "formatting"
        });
      // Tu
      case "EEEEEE":
        return match2.day(dateString, { width: "short", context: "formatting" }) || match2.day(dateString, { width: "narrow", context: "formatting" });
      // Tuesday
      case "EEEE":
      default:
        return match2.day(dateString, { width: "wide", context: "formatting" }) || match2.day(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.day(dateString, { width: "short", context: "formatting" }) || match2.day(dateString, { width: "narrow", context: "formatting" });
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 6;
  }
  set(date, _flags, value, options2) {
    date = setDay(date, value, options2);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["D", "i", "e", "c", "t", "T"];
}
class LocalDayParser extends Parser$1 {
  priority = 90;
  parse(dateString, token, match2, options2) {
    const valueCallback = (value) => {
      const wholeWeekDays = Math.floor((value - 1) / 7) * 7;
      return (value + options2.weekStartsOn + 6) % 7 + wholeWeekDays;
    };
    switch (token) {
      // 3
      case "e":
      case "ee":
        return mapValue(parseNDigits(token.length, dateString), valueCallback);
      // 3rd
      case "eo":
        return mapValue(
          match2.ordinalNumber(dateString, {
            unit: "day"
          }),
          valueCallback
        );
      // Tue
      case "eee":
        return match2.day(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.day(dateString, { width: "short", context: "formatting" }) || match2.day(dateString, { width: "narrow", context: "formatting" });
      // T
      case "eeeee":
        return match2.day(dateString, {
          width: "narrow",
          context: "formatting"
        });
      // Tu
      case "eeeeee":
        return match2.day(dateString, { width: "short", context: "formatting" }) || match2.day(dateString, { width: "narrow", context: "formatting" });
      // Tuesday
      case "eeee":
      default:
        return match2.day(dateString, { width: "wide", context: "formatting" }) || match2.day(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.day(dateString, { width: "short", context: "formatting" }) || match2.day(dateString, { width: "narrow", context: "formatting" });
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 6;
  }
  set(date, _flags, value, options2) {
    date = setDay(date, value, options2);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "y",
    "R",
    "u",
    "q",
    "Q",
    "M",
    "L",
    "I",
    "d",
    "D",
    "E",
    "i",
    "c",
    "t",
    "T"
  ];
}
class StandAloneLocalDayParser extends Parser$1 {
  priority = 90;
  parse(dateString, token, match2, options2) {
    const valueCallback = (value) => {
      const wholeWeekDays = Math.floor((value - 1) / 7) * 7;
      return (value + options2.weekStartsOn + 6) % 7 + wholeWeekDays;
    };
    switch (token) {
      // 3
      case "c":
      case "cc":
        return mapValue(parseNDigits(token.length, dateString), valueCallback);
      // 3rd
      case "co":
        return mapValue(
          match2.ordinalNumber(dateString, {
            unit: "day"
          }),
          valueCallback
        );
      // Tue
      case "ccc":
        return match2.day(dateString, {
          width: "abbreviated",
          context: "standalone"
        }) || match2.day(dateString, { width: "short", context: "standalone" }) || match2.day(dateString, { width: "narrow", context: "standalone" });
      // T
      case "ccccc":
        return match2.day(dateString, {
          width: "narrow",
          context: "standalone"
        });
      // Tu
      case "cccccc":
        return match2.day(dateString, { width: "short", context: "standalone" }) || match2.day(dateString, { width: "narrow", context: "standalone" });
      // Tuesday
      case "cccc":
      default:
        return match2.day(dateString, { width: "wide", context: "standalone" }) || match2.day(dateString, {
          width: "abbreviated",
          context: "standalone"
        }) || match2.day(dateString, { width: "short", context: "standalone" }) || match2.day(dateString, { width: "narrow", context: "standalone" });
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 6;
  }
  set(date, _flags, value, options2) {
    date = setDay(date, value, options2);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "y",
    "R",
    "u",
    "q",
    "Q",
    "M",
    "L",
    "I",
    "d",
    "D",
    "E",
    "i",
    "e",
    "t",
    "T"
  ];
}
function getISODay(date, options2) {
  const day = toDate(date, options2?.in).getDay();
  return day === 0 ? 7 : day;
}
function setISODay(date, day, options2) {
  const date_ = toDate(date, options2?.in);
  const currentDay = getISODay(date_, options2);
  const diff = day - currentDay;
  return addDays(date_, diff, options2);
}
class ISODayParser extends Parser$1 {
  priority = 90;
  parse(dateString, token, match2) {
    const valueCallback = (value) => {
      if (value === 0) {
        return 7;
      }
      return value;
    };
    switch (token) {
      // 2
      case "i":
      case "ii":
        return parseNDigits(token.length, dateString);
      // 2nd
      case "io":
        return match2.ordinalNumber(dateString, { unit: "day" });
      // Tue
      case "iii":
        return mapValue(
          match2.day(dateString, {
            width: "abbreviated",
            context: "formatting"
          }) || match2.day(dateString, {
            width: "short",
            context: "formatting"
          }) || match2.day(dateString, {
            width: "narrow",
            context: "formatting"
          }),
          valueCallback
        );
      // T
      case "iiiii":
        return mapValue(
          match2.day(dateString, {
            width: "narrow",
            context: "formatting"
          }),
          valueCallback
        );
      // Tu
      case "iiiiii":
        return mapValue(
          match2.day(dateString, {
            width: "short",
            context: "formatting"
          }) || match2.day(dateString, {
            width: "narrow",
            context: "formatting"
          }),
          valueCallback
        );
      // Tuesday
      case "iiii":
      default:
        return mapValue(
          match2.day(dateString, {
            width: "wide",
            context: "formatting"
          }) || match2.day(dateString, {
            width: "abbreviated",
            context: "formatting"
          }) || match2.day(dateString, {
            width: "short",
            context: "formatting"
          }) || match2.day(dateString, {
            width: "narrow",
            context: "formatting"
          }),
          valueCallback
        );
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 7;
  }
  set(date, _flags, value) {
    date = setISODay(date, value);
    date.setHours(0, 0, 0, 0);
    return date;
  }
  incompatibleTokens = [
    "y",
    "Y",
    "u",
    "q",
    "Q",
    "M",
    "L",
    "w",
    "d",
    "D",
    "E",
    "e",
    "c",
    "t",
    "T"
  ];
}
class AMPMParser extends Parser$1 {
  priority = 80;
  parse(dateString, token, match2) {
    switch (token) {
      case "a":
      case "aa":
      case "aaa":
        return match2.dayPeriod(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
      case "aaaaa":
        return match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
      case "aaaa":
      default:
        return match2.dayPeriod(dateString, {
          width: "wide",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
    }
  }
  set(date, _flags, value) {
    date.setHours(dayPeriodEnumToHours(value), 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["b", "B", "H", "k", "t", "T"];
}
class AMPMMidnightParser extends Parser$1 {
  priority = 80;
  parse(dateString, token, match2) {
    switch (token) {
      case "b":
      case "bb":
      case "bbb":
        return match2.dayPeriod(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
      case "bbbbb":
        return match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
      case "bbbb":
      default:
        return match2.dayPeriod(dateString, {
          width: "wide",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
    }
  }
  set(date, _flags, value) {
    date.setHours(dayPeriodEnumToHours(value), 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["a", "B", "H", "k", "t", "T"];
}
class DayPeriodParser extends Parser$1 {
  priority = 80;
  parse(dateString, token, match2) {
    switch (token) {
      case "B":
      case "BB":
      case "BBB":
        return match2.dayPeriod(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
      case "BBBBB":
        return match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
      case "BBBB":
      default:
        return match2.dayPeriod(dateString, {
          width: "wide",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "abbreviated",
          context: "formatting"
        }) || match2.dayPeriod(dateString, {
          width: "narrow",
          context: "formatting"
        });
    }
  }
  set(date, _flags, value) {
    date.setHours(dayPeriodEnumToHours(value), 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["a", "b", "t", "T"];
}
class Hour1to12Parser extends Parser$1 {
  priority = 70;
  parse(dateString, token, match2) {
    switch (token) {
      case "h":
        return parseNumericPattern(numericPatterns.hour12h, dateString);
      case "ho":
        return match2.ordinalNumber(dateString, { unit: "hour" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 12;
  }
  set(date, _flags, value) {
    const isPM = date.getHours() >= 12;
    if (isPM && value < 12) {
      date.setHours(value + 12, 0, 0, 0);
    } else if (!isPM && value === 12) {
      date.setHours(0, 0, 0, 0);
    } else {
      date.setHours(value, 0, 0, 0);
    }
    return date;
  }
  incompatibleTokens = ["H", "K", "k", "t", "T"];
}
class Hour0to23Parser extends Parser$1 {
  priority = 70;
  parse(dateString, token, match2) {
    switch (token) {
      case "H":
        return parseNumericPattern(numericPatterns.hour23h, dateString);
      case "Ho":
        return match2.ordinalNumber(dateString, { unit: "hour" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 23;
  }
  set(date, _flags, value) {
    date.setHours(value, 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["a", "b", "h", "K", "k", "t", "T"];
}
class Hour0To11Parser extends Parser$1 {
  priority = 70;
  parse(dateString, token, match2) {
    switch (token) {
      case "K":
        return parseNumericPattern(numericPatterns.hour11h, dateString);
      case "Ko":
        return match2.ordinalNumber(dateString, { unit: "hour" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 11;
  }
  set(date, _flags, value) {
    const isPM = date.getHours() >= 12;
    if (isPM && value < 12) {
      date.setHours(value + 12, 0, 0, 0);
    } else {
      date.setHours(value, 0, 0, 0);
    }
    return date;
  }
  incompatibleTokens = ["h", "H", "k", "t", "T"];
}
class Hour1To24Parser extends Parser$1 {
  priority = 70;
  parse(dateString, token, match2) {
    switch (token) {
      case "k":
        return parseNumericPattern(numericPatterns.hour24h, dateString);
      case "ko":
        return match2.ordinalNumber(dateString, { unit: "hour" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 1 && value <= 24;
  }
  set(date, _flags, value) {
    const hours = value <= 24 ? value % 24 : value;
    date.setHours(hours, 0, 0, 0);
    return date;
  }
  incompatibleTokens = ["a", "b", "h", "H", "K", "t", "T"];
}
class MinuteParser extends Parser$1 {
  priority = 60;
  parse(dateString, token, match2) {
    switch (token) {
      case "m":
        return parseNumericPattern(numericPatterns.minute, dateString);
      case "mo":
        return match2.ordinalNumber(dateString, { unit: "minute" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 59;
  }
  set(date, _flags, value) {
    date.setMinutes(value, 0, 0);
    return date;
  }
  incompatibleTokens = ["t", "T"];
}
class SecondParser extends Parser$1 {
  priority = 50;
  parse(dateString, token, match2) {
    switch (token) {
      case "s":
        return parseNumericPattern(numericPatterns.second, dateString);
      case "so":
        return match2.ordinalNumber(dateString, { unit: "second" });
      default:
        return parseNDigits(token.length, dateString);
    }
  }
  validate(_date, value) {
    return value >= 0 && value <= 59;
  }
  set(date, _flags, value) {
    date.setSeconds(value, 0);
    return date;
  }
  incompatibleTokens = ["t", "T"];
}
class FractionOfSecondParser extends Parser$1 {
  priority = 30;
  parse(dateString, token) {
    const valueCallback = (value) => Math.trunc(value * Math.pow(10, -token.length + 3));
    return mapValue(parseNDigits(token.length, dateString), valueCallback);
  }
  set(date, _flags, value) {
    date.setMilliseconds(value);
    return date;
  }
  incompatibleTokens = ["t", "T"];
}
class ISOTimezoneWithZParser extends Parser$1 {
  priority = 10;
  parse(dateString, token) {
    switch (token) {
      case "X":
        return parseTimezonePattern(
          timezonePatterns.basicOptionalMinutes,
          dateString
        );
      case "XX":
        return parseTimezonePattern(timezonePatterns.basic, dateString);
      case "XXXX":
        return parseTimezonePattern(
          timezonePatterns.basicOptionalSeconds,
          dateString
        );
      case "XXXXX":
        return parseTimezonePattern(
          timezonePatterns.extendedOptionalSeconds,
          dateString
        );
      case "XXX":
      default:
        return parseTimezonePattern(timezonePatterns.extended, dateString);
    }
  }
  set(date, flags2, value) {
    if (flags2.timestampIsSet) return date;
    return constructFrom(
      date,
      date.getTime() - getTimezoneOffsetInMilliseconds(date) - value
    );
  }
  incompatibleTokens = ["t", "T", "x"];
}
class ISOTimezoneParser extends Parser$1 {
  priority = 10;
  parse(dateString, token) {
    switch (token) {
      case "x":
        return parseTimezonePattern(
          timezonePatterns.basicOptionalMinutes,
          dateString
        );
      case "xx":
        return parseTimezonePattern(timezonePatterns.basic, dateString);
      case "xxxx":
        return parseTimezonePattern(
          timezonePatterns.basicOptionalSeconds,
          dateString
        );
      case "xxxxx":
        return parseTimezonePattern(
          timezonePatterns.extendedOptionalSeconds,
          dateString
        );
      case "xxx":
      default:
        return parseTimezonePattern(timezonePatterns.extended, dateString);
    }
  }
  set(date, flags2, value) {
    if (flags2.timestampIsSet) return date;
    return constructFrom(
      date,
      date.getTime() - getTimezoneOffsetInMilliseconds(date) - value
    );
  }
  incompatibleTokens = ["t", "T", "X"];
}
class TimestampSecondsParser extends Parser$1 {
  priority = 40;
  parse(dateString) {
    return parseAnyDigitsSigned(dateString);
  }
  set(date, _flags, value) {
    return [constructFrom(date, value * 1e3), { timestampIsSet: true }];
  }
  incompatibleTokens = "*";
}
class TimestampMillisecondsParser extends Parser$1 {
  priority = 20;
  parse(dateString) {
    return parseAnyDigitsSigned(dateString);
  }
  set(date, _flags, value) {
    return [constructFrom(date, value), { timestampIsSet: true }];
  }
  incompatibleTokens = "*";
}
const parsers$1 = {
  G: new EraParser(),
  y: new YearParser(),
  Y: new LocalWeekYearParser(),
  R: new ISOWeekYearParser(),
  u: new ExtendedYearParser(),
  Q: new QuarterParser(),
  q: new StandAloneQuarterParser(),
  M: new MonthParser(),
  L: new StandAloneMonthParser(),
  w: new LocalWeekParser(),
  I: new ISOWeekParser(),
  d: new DateParser(),
  D: new DayOfYearParser(),
  E: new DayParser(),
  e: new LocalDayParser(),
  c: new StandAloneLocalDayParser(),
  i: new ISODayParser(),
  a: new AMPMParser(),
  b: new AMPMMidnightParser(),
  B: new DayPeriodParser(),
  h: new Hour1to12Parser(),
  H: new Hour0to23Parser(),
  K: new Hour0To11Parser(),
  k: new Hour1To24Parser(),
  m: new MinuteParser(),
  s: new SecondParser(),
  S: new FractionOfSecondParser(),
  X: new ISOTimezoneWithZParser(),
  x: new ISOTimezoneParser(),
  t: new TimestampSecondsParser(),
  T: new TimestampMillisecondsParser()
};
const formattingTokensRegExp = /[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g;
const longFormattingTokensRegExp = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g;
const escapedStringRegExp = /^'([^]*?)'?$/;
const doubleQuoteRegExp = /''/g;
const notWhitespaceRegExp = /\S/;
const unescapedLatinCharacterRegExp = /[a-zA-Z]/;
function parse$2(dateStr, formatStr, referenceDate, options2) {
  const invalidDate = () => constructFrom(referenceDate, NaN);
  const defaultOptions2 = getDefaultOptions();
  const locale = defaultOptions2.locale ?? enUS;
  const firstWeekContainsDate = defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
  const weekStartsOn = defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
  if (!formatStr)
    return dateStr ? invalidDate() : toDate(referenceDate, options2?.in);
  const subFnOptions = {
    firstWeekContainsDate,
    weekStartsOn,
    locale
  };
  const setters = [new DateTimezoneSetter(options2?.in, referenceDate)];
  const tokens = formatStr.match(longFormattingTokensRegExp).map((substring) => {
    const firstCharacter = substring[0];
    if (firstCharacter in longFormatters) {
      const longFormatter = longFormatters[firstCharacter];
      return longFormatter(substring, locale.formatLong);
    }
    return substring;
  }).join("").match(formattingTokensRegExp);
  const usedTokens = [];
  for (let token of tokens) {
    if (isProtectedWeekYearToken(token)) {
      warnOrThrowProtectedError(token, formatStr, dateStr);
    }
    if (isProtectedDayOfYearToken(token)) {
      warnOrThrowProtectedError(token, formatStr, dateStr);
    }
    const firstCharacter = token[0];
    const parser = parsers$1[firstCharacter];
    if (parser) {
      const { incompatibleTokens } = parser;
      if (Array.isArray(incompatibleTokens)) {
        const incompatibleToken = usedTokens.find(
          (usedToken) => incompatibleTokens.includes(usedToken.token) || usedToken.token === firstCharacter
        );
        if (incompatibleToken) {
          throw new RangeError(
            `The format string mustn't contain \`${incompatibleToken.fullToken}\` and \`${token}\` at the same time`
          );
        }
      } else if (parser.incompatibleTokens === "*" && usedTokens.length > 0) {
        throw new RangeError(
          `The format string mustn't contain \`${token}\` and any other token at the same time`
        );
      }
      usedTokens.push({ token: firstCharacter, fullToken: token });
      const parseResult = parser.run(
        dateStr,
        token,
        locale.match,
        subFnOptions
      );
      if (!parseResult) {
        return invalidDate();
      }
      setters.push(parseResult.setter);
      dateStr = parseResult.rest;
    } else {
      if (firstCharacter.match(unescapedLatinCharacterRegExp)) {
        throw new RangeError(
          "Format string contains an unescaped latin alphabet character `" + firstCharacter + "`"
        );
      }
      if (token === "''") {
        token = "'";
      } else if (firstCharacter === "'") {
        token = cleanEscapedString(token);
      }
      if (dateStr.indexOf(token) === 0) {
        dateStr = dateStr.slice(token.length);
      } else {
        return invalidDate();
      }
    }
  }
  if (dateStr.length > 0 && notWhitespaceRegExp.test(dateStr)) {
    return invalidDate();
  }
  const uniquePrioritySetters = setters.map((setter) => setter.priority).sort((a, b) => b - a).filter((priority, index, array) => array.indexOf(priority) === index).map(
    (priority) => setters.filter((setter) => setter.priority === priority).sort((a, b) => b.subPriority - a.subPriority)
  ).map((setterArray) => setterArray[0]);
  let date = toDate(referenceDate, options2?.in);
  if (isNaN(+date)) return invalidDate();
  const flags2 = {};
  for (const setter of uniquePrioritySetters) {
    if (!setter.validate(date, subFnOptions)) {
      return invalidDate();
    }
    const result = setter.set(date, flags2, subFnOptions);
    if (Array.isArray(result)) {
      date = result[0];
      Object.assign(flags2, result[1]);
    } else {
      date = result;
    }
  }
  return date;
}
function cleanEscapedString(input) {
  return input.match(escapedStringRegExp)[1].replace(doubleQuoteRegExp, "'");
}
window.Vaadin.Flow.datepickerConnector = {};
window.Vaadin.Flow.datepickerConnector.initLazy = (datepicker) => {
  if (datepicker.$connector) {
    return;
  }
  datepicker.$connector = {};
  const createLocaleBasedDateFormat = function(locale) {
    try {
      (/* @__PURE__ */ new Date()).toLocaleDateString(locale);
    } catch (e) {
      console.warn("The locale is not supported, using default format setting (ISO 8601).");
      return "yyyy-MM-dd";
    }
    const testDate = new Date(Date.UTC(1234, 4, 6));
    let pattern = testDate.toLocaleDateString(locale, { timeZone: "UTC" });
    pattern = pattern.replace(/([a-zA-Z]+)/g, "'$1'").replace("06", "dd").replace("6", "d").replace("05", "MM").replace("5", "M").replace("1234", "yyyy");
    const isValidPattern = pattern.includes("d") && pattern.includes("M") && pattern.includes("y");
    if (!isValidPattern) {
      console.warn("The locale is not supported, using default format setting (ISO 8601).");
      return "yyyy-MM-dd";
    }
    return pattern;
  };
  function createFormatterAndParser(formats) {
    if (!formats || formats.length === 0) {
      throw new Error("Array of custom date formats is null or empty");
    }
    function getShortYearFormat(format2) {
      if (format2.includes("yyyy") && !format2.includes("yyyyy")) {
        return format2.replace("yyyy", "yy");
      }
      if (format2.includes("YYYY") && !format2.includes("YYYYY")) {
        return format2.replace("YYYY", "YY");
      }
      return void 0;
    }
    function isFormatWithYear(format2) {
      return format2.includes("y") || format2.includes("Y");
    }
    function isShortYearFormat(format2) {
      return !format2.includes("yyyy") && !format2.includes("YYYY");
    }
    function getExtendedFormats(formats2) {
      return formats2.reduce((acc, format2) => {
        if (isFormatWithYear(format2) && !isShortYearFormat(format2)) {
          acc.push(getShortYearFormat(format2));
        }
        acc.push(format2);
        return acc;
      }, []);
    }
    function correctFullYear(date) {
      if (datepicker.$connector._lastParseStatus === "error") {
        return;
      }
      if (datepicker.$connector._lastParseStatus === "successful") {
        if (datepicker.$connector._lastParsedDate.day === date.getDate() && datepicker.$connector._lastParsedDate.month === date.getMonth() && datepicker.$connector._lastParsedDate.year % 100 === date.getFullYear() % 100) {
          date.setFullYear(datepicker.$connector._lastParsedDate.year);
        }
        return;
      }
      const currentValue = parseDate(datepicker.value);
      if (isValid(currentValue) && currentValue.getDate() === date.getDate() && currentValue.getMonth() === date.getMonth() && currentValue.getFullYear() % 100 === date.getFullYear() % 100) {
        date.setFullYear(currentValue.getFullYear());
      }
    }
    function formatDate(dateParts) {
      const format$12 = formats[0];
      const date = parseDate(`${dateParts.year}-${dateParts.month + 1}-${dateParts.day}`);
      return format(date, format$12);
    }
    function doParseDate(dateString, format2, referenceDate) {
      const refDate = isFormatWithYear(format2) ? referenceDate : /* @__PURE__ */ new Date();
      const date = parse$2(dateString, format2, refDate);
      if (isValid(date)) {
        if (isFormatWithYear(format2) && isShortYearFormat(format2)) {
          correctFullYear(date);
        }
        return {
          day: date.getDate(),
          month: date.getMonth(),
          year: date.getFullYear()
        };
      }
    }
    function parseDate$1(dateString) {
      const referenceDate = _getReferenceDate();
      for (let format2 of getExtendedFormats(formats)) {
        const parsedDate = doParseDate(dateString, format2, referenceDate);
        if (parsedDate) {
          datepicker.$connector._lastParseStatus = "successful";
          datepicker.$connector._lastParsedDate = parsedDate;
          return parsedDate;
        }
      }
      datepicker.$connector._lastParseStatus = "error";
      return false;
    }
    return {
      formatDate,
      parseDate: parseDate$1
    };
  }
  function _getReferenceDate() {
    const { referenceDate } = datepicker.i18n;
    return referenceDate ? new Date(referenceDate.year, referenceDate.month, referenceDate.day) : /* @__PURE__ */ new Date();
  }
  datepicker.$connector.updateI18n = (locale, i18n) => {
    const hasCustomFormats = i18n && i18n.dateFormats && i18n.dateFormats.length > 0;
    if (i18n && i18n.referenceDate) {
      i18n.referenceDate = extractDateParts(new Date(i18n.referenceDate));
    }
    const usedFormats = hasCustomFormats ? i18n.dateFormats : [createLocaleBasedDateFormat(locale)];
    const formatterAndParser = createFormatterAndParser(usedFormats);
    datepicker.i18n = Object.assign({}, i18n, formatterAndParser);
  };
  datepicker.addEventListener("opened-changed", () => datepicker.$connector._lastParseStatus = void 0);
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class TimePickerItem extends ComboBoxItemMixin(
  ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-time-picker-item";
  }
  static get styles() {
    return [itemStyles, comboBoxItemStyles];
  }
  /** @protected */
  render() {
    return html`
      <span part="checkmark" aria-hidden="true"></span>
      <div part="content">
        <slot></slot>
      </div>
    `;
  }
}
defineCustomElement(TimePickerItem);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const timePickerOverlayStyles = css$h`
  :host {
    --vaadin-item-checkmark-display: block;
  }

  #overlay {
    width: var(--vaadin-time-picker-overlay-width, var(--_vaadin-time-picker-overlay-default-width, auto));
  }

  [part='content'] {
    display: flex;
    flex-direction: column;
    height: 100%;
  }
`;
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class TimePickerOverlay extends ComboBoxOverlayMixin(
  OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-time-picker-overlay";
  }
  static get styles() {
    return [overlayStyles, timePickerOverlayStyles];
  }
  /** @protected */
  render() {
    return html`
      <div part="overlay" id="overlay">
        <div part="content" id="content">
          <slot></slot>
        </div>
      </div>
    `;
  }
}
defineCustomElement(TimePickerOverlay);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class TimePickerScroller extends ComboBoxScrollerMixin(PolylitMixin(LitElement)) {
  static get is() {
    return "vaadin-time-picker-scroller";
  }
  static get styles() {
    return comboBoxScrollerStyles;
  }
  /** @protected */
  render() {
    return html`
      <div id="selector">
        <slot></slot>
      </div>
    `;
  }
}
defineCustomElement(TimePickerScroller);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const timePickerStyles = css$h`
  :host([opened]) {
    pointer-events: auto;
  }

  [part~='toggle-button']::before {
    mask-image: var(--_vaadin-icon-clock);
  }

  :host([readonly]) [part~='toggle-button'] {
    display: none;
  }

  /* See https://github.com/vaadin/vaadin-time-picker/issues/145 */
  :host([dir='rtl']) [part='input-field'] {
    direction: ltr;
  }

  :host([dir='rtl']) [part='input-field'] ::slotted(input)::placeholder {
    direction: rtl;
    text-align: left;
  }
`;
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function formatISOTime(time) {
  if (!time) {
    return "";
  }
  const pad2 = (num = 0, fmt = "00") => (fmt + num).substr((fmt + num).length - fmt.length);
  let timeString = `${pad2(time.hours)}:${pad2(time.minutes)}`;
  if (time.seconds !== void 0) {
    timeString += `:${pad2(time.seconds)}`;
  }
  if (time.milliseconds !== void 0) {
    timeString += `.${pad2(time.milliseconds, "000")}`;
  }
  return timeString;
}
const MATCH_HOURS = "(\\d|[0-1]\\d|2[0-3])";
const MATCH_MINUTES = "(\\d|[0-5]\\d)";
const MATCH_SECONDS = MATCH_MINUTES;
const MATCH_MILLISECONDS = "(\\d{1,3})";
const re = new RegExp(`^${MATCH_HOURS}(?::${MATCH_MINUTES}(?::${MATCH_SECONDS}(?:\\.${MATCH_MILLISECONDS})?)?)?$`, "u");
function parseISOTime(timeString) {
  const parts = re.exec(timeString);
  if (parts) {
    if (parts[4]) {
      while (parts[4].length < 3) {
        parts[4] += "0";
      }
    }
    return { hours: parts[1], minutes: parts[2], seconds: parts[3], milliseconds: parts[4] };
  }
}
function getStepSegment(stepValue) {
  const step = stepValue == null ? 60 : parseFloat(stepValue);
  if (step % 3600 === 0) {
    return 1;
  } else if (step % 60 === 0 || !step) {
    return 2;
  } else if (step % 1 === 0) {
    return 3;
  } else if (step < 1) {
    return 4;
  }
}
function validateTime(timeObject, step) {
  if (timeObject) {
    const stepSegment = getStepSegment(step);
    timeObject.hours = parseInt(timeObject.hours);
    timeObject.minutes = parseInt(timeObject.minutes || 0);
    timeObject.seconds = stepSegment < 3 ? void 0 : parseInt(timeObject.seconds || 0);
    timeObject.milliseconds = stepSegment < 4 ? void 0 : parseInt(timeObject.milliseconds || 0);
  }
  return timeObject;
}
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const timePickerI18nDefaults = Object.freeze({
  formatTime: formatISOTime,
  parseTime: parseISOTime
});
const MIN_ALLOWED_TIME = "00:00:00.000";
const MAX_ALLOWED_TIME = "23:59:59.999";
const TimePickerMixin = (superClass) => class TimePickerMixinClass extends I18nMixin(
  timePickerI18nDefaults,
  PatternMixin(ComboBoxBaseMixin(InputControlMixin(superClass)))
) {
  static get properties() {
    return {
      /**
       * The time value for this element.
       *
       * Supported time formats are in ISO 8601:
       * - `hh:mm` (default)
       * - `hh:mm:ss`
       * - `hh:mm:ss.fff`
       */
      value: {
        type: String,
        notify: true,
        value: "",
        sync: true
      },
      /**
       * Minimum time allowed.
       *
       * Supported time formats are in ISO 8601:
       * - `hh:mm`
       * - `hh:mm:ss`
       * - `hh:mm:ss.fff`
       */
      min: {
        type: String,
        value: "",
        sync: true
      },
      /**
       * Maximum time allowed.
       *
       * Supported time formats are in ISO 8601:
       * - `hh:mm`
       * - `hh:mm:ss`
       * - `hh:mm:ss.fff`
       */
      max: {
        type: String,
        value: "",
        sync: true
      },
      /**
       * Defines the time interval (in seconds) between the items displayed
       * in the time selection box. The default is 1 hour (i.e. `3600`).
       *
       * It also configures the precision of the value string. By default
       * the component formats values as `hh:mm` but setting a step value
       * lower than one minute or one second, format resolution changes to
       * `hh:mm:ss` and `hh:mm:ss.fff` respectively.
       *
       * Unit must be set in seconds, and for correctly configuring intervals
       * in the dropdown, it need to evenly divide a day.
       *
       * Note: it is possible to define step that is dividing an hour in inexact
       * fragments (i.e. 5760 seconds which equals 1 hour 36 minutes), but it is
       * not recommended to use it for better UX experience.
       */
      step: {
        type: Number,
        sync: true
      },
      /** @private */
      _comboBoxValue: {
        type: String,
        sync: true,
        observer: "__comboBoxValueChanged"
      },
      /** @private */
      _inputContainer: {
        type: Object
      }
    };
  }
  static get observers() {
    return [
      "_openedOrItemsChanged(opened, _dropdownItems)",
      "_updateScroller(opened, _dropdownItems, _focusedIndex, _theme)",
      "__updateAriaAttributes(_dropdownItems, opened, inputElement)",
      "__updateDropdownItems(__effectiveI18n, min, max, step)"
    ];
  }
  static get constraints() {
    return [...super.constraints, "min", "max"];
  }
  /**
   * Tag name prefix used by `ComboBoxBaseMixin` for scroller and items.
   * @protected
   * @return {string}
   */
  get _tagNamePrefix() {
    return "vaadin-time-picker";
  }
  /**
   * Used by `ClearButtonMixin` as a reference to the clear button element.
   * @protected
   * @return {!HTMLElement}
   */
  get clearElement() {
    return this.$.clearButton;
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides both the
   * time parsing and formatting functions.
   *
   * The object has the following JSON structure:
   *
   * ```js
   * {
   *   // A function to format given `Object` as
   *   // time string. Object is in the format `{ hours: ..., minutes: ..., seconds: ..., milliseconds: ... }`
   *   formatTime: (time) => {
   *     // returns a string representation of the given
   *     // object in `hh` / 'hh:mm' / 'hh:mm:ss' / 'hh:mm:ss.fff' - formats
   *   },
   *
   *   // A function to parse the given text to an `Object` in the format
   *   // `{ hours: ..., minutes: ..., seconds: ..., milliseconds: ... }`.
   *   // Must properly parse (at least) text
   *   // formatted by `formatTime`.
   *   parseTime: text => {
   *     // Parses a string in object/string that can be formatted by`formatTime`.
   *   }
   * }
   * ```
   *
   * NOTE: `formatTime` and `parseTime` must be implemented in a
   * compatible manner to ensure the component works properly.
   *
   * @type {!TimePickerI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /**
   * The input element's value when it cannot be parsed as a time, and an empty string otherwise.
   *
   * @private
   * @return {string}
   */
  get __unparsableValue() {
    if (this._inputElementValue && !this.__effectiveI18n.parseTime(this._inputElementValue)) {
      return this._inputElementValue;
    }
    return "";
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(
      new InputController(
        this,
        (input) => {
          this._setInputElement(input);
          this._setFocusElement(input);
          this.stateTarget = input;
          this.ariaTarget = input;
        },
        {
          // The "search" word is a trick to prevent Safari from enabling AutoFill,
          // which is causing click issues:
          // https://github.com/vaadin/web-components/issues/6817#issuecomment-2268229567
          uniqueIdPrefix: "search-input"
        }
      )
    );
    this.addController(new LabelledInputController(this.inputElement, this._labelController));
    this._inputContainer = this.shadowRoot.querySelector('[part~="input-field"]');
    this._toggleElement = this.$.toggleButton;
    this._tooltipController = new TooltipController(this);
    this._tooltipController.setShouldShow((timePicker) => !timePicker.opened);
    this._tooltipController.setPosition("top");
    this._tooltipController.setAriaTarget(this.inputElement);
    this.addController(this._tooltipController);
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("_comboBoxValue") && this._dropdownItems) {
      this._scroller.selectedItem = this._dropdownItems.find((item) => item.value === this._comboBoxValue);
    }
  }
  /**
   * Returns true if the current input value satisfies all constraints (if any).
   * You can override this method for custom validations.
   *
   * @return {boolean} True if the value is valid
   */
  checkValidity() {
    return !!(this.inputElement.checkValidity() && (!this.value || this._timeAllowed(this.__effectiveI18n.parseTime(this.value))) && (!this._comboBoxValue || this.__effectiveI18n.parseTime(this._comboBoxValue)));
  }
  /**
   * Override method from `ComboBoxBaseMixin` to handle item label path.
   * @protected
   * @override
   */
  _getItemLabel(item) {
    return item ? item.label : "";
  }
  /** @private */
  _updateScroller(opened, items, focusedIndex, theme2) {
    if (opened) {
      this._scroller.style.maxHeight = getComputedStyle(this).getPropertyValue(`--${this._tagNamePrefix}-overlay-max-height`) || "65vh";
    }
    this._scroller.setProperties({
      items: opened ? items : [],
      opened,
      focusedIndex,
      theme: theme2
    });
  }
  /** @private */
  _openedOrItemsChanged(opened, items) {
    this._overlayOpened = opened && !!(items && items.length);
  }
  /**
   * Override method from `ComboBoxBaseMixin` to commit value on overlay closing.
   * @protected
   * @override
   */
  _onClosed() {
    this._commitValue();
  }
  /**
   * Override method from `ComboBoxBaseMixin` to handle Escape pres..
   * @protected
   * @override
   */
  _onEscapeCancel() {
    this._inputElementValue = this._comboBoxValue;
    this._closeOrCommit();
  }
  /**
   * Override method from `ComboBoxBaseMixin` to implement clearing logic.
   * @protected
   * @override
   */
  _onClearAction() {
    this._comboBoxValue = "";
    this._inputElementValue = "";
    this.__commitValueChange();
  }
  /**
   * Override method from `ComboBoxBaseMixin` to implement value commit logic.
   * @protected
   * @override
   */
  _commitValue() {
    if (this._focusedIndex > -1) {
      const focusedItem = this._dropdownItems[this._focusedIndex];
      const itemValue = this._getItemLabel(focusedItem);
      this._inputElementValue = itemValue;
      this._comboBoxValue = itemValue;
      this._focusedIndex = -1;
    } else if (this._inputElementValue === "" || this._inputElementValue === void 0) {
      this._comboBoxValue = "";
    } else {
      this._comboBoxValue = this._inputElementValue;
    }
    this.__commitValueChange();
    this._clearSelectionRange();
  }
  /**
   * Override method from `ComboBoxBaseMixin` to handle loading.
   * @protected
   * @override
   */
  _closeOrCommit() {
    if (!this.opened) {
      this._commitValue();
    } else {
      this.close();
    }
  }
  /**
   * Override method from `ComboBoxBaseMixin` to handle reverting value.
   * @protected
   * @override
   */
  _revertInputValue() {
    this._inputElementValue = this._comboBoxValue;
    this._clearSelectionRange();
  }
  /**
   * @param {boolean} focused
   * @override
   * @protected
   */
  _setFocused(focused) {
    super._setFocused(focused);
    if (!focused) {
      if (document.hasFocus()) {
        this._requestValidation();
      }
    }
  }
  /** @private */
  __validDayDivisor(step) {
    return !step || 24 * 3600 % step === 0 || step < 1 && step % 1 * 1e3 % 1 === 0;
  }
  /**
   * Override an event listener from `KeyboardMixin`.
   * @param {!KeyboardEvent} e
   * @protected
   */
  _onKeyDown(e) {
    super._onKeyDown(e);
    if (this.readonly || this.disabled || this._dropdownItems.length) {
      return;
    }
    const stepResolution = this.__validDayDivisor(this.step) && this.step || 60;
    if (e.keyCode === 40) {
      this.__onArrowPressWithStep(-stepResolution);
    } else if (e.keyCode === 38) {
      this.__onArrowPressWithStep(stepResolution);
    }
  }
  /** @private */
  __onArrowPressWithStep(step) {
    const objWithStep = this.__addStep(this.__getMsec(this.__memoValue), step, true);
    this.__memoValue = objWithStep;
    this.__useMemo = true;
    this._comboBoxValue = this.__effectiveI18n.formatTime(objWithStep);
    this.__useMemo = false;
    this.__commitValueChange();
  }
  /**
   * Depending on the nature of the value change that has occurred since
   * the last commit attempt, triggers validation and fires an event:
   *
   * Value change             | Event
   * -------------------------|-------------------
   * empty => parsable        | change
   * empty => unparsable      | unparsable-change
   * parsable => empty        | change
   * parsable => parsable     | change
   * parsable => unparsable   | change
   * unparsable => empty      | unparsable-change
   * unparsable => parsable   | change
   * unparsable => unparsable | unparsable-change
   *
   * @private
   */
  __commitValueChange() {
    const unparsableValue = this.__unparsableValue;
    if (this.__committedValue !== this.value) {
      this._requestValidation();
      this.dispatchEvent(new CustomEvent("change", { bubbles: true }));
    } else if (this.__committedUnparsableValue !== unparsableValue) {
      this._requestValidation();
      this.dispatchEvent(new CustomEvent("unparsable-change"));
    }
    this.__committedValue = this.value;
    this.__committedUnparsableValue = unparsableValue;
  }
  /**
   * Returning milliseconds from Object in the format `{ hours: ..., minutes: ..., seconds: ..., milliseconds: ... }`
   * @private
   */
  __getMsec(obj) {
    let result = (obj && obj.hours || 0) * 60 * 60 * 1e3;
    result += (obj && obj.minutes || 0) * 60 * 1e3;
    result += (obj && obj.seconds || 0) * 1e3;
    result += obj && parseInt(obj.milliseconds) || 0;
    return result;
  }
  /**
   * Returning seconds from Object in the format `{ hours: ..., minutes: ..., seconds: ..., milliseconds: ... }`
   * @private
   */
  __getSec(obj) {
    let result = (obj && obj.hours || 0) * 60 * 60;
    result += (obj && obj.minutes || 0) * 60;
    result += obj && obj.seconds || 0;
    result += obj && obj.milliseconds / 1e3 || 0;
    return result;
  }
  /**
   * Returning Object in the format `{ hours: ..., minutes: ..., seconds: ..., milliseconds: ... }`
   * from the result of adding step value in milliseconds to the milliseconds amount.
   * With `precision` parameter rounding the value to the closest step valid interval.
   * @private
   */
  __addStep(msec, step, precision) {
    if (msec === 0 && step < 0) {
      msec = 24 * 60 * 60 * 1e3;
    }
    const stepMsec = step * 1e3;
    const diffToNext = msec % stepMsec;
    if (stepMsec < 0 && diffToNext && precision) {
      msec -= diffToNext;
    } else if (stepMsec > 0 && diffToNext && precision) {
      msec -= diffToNext - stepMsec;
    } else {
      msec += stepMsec;
    }
    const hh = Math.floor(msec / 1e3 / 60 / 60);
    msec -= hh * 1e3 * 60 * 60;
    const mm = Math.floor(msec / 1e3 / 60);
    msec -= mm * 1e3 * 60;
    const ss = Math.floor(msec / 1e3);
    msec -= ss * 1e3;
    return { hours: hh < 24 ? hh : 0, minutes: mm, seconds: ss, milliseconds: msec };
  }
  /** @private */
  __updateDropdownItems(effectiveI18n, min2, max2, step) {
    const minTimeObj = validateTime(parseISOTime(min2 || MIN_ALLOWED_TIME), step);
    const minSec = this.__getSec(minTimeObj);
    const maxTimeObj = validateTime(parseISOTime(max2 || MAX_ALLOWED_TIME), step);
    const maxSec = this.__getSec(maxTimeObj);
    this._dropdownItems = this.__generateDropdownList(minSec, maxSec, step);
    if (step !== this.__oldStep) {
      this.__oldStep = step;
      const parsedObj = validateTime(parseISOTime(this.value), step);
      this.__updateValue(parsedObj);
    }
    if (this.value) {
      this._comboBoxValue = effectiveI18n.formatTime(effectiveI18n.parseTime(this.value));
    }
  }
  /** @private */
  __updateAriaAttributes(items, opened, input) {
    if (items === void 0 || input === void 0) {
      return;
    }
    if (items.length === 0) {
      input.removeAttribute("role");
      input.removeAttribute("aria-expanded");
    } else {
      input.setAttribute("role", "combobox");
      input.setAttribute("aria-expanded", !!opened);
    }
  }
  /** @private */
  __generateDropdownList(minSec, maxSec, step) {
    if (step < 15 * 60 || !this.__validDayDivisor(step)) {
      return [];
    }
    const generatedList = [];
    if (!step) {
      step = 3600;
    }
    let time = -step + minSec;
    while (time + step >= minSec && time + step <= maxSec) {
      const timeObj = validateTime(this.__addStep(time * 1e3, step), step);
      time += step;
      const formatted = this.__effectiveI18n.formatTime(timeObj);
      generatedList.push({ label: formatted, value: formatted });
    }
    return generatedList;
  }
  /**
   * Override an observer from `InputMixin`.
   * @protected
   * @override
   */
  _valueChanged(value, oldValue) {
    const parsedObj = this.__memoValue = parseISOTime(value);
    const newValue = formatISOTime(parsedObj) || "";
    if (!this.__keepCommittedValue) {
      this.__committedValue = value;
      this.__committedUnparsableValue = "";
    }
    if (value !== "" && value !== null && !parsedObj) {
      this.value = oldValue === void 0 ? "" : oldValue;
    } else if (value !== newValue) {
      this.value = newValue;
    } else if (this.__keepInvalidInput) {
      delete this.__keepInvalidInput;
    } else {
      this.__updateInputValue(parsedObj);
    }
    this._toggleHasValue(this._hasValue);
  }
  /** @private */
  __comboBoxValueChanged(value, oldValue) {
    if (value === "" && oldValue === void 0) {
      return;
    }
    const parsedObj = this.__useMemo ? this.__memoValue : this.__effectiveI18n.parseTime(value);
    const newValue = this.__effectiveI18n.formatTime(parsedObj) || "";
    if (parsedObj) {
      if (value !== newValue) {
        this._comboBoxValue = newValue;
      } else {
        this.__keepCommittedValue = true;
        this.__updateValue(parsedObj);
        this.__keepCommittedValue = false;
      }
    } else {
      if (this.value !== "" && value !== "") {
        this.__keepInvalidInput = true;
      }
      this.__keepCommittedValue = true;
      this.value = "";
      this.__keepCommittedValue = false;
    }
  }
  /** @private */
  __updateValue(obj) {
    const timeString = formatISOTime(validateTime(obj, this.step)) || "";
    this.value = timeString;
    this.__updateInputValue(obj);
  }
  /** @private */
  __updateInputValue(obj) {
    const timeString = this.__effectiveI18n.formatTime(validateTime(obj, this.step)) || "";
    this._inputElementValue = timeString;
    this._comboBoxValue = timeString;
  }
  /**
   * Returns true if `time` satisfies the `min` and `max` constraints (if any).
   *
   * @param {!TimePickerTime} time Value to check against constraints
   * @return {boolean} True if `time` satisfies the constraints
   * @protected
   */
  _timeAllowed(time) {
    const parsedMin = this.__effectiveI18n.parseTime(this.min || MIN_ALLOWED_TIME);
    const parsedMax = this.__effectiveI18n.parseTime(this.max || MAX_ALLOWED_TIME);
    return (!this.__getMsec(parsedMin) || this.__getMsec(time) >= this.__getMsec(parsedMin)) && (!this.__getMsec(parsedMax) || this.__getMsec(time) <= this.__getMsec(parsedMax));
  }
  /**
   * Override method from `ComboBoxBaseMixin` to deselect
   * dropdown item by requesting content update on clear.
   * @param {Event} event
   * @protected
   */
  _onClearButtonClick(event) {
    event.stopPropagation();
    super._onClearButtonClick(event);
    if (this.opened) {
      this._scroller.requestContentUpdate();
    }
  }
  /**
   * @param {Event} event
   * @protected
   */
  _onHostClick(event) {
    const path = event.composedPath();
    if (path.includes(this._labelNode) || path.includes(this._inputContainer)) {
      super._onHostClick(event);
    }
  }
  /**
   * Override an event listener from `InputMixin`.
   * @param {!Event} event
   * @protected
   * @override
   */
  _onChange(event) {
    event.stopPropagation();
  }
  /**
   * Fired when the user commits a value change.
   *
   * @event change
   */
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class TimePicker extends TimePickerMixin(ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-time-picker";
  }
  static get styles() {
    return [inputFieldShared, timePickerStyles];
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-time-picker-container">
        <div part="label">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true" @click="${this.focus}"></span>
        </div>

        <vaadin-input-container
          part="input-field"
          .readonly="${this.readonly}"
          .disabled="${this.disabled}"
          .invalid="${this.invalid}"
          theme="${ifDefined(this._theme)}"
        >
          <slot name="prefix" slot="prefix"></slot>
          <slot name="input"></slot>
          <div id="clearButton" part="field-button clear-button" slot="suffix" aria-hidden="true"></div>
          <div id="toggleButton" part="field-button toggle-button" slot="suffix" aria-hidden="true"></div>
        </vaadin-input-container>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>

        <slot name="tooltip"></slot>
      </div>

      <vaadin-time-picker-overlay
        id="overlay"
        dir="ltr"
        .owner="${this}"
        .opened="${this._overlayOpened}"
        theme="${ifDefined(this._theme)}"
        .positionTarget="${this._inputContainer}"
        no-vertical-overlap
        exportparts="overlay, content"
      >
        <slot name="overlay"></slot>
      </vaadin-time-picker-overlay>
    `;
  }
}
defineCustomElement(TimePicker);
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const dateTimePickerStyles = css$h`
  .vaadin-date-time-picker-container {
    width: calc(var(--vaadin-field-default-width, 12em) * 2 + var(--vaadin-date-time-picker-gap, var(--vaadin-gap-s)));
  }

  [part='input-fields'] {
    display: flex;
    gap: var(--vaadin-date-time-picker-gap, var(--vaadin-gap-s));
  }

  [part='input-fields'] ::slotted([slot='date-picker']) {
    min-width: 0;
    flex: 1 1 auto;
  }

  [part='input-fields'] ::slotted([slot='time-picker']) {
    min-width: 0;
    flex: 1 1.65 auto;
  }
`;
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const datePickerI18nProps = Object.keys(datePickerI18nDefaults);
const timePickerI18nProps = Object.keys(timePickerI18nDefaults);
const DEFAULT_I18N$6 = { ...datePickerI18nDefaults, ...timePickerI18nDefaults };
class PickerSlotController extends SlotController {
  constructor(host, type) {
    super(host, `${type}-picker`, `vaadin-${type}-picker`, {
      initializer: (picker, host2) => {
        const prop = `__${type}Picker`;
        host2[prop] = picker;
      }
    });
  }
}
const DateTimePickerMixin = (superClass) => class DateTimePickerMixinClass extends I18nMixin(DEFAULT_I18N$6, FieldMixin(FocusMixin(DisabledMixin(superClass)))) {
  static get properties() {
    return {
      /**
       * The name of the control, which is submitted with the form data.
       */
      name: {
        type: String
      },
      /**
       * The value for this element.
       *
       * Supported date time format is based on ISO 8601 (without a time zone designator):
       * - Minute precision `"YYYY-MM-DDThh:mm"` (default)
       * - Second precision `"YYYY-MM-DDThh:mm:ss"`
       * - Millisecond precision `"YYYY-MM-DDThh:mm:ss.fff"`
       */
      value: {
        type: String,
        notify: true,
        value: "",
        observer: "__valueChanged",
        sync: true
      },
      /**
       * The earliest allowed value (date and time) that can be selected. All earlier values will be disabled.
       *
       * Supported date time format is based on ISO 8601 (without a time zone designator):
       * - Minute precision `"YYYY-MM-DDThh:mm"`
       * - Second precision `"YYYY-MM-DDThh:mm:ss"`
       * - Millisecond precision `"YYYY-MM-DDThh:mm:ss.fff"`
       */
      min: {
        type: String,
        observer: "__minChanged",
        sync: true
      },
      /**
       * The latest value (date and time) that can be selected. All later values will be disabled.
       *
       * Supported date time format is based on ISO 8601 (without a time zone designator):
       * - Minute precision `"YYYY-MM-DDThh:mm"`
       * - Second precision `"YYYY-MM-DDThh:mm:ss"`
       * - Millisecond precision `"YYYY-MM-DDThh:mm:ss.fff"`
       */
      max: {
        type: String,
        observer: "__maxChanged",
        sync: true
      },
      /**
       * The earliest value that can be selected. All earlier values will be disabled.
       * @private
       */
      __minDateTime: {
        type: Date,
        value: "",
        sync: true
      },
      /**
       * The latest value that can be selected. All later values will be disabled.
       * @private
       */
      __maxDateTime: {
        type: Date,
        value: "",
        sync: true
      },
      /**
       * A placeholder string for the date field.
       * @attr {string} date-placeholder
       */
      datePlaceholder: {
        type: String,
        sync: true
      },
      /**
       * A placeholder string for the time field.
       * @attr {string} time-placeholder
       */
      timePlaceholder: {
        type: String,
        sync: true
      },
      /**
       * Defines the time interval (in seconds) between the items displayed
       * in the time selection box. The default is 1 hour (i.e. `3600`).
       *
       * It also configures the precision of the time part of the value string. By default
       * the component formats time values as `hh:mm` but setting a step value
       * lower than one minute or one second, format resolution changes to
       * `hh:mm:ss` and `hh:mm:ss.fff` respectively.
       *
       * Unit must be set in seconds, and for correctly configuring intervals
       * in the dropdown, it need to evenly divide a day.
       *
       * Note: it is possible to define step that is dividing an hour in inexact
       * fragments (i.e. 5760 seconds which equals 1 hour 36 minutes), but it is
       * not recommended to use it for better UX.
       */
      step: {
        type: Number,
        sync: true
      },
      /**
       * Date which should be visible in the date picker overlay when there is no value selected.
       *
       * The same date formats as for the `value` property are supported but without the time part.
       * @attr {string} initial-position
       */
      initialPosition: {
        type: String,
        sync: true
      },
      /**
       * Set true to display ISO-8601 week numbers in the calendar. Notice that
       * displaying week numbers is only supported when `i18n.firstDayOfWeek`
       * is 1 (Monday).
       * @attr {boolean} show-week-numbers
       */
      showWeekNumbers: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * Set to true to prevent the overlays from opening automatically.
       * @attr {boolean} auto-open-disabled
       */
      autoOpenDisabled: {
        type: Boolean,
        sync: true
      },
      /**
       * Set to true to make this element read-only.
       */
      readonly: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Specify that this control should have input focus when the page loads.
       */
      autofocus: {
        type: Boolean
      },
      /**
       * The current selected date time.
       * @private
       */
      __selectedDateTime: {
        type: Date,
        sync: true
      },
      /**
       * The current slotted date picker.
       * @private
       */
      __datePicker: {
        type: Object,
        sync: true,
        observer: "__datePickerChanged"
      },
      /**
       * The current slotted time picker.
       * @private
       */
      __timePicker: {
        type: Object,
        sync: true,
        observer: "__timePickerChanged"
      }
    };
  }
  static get observers() {
    return [
      "__selectedDateTimeChanged(__selectedDateTime)",
      "__datePlaceholderChanged(datePlaceholder, __datePicker)",
      "__timePlaceholderChanged(timePlaceholder, __timePicker)",
      "__stepChanged(step, __timePicker)",
      "__initialPositionChanged(initialPosition, __datePicker)",
      "__showWeekNumbersChanged(showWeekNumbers, __datePicker)",
      "__requiredChanged(required, __datePicker, __timePicker)",
      "__invalidChanged(invalid, __datePicker, __timePicker)",
      "__disabledChanged(disabled, __datePicker, __timePicker)",
      "__readonlyChanged(readonly, __datePicker, __timePicker)",
      "__i18nChanged(__effectiveI18n, __datePicker, __timePicker)",
      "__autoOpenDisabledChanged(autoOpenDisabled, __datePicker, __timePicker)",
      "__themeChanged(_theme, __datePicker, __timePicker)",
      "__pickersChanged(__datePicker, __timePicker)",
      "__labelOrAccessibleNameChanged(label, accessibleName, __effectiveI18n, __datePicker, __timePicker)"
    ];
  }
  constructor() {
    super();
    this.__defaultDateMinMaxValue = void 0;
    this.__defaultTimeMinValue = "00:00:00.000";
    this.__defaultTimeMaxValue = "23:59:59.999";
    this.__onGlobalClick = this.__onGlobalClick.bind(this);
    this.__changeEventHandler = this.__changeEventHandler.bind(this);
    this.__valueChangedEventHandler = this.__valueChangedEventHandler.bind(this);
    this.__openedChangedEventHandler = this.__openedChangedEventHandler.bind(this);
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following structure and default values:
   *
   * ```js
   * {
   *   // Accessible label to the date picker.
   *   // The property works in conjunction with label and accessibleName defined on the field.
   *   // If both properties are defined, then accessibleName takes precedence.
   *   // Then, the dateLabel value is concatenated with it.
   *   dateLabel: undefined;
   *
   *   // Accessible label to the time picker.
   *   // The property works in conjunction with label and accessibleName defined on the field.
   *   // If both properties are defined, then accessibleName takes precedence.
   *   // Then, the dateLabel value is concatenated with it.
   *   timeLabel: undefined;
   * }
   * ```
   *
   * Additionally, all i18n properties from
   * [`<vaadin-date-picker>`](#/elements/vaadin-date-picker) and
   * [`<vaadin-time-picker>`](#/elements/vaadin-time-picker) are supported.
   *
   * @type {!DateTimePickerI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @private */
  get __pickers() {
    return [this.__datePicker, this.__timePicker];
  }
  /** @private */
  get __filledPickers() {
    return this.__pickers.filter((picker) => picker.value || picker.__unparsableValue);
  }
  /** @private */
  get __formattedValue() {
    const values = this.__pickers.map((picker) => picker.value);
    return values.every(Boolean) ? values.join("T") : "";
  }
  /**
   * Values:
   * - ""
   * - "fooT"
   * - "Tbar"
   * - "fooTbar"
   * - "T12:00"
   * - "fooT12:00"
   * - "2024-01-01T"
   * - "2024-01-01Tbar"
   *
   * @private
   */
  get __unparsableValue() {
    if (this.__filledPickers.length > 0 && !this.__pickers.every((picker) => picker.value)) {
      return this.__pickers.map((picker) => picker.value || picker.__unparsableValue).join("T");
    }
    return "";
  }
  /** @protected */
  ready() {
    super.ready();
    this._datePickerController = new PickerSlotController(this, "date");
    this.addController(this._datePickerController);
    this._timePickerController = new PickerSlotController(this, "time");
    this.addController(this._timePickerController);
    if (this.autofocus && !this.disabled) {
      window.requestAnimationFrame(() => this.focus());
    }
    this.setAttribute("role", "group");
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
    this._tooltipController.setPosition("top");
    this._tooltipController.setShouldShow((target) => {
      return target.__datePicker && !target.__datePicker.opened && target.__timePicker && !target.__timePicker.opened;
    });
    this.ariaTarget = this;
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    document.addEventListener("click", this.__onGlobalClick, true);
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    document.removeEventListener("click", this.__onGlobalClick, true);
  }
  /**
   * @param {FocusOptions=} options
   * @protected
   * @override
   */
  focus(options2) {
    if (this.__datePicker) {
      this.__datePicker.focus(options2);
    }
  }
  /** @private */
  __onGlobalClick(event) {
    const isOpened = this.__datePicker.opened || this.__timePicker.opened;
    if (!isOpened) {
      return;
    }
    const isOutsideClick = event.composedPath().every((node) => {
      return ![
        this.__datePicker,
        this.__datePicker.$.overlay,
        this.__timePicker,
        this.__timePicker.$.overlay
      ].includes(node);
    });
    if (isOutsideClick) {
      this.__outsideClickInProgress = true;
      setTimeout(() => {
        this.__outsideClickInProgress = false;
      });
    }
  }
  /**
   * Override method inherited from `FocusMixin` to validate on blur.
   * @param {boolean} focused
   * @protected
   * @override
   */
  _setFocused(focused) {
    super._setFocused(focused);
    if (!focused && document.hasFocus()) {
      this.__commitPendingValueChange();
    }
  }
  /**
   * Override method inherited from `FocusMixin` to not remove focused
   * state when focus moves between pickers or to the overlay.
   * @param {FocusEvent} event
   * @return {boolean}
   * @protected
   * @override
   */
  _shouldRemoveFocus(event) {
    const target = event.relatedTarget;
    if (this.__datePicker.opened || this.__timePicker.opened || this.__datePicker.contains(target) || this.__timePicker.contains(target)) {
      return false;
    }
    return true;
  }
  /** @private */
  __syncI18n(target, i18n, props) {
    const targetI18n = {};
    props.forEach((prop) => {
      if (i18n && i18n.hasOwnProperty(prop)) {
        targetI18n[prop] = i18n[prop];
      }
    });
    target.i18n = targetI18n;
  }
  /** @private */
  __changeEventHandler(event) {
    event.stopPropagation();
    const isAlreadyInvalid = this.invalid;
    const filledPickers = this.__filledPickers;
    if (filledPickers.length === 1 && filledPickers[0].checkValidity() && !isAlreadyInvalid) {
      return;
    }
    if (this.__hasPendingValueChange) {
      this.__commitPendingValueChange();
    }
  }
  /** @private */
  __openedChangedEventHandler() {
    const opened = this.__datePicker.opened || this.__timePicker.opened;
    this.style.pointerEvents = opened ? "auto" : "";
    if (!opened && this.__outsideClickInProgress) {
      this.__commitPendingValueChange();
    }
  }
  /** @private */
  __addInputListeners(node) {
    node.addEventListener("change", this.__changeEventHandler);
    node.addEventListener("unparsable-change", this.__changeEventHandler);
    node.addEventListener("value-changed", this.__valueChangedEventHandler);
    node.addEventListener("opened-changed", this.__openedChangedEventHandler);
  }
  /** @private */
  __removeInputListeners(node) {
    node.removeEventListener("change", this.__changeEventHandler);
    node.removeEventListener("unparsable-change", this.__changeEventHandler);
    node.removeEventListener("value-changed", this.__valueChangedEventHandler);
    node.removeEventListener("opened-changed", this.__openedChangedEventHandler);
  }
  /** @private */
  __isDefaultPicker(picker, type) {
    const controller = this[`_${type}PickerController`];
    return controller && picker === controller.defaultNode;
  }
  /** @private */
  __datePickerChanged(newDatePicker, existingDatePicker) {
    if (!newDatePicker) {
      return;
    }
    if (existingDatePicker) {
      this.__removeInputListeners(existingDatePicker);
      existingDatePicker.remove();
    }
    this.__addInputListeners(newDatePicker);
    if (!this.__isDefaultPicker(newDatePicker, "date")) {
      this.datePlaceholder = newDatePicker.placeholder;
      this.initialPosition = newDatePicker.initialPosition;
      this.showWeekNumbers = newDatePicker.showWeekNumbers;
    }
    newDatePicker.min = this.__formatDateISO(this.__minDateTime, this.__defaultDateMinMaxValue);
    newDatePicker.max = this.__formatDateISO(this.__maxDateTime, this.__defaultDateMinMaxValue);
    newDatePicker.manualValidation = true;
  }
  /** @private */
  __timePickerChanged(newTimePicker, existingTimePicker) {
    if (!newTimePicker) {
      return;
    }
    if (existingTimePicker) {
      this.__removeInputListeners(existingTimePicker);
      existingTimePicker.remove();
    }
    this.__addInputListeners(newTimePicker);
    if (!this.__isDefaultPicker(newTimePicker, "time")) {
      this.timePlaceholder = newTimePicker.placeholder;
      this.step = newTimePicker.step;
    }
    this.__updateTimePickerMinMax();
    newTimePicker.manualValidation = true;
  }
  /** @private */
  __updateTimePickerMinMax() {
    if (this.__timePicker && this.__datePicker) {
      const selectedDate = this.__parseDate(this.__datePicker.value);
      const isMinMaxSameDay = dateEquals(this.__minDateTime, this.__maxDateTime, normalizeUTCDate);
      if (this.__minDateTime && dateEquals(selectedDate, this.__minDateTime, normalizeUTCDate) || isMinMaxSameDay) {
        this.__timePicker.min = this.__dateToIsoTimeString(this.__minDateTime);
      } else {
        this.__timePicker.min = this.__defaultTimeMinValue;
      }
      if (this.__maxDateTime && dateEquals(selectedDate, this.__maxDateTime, normalizeUTCDate) || isMinMaxSameDay) {
        this.__timePicker.max = this.__dateToIsoTimeString(this.__maxDateTime);
      } else {
        this.__timePicker.max = this.__defaultTimeMaxValue;
      }
    }
  }
  /** @private */
  __i18nChanged(effectiveI18n, datePicker, timePicker) {
    if (datePicker && this.__isDefaultPicker(datePicker, "date")) {
      this.__syncI18n(datePicker, effectiveI18n, datePickerI18nProps);
    }
    if (timePicker && this.__isDefaultPicker(timePicker, "time")) {
      this.__syncI18n(timePicker, effectiveI18n, timePickerI18nProps);
    }
  }
  /** @private */
  __labelOrAccessibleNameChanged(label, accessibleName, effectiveI18n, datePicker, timePicker) {
    const name = accessibleName || label || "";
    if (datePicker) {
      datePicker.accessibleName = `${name} ${effectiveI18n.dateLabel || ""}`.trim();
    }
    if (timePicker) {
      timePicker.accessibleName = `${name} ${effectiveI18n.timeLabel || ""}`.trim();
    }
  }
  /** @private */
  __datePlaceholderChanged(datePlaceholder, datePicker) {
    if (datePicker) {
      datePicker.placeholder = datePlaceholder;
    }
  }
  /** @private */
  __timePlaceholderChanged(timePlaceholder, timePicker) {
    if (timePicker) {
      timePicker.placeholder = timePlaceholder;
    }
  }
  /** @private */
  __stepChanged(step, timePicker) {
    if (timePicker && timePicker.step !== step) {
      timePicker.step = step;
    }
  }
  /** @private */
  __initialPositionChanged(initialPosition, datePicker) {
    if (datePicker) {
      datePicker.initialPosition = initialPosition;
    }
  }
  /** @private */
  __showWeekNumbersChanged(showWeekNumbers, datePicker) {
    if (datePicker) {
      datePicker.showWeekNumbers = showWeekNumbers;
    }
  }
  /** @private */
  __invalidChanged(invalid, datePicker, timePicker) {
    if (datePicker) {
      datePicker.invalid = invalid;
    }
    if (timePicker) {
      timePicker.invalid = invalid;
    }
  }
  /** @private */
  __requiredChanged(required, datePicker, timePicker) {
    if (datePicker) {
      datePicker.required = required;
    }
    if (timePicker) {
      timePicker.required = required;
    }
    if (this.__oldRequired && !required) {
      this._requestValidation();
    }
    this.__oldRequired = required;
  }
  /** @private */
  __disabledChanged(disabled, datePicker, timePicker) {
    if (datePicker) {
      datePicker.disabled = disabled;
    }
    if (timePicker) {
      timePicker.disabled = disabled;
    }
  }
  /** @private */
  __readonlyChanged(readonly, datePicker, timePicker) {
    if (datePicker) {
      datePicker.readonly = readonly;
    }
    if (timePicker) {
      timePicker.readonly = readonly;
    }
  }
  /**
   * String (ISO date) to Date object
   * @param {string} str e.g. 'yyyy-mm-dd'
   * @return {Date | undefined}
   * @private
   */
  __parseDate(str) {
    return parseUTCDate(str);
  }
  /**
   * Date object to string (ISO date)
   * @param {Date} date
   * @param {string} defaultValue
   * @return {string} e.g. 'yyyy-mm-dd' (or defaultValue when date is falsy)
   * @private
   */
  __formatDateISO(date, defaultValue) {
    if (!date) {
      return defaultValue;
    }
    return formatUTCISODate(date);
  }
  /**
   * String (ISO date time) to Date object
   * @param {string} str e.g. 'yyyy-mm-ddThh:mm', 'yyyy-mm-ddThh:mm:ss', 'yyyy-mm-ddThh:mm:ss.fff'
   * @return {Date | undefined}
   * @private
   */
  __parseDateTime(str) {
    const [dateValue, timeValue] = str.split("T");
    if (!(dateValue && timeValue)) {
      return;
    }
    const date = this.__parseDate(dateValue);
    if (!date) {
      return;
    }
    const time = parseISOTime(timeValue);
    if (!time) {
      return;
    }
    date.setUTCHours(parseInt(time.hours));
    date.setUTCMinutes(parseInt(time.minutes || 0));
    date.setUTCSeconds(parseInt(time.seconds || 0));
    date.setUTCMilliseconds(parseInt(time.milliseconds || 0));
    return date;
  }
  /**
   * Date object to string (ISO date time)
   * @param {Date} date
   * @return {string} e.g. 'yyyy-mm-ddThh:mm', 'yyyy-mm-ddThh:mm:ss', 'yyyy-mm-ddThh:mm:ss.fff'
   *                  (depending on precision defined by "step" property)
   * @private
   */
  __formatDateTime(date) {
    if (!date) {
      return "";
    }
    const dateValue = this.__formatDateISO(date, "");
    const timeValue = this.__dateToIsoTimeString(date);
    return `${dateValue}T${timeValue}`;
  }
  /**
   * Date object to string (ISO time)
   * @param {Date} date
   * @return {string} e.g. 'hh:mm', 'hh:mm:ss', 'hh:mm:ss.fff' (depending on precision defined by "step" property)
   * @private
   */
  __dateToIsoTimeString(date) {
    return formatISOTime(
      validateTime(
        {
          hours: date.getUTCHours(),
          minutes: date.getUTCMinutes(),
          seconds: date.getUTCSeconds(),
          milliseconds: date.getUTCMilliseconds()
        },
        this.step
      )
    );
  }
  /**
   * Returns true if the current input value satisfies all constraints (if any)
   *
   * You can override the `checkValidity` method for custom validations.
   * @return {boolean}
   */
  checkValidity() {
    const hasInvalidPickers = this.__pickers.some((picker) => !picker.checkValidity());
    const hasOnlyOneFilledPicker = this.__filledPickers.length === 1;
    const hasEmptyRequiredPickers = this.required && this.__pickers.some((picker) => !picker.value);
    return !hasInvalidPickers && !hasEmptyRequiredPickers && !hasOnlyOneFilledPicker;
  }
  /** @private */
  __commitPendingValueChange() {
    this._requestValidation();
    if (this.__committedValue !== this.value) {
      this.dispatchEvent(new CustomEvent("change", { bubbles: true }));
    } else if (this.__committedUnparsableValue !== this.__unparsableValue) {
      this.dispatchEvent(new CustomEvent("unparsable-change"));
    }
    this.__committedValue = this.value;
    this.__committedUnparsableValue = this.__unparsableValue;
  }
  /** @private */
  get __hasPendingValueChange() {
    return this.__committedValue !== this.value || this.__committedUnparsableValue !== this.__unparsableValue;
  }
  /**
   * @param {Date} date1
   * @param {Date} date2
   * @return {boolean}
   * @private
   */
  __dateTimeEquals(date1, date2) {
    if (!dateEquals(date1, date2, normalizeUTCDate)) {
      return false;
    }
    return date1.getUTCHours() === date2.getUTCHours() && date1.getUTCMinutes() === date2.getUTCMinutes() && date1.getUTCSeconds() === date2.getUTCSeconds() && date1.getUTCMilliseconds() === date2.getUTCMilliseconds();
  }
  /** @private */
  __handleDateTimeChange(property, parsedProperty, value, oldValue) {
    if (!value) {
      this[property] = "";
      this[parsedProperty] = "";
      return;
    }
    const dateTime = this.__parseDateTime(value);
    if (!dateTime) {
      this[property] = oldValue;
      return;
    }
    if (!this.__dateTimeEquals(this[parsedProperty], dateTime)) {
      this[parsedProperty] = dateTime;
    }
  }
  /** @private */
  __valueChanged(value, oldValue) {
    this.__handleDateTimeChange("value", "__selectedDateTime", value, oldValue);
    if (!this.__keepCommittedValue) {
      this.__committedValue = value;
      this.__committedUnparsableValue = "";
    }
    this.toggleAttribute("has-value", !!value);
    this.__updateTimePickerMinMax();
  }
  /** @private */
  __dispatchChange() {
    this.dispatchEvent(new CustomEvent("change", { bubbles: true }));
  }
  /** @private */
  __minChanged(value, oldValue) {
    this.__handleDateTimeChange("min", "__minDateTime", value, oldValue);
    if (this.__datePicker) {
      this.__datePicker.min = this.__formatDateISO(this.__minDateTime, this.__defaultDateMinMaxValue);
    }
    this.__updateTimePickerMinMax();
    if (this.__datePicker && this.__timePicker && this.value) {
      this._requestValidation();
    }
  }
  /** @private */
  __maxChanged(value, oldValue) {
    this.__handleDateTimeChange("max", "__maxDateTime", value, oldValue);
    if (this.__datePicker) {
      this.__datePicker.max = this.__formatDateISO(this.__maxDateTime, this.__defaultDateMinMaxValue);
    }
    this.__updateTimePickerMinMax();
    if (this.__datePicker && this.__timePicker && this.value) {
      this._requestValidation();
    }
  }
  /** @private */
  __selectedDateTimeChanged(selectedDateTime) {
    const formattedValue = this.__formatDateTime(selectedDateTime);
    if (this.value !== formattedValue) {
      this.value = formattedValue;
    }
    const isDatePickerReady = Boolean(this.__datePicker && this.__datePicker.$);
    if (isDatePickerReady && !this.__ignoreInputValueChange) {
      this.__ignoreInputValueChange = true;
      const [dateValue, timeValue] = this.value.split("T");
      this.__datePicker.value = dateValue || "";
      this.__timePicker.value = timeValue || "";
      this.__ignoreInputValueChange = false;
    }
  }
  /** @private */
  __valueChangedEventHandler() {
    if (this.__ignoreInputValueChange) {
      return;
    }
    this.__ignoreInputValueChange = true;
    this.__keepCommittedValue = true;
    this.__updateTimePickerMinMax();
    this.value = this.__formattedValue;
    this.__keepCommittedValue = false;
    this.__ignoreInputValueChange = false;
  }
  /** @private */
  __autoOpenDisabledChanged(autoOpenDisabled, datePicker, timePicker) {
    if (datePicker) {
      datePicker.autoOpenDisabled = autoOpenDisabled;
    }
    if (timePicker) {
      timePicker.autoOpenDisabled = autoOpenDisabled;
    }
  }
  /** @private */
  __themeChanged(theme2, datePicker, timePicker) {
    if (!datePicker || !timePicker) {
      return;
    }
    [datePicker, timePicker].forEach((picker) => {
      if (theme2) {
        picker.setAttribute("theme", theme2);
      } else {
        picker.removeAttribute("theme");
      }
    });
  }
  /** @private */
  __pickersChanged(datePicker, timePicker) {
    if (!datePicker || !timePicker) {
      return;
    }
    if (this.__isDefaultPicker(datePicker, "date") !== this.__isDefaultPicker(timePicker, "time")) {
      return;
    }
    if (datePicker.value) {
      this.__valueChangedEventHandler();
    } else if (this.value) {
      this.__selectedDateTimeChanged(this.__selectedDateTime);
      if (this.min && this.__minDateTime || this.max && this.__maxDateTime) {
        this._requestValidation();
      }
    }
  }
  /**
   * Fired when the user commits a value change.
   *
   * @event change
   */
};
/**
 * @license
 * Copyright (c) 2019 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class DateTimePicker extends DateTimePickerMixin(
  ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-date-time-picker";
  }
  static get styles() {
    return [inputFieldShared, dateTimePickerStyles];
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-date-time-picker-container">
        <div part="label" @click="${this.focus}">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true"></span>
        </div>

        <div part="input-fields">
          <slot name="date-picker" id="dateSlot"></slot>
          <slot name="time-picker" id="timeSlot"></slot>
        </div>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>
      </div>

      <slot name="tooltip"></slot>
    `;
  }
}
defineCustomElement(DateTimePicker);
const EASTERN_ARABIC_DIGIT_MAP = {
  "\\u0660": "0",
  "\\u0661": "1",
  "\\u0662": "2",
  "\\u0663": "3",
  "\\u0664": "4",
  "\\u0665": "5",
  "\\u0666": "6",
  "\\u0667": "7",
  "\\u0668": "8",
  "\\u0669": "9"
};
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function parseEasternArabicDigits(digits) {
  return digits.replace(/[\u0660-\u0669]/g, function(char) {
    const unicode = "\\u0" + char.charCodeAt(0).toString(16);
    return EASTERN_ARABIC_DIGIT_MAP[unicode];
  });
}
function getAmOrPmString(locale, testTime) {
  const testTimeString = testTime.toLocaleTimeString(locale);
  const amOrPmRegExp = /[^\d\u0660-\u0669]/;
  const matches = (
    // In most locales, the time ends with AM/PM:
    testTimeString.match(new RegExp(`${amOrPmRegExp.source}+$`, "g")) || // In some locales, the time starts with AM/PM e.g in Chinese:
    testTimeString.match(new RegExp(`^${amOrPmRegExp.source}+`, "g"))
  );
  return matches && matches[0].trim();
}
function getSeparator(locale) {
  let timeString = TEST_PM_TIME.toLocaleTimeString(locale);
  const pmString = getPmString(locale);
  if (pmString && timeString.startsWith(pmString)) {
    timeString = timeString.replace(pmString, "");
  }
  const matches = timeString.match(/[^\u0660-\u0669\s\d]/);
  return matches && matches[0];
}
function searchAmOrPmToken(timeString, amOrPmString) {
  if (!amOrPmString) return null;
  const tokenRegExpString = amOrPmString.split(/\s*/).map(escapeRegExp).join("\\s*");
  const tokenRegExp = new RegExp(tokenRegExpString, "i");
  const tokenMatches = timeString.match(tokenRegExp);
  if (tokenMatches) {
    return tokenMatches[0];
  }
}
const TEST_PM_TIME = /* @__PURE__ */ new Date("August 19, 1975 23:15:30");
const TEST_AM_TIME = /* @__PURE__ */ new Date("August 19, 1975 05:15:30");
function getPmString(locale) {
  return getAmOrPmString(locale, TEST_PM_TIME);
}
function getAmString(locale) {
  return getAmOrPmString(locale, TEST_AM_TIME);
}
function parseDigitsIntoInteger(digits) {
  return parseInt(parseEasternArabicDigits(digits));
}
function parseMillisecondsIntoInteger(milliseconds) {
  milliseconds = parseEasternArabicDigits(milliseconds);
  if (milliseconds.length === 1) {
    milliseconds += "00";
  } else if (milliseconds.length === 2) {
    milliseconds += "0";
  }
  return parseInt(milliseconds);
}
function formatMilliseconds(timeString, milliseconds, amString, pmString) {
  let cleanedTimeString = timeString;
  if (timeString.endsWith(amString)) {
    cleanedTimeString = timeString.replace(" " + amString, "");
  } else if (timeString.endsWith(pmString)) {
    cleanedTimeString = timeString.replace(" " + pmString, "");
  }
  if (milliseconds) {
    let millisecondsString = milliseconds < 10 ? "0" : "";
    millisecondsString += milliseconds < 100 ? "0" : "";
    millisecondsString += milliseconds;
    cleanedTimeString += "." + millisecondsString;
  } else {
    cleanedTimeString += ".000";
  }
  if (timeString.endsWith(amString)) {
    cleanedTimeString = cleanedTimeString + " " + amString;
  } else if (timeString.endsWith(pmString)) {
    cleanedTimeString = cleanedTimeString + " " + pmString;
  }
  return cleanedTimeString;
}
function when(predicate, callback, timeout = 0) {
  if (predicate()) {
    callback();
  } else {
    setTimeout(() => when(predicate, callback, 200), timeout);
  }
}
function parseISO(text) {
  const timeObject = parseISOTime(text);
  return {
    hours: parseInt(timeObject.hours || 0),
    minutes: parseInt(timeObject.minutes || 0),
    seconds: parseInt(timeObject.seconds || 0),
    milliseconds: parseInt(timeObject.milliseconds || 0)
  };
}
window.Vaadin.Flow.timepickerConnector = {};
window.Vaadin.Flow.timepickerConnector.initLazy = (timepicker) => {
  if (timepicker.$connector) {
    return;
  }
  timepicker.$connector = {};
  timepicker.$connector.setLocale = (locale) => {
    let previousValueObject;
    if (timepicker.value && timepicker.value !== "") {
      previousValueObject = parseISO(timepicker.value);
    }
    try {
      TEST_PM_TIME.toLocaleTimeString(locale);
    } catch (e) {
      locale = "en-US";
      throw new Error(
        "vaadin-time-picker: The locale " + locale + " is not supported, falling back to default locale setting(en-US)."
      );
    }
    const pmString = getPmString(locale);
    const amString = getAmString(locale);
    const separator = getSeparator(locale);
    const includeSeconds = function() {
      return timepicker.step && timepicker.step < 60;
    };
    const includeMilliSeconds = function() {
      return timepicker.step && timepicker.step < 1;
    };
    let cachedTimeString;
    let cachedTimeObject;
    timepicker.i18n = {
      formatTime(timeObject) {
        if (!timeObject) return;
        const timeToBeFormatted = /* @__PURE__ */ new Date();
        timeToBeFormatted.setHours(timeObject.hours);
        timeToBeFormatted.setMinutes(timeObject.minutes);
        timeToBeFormatted.setSeconds(timeObject.seconds !== void 0 ? timeObject.seconds : 0);
        let localeTimeString = timeToBeFormatted.toLocaleTimeString(locale, {
          hour: "numeric",
          minute: "numeric",
          second: includeSeconds() ? "numeric" : void 0
        });
        if (includeMilliSeconds()) {
          localeTimeString = formatMilliseconds(localeTimeString, timeObject.milliseconds, amString, pmString);
        }
        return localeTimeString;
      },
      parseTime(timeString) {
        if (timeString && timeString === cachedTimeString && cachedTimeObject) {
          return cachedTimeObject;
        }
        if (!timeString) {
          return;
        }
        const amToken = searchAmOrPmToken(timeString, amString);
        const pmToken = searchAmOrPmToken(timeString, pmString);
        const numbersOnlyTimeString = timeString.replace(amToken || "", "").replace(pmToken || "", "").trim();
        const numbersRegExp = new RegExp("([\\d\\u0660-\\u0669]){1,2}(?:" + separator + ")?", "g");
        let hours = numbersRegExp.exec(numbersOnlyTimeString);
        if (hours) {
          hours = parseDigitsIntoInteger(hours[0].replace(separator, ""));
          if (amToken !== pmToken) {
            if (hours === 12 && amToken) {
              hours = 0;
            }
            if (hours !== 12 && pmToken) {
              hours += 12;
            }
          }
          const minutes = numbersRegExp.exec(numbersOnlyTimeString);
          const seconds = minutes && numbersRegExp.exec(numbersOnlyTimeString);
          const millisecondRegExp = /[[\.][\d\u0660-\u0669]{1,3}$/;
          let milliseconds = seconds && includeMilliSeconds() && millisecondRegExp.exec(numbersOnlyTimeString);
          if (milliseconds && milliseconds["index"] <= seconds["index"]) {
            milliseconds = void 0;
          }
          cachedTimeObject = hours !== void 0 && {
            hours,
            minutes: minutes ? parseDigitsIntoInteger(minutes[0].replace(separator, "")) : 0,
            seconds: seconds ? parseDigitsIntoInteger(seconds[0].replace(separator, "")) : 0,
            milliseconds: minutes && seconds && milliseconds ? parseMillisecondsIntoInteger(milliseconds[0].replace(".", "")) : 0
          };
          cachedTimeString = timeString;
          return cachedTimeObject;
        }
      }
    };
    if (previousValueObject) {
      when(
        () => timepicker.$,
        () => {
          const newValue = timepicker.i18n.formatTime(previousValueObject);
          if (timepicker.inputElement.value !== newValue) {
            timepicker.inputElement.value = newValue;
            timepicker.value = newValue;
          }
        }
      );
    }
  };
};
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};
window.Vaadin.Flow.dndConnector = {
  __ondragenterListener: function(event) {
    const effect = event.currentTarget["__dropEffect"];
    if (!event.currentTarget.hasAttribute("disabled")) {
      if (effect) {
        event.dataTransfer.dropEffect = effect;
      }
      if (effect !== "none") {
        if (event.currentTarget.classList.contains("v-drag-over-target")) {
          event.currentTarget["__skip-leave"] = true;
        } else {
          event.currentTarget.classList.add("v-drag-over-target");
        }
        event.preventDefault();
        event.stopPropagation();
      }
    }
  },
  __ondragoverListener: function(event) {
    if (!event.currentTarget.hasAttribute("disabled")) {
      const effect = event.currentTarget["__dropEffect"];
      if (effect) {
        event.dataTransfer.dropEffect = effect;
      }
      event.preventDefault();
      event.stopPropagation();
    }
  },
  __ondragleaveListener: function(event) {
    if (event.currentTarget["__skip-leave"]) {
      event.currentTarget["__skip-leave"] = false;
    } else {
      event.currentTarget.classList.remove("v-drag-over-target");
    }
    event.stopPropagation();
  },
  __ondropListener: function(event) {
    const effect = event.currentTarget["__dropEffect"];
    if (effect) {
      event.dataTransfer.dropEffect = effect;
    }
    event.currentTarget.classList.remove("v-drag-over-target");
    event.preventDefault();
    event.stopPropagation();
  },
  updateDropTarget: function(element) {
    if (element["__active"]) {
      element.addEventListener("dragenter", this.__ondragenterListener, false);
      element.addEventListener("dragover", this.__ondragoverListener, false);
      element.addEventListener("dragleave", this.__ondragleaveListener, false);
      element.addEventListener("drop", this.__ondropListener, false);
    } else {
      element.removeEventListener("dragenter", this.__ondragenterListener, false);
      element.removeEventListener("dragover", this.__ondragoverListener, false);
      element.removeEventListener("dragleave", this.__ondragleaveListener, false);
      element.removeEventListener("drop", this.__ondropListener, false);
      element.classList.remove("v-drag-over-target");
    }
  },
  /** DRAG SOURCE METHODS: */
  __dragstartListener: function(event) {
    event.stopPropagation();
    event.dataTransfer.setData("text/plain", "");
    if (event.currentTarget.hasAttribute("disabled")) {
      event.preventDefault();
    } else {
      if (event.currentTarget["__effectAllowed"]) {
        event.dataTransfer.effectAllowed = event.currentTarget["__effectAllowed"];
      }
      event.currentTarget.classList.add("v-dragged");
    }
    if (event.currentTarget.__dragImage) {
      if (event.currentTarget.__dragImage.style.display === "none") {
        event.currentTarget.__dragImage.style.display = "block";
        event.currentTarget.classList.add("shown");
      }
      event.dataTransfer.setDragImage(
        event.currentTarget.__dragImage,
        event.currentTarget.__dragImageOffsetX,
        event.currentTarget.__dragImageOffsetY
      );
    }
  },
  __dragendListener: function(event) {
    event.currentTarget.classList.remove("v-dragged");
    if (event.currentTarget.classList.contains("shown")) {
      event.currentTarget.classList.remove("shown");
      event.currentTarget.__dragImage.style.display = "none";
    }
  },
  updateDragSource: function(element) {
    if (element["draggable"]) {
      element.addEventListener("dragstart", this.__dragstartListener, false);
      element.addEventListener("dragend", this.__dragendListener, false);
    } else {
      element.removeEventListener("dragstart", this.__dragstartListener, false);
      element.removeEventListener("dragend", this.__dragendListener, false);
    }
  },
  setDragImage: function(dragImage, offsetX, offsetY, dragSource) {
    dragSource.__dragImage = dragImage;
    dragSource.__dragImageOffsetX = offsetX;
    dragSource.__dragImageOffsetY = offsetY;
  }
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const formItemStyles = css$h`
  :host {
    /* By default, when auto-responsive mode is disabled, labels should be displayed beside the fields. */
    --_form-item-labels-above: ' '; /* false */
    --_form-item-labels-aside: initial; /* true */

    align-items: var(--_form-item-labels-aside, baseline);
    display: inline-flex;
    flex-flow: var(--_form-item-labels-above, column) nowrap;
    justify-self: stretch;
  }

  :host([label-position='top']) {
    --_form-item-labels-above: initial; /* true */
    --_form-item-labels-aside: ' '; /* false */
  }

  :host([hidden]) {
    display: none !important;
  }

  [part='label'] {
    color: var(--vaadin-form-item-label-color, var(--vaadin-text-color));
    flex: 0 0 auto;
    font-size: var(--vaadin-form-item-label-font-size, inherit);
    font-weight: var(--vaadin-form-item-label-font-weight, 500);
    line-height: var(--vaadin-form-item-label-line-height, inherit);
    width: var(--_form-item-labels-aside, var(--_label-width, 8em));
    word-break: break-word;
  }

  #spacing {
    flex: 0 0 auto;
    width: var(--_label-spacing, 1em);
  }

  #content {
    flex: 1 1 auto;
    min-width: 0;
  }

  #content ::slotted(.full-width) {
    box-sizing: border-box;
    min-width: 0;
    width: 100%;
  }
`;
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const FormItemMixin = (superClass) => class extends superClass {
  constructor() {
    super();
    this.__onFieldInteraction = this.__onFieldInteraction.bind(this);
    this.__fieldNodeObserver = new MutationObserver(() => this.__synchronizeAttributes());
    this.__labelNode = null;
    this.__fieldNode = null;
    this.__isFieldDirty = false;
  }
  /** @protected */
  ready() {
    super.ready();
  }
  /**
   * Returns a target element to add ARIA attributes to for a field.
   *
   * - For Vaadin field components, the method returns an element
   * obtained through the `ariaTarget` property defined in `FieldMixin`.
   * - In other cases, the method returns the field element itself.
   *
   * @param {HTMLElement} field
   * @protected
   */
  _getFieldAriaTarget(field2) {
    return field2.ariaTarget || field2;
  }
  /**
   * Links the label to a field by adding the label id to
   * the `aria-labelledby` attribute of the field's ARIA target element.
   *
   * @param {HTMLElement} field
   * @private
   */
  __linkLabelToField(field2) {
    addValueToAttribute(this._getFieldAriaTarget(field2), "aria-labelledby", this.__labelId);
  }
  /**
   * Unlinks the label from a field by removing the label id from
   * the `aria-labelledby` attribute of the field's ARIA target element.
   *
   * @param {HTMLElement} field
   * @private
   */
  __unlinkLabelFromField(field2) {
    removeValueFromAttribute(this._getFieldAriaTarget(field2), "aria-labelledby", this.__labelId);
  }
  /** @private */
  __onLabelClick() {
    const fieldNode = this.__fieldNode;
    if (fieldNode) {
      fieldNode.focus({ focusVisible: false });
      fieldNode.click();
    }
  }
  /**
   * A `slotchange` event handler for the label slot.
   *
   * - Ensures the label id is only assigned to the first label node.
   * - Ensures the label node is linked to the first field node via the `aria-labelledby` attribute
   * if both nodes are provided, and unlinked otherwise.
   *
   * @private
   */
  __onLabelSlotChange() {
    if (this.__labelNode) {
      this.__labelNode = null;
      if (this.__fieldNode) {
        this.__unlinkLabelFromField(this.__fieldNode);
      }
    }
    const newLabelNode = this.$.labelSlot.assignedElements()[0];
    if (newLabelNode) {
      this.__labelNode = newLabelNode;
      if (this.__labelNode.id) {
        this.__labelId = this.__labelNode.id;
      } else {
        this.__labelId = `label-${this.localName}-${generateUniqueId()}`;
        this.__labelNode.id = this.__labelId;
      }
      if (this.__fieldNode) {
        this.__linkLabelToField(this.__fieldNode);
      }
    }
  }
  /**
   * A `slotchange` event handler for the content slot.
   *
   * - Ensures the label node is only linked to the first field node via the `aria-labelledby` attribute.
   * - Sets up an observer for the `required` attribute changes on the first field
   * to reflect the attribute on the component. Ensures the observer is disconnected from the field
   * as soon as it is removed or replaced by another one.
   *
   * @private
   */
  __onContentSlotChange() {
    if (this.__fieldNode) {
      this.__unlinkLabelFromField(this.__fieldNode);
      this.__fieldNodeObserver.disconnect();
      this.__fieldNode.removeEventListener("blur", this.__onFieldInteraction);
      this.__fieldNode.removeEventListener("change", this.__onFieldInteraction);
      this.__fieldNode = null;
      this.__isFieldDirty = false;
    }
    const fieldNodes = this.$.contentSlot.assignedElements();
    if (fieldNodes.length > 1) {
      issueWarning(
        `WARNING: Since Vaadin 23, placing multiple fields directly to a <vaadin-form-item> is deprecated.
Please wrap fields with a <vaadin-custom-field> instead.`
      );
    }
    const newFieldNode = fieldNodes.find((field2) => field2.validate || field2.checkValidity);
    if (newFieldNode) {
      this.__fieldNode = newFieldNode;
      this.__fieldNode.addEventListener("blur", this.__onFieldInteraction);
      this.__fieldNode.addEventListener("change", this.__onFieldInteraction);
      this.__fieldNodeObserver.observe(this.__fieldNode, {
        attributes: true,
        attributeFilter: ["required", "invalid"]
      });
      if (this.__labelNode) {
        this.__linkLabelToField(this.__fieldNode);
      }
    }
    this.__synchronizeAttributes();
  }
  /** @private */
  __onFieldInteraction() {
    this.__isFieldDirty = true;
    this.__synchronizeAttributes();
  }
  /** @private */
  __synchronizeAttributes() {
    const field2 = this.__fieldNode;
    if (!field2) {
      this.removeAttribute("required");
      this.removeAttribute("invalid");
      return;
    }
    this.toggleAttribute("required", field2.hasAttribute("required"));
    this.toggleAttribute(
      "invalid",
      field2.hasAttribute("invalid") || field2.matches(":invalid") && this.__isFieldDirty
    );
  }
};
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class FormItem extends FormItemMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-form-item";
  }
  static get styles() {
    return formItemStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <div id="label" part="label" @click="${this.__onLabelClick}">
        <slot name="label" id="labelSlot" @slotchange="${this.__onLabelSlotChange}"></slot>
        <span part="required-indicator" aria-hidden="true"></span>
      </div>
      <div id="spacing"></div>
      <div id="content">
        <slot id="contentSlot" @slotchange="${this.__onContentSlotChange}"></slot>
      </div>
    `;
  }
}
defineCustomElement(FormItem);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const formRowStyles = css$h`
  :host {
    display: contents;
  }

  :host([hidden]) {
    display: none !important;
  }

  ::slotted(*) {
    /* Make form items inherit label position from the layout */
    --_form-item-labels-above: inherit;
    --_form-item-labels-aside: inherit;

    grid-column: auto / span min(var(--_grid-colspan, 1), var(--_grid-rendered-column-count));
  }

  ::slotted(:first-child) {
    grid-column-start: 1;
  }
`;
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class FormRow extends ThemableMixin(PolylitMixin(LitElement)) {
  static get is() {
    return "vaadin-form-row";
  }
  static get styles() {
    return formRowStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`<slot></slot>`;
  }
}
defineCustomElement(FormRow);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const gridPro = css$h`
  [part~='body-cell'] {
    --_highlight-color: color-mix(in srgb, currentColor 5%, transparent);
    --_highlight-color2: color-mix(in srgb, currentColor 10%, transparent);
  }

  [part~='editable-cell'] {
    display: flex;
    align-items: inherit;
    align-self: stretch;
    flex-grow: 1;
    min-width: 0;
    cursor: var(--vaadin-clickable-cursor);
    outline: 0;
  }

  /* Show cell focus outline */
  [part~='cell']:is([part~='editable-cell']:focus, :has([part~='editable-cell']:focus))::after {
    content: '';
  }

  /* On macOS the editable-cell part is a button inside the body cell. On other platforms the body cell is the editable-cell part. */

  @media (any-hover: hover) {
    .body-cell:is([part~='editable-cell'], :has([part~='editable-cell'])):hover {
      --vaadin-grid-cell-background-color: var(--_highlight-color);
    }
  }

  :host([navigating]) .body-cell:is([part~='editable-cell']:focus, :has([part~='editable-cell']:focus)) {
    --vaadin-grid-cell-background-color: var(--_highlight-color);
  }

  /* Indicate editable cells */

  :host([theme~='highlight-editable-cells']) .body-cell:is([part~='editable-cell'], :has([part~='editable-cell'])) {
    --vaadin-grid-row-highlight-background-color: var(
      --vaadin-grid-pro-editable-cell-background-color,
      var(--_highlight-color)
    );
  }

  /* Indicate read-only cells */

  :host([theme~='highlight-read-only-cells']) .body-cell:not([part~='editable-cell'], :has([part~='editable-cell'])) {
    --_cell-highlight-background-image: repeating-linear-gradient(
      -45deg,
      transparent,
      transparent 30%,
      var(--_highlight-color2) 30%,
      var(--_highlight-color2) 50%
    );
    background-repeat: repeat;
    background-size: 6px 6px;
    background-clip: padding-box;
  }

  /* Loading editor cell styles are used by Flow GridPro */
  :host([loading-editor]) [part~='focused-cell']::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    box-shadow: inset 0 0 0 var(--vaadin-focus-ring-width) var(--vaadin-focus-ring-color);
    animation: loading-editor 1.4s infinite;
    opacity: 0;
  }

  @keyframes loading-editor {
    50% {
      opacity: 1;
    }
  }

  [part~='updating-cell']::after {
    content: '';
    position: absolute;
    inset: var(--_cell-padding);
    margin: var(--vaadin-focus-ring-width);
    border-radius: 4px;
    background-size: max(4em, 50%);
    background-repeat: no-repeat;
    background-position: min(-200%, -4em) 0;
    background-image: linear-gradient(90deg, transparent, currentColor, transparent);
    animation: updating-cell 1.3s ease-out infinite;
    opacity: 0.1;
  }

  @keyframes updating-cell {
    100% {
      background-position: max(300%, 8em) 0;
    }
  }

  :host([loading-editor]) [part~='focused-cell'] ::slotted(vaadin-grid-cell-content),
  [part~='updating-cell'] ::slotted(vaadin-grid-cell-content) {
    opacity: 0;
    pointer-events: none;
  }
`;
const gridProStyles = [gridPro, gridStyles];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const InlineEditingMixin = (superClass) => class InlineEditingMixin extends superClass {
  static get properties() {
    return {
      /**
       * When true, pressing Enter while in cell edit mode
       * will move focus to the editable cell in the next row
       * (Shift + Enter - same, but for previous row).
       * @attr {boolean} enter-next-row
       */
      enterNextRow: {
        type: Boolean,
        notify: true
        // FIXME(yuriy-fix): needed by Flow counterpart
      },
      /**
       * When true, after moving to next or previous editable cell using
       * Tab / Shift+Tab, it will be focused without edit mode.
       *
       * When `enterNextRow` is true, pressing Enter will also
       * preserve edit mode, otherwise, it will have no effect.
       * @attr {boolean} single-cell-edit
       */
      singleCellEdit: {
        type: Boolean,
        notify: true
        // FIXME(yuriy-fix): needed by Flow counterpart
      },
      /**
       * When true, the grid enters cell edit mode on a single click
       * instead of the default double click.
       * @attr {boolean} edit-on-click
       */
      editOnClick: {
        type: Boolean
      },
      /** @private */
      _editingDisabled: {
        type: Boolean
      }
    };
  }
  constructor() {
    super();
    this.__boundItemPropertyChanged = this._onItemPropertyChanged.bind(this);
    this.__boundEditorFocusOut = this._onEditorFocusOut.bind(this);
    this.__boundEditorFocusIn = this._onEditorFocusIn.bind(this);
    this._addEditColumnListener("mousedown", (e) => {
      e.stopImmediatePropagation();
      this.toggleAttribute("navigating", true);
    });
    this._addEditColumnListener("focusout", (e) => {
      e.stopImmediatePropagation();
    });
  }
  /** @protected */
  ready() {
    this.addEventListener(
      "keydown",
      (e) => {
        if (this.hasAttribute("loading-editor") && !["Tab", "Escape", "Enter"].includes(e.key)) {
          e.preventDefault();
          e.stopPropagation();
        }
      },
      true
    );
    this.addEventListener("keydown", (e) => {
      switch (e.keyCode) {
        case 27:
          if (this.__edited) {
            this._stopEdit(true);
          }
          break;
        case 9:
          if (this.__edited) {
            this._switchEditCell(e);
          }
          break;
        case 13:
          if (this.__edited) {
            this._switchEditCell(e);
          } else {
            this._enterEditFromEvent(e);
          }
          break;
        case 32:
          if (!this.__edited) {
            this._enterEditFromEvent(e);
          }
          break;
        default:
          if (e.key && e.key.length === 1) {
            this._enterEditFromEvent(e, "text");
          }
          break;
      }
    });
    super.ready();
    this.$.table.addEventListener("click", (e) => {
      const column2 = this.getEventContext(e).column;
      if (column2 && this._isEditColumn(column2)) {
        if (this.editOnClick) {
          this._enterEditFromEvent(e);
        }
      }
    });
    if (this._ios) {
      let firstClickTime;
      let waitingSecondClick = false;
      this.addEventListener("click", (e) => {
        if (!waitingSecondClick) {
          firstClickTime = (/* @__PURE__ */ new Date()).getTime();
          waitingSecondClick = true;
          setTimeout(() => {
            waitingSecondClick = false;
          }, 300);
        } else {
          waitingSecondClick = false;
          const time = (/* @__PURE__ */ new Date()).getTime();
          if (time - firstClickTime < 300) {
            this._enterEditFromEvent(e);
          }
        }
      });
    } else {
      this.addEventListener("dblclick", (e) => {
        if (!this.editOnClick) {
          this._enterEditFromEvent(e);
        }
      });
    }
  }
  /**
   * Prevents making an edit column cell's parent row active on click.
   *
   * @override
   * @protected
   */
  _shouldPreventCellActivationOnClick(e) {
    return super._shouldPreventCellActivationOnClick(e) || // The clicked cell is editable
    this._isEditColumn(this.getEventContext(e).column);
  }
  /**
   * Override an observer from `DisabledMixin` to stop
   * editing when grid element becomes disabled.
   *
   * @param {boolean} disabled
   * @param {boolean} oldDisabled
   * @protected
   * @override
   */
  _disabledChanged(disabled, oldDisabled) {
    super._disabledChanged(disabled, oldDisabled);
    if (disabled && this.__edited) {
      this._stopEdit(true);
    }
  }
  /** @protected */
  _checkImports() {
    super._checkImports();
    ["vaadin-grid-pro-edit-column"].forEach((elementName) => {
      const element = this.querySelector(elementName);
      if (element && !customElements.get(elementName)) {
        console.warn(`Make sure you have imported the required module for <${elementName}> element.`);
      }
    });
  }
  /** @private */
  _applyEdit({ path, value, item }) {
    set(path, value, item);
    this.requestContentUpdate();
  }
  /** @private */
  _addEditColumnListener(type, callback) {
    this.addEventListener(type, (e) => {
      const context = this.getEventContext(e);
      const column2 = context.column;
      const edited = this.__edited;
      if (context.item && this._isEditColumn(column2)) {
        const { cell } = this._getGridEventLocation(e);
        if (!cell || cell.getAttribute("part").indexOf("details-cell") > -1) {
          return;
        }
        if (edited && edited.cell === cell) {
          return;
        }
        if (!this._isCellEditable(cell)) {
          return;
        }
        callback(e);
      }
    });
  }
  /** @private */
  _onItemPropertyChanged(e) {
    if (!e.defaultPrevented) {
      this._applyEdit(e.detail);
    }
  }
  /** @private */
  _getRowByIndex(index) {
    return Array.from(this.$.items.children).find((el) => el.index === index);
  }
  /** @private */
  _isEditColumn(column2) {
    return column2 && column2.localName.toLowerCase() === "vaadin-grid-pro-edit-column";
  }
  /** @private */
  _getEditColumns() {
    const columnTreeLevel = this._columnTree.length - 1;
    return this._columnTree[columnTreeLevel].filter((column2) => this._isEditColumn(column2) && !column2.hidden).sort((a, b) => a._order - b._order);
  }
  /** @private */
  _cancelStopEdit() {
    if (this._debouncerStopEdit) {
      this._debouncerStopEdit.cancel();
      delete this._debouncerStopEdit;
    }
  }
  /** @private */
  _flushStopEdit() {
    if (this._debouncerStopEdit) {
      this._debouncerStopEdit.flush();
      delete this._debouncerStopEdit;
    }
  }
  /** @private */
  _enterEditFromEvent(e, type) {
    const context = this.getEventContext(e);
    const column2 = context.column;
    const edited = this.__edited;
    if (context.item && this._isEditColumn(column2)) {
      const { cell } = this._getGridEventLocation(e);
      if (!cell || cell.getAttribute("part").indexOf("details-cell") > -1) {
        return;
      }
      if (type && column2.editorType !== type) {
        return;
      }
      if (edited && edited.cell === cell && column2._getEditorComponent(cell).contains(e.target)) {
        return;
      }
      this._flushStopEdit();
      this._startEdit(cell, column2);
    } else if (edited) {
      this._stopEdit();
    }
  }
  /** @private */
  _onEditorFocusOut(event) {
    if (this.__shouldIgnoreFocusOut(event)) {
      return;
    }
    this._debouncerStopEdit = Debouncer.debounce(this._debouncerStopEdit, animationFrame, this._stopEdit.bind(this));
  }
  /** @private */
  __shouldIgnoreFocusOut(event) {
    const edited = this.__edited;
    if (edited) {
      const { cell, column: column2 } = this.__edited;
      const editor = column2._getEditorComponent(cell);
      const path = event.composedPath();
      const nodes = path.slice(0, path.indexOf(editor) + 1).filter((node) => node.nodeType === Node.ELEMENT_NODE);
      if (nodes.some((el) => typeof el._shouldRemoveFocus === "function" && !el._shouldRemoveFocus(event))) {
        return true;
      }
    }
  }
  /** @private */
  _onEditorFocusIn() {
    this._cancelStopEdit();
  }
  /** @private */
  _startEdit(cell, column2) {
    const isCellEditable = this._isCellEditable(cell);
    if (this.disabled || this._editingDisabled || !isCellEditable) {
      return;
    }
    this._cancelStopEdit();
    this._scrollHorizontallyToCell(cell);
    const model = this.__getRowModel(cell.parentElement);
    this.__edited = { cell, column: column2, model };
    column2._startCellEdit(cell, model);
    this.dispatchEvent(
      new CustomEvent("cell-edit-started", {
        detail: {
          index: model.index,
          item: model.item,
          path: column2.path
        },
        composed: true
      })
    );
    this.addEventListener("item-property-changed", this.__boundItemPropertyChanged);
  }
  /**
   * @param {boolean=} shouldCancel
   * @param {boolean=} shouldRestoreFocus
   * @protected
   */
  _stopEdit(shouldCancel, shouldRestoreFocus) {
    if (!this.__edited) {
      return;
    }
    const { cell, column: column2, model } = this.__edited;
    if (!shouldCancel && !this.hasAttribute("loading-editor")) {
      const editor = column2._getEditorComponent(cell);
      if (editor) {
        const value = column2._getEditorValue(editor);
        if (value !== get$5(column2.path, model.item)) {
          editor.blur();
          this.dispatchEvent(
            new CustomEvent("item-property-changed", {
              detail: {
                index: model.index,
                item: model.item,
                path: column2.path,
                value
              },
              bubbles: true,
              cancelable: true,
              composed: true
            })
          );
        }
      }
    }
    column2._stopCellEdit(cell, model);
    this.__edited = null;
    this.removeEventListener("item-property-changed", this.__boundItemPropertyChanged);
    if (shouldRestoreFocus) {
      cell.focus();
    }
  }
  /**
   * @param {!KeyboardEvent} e
   * @protected
   */
  async _switchEditCell(e) {
    if (e.defaultPrevented && e.keyCode === 9) {
      return;
    }
    this._cancelStopEdit();
    const editableColumns = this._getEditColumns();
    const { cell, column: column2, model } = this.__edited;
    e.stopImmediatePropagation();
    const editor = column2._getEditorComponent(cell);
    if (e.key === "Tab" && editor && editor.contains(e.target)) {
      const ignore = await new Promise((resolve) => {
        editor.addEventListener(
          "focusout",
          (event) => {
            resolve(this.__shouldIgnoreFocusOut(event));
          },
          { once: true }
        );
      });
      if (ignore) {
        return;
      }
    } else {
      e.preventDefault();
    }
    this._stopEdit();
    let nextIndex = model.index;
    let nextColumn = column2;
    let nextCell = cell;
    let directionX = 0;
    let directionY = 0;
    if (e.keyCode === 13 && this.enterNextRow) {
      directionY = e.shiftKey ? -1 : 1;
    }
    if (e.keyCode === 9) {
      directionX = e.shiftKey ? -1 : 1;
    }
    if (directionX || directionY) {
      while (nextCell) {
        if (directionX) {
          nextColumn = editableColumns[editableColumns.indexOf(nextColumn) + directionX];
          if (!nextColumn) {
            nextIndex += directionX;
            nextColumn = editableColumns[directionX > 0 ? 0 : editableColumns.length - 1];
          }
        }
        if (directionY) {
          nextIndex += directionY;
        }
        const nextRow = this._getRowByIndex(nextIndex);
        nextCell = nextRow && Array.from(nextRow.children).find((cell2) => cell2._column === nextColumn);
        if (nextCell && this._isCellEditable(nextCell)) {
          break;
        }
      }
    }
    if (!nextCell) {
      nextCell = cell;
      nextIndex = model.index;
    }
    if (!this.singleCellEdit && nextCell !== cell) {
      this._startEdit(nextCell, nextColumn);
    } else {
      this.__ensureFlatIndexInViewport(nextIndex);
      nextCell.focus();
    }
  }
  /**
   * @param {!HTMLElement} row
   * @private
   */
  __updateRow(row) {
    const item = this.__getRowItem(row);
    if (this.__edited) {
      const { cell, model } = this.__edited;
      if (!this._isCellEditable(cell)) {
        this._stopEdit(true, true);
      } else if (cell.parentNode === row && item && this.getItemId(model.item) !== this.getItemId(item)) {
        this._stopEdit();
      }
    }
    super.__updateRow(row, item);
  }
  /**
   * Override method from `StylingMixin` to apply `editable-cell` part to the
   * cells of edit columns.
   *
   * @override
   */
  _generateCellPartNames(row, model) {
    super._generateCellPartNames(row, model);
    iterateRowCells(row, (cell) => {
      const isEditable = !row.hasAttribute("loading") && this._isCellEditable(cell);
      const target = cell._focusButton || cell;
      updatePart(target, "editable-cell", isEditable);
    });
  }
  /** @private */
  _isCellEditable(cell) {
    const column2 = cell._column;
    if (!this._isEditColumn(column2)) {
      return false;
    }
    if (!column2.isCellEditable) {
      return true;
    }
    const model = this.__getRowModel(cell.parentElement);
    return column2.isCellEditable(model);
  }
  /**
   * Fired before exiting the cell edit mode, if the value has been changed.
   * If the default is prevented, value change would not be applied.
   *
   * @event item-property-changed
   * @param {Object} detail
   * @param {Object} detail.index the row index of the edited cell
   * @param {Object} detail.item the grid item rendered to the row of the edited cell
   * @param {Object} detail.path the column path of the edited cell
   * @param {Object} detail.value the new value of the edited cell
   */
  /**
   * Fired when the user starts editing a grid cell.
   *
   * @event cell-edit-started
   * @param {Object} detail
   * @param {Object} detail.index the row index of the edited cell
   * @param {Object} detail.item the grid item rendered to the row of the edited cell
   * @param {Object} detail.path the column path of the edited cell
   */
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class GridPro extends SlotStylesMixin(InlineEditingMixin(Grid)) {
  static get is() {
    return "vaadin-grid-pro";
  }
  static get cvdlName() {
    return "vaadin-grid-pro";
  }
  static get styles() {
    return gridProStyles;
  }
  get slotStyles() {
    const tag = this.localName;
    return [
      `
      ${tag} [theme="grid-pro-editor"] {
        --vaadin-input-field-border-radius: 0px;
        --vaadin-input-field-border-width: 0px;
        width: 100%;
      }

      ${tag} [theme="grid-pro-editor"]::part(input-field) {
        height: 100%;
        outline-offset: calc(var(--vaadin-focus-ring-width) * -1);
      }

      vaadin-grid-cell-content:has([theme="grid-pro-editor"]) {
        padding: 0;
        overflow: visible;
      }
    `
    ];
  }
}
defineCustomElement(GridPro);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class GridProEditCheckbox extends Checkbox {
  static get is() {
    return "vaadin-grid-pro-edit-checkbox";
  }
}
defineCustomElement(GridProEditCheckbox);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const GridProEditSelectMixin = (superClass) => class extends superClass {
  static get properties() {
    return {
      options: {
        type: Array,
        value: () => []
      },
      _grid: {
        type: Object
      },
      _initialized: {
        type: Boolean
      }
    };
  }
  static get observers() {
    return ["_optionsChanged(options)"];
  }
  ready() {
    super.ready();
    this.setAttribute("theme", "grid-pro-editor");
  }
  _onKeyDown(e) {
    super._onKeyDown(e);
    if (this.options.length === 0 && /^(ArrowDown|Down|ArrowUp|Up|Enter|SpaceBar| )$/u.test(e.key)) {
      console.warn('Missing "editorOptions" for <vaadin-grid-pro-edit-column> select editor!');
    }
    if (e.defaultPrevented) {
      e.stopPropagation();
    }
  }
  /**
   * Override list-box event listener inherited from `Select`:
   * - Enter: set flag for moving to next row on value change,
   * - Tab: switch to next cell when "singleCellEdit" is false.
   * @param {!KeyboardEvent} event
   * @protected
   * @override
   */
  _onKeyDownInside(event) {
    if (event.keyCode === 13) {
      this._enterKeydown = event;
    }
    if (event.keyCode === 9) {
      if (!this._grid.singleCellEdit) {
        this._grid._switchEditCell(event);
      }
    }
    super._onKeyDownInside(event);
  }
  _valueChanged(value, oldValue) {
    super._valueChanged(value, oldValue);
    if (value === "" && oldValue === void 0) {
      return;
    }
    if (this._initialized) {
      const enter = this._enterKeydown;
      if (enter && this._grid.enterNextRow) {
        this._grid._switchEditCell(enter);
      } else if (this._grid.singleCellEdit) {
        this._grid._stopEdit(false, true);
      } else {
        this.focus();
      }
    }
  }
  _optionsChanged(options2) {
    if (options2 && options2.length) {
      this.items = options2.map((option) => ({
        label: option,
        value: option
      }));
      this._overlayElement = this._overlayElement || this.shadowRoot.querySelector("vaadin-select-overlay");
      this._overlayElement.addEventListener("vaadin-overlay-outside-click", () => {
        this._grid._stopEdit();
      });
      setTimeout(() => {
        this.opened = true;
        this._initialized = true;
      });
    }
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class GridProEditSelect extends GridProEditSelectMixin(Select) {
  static get is() {
    return "vaadin-grid-pro-edit-select";
  }
}
defineCustomElement(GridProEditSelect);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class GridProEditText extends TextField {
  static get is() {
    return "vaadin-grid-pro-edit-text-field";
  }
  ready() {
    super.ready();
    this.setAttribute("theme", "grid-pro-editor");
  }
}
defineCustomElement(GridProEditText);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const GridProEditColumnMixin = (superClass) => class extends superClass {
  static get properties() {
    return {
      /**
       * Custom function for rendering the cell content in edit mode.
       * Receives three arguments:
       *
       * - `root` The cell content DOM element. Append your editor component to it.
       * - `column` The `<vaadin-grid-pro-edit-column>` element.
       * - `model` The object with the properties related with
       *   the rendered item, contains:
       *   - `model.index` The index of the item.
       *   - `model.item` The item.
       *   - `model.expanded` Sublevel toggle state.
       *   - `model.level` Level of the tree represented with a horizontal offset of the toggle button.
       *   - `model.selected` Selected state.
       *   - `model.detailsOpened` Details opened state.
       * @type {!GridBodyRenderer | null | undefined}
       */
      editModeRenderer: {
        type: Function,
        sync: true
      },
      /**
       * The list of options which should be passed to cell editor component.
       * Used with the `select` editor type, to provide a list of items.
       * @type {!Array<string>}
       */
      editorOptions: {
        type: Array,
        value: () => []
      },
      /**
       * Type of the cell editor component to be rendered. Allowed values:
       * - `text` (default) - renders a text field
       * - `checkbox` - renders a checkbox
       * - `select` - renders a select with a list of items passed as `editorOptions`
       *
       * Editor type is set to `custom` when `editModeRenderer` is set.
       * @attr {text|checkbox|select|custom} editor-type
       */
      editorType: {
        type: String,
        notify: true,
        // FIXME(web-padawan): needed by Flow counterpart
        value: "text"
      },
      /**
       * Path of the property used for the value of the editor component.
       * @attr {string} editor-value-path
       */
      editorValuePath: {
        type: String,
        value: "value"
      },
      /**
       * JS Path of the property in the item used for the editable content.
       */
      path: {
        type: String,
        observer: "_pathChanged",
        sync: true
      },
      /**
       * A function to check whether a specific cell of this column can be
       * edited. This allows to disable editing of individual rows or cells,
       * based on the item.
       *
       * Receives a `model` object containing the item for an individual row,
       * and should return a boolean indicating whether the column's cell in
       * that row is editable.
       *
       * The `model` object contains:
       * - `model.index` The index of the item.
       * - `model.item` The item.
       * - `model.expanded` Sublevel toggle state.
       * - `model.level` Level of the tree represented with a horizontal offset of the toggle button.
       * - `model.selected` Selected state.
       *
       * @type {(model: GridItemModel) => boolean}
       */
      isCellEditable: {
        type: Function,
        observer: "_isCellEditableChanged"
      },
      /** @private */
      _oldRenderer: Function
    };
  }
  static get observers() {
    return ["_editModeRendererChanged(editModeRenderer, __initialized)"];
  }
  constructor() {
    super();
    this._focusButtonMode = navigator.platform.includes("Mac");
    this.__editModeRenderer = function(root, column2) {
      const cell = root.assignedSlot.parentNode;
      const tagName = column2._getEditorTagName(cell);
      if (!root.firstElementChild || root.firstElementChild.localName.toLowerCase() !== tagName) {
        root.innerHTML = `
          <${tagName}></${tagName}>
        `;
      }
    };
  }
  /** @private */
  _pathChanged(path) {
    if (!path || path.length === 0) {
      throw new Error("You should specify the path for the edit column");
    }
  }
  /** @private */
  _isCellEditableChanged() {
    this._grid.requestContentUpdate();
  }
  /** @private */
  _editModeRendererChanged(renderer) {
    if (renderer) {
      this.editorType = "custom";
    } else if (this._oldRenderer) {
      this.editorType = "text";
    }
    this._oldRenderer = renderer;
  }
  /**
   * @param {!HTMLElement} cell
   * @return {string}
   * @protected
   */
  _getEditorTagName(cell) {
    return this.editorType === "custom" ? this._getEditorComponent(cell).localName : this._getTagNameByType();
  }
  /**
   * @param {!HTMLElement} cell
   * @return {HTMLElement | null}
   * @protected
   */
  _getEditorComponent(cell) {
    return this.editorType === "custom" ? cell._content.firstElementChild : cell._content.querySelector(this._getEditorTagName(cell));
  }
  /** @private */
  _getTagNameByType() {
    let type;
    switch (this.editorType) {
      case "checkbox":
        type = "checkbox";
        break;
      case "select":
        type = "select";
        break;
      case "text":
      default:
        type = "text-field";
        break;
    }
    return this.constructor.is.replace("column", type);
  }
  /** @private */
  _focusEditor(editor) {
    editor.focus();
    if (this.editorType === "checkbox") {
      editor.setAttribute("focus-ring", "");
    } else if (editor instanceof HTMLInputElement) {
      editor.select();
    } else if (editor.focusElement && editor.focusElement instanceof HTMLInputElement) {
      editor.focusElement.select();
    }
  }
  /**
   * @param {!HTMLElement} editor
   * @return {unknown}
   * @protected
   */
  _getEditorValue(editor) {
    const path = this.editorType === "checkbox" ? "checked" : this.editorValuePath;
    return get$5(path, editor);
  }
  /** @private */
  _renderEditor(cell, model) {
    cell.__savedRenderer = this._renderer || cell._renderer;
    cell._renderer = this.editModeRenderer || this.__editModeRenderer;
    if (cell._focusButton) {
      cell._focusButton.removeAttribute("role");
    }
    this._clearCellContent(cell);
    this._runRenderer(cell._renderer, cell, model);
  }
  /** @private */
  _removeEditor(cell, _model) {
    if (!cell.__savedRenderer) {
      return;
    }
    cell._renderer = cell.__savedRenderer;
    cell.__savedRenderer = void 0;
    this._clearCellContent(cell);
    if (cell._focusButton) {
      cell._focusButton.setAttribute("role", "button");
    }
    this.__renderCellsContent(cell._renderer, [cell]);
  }
  /** @private */
  _setEditorOptions(editor) {
    if (this.editorOptions && this.editorOptions.length) {
      editor.options = this.editorOptions;
    }
  }
  /** @private */
  _setEditorValue(editor, value) {
    const path = this.editorType === "checkbox" ? "checked" : this.editorValuePath;
    value = this.editorType === "checkbox" && typeof value === "string" ? value === "true" : value;
    set(path, value, editor);
    if (editor.notifyPath) {
      editor.notifyPath(path, value);
    }
  }
  /**
   * @param {!HTMLElement} cell
   * @param {!GridItemModel} model
   * @protected
   */
  _startCellEdit(cell, model) {
    this._renderEditor(cell, model);
    const editor = this._getEditorComponent(cell);
    editor.addEventListener("focusout", this._grid.__boundEditorFocusOut);
    editor.addEventListener("focusin", this._grid.__boundEditorFocusIn);
    this._setEditorOptions(editor);
    this._setEditorValue(editor, get$5(this.path, model.item));
    editor._grid = this._grid;
    if (editor.updateComplete) {
      editor.updateComplete.then(() => this._focusEditor(editor));
    } else {
      this._focusEditor(editor);
    }
    if (this.editorType === "custom") {
      editor.addEventListener("opened-changed", (event) => {
        const element = event.target;
        const activeElement = getDeepActiveElement();
        if (!element.opened && !element.contains(activeElement)) {
          this._grid._stopEdit();
        }
      });
    }
  }
  /**
   * @param {!HTMLElement} cell
   * @param {!GridItemModel} model
   * @protected
   */
  _stopCellEdit(cell, model) {
    this._removeEditor(cell, model);
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class GridProEditColumn extends GridProEditColumnMixin(GridColumn) {
  static get is() {
    return "vaadin-grid-pro-edit-column";
  }
}
defineCustomElement(GridProEditColumn);
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
function isEditedRow(grid, rowData) {
  return grid.__edited && grid.__edited.model.item.key === rowData.item.key;
}
const LOADING_EDITOR_CELL_ATTRIBUTE = "loading-editor";
window.Vaadin.Flow.gridProConnector = {
  selectAll: (editor, itemKey, grid) => {
    if (editor.__itemKey !== itemKey) {
      return;
    }
    grid.toggleAttribute(LOADING_EDITOR_CELL_ATTRIBUTE, false);
    if (editor instanceof HTMLInputElement) {
      editor.select();
    } else if (editor.focusElement && editor.focusElement instanceof HTMLInputElement) {
      editor.focusElement.select();
    }
  },
  setEditModeRenderer(column2, component) {
    column2.editModeRenderer = function editModeRenderer(root, _2, rowData) {
      if (!isEditedRow(this._grid, rowData)) {
        this._grid._stopEdit();
        return;
      }
      if (component.parentNode === root) {
        return;
      }
      root.appendChild(component);
      this._grid._cancelStopEdit();
      component.focus();
      component.__itemKey = rowData.item.key;
      this._grid.toggleAttribute(LOADING_EDITOR_CELL_ATTRIBUTE, true);
    };
    column2._setEditorValue = function(editor, value) {
    };
    const stopCellEdit = column2._stopCellEdit;
    column2._stopCellEdit = function() {
      stopCellEdit.apply(this, arguments);
      this._grid.toggleAttribute(LOADING_EDITOR_CELL_ATTRIBUTE, false);
    };
  },
  patchEditModeRenderer(column2) {
    column2.__editModeRenderer = function __editModeRenderer(root, column3, rowData) {
      const cell = root.assignedSlot.parentNode;
      const grid = column3._grid;
      if (!isEditedRow(grid, rowData)) {
        grid._stopEdit();
        return;
      }
      const tagName = column3._getEditorTagName(cell);
      if (!root.firstElementChild || root.firstElementChild.localName.toLowerCase() !== tagName) {
        root.innerHTML = `<${tagName}></${tagName}>`;
      }
    };
  },
  initCellEditableProvider(column2) {
    column2.isCellEditable = function(model) {
      const isEditable = model.item.cellEditable && model.item.cellEditable[column2._flowId];
      return isEditable === void 0 || isEditable;
    };
  },
  initUpdatingCellAnimation(grid) {
    grid.addEventListener("item-property-changed", (e) => {
      const { column: column2, model } = grid.__edited;
      if (column2.editorType !== "custom") {
        return;
      }
      e.preventDefault();
      grid.__pendingCellUpdate = `${model.item.key}:${column2.path}`;
      grid.requestContentUpdate();
    });
    const generateCellPartNames = grid._generateCellPartNames;
    grid._generateCellPartNames = function(row, model) {
      generateCellPartNames.apply(this, arguments);
      iterateRowCells(row, (cell) => {
        const isUpdating = model && cell._column && grid.__pendingCellUpdate === `${model.item.key}:${cell._column.path}`;
        const target = cell._focusButton || cell;
        updatePart(target, "updating-cell", isUpdating);
      });
    };
  },
  clearUpdatingCell(grid) {
    grid.__pendingCellUpdate = null;
    grid.requestContentUpdate();
  }
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const passwordFieldBase = css$h`
  :host {
    --vaadin-button-background: transparent;
    --vaadin-button-padding: 0;
    color: var(--vaadin-input-field-button-text-color, inherit);
    display: block;
    border: none;
    cursor: var(--vaadin-clickable-cursor);
  }

  :host::before {
    background: currentColor;
    content: '';
    display: block;
    height: var(--vaadin-icon-size, 1lh);
    mask: var(--_vaadin-icon-eye) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
    width: var(--vaadin-icon-size, 1lh);
  }

  :host([aria-pressed='true'])::before {
    mask-image: var(--_vaadin-icon-eye-slash);
  }

  @media (forced-colors: active) {
    :host::before {
      background: CanvasText;
    }

    :host([disabled])::before {
      background: GrayText;
    }
  }
`;
const passwordFieldButton = [buttonStyles, passwordFieldBase];
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class PasswordFieldButton extends ButtonMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-password-field-button";
  }
  static get styles() {
    return passwordFieldButton;
  }
  /** @protected */
  render() {
    return html``;
  }
}
defineCustomElement(PasswordFieldButton);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const passwordFieldStyles = css$h`
  [part~='reveal-button']::before {
    display: none;
  }

  [part='input-field']:has([part~='reveal-button']:focus-within) {
    outline: none;
    --vaadin-input-field-border-color: inherit;
  }

  :host([readonly]) [part~='reveal-button'] {
    color: var(--vaadin-input-field-button-text-color, var(--vaadin-text-color-secondary));
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const PasswordFieldMixin = (superClass) => class PasswordFieldMixinClass extends SlotStylesMixin(DisabledMixin(FocusMixin(InputMixin(superClass)))) {
  static get properties() {
    return {
      /**
       * Set to true to hide the eye icon which toggles the password visibility.
       * @attr {boolean} reveal-button-hidden
       */
      revealButtonHidden: {
        type: Boolean,
        value: false
      },
      /**
       * True if the password is visible ([type=text]).
       * @attr {boolean} password-visible
       */
      passwordVisible: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        readOnly: true
      },
      /**
       * An object with translated strings used for localization.
       * It has the following structure and default values:
       *
       * ```js
       * {
       *   // Translation of the reveal icon button accessible label
       *   reveal: 'Show password'
       * }
       * ```
       */
      i18n: {
        type: Object,
        value: () => {
          return {
            reveal: "Show password"
          };
        }
      }
    };
  }
  /** @override */
  static get delegateAttrs() {
    return super.delegateAttrs.filter((attr2) => attr2 !== "autocapitalize");
  }
  constructor() {
    super();
    this._setType("password");
    this.__boundRevealButtonClick = this._onRevealButtonClick.bind(this);
    this.__boundRevealButtonMouseDown = this._onRevealButtonMouseDown.bind(this);
    this.__lastChange = "";
  }
  /** @protected */
  get slotStyles() {
    const tag = this.localName;
    return [
      ...super.slotStyles,
      `
          ${tag} [slot="input"]::-ms-reveal {
            display: none;
          }
        `
    ];
  }
  /** @protected */
  ready() {
    super.ready();
    this._revealPart = this.shadowRoot.querySelector('[part~="reveal-button"]');
    this._revealButtonController = new SlotController(this, "reveal", "vaadin-password-field-button", {
      initializer: (btn) => {
        this._revealNode = btn;
        btn.addEventListener("click", this.__boundRevealButtonClick);
        btn.addEventListener("mousedown", this.__boundRevealButtonMouseDown);
      }
    });
    this.addController(this._revealButtonController);
    if (this.inputElement) {
      this.inputElement.autocapitalize = "off";
    }
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("disabled")) {
      this._revealNode.disabled = this.disabled;
    }
    if (props.has("revealButtonHidden")) {
      this._toggleRevealHidden(this.revealButtonHidden);
    }
    if (props.has("passwordVisible")) {
      this._setType(this.passwordVisible ? "text" : "password");
      this._revealNode.setAttribute("aria-pressed", this.passwordVisible ? "true" : "false");
    }
    if (props.has("i18n") && this.i18n && this.i18n.reveal) {
      this._revealNode.setAttribute("aria-label", this.i18n.reveal);
    }
  }
  /**
   * Override an event listener inherited from `InputControlMixin`
   * to store the value at the moment of the native `change` event.
   * @param {Event} event
   * @protected
   * @override
   */
  _onChange(event) {
    super._onChange(event);
    this.__lastChange = this.inputElement.value;
  }
  /**
   * Override method inherited from `FocusMixin` to mark field as focused
   * when focus moves to the reveal button using Shift Tab.
   * @param {Event} event
   * @return {boolean}
   * @protected
   */
  _shouldSetFocus(event) {
    return event.target === this.inputElement || event.target === this._revealNode;
  }
  /**
   * Override method inherited from `FocusMixin` to not hide password
   * when focus moves to the reveal button or back to the input.
   * @param {Event} event
   * @return {boolean}
   * @protected
   */
  _shouldRemoveFocus(event) {
    return !(event.relatedTarget === this._revealNode || event.relatedTarget === this.inputElement && event.target === this._revealNode);
  }
  /**
   * Override method inherited from `FocusMixin` to toggle password visibility.
   * @param {boolean} focused
   * @protected
   * @override
   */
  _setFocused(focused) {
    super._setFocused(focused);
    if (!focused) {
      this._setPasswordVisible(false);
      if (this.__lastChange !== this.inputElement.value) {
        this.__lastChange = this.inputElement.value;
        this.dispatchEvent(new CustomEvent("change", { bubbles: true }));
      }
    } else {
      const isButtonFocused = this.getRootNode().activeElement === this._revealNode;
      this.toggleAttribute("focus-ring", this._keyboardActive && !isButtonFocused);
    }
  }
  /** @private */
  _onRevealButtonClick() {
    this._setPasswordVisible(!this.passwordVisible);
  }
  /** @private */
  _onRevealButtonMouseDown(e) {
    e.preventDefault();
    this.inputElement.focus();
  }
  /** @private */
  _toggleRevealHidden(hidden) {
    if (this._revealNode) {
      if (hidden) {
        this._revealPart.setAttribute("hidden", "");
        this._revealNode.setAttribute("tabindex", "-1");
        this._revealNode.setAttribute("aria-hidden", "true");
      } else {
        this._revealPart.removeAttribute("hidden");
        this._revealNode.setAttribute("tabindex", "0");
        this._revealNode.removeAttribute("aria-hidden");
      }
    }
  }
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class PasswordField extends PasswordFieldMixin(TextField) {
  static get is() {
    return "vaadin-password-field";
  }
  static get styles() {
    return [...super.styles, passwordFieldStyles];
  }
  /**
   * @protected
   * @override
   */
  _renderSuffix() {
    return html`
      ${super._renderSuffix()}
      <div part="field-button reveal-button" slot="suffix">
        <slot name="reveal"></slot>
      </div>
    `;
  }
}
defineCustomElement(PasswordField);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const loginFormWrapperStyles = css$h`
  :host {
    background: var(--vaadin-login-form-background, transparent);
    border-radius: var(--vaadin-login-form-border-radius, 0);
    display: flex;
    box-sizing: border-box;
    flex-direction: column;
    gap: var(--vaadin-login-form-gap, var(--vaadin-gap-l));
    padding: var(--vaadin-login-form-padding, var(--vaadin-padding-l));
    max-width: 100%;
    width: var(--vaadin-login-form-width, 360px);
  }

  :host([hidden]) {
    display: none !important;
  }

  ::slotted(form) {
    display: flex;
    flex-direction: column;
    gap: var(--vaadin-login-form-gap, var(--vaadin-gap-m));
  }

  ::slotted([slot='form-title']) {
    color: var(--vaadin-login-form-title-color, var(--vaadin-text-color));
    font-size: var(--vaadin-login-form-title-font-size, 1.25rem);
    font-weight: var(--vaadin-login-form-title-font-weight, 600);
    line-height: var(--vaadin-login-form-title-line-height, inherit);
  }

  :host([error]) [part='error-message'] {
    display: grid;
  }

  [part='error-message'] {
    color: var(--vaadin-login-form-error-color, var(--vaadin-text-color));
    font-size: var(--vaadin-login-form-error-font-size, inherit);
    font-weight: var(--vaadin-login-form-error-font-weight, 400);
    gap: var(--vaadin-login-form-error-gap, 0 var(--vaadin-gap-s));
    grid-template-columns: auto 1fr;
    line-height: var(--vaadin-login-form-error-line-height, inherit);
  }

  [part='error-message']::before {
    background: currentColor;
    content: '';
    display: inline-block;
    flex: none;
    height: var(--vaadin-icon-size, 1lh);
    mask: var(--_vaadin-icon-warn) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
    width: var(--vaadin-icon-size, 1lh);
  }

  [part='error-message-description'] {
    grid-column: 2;
  }
`;
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class LoginFormWrapper extends ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))) {
  static get is() {
    return "vaadin-login-form-wrapper";
  }
  static get styles() {
    return loginFormWrapperStyles;
  }
  static get properties() {
    return {
      /**
       * If set, the error message is shown. The message is hidden by default.
       * When set, it changes the disabled state of the submit button.
       */
      error: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * The object used to localize this component.
       */
      i18n: {
        type: Object
      }
    };
  }
  /** @protected */
  render() {
    return html`
      <slot name="form-title"></slot>
      <div part="error-message" ?hidden="${!this.error}">
        <strong part="error-message-title">${this.i18n.errorMessage.title}</strong>
        <div part="error-message-description">${this.i18n.errorMessage.message}</div>
      </div>

      <slot name="form"></slot>

      <slot name="custom-form-area"></slot>

      <slot name="submit"></slot>

      <slot name="forgot-password"></slot>

      <div part="footer">
        <slot name="footer"></slot>
        <div>${this.i18n.additionalInformation}</div>
      </div>
    `;
  }
}
defineCustomElement(LoginFormWrapper);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N$5 = {
  form: {
    title: "Log in",
    username: "Username",
    password: "Password",
    submit: "Log in",
    forgotPassword: "Forgot password"
  },
  errorMessage: {
    title: "Incorrect username or password",
    message: "Check that you have entered the correct username and password and try again.",
    username: "Username is required",
    password: "Password is required"
  }
};
const LoginMixin = (superClass) => class LoginMixin extends I18nMixin(DEFAULT_I18N$5, superClass) {
  /**
   * Fired when user clicks on the "Forgot password" button.
   *
   * @event forgot-password
   */
  /**
   * Fired when an user submits the login.
   * The event contains `username` and `password` values in the `detail` property.
   *
   * @event login
   */
  static get properties() {
    return {
      /**
       * If set, a synchronous POST call will be fired to the path defined.
       * The `login` event is also dispatched, so `event.preventDefault()` can be called to prevent the POST call.
       */
      action: {
        type: String,
        value: null
      },
      /**
       * If set, disable the "Log in" button and prevent user from submitting login form.
       * It is re-enabled automatically, when error is set to true, allowing form resubmission
       * after user makes changes.
       */
      disabled: {
        type: Boolean,
        value: false,
        notify: true
      },
      /**
       * If set, the error message is shown. The message is hidden by default.
       * When set, it changes the disabled state of the submit button.
       */
      error: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        notify: true
      },
      /**
       * Whether to hide the forgot password button. The button is visible by default.
       * @attr {boolean} no-forgot-password
       */
      noForgotPassword: {
        type: Boolean,
        value: false
      },
      /**
       * If set, the user name field automatically receives focus when the component is attached to the document.
       * @attr {boolean} no-autofocus
       */
      noAutofocus: {
        type: Boolean,
        value: false
      },
      /**
       * Sets the root heading level (`aria-level`) for the heading hierarchy. Default value: 1.
       * Child headings automatically increment from this base level i.e. standalone login form
       * renders its title as `<h1>`, whereas the form in the overlay uses `<h2>`, as the `<h1>`
       * element is used by the overlay's own title.
       *
       * @attr {number} heading-level
       */
      headingLevel: {
        type: Number,
        value: 1
      },
      /**
       * If set, prevents auto enabling the component when error property is set to true.
       * @private
       */
      _preventAutoEnable: {
        type: Boolean,
        value: false
      }
    };
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure (by default it doesn't include `additionalInformation`
   * and `header` sections, `header` can be added to override `title` and `description` properties
   * in `vaadin-login-overlay`):
   *
   * ```js
   * {
   *   header: {
   *     title: 'App name',
   *     description: 'Inspiring application description'
   *   },
   *   form: {
   *     title: 'Log in',
   *     username: 'Username',
   *     password: 'Password',
   *     submit: 'Log in',
   *     forgotPassword: 'Forgot password'
   *   },
   *   errorMessage: {
   *     title: 'Incorrect username or password',
   *     message: 'Check that you have entered the correct username and password and try again.',
   *     username: 'Username is required',
   *     password: 'Password is required'
   *   },
   *   additionalInformation: 'In case you need to provide some additional info for the user.'
   * }
   * ```
   * @type {!LoginI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function isCheckbox(field2) {
  return (field2.inputElement || field2).type === "checkbox";
}
const LoginFormMixin = (superClass) => class LoginFormMixin extends LoginMixin(superClass) {
  /** @protected */
  get _customFields() {
    return [...this.children].filter((node) => {
      return node.getAttribute("slot") === "custom-form-area" && node.hasAttribute("name");
    });
  }
  /** @protected */
  get _userNameField() {
    return this.querySelector("#vaadinLoginUsername");
  }
  /** @protected */
  get _passwordField() {
    return this.querySelector("#vaadinLoginPassword");
  }
  /**
   * Override update to render slotted form and buttons
   * into light DOM after rendering shadow DOM.
   * @protected
   */
  update(props) {
    super.update(props);
    this.__renderSlottedForm();
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("error") && this.error && !this._preventAutoEnable) {
      this.disabled = false;
    }
  }
  /** @protected */
  async connectedCallback() {
    super.connectedCallback();
    if (!this.noAutofocus) {
      await new Promise(requestAnimationFrame);
      this._userNameField.focus();
    }
  }
  __renderSlottedForm() {
    render$1(
      html`
          <form method="POST" action="${ifDefined(this.action)}" @formdata="${this._onFormData}" slot="form">
            <input id="csrf" type="hidden" />
            <vaadin-text-field
              name="username"
              .label="${this.__effectiveI18n.form.username}"
              .errorMessage="${this.__effectiveI18n.errorMessage.username}"
              id="vaadinLoginUsername"
              required
              @keydown="${this._handleInputKeydown}"
              autocapitalize="none"
              autocorrect="off"
              spellcheck="false"
              autocomplete="username"
              manual-validation
            >
              <input type="text" slot="input" @keyup="${this._handleInputKeyup}" />
            </vaadin-text-field>

            <vaadin-password-field
              name="password"
              .label="${this.__effectiveI18n.form.password}"
              .errorMessage="${this.__effectiveI18n.errorMessage.password}"
              id="vaadinLoginPassword"
              required
              @keydown="${this._handleInputKeydown}"
              spellcheck="false"
              autocomplete="current-password"
              manual-validation
            >
              <input type="password" slot="input" @keyup="${this._handleInputKeyup}" />
            </vaadin-password-field>
          </form>

          <vaadin-button slot="submit" theme="primary submit" @click="${this.submit}" .disabled="${this.disabled}">
            ${this.__effectiveI18n.form.submit}
          </vaadin-button>

          <vaadin-button
            slot="forgot-password"
            theme="tertiary small"
            @click="${this._onForgotPasswordClick}"
            ?hidden="${this.noForgotPassword}"
          >
            ${this.__effectiveI18n.form.forgotPassword}
          </vaadin-button>
        `,
      this,
      { host: this }
    );
  }
  /**
   * Submits the form.
   */
  submit() {
    const userName = this._userNameField;
    const password = this._passwordField;
    userName.validate();
    password.validate();
    if (this.disabled || userName.invalid || password.invalid) {
      return;
    }
    this.error = false;
    this.disabled = true;
    const detail = {
      username: userName.value,
      password: password.value
    };
    const fields2 = this._customFields;
    if (fields2.length) {
      detail.custom = {};
      fields2.forEach((field2) => {
        if (isCheckbox(field2) && !field2.checked) {
          return;
        }
        detail.custom[field2.name] = field2.value;
      });
    }
    const loginEventDetails = {
      bubbles: true,
      cancelable: true,
      detail
    };
    const firedEvent = this.dispatchEvent(new CustomEvent("login", loginEventDetails));
    if (this.action && firedEvent) {
      const csrfMetaName = document.querySelector("meta[name=_csrf_parameter]");
      const csrfMetaValue = document.querySelector("meta[name=_csrf]");
      if (csrfMetaName && csrfMetaValue) {
        const csrf = this.querySelector("#csrf");
        csrf.name = csrfMetaName.content;
        csrf.value = csrfMetaValue.content;
      }
      this.querySelector("form").submit();
    }
  }
  /** @protected */
  _onFormData(event) {
    const { formData } = event;
    if (this._customFields.length) {
      this._customFields.forEach((field2) => {
        if (isCheckbox(field2) && !field2.checked) {
          return;
        }
        formData.append(field2.name, field2.value);
      });
    }
  }
  /** @protected */
  _handleInputKeydown(e) {
    if (e.key === "Enter") {
      const { currentTarget: inputActive } = e;
      const nextInput = inputActive.id === "vaadinLoginUsername" ? this._passwordField : this._userNameField;
      if (inputActive.validate()) {
        if (nextInput.checkValidity()) {
          this.submit();
        } else {
          nextInput.focus();
        }
      }
    }
  }
  /** @protected */
  _handleInputKeyup(e) {
    const input = e.currentTarget;
    if (e.key === "Tab" && input instanceof HTMLInputElement) {
      input.select();
    }
  }
  /** @protected */
  _onForgotPasswordClick() {
    this.dispatchEvent(new CustomEvent("forgot-password"));
  }
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class LoginForm extends LoginFormMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
  static get is() {
    return "vaadin-login-form";
  }
  static get styles() {
    return css$h`
      :host {
        display: block;
        max-width: 100%;
      }

      :host([hidden]) {
        display: none !important;
      }
    `;
  }
  /** @protected */
  render() {
    return html`
      <vaadin-login-form-wrapper
        id="form"
        theme="${ifDefined(this._theme)}"
        .error="${this.error}"
        .i18n="${this.__effectiveI18n}"
        part="form"
        role="region"
        aria-labelledby="title"
        exportparts="error-message, error-message-title, error-message-description, footer"
      >
        <div id="title" slot="form-title" part="form-title" role="heading" aria-level="${this.headingLevel}">
          ${this.__effectiveI18n.form.title}
        </div>
        <slot name="form" slot="form"></slot>
        <slot name="custom-form-area" slot="custom-form-area"></slot>
        <slot name="submit" slot="submit"></slot>
        <slot name="forgot-password" slot="forgot-password"></slot>
        <slot name="footer" slot="footer"></slot>
      </vaadin-login-form-wrapper>
    `;
  }
}
defineCustomElement(LoginForm);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const loginOverlayWrapper = css$h`
  [part='overlay'] {
    color: var(--vaadin-login-overlay-text-color, var(--vaadin-overlay-text-color, var(--vaadin-text-color)));
    background: var(
      --vaadin-login-overlay-background,
      var(--vaadin-overlay-background, var(--vaadin-background-color))
    );
    border: var(--vaadin-login-overlay-border-width, var(--vaadin-overlay-border-width, 1px)) solid
      var(--vaadin-login-overlay-border-color, var(--vaadin-overlay-border-color, var(--vaadin-border-color-secondary)));
    border-radius: var(--vaadin-login-overlay-border-radius, var(--vaadin-radius-l));
    box-shadow: var(--vaadin-login-overlay-shadow, var(--vaadin-overlay-shadow, 0 8px 24px -4px rgba(0, 0, 0, 0.3)));
  }

  [part='card'] {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    max-width: 100%;
    overflow: hidden;
  }

  [part='brand'] {
    background: var(--vaadin-login-overlay-brand-background, var(--vaadin-background-container));
    display: flex;
    flex-direction: column;
    padding: var(--vaadin-login-overlay-brand-padding, var(--vaadin-padding-l));
  }

  ::slotted([slot='title']) {
    color: var(--vaadin-login-overlay-title-color, var(--vaadin-text-color));
    font-size: var(--vaadin-login-overlay-title-font-size, inherit);
    font-weight: var(--vaadin-login-overlay-title-font-weight, 600);
    line-height: var(--vaadin-login-overlay-title-line-height, inherit);
  }

  [part='description'] {
    color: var(--vaadin-login-overlay-description-color, var(--vaadin-text-color-secondary));
    font-size: var(--vaadin-login-overlay-description-font-size, inherit);
    font-weight: var(--vaadin-login-overlay-description-font-weight, inherit);
    line-height: var(--vaadin-login-overlay-description-line-height, inherit);
  }
`;
const loginOverlayWrapperStyles = [overlayStyles, loginOverlayWrapper];
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class LoginOverlayWrapper extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-login-overlay-wrapper";
  }
  static get styles() {
    return loginOverlayWrapperStyles;
  }
  static get properties() {
    return {
      /**
       * Application description. Displayed under the title.
       */
      description: {
        type: String
      }
    };
  }
  /**
   * Override method from OverlayFocusMixin to use owner as focus trap root
   * @protected
   * @override
   */
  get _focusTrapRoot() {
    return this.owner;
  }
  /** @protected */
  render() {
    return html`
      <div id="backdrop" part="backdrop" ?hidden="${!this.withBackdrop}"></div>
      <div part="overlay" id="overlay">
        <div part="content" id="content">
          <section part="card">
            <div part="brand">
              <slot name="title"></slot>
              <div part="description">${this.description}</div>
            </div>
            <div part="form-wrapper">
              <slot></slot>
            </div>
          </section>
        </div>
      </div>
    `;
  }
}
defineCustomElement(LoginOverlayWrapper);
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class TitleController extends SlotChildObserveController {
  constructor(host) {
    super(host, "title", "div");
  }
  /**
   * Set title based on corresponding host property.
   *
   * @param {string} title
   */
  setTitle(title) {
    this.title = title;
    const titleNode = this.getSlotChild();
    if (!titleNode) {
      this.restoreDefaultNode();
    }
    if (this.node === this.defaultNode) {
      this.updateDefaultNode(this.node);
    }
  }
  /**
   * Set level based on corresponding host property.
   *
   * @param {string} level
   */
  setLevel(level) {
    this.level = level;
    if (this.node === this.defaultNode) {
      this.updateDefaultNode(this.node);
    }
  }
  /**
   * Override method inherited from `SlotController`
   * to customize heading on the default title node.
   *
   * @param {Node} node
   * @protected
   * @override
   */
  initNode(node) {
    if (node === this.defaultNode) {
      node.setAttribute("role", "heading");
    }
    this.host.setAttribute("aria-labelledby", node.id);
  }
  /**
   * Override method inherited from `SlotChildObserveController`
   * to restore the default title element.
   *
   * @protected
   * @override
   */
  restoreDefaultNode() {
    const { title } = this;
    if (title && title.trim() !== "") {
      const node = this.attachDefaultNode();
      this.initNode(node);
    }
  }
  /**
   * Override method inherited from `SlotChildObserveController`
   * to update the default title element.
   *
   * @param {Node | undefined} node
   * @protected
   * @override
   */
  updateDefaultNode(node) {
    if (node) {
      node.textContent = this.title;
      node.setAttribute("aria-level", this.level);
    }
    super.updateDefaultNode(node);
  }
}
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const LoginOverlayMixin = (superClass) => class LoginOverlayMixin extends superClass {
  static get properties() {
    return {
      /**
       * Defines the application description
       */
      description: {
        type: String,
        value: "Application description",
        notify: true
      },
      /**
       * True if the overlay is currently displayed.
       */
      opened: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        sync: true
      },
      /**
       * Defines the application title
       */
      title: {
        type: String,
        value: "App name"
      },
      /** @private */
      __effectiveTitle: {
        type: String
      },
      /** @private */
      __effectiveDescription: {
        type: String
      }
    };
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    this.setAttribute("role", "dialog");
    this.setAttribute("aria-modal", "true");
    this.setAttribute("tabindex", "0");
    this.__titleController = new TitleController(this);
    this.addController(this.__titleController);
    this._overlayElement = this.$.overlay;
  }
  /** @protected */
  willUpdate(props) {
    super.willUpdate(props);
    if (props.has("__effectiveI18n") || props.has("title") || props.has("description")) {
      const header = this.__effectiveI18n && this.__effectiveI18n.header;
      this.__effectiveTitle = header && header.title != null ? header.title : this.title;
      this.__effectiveDescription = header && header.description != null ? header.description : this.description;
    }
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("__effectiveTitle")) {
      this.__titleController.setTitle(this.__effectiveTitle);
    }
    if (props.has("headingLevel")) {
      this.__titleController.setLevel(this.headingLevel);
    }
    if (props.has("opened")) {
      this._openedChanged(this.opened);
    }
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this.__restoreOpened) {
      this.opened = true;
    }
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    setTimeout(() => {
      if (!this.isConnected) {
        this.__restoreOpened = this.opened;
        this.opened = false;
      }
    });
  }
  /** @protected */
  _preventClosingLogin(e) {
    e.preventDefault();
  }
  /** @private */
  __handleOverlayClosed() {
    this.dispatchEvent(new CustomEvent("closed"));
  }
  /** @private */
  _openedChanged(opened, oldOpened) {
    if (oldOpened) {
      this._userNameField.value = "";
      this._passwordField.value = "";
      this.disabled = false;
    } else if (opened) {
      document.body.style.pointerEvents = this.$.overlay._previousDocumentPointerEvents;
    }
  }
  /**
   * Fired when the overlay is closed.
   *
   * @event closed
   */
};
/**
 * @license
 * Copyright (c) 2018 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class LoginOverlay extends LoginFormMixin(LoginOverlayMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement))))) {
  static get is() {
    return "vaadin-login-overlay";
  }
  static get styles() {
    return css$h`
      :host([opened]),
      :host([opening]),
      :host([closing]) {
        display: block !important;
        position: fixed;
        outline: none;
      }

      :host,
      :host([hidden]) {
        display: none !important;
      }

      :host(:focus-visible) ::part(overlay) {
        outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
      }
    `;
  }
  /** @protected */
  render() {
    return html`
      <vaadin-login-overlay-wrapper
        id="overlay"
        .owner="${this}"
        .opened="${this.opened}"
        .description="${this.__effectiveDescription}"
        focus-trap
        with-backdrop
        theme="${ifDefined(this._theme)}"
        @vaadin-overlay-escape-press="${this._preventClosingLogin}"
        @vaadin-overlay-outside-click="${this._preventClosingLogin}"
        @vaadin-overlay-closed="${this.__handleOverlayClosed}"
        @opened-changed="${this._onOpenedChanged}"
        exportparts="backdrop, overlay, content, card, brand, description, form-wrapper"
      >
        <slot name="title" slot="title"></slot>
        <vaadin-login-form-wrapper
          id="form"
          .error="${this.error}"
          .i18n="${this.__effectiveI18n}"
          part="form"
          role="region"
          aria-labelledby="title"
          exportparts="error-message, error-message-title, error-message-description, footer"
        >
          <div id="title" slot="form-title" part="form-title" role="heading" aria-level="${this.headingLevel + 1}">
            ${this.__effectiveI18n.form.title}
          </div>
          <slot name="form" slot="form"></slot>
          <slot name="custom-form-area" slot="custom-form-area"></slot>
          <slot name="submit" slot="submit"></slot>
          <slot name="forgot-password" slot="forgot-password"></slot>
          <slot name="footer" slot="footer"></slot>
        </vaadin-login-form-wrapper>
      </vaadin-login-overlay-wrapper>
    `;
  }
  /** @private */
  _onOpenedChanged(event) {
    this.opened = event.detail.value;
  }
}
defineCustomElement(LoginOverlay);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const mapStyles = css$h`
  :host {
    display: block;
    height: 400px;
    flex: 1 1 auto;
    align-self: stretch;
    overflow: hidden;
  }

  :host([hidden]) {
    display: none !important;
  }

  :host([focus-ring]) {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }

  :host(:not([theme~='no-border'])) {
    border-radius: var(--vaadin-map-border-radius, var(--vaadin-radius-m));
    position: relative;
  }

  :host(:not([theme~='no-border']))::before {
    content: '';
    position: absolute;
    inset: 0;
    border: 1px solid var(--vaadin-map-border-color, var(--vaadin-border-color-secondary));
    border-radius: inherit;
    z-index: 1;
    pointer-events: none;
  }

  #map {
    width: 100%;
    height: 100%;
    outline: none;
  }

  #map,
  .ol-viewport,
  .ol-layers {
    border-radius: inherit;
    overflow: hidden;
  }

  #map:fullscreen {
    border-radius: 0;
  }

  #map:-webkit-full-screen {
    border-radius: 0;
  }

  /* Functional styles, copied from 'ol/ol.css' */

  .ol-box {
    box-sizing: border-box;
    border-radius: 2px;
    border: 1px solid rgba(0, 0, 0, 0.5);
    background-color: rgba(255, 255, 255, 0.2);
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.5);
  }

  .ol-unsupported {
    display: none;
  }

  .ol-viewport,
  .ol-unselectable {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }

  .ol-viewport canvas {
    all: unset;
  }

  .ol-selectable {
    -webkit-touch-callout: default;
    -webkit-user-select: text;
    user-select: text;
  }

  .ol-grabbing {
    cursor: grabbing;
  }

  .ol-grab {
    cursor: move;
    cursor: grab;
  }

  /* Control positioning and styling */

  .ol-overlaycontainer-stopevent {
    /* stylelint-disable declaration-block-no-redundant-longhand-properties */
    display: grid;
    grid-template-columns: min-content 1fr min-content;
    grid-template-rows: min-content 1fr min-content min-content min-content min-content;
    padding: var(--vaadin-map-controls-inset, 4px);
    box-sizing: border-box;
    grid-template-areas:
      'scale mouse-position fullscreen'
      'overview-map . zoom-extent'
      'overview-map . compass'
      'overview-map . zoom-slider'
      'overview-map . zoom'
      'overview-map attribution attribution';
  }

  .ol-mouse-position {
    grid-area: mouse-position;
    align-self: start;
    text-align: center;
    font-size: 0.625em;
    color: #000;
    filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
  }

  .ol-scale-line,
  .ol-scale-bar {
    grid-area: scale;
    position: relative;
    pointer-events: none !important;
    color: #000;
  }

  .ol-scale-line-inner {
    border: 1px solid rgba(0, 0, 0, 0.5);
    border-top: none;
    font-size: 0.625em;
    text-align: center;
    will-change: contents, width, filter;
    transition: all 0.25s;
    filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
  }

  .ol-scale-bar-inner {
    display: flex;
    border: 1px solid rgba(0, 0, 0, 0.5);
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.5);
    overflow: hidden;
  }

  .ol-scale-singlebar-even {
    background: #000;
  }

  .ol-scale-singlebar-odd {
    background: #fff;
  }

  .ol-scale-step-marker {
    display: none;
  }

  .ol-scale-step-text {
    position: absolute;
    top: 12px;
    font-size: 0.625em;
    color: #000;
    filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
    white-space: nowrap;
    overflow: hidden;
  }

  .ol-scale-text {
    position: absolute;
    font-size: 0.625em;
    top: 32px;
    color: #000;
    white-space: nowrap;
    filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
  }

  .ol-scale-singlebar {
    height: 4px;
    opacity: 0.5;
  }

  .ol-control {
    margin: 4px;
    border-radius: var(--vaadin-button-border-radius, var(--vaadin-radius-m));
  }

  .ol-control button {
    appearance: none;
    display: block;
    border: 0;
    margin: 0;
    padding: 0;
    color: inherit;
    font: inherit;
    width: var(--vaadin-map-control-size, 24px);
    height: var(--vaadin-map-control-size, 24px);
    border-radius: inherit;
  }

  .ol-control button::-moz-focus-inner {
    border: none;
    padding: 0;
  }

  .ol-compass {
    grid-area: compass;
    display: block;
    will-change: transform;
  }

  .ol-zoom {
    grid-area: zoom;
    display: flex;
    flex-direction: column;
    gap: 2px;
  }

  .ol-attribution {
    grid-area: attribution;
    margin-inline-start: auto !important;
    display: flex;
    flex-flow: row-reverse;
  }

  .ol-attribution.ol-uncollapsible {
    margin-inline-end: calc(var(--vaadin-map-controls-inset, 4px) * -1);
    margin-block-end: calc(var(--vaadin-map-controls-inset, 4px) * -1);
    border-radius: var(--vaadin-radius) 0 0 0;
  }

  .ol-attribution button span:empty::before {
    content: var(--vaadin-map-icon-attribution-collapse, '\\25B8');
  }

  .ol-attribution.ol-collapsed button span:empty::before {
    content: var(--vaadin-map-icon-attribution-expand, '\\2139');
  }

  .ol-attribution ul {
    display: flex;
    align-items: center;
    gap: 1em;
    list-style: none;
    margin: 0;
    color: var(--vaadin-map-attribution-text-color, var(--vaadin-text-color-secondary));
    padding: var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container);
    font-size: 0.8em;
  }

  .ol-attribution.ol-collapsed ul {
    display: none;
  }

  .ol-attribution.ol-uncollapsible button {
    display: none;
  }

  .ol-rotate {
    grid-area: compass;
  }

  .ol-compass:empty::before {
    mask: var(--vaadin-map-icon-compass, var(--_vaadin-icon-arrow-up)) 50% / var(--vaadin-icon-visual-size, 100%)
      no-repeat;
  }

  .ol-full-screen {
    grid-area: fullscreen;
  }

  .ol-full-screen button:empty::before {
    mask: var(--vaadin-map-icon-fullscreen, var(--_vaadin-icon-fullscreen)) 50% / var(--vaadin-icon-visual-size, 100%)
      no-repeat;
  }

  .ol-full-screen .ol-full-screen-true:empty::before {
    mask: var(--vaadin-map-icon-close, var(--_vaadin-icon-cross)) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
  }

  .ol-overviewmap {
    grid-area: overview-map;
    align-self: end;
    width: max-content;
  }

  .ol-overviewmap-map {
    height: 160px;
    width: 160px;
    margin: 4px;
    border: 0;
    border-radius: var(--vaadin-button-border-radius, var(--vaadin-radius));
  }

  .ol-overviewmap:not(.ol-uncollapsible) .ol-overviewmap-map {
    margin-bottom: 0;
  }

  .ol-overviewmap.ol-collapsed .ol-overviewmap-map,
  .ol-overviewmap.ol-uncollapsible button {
    display: none;
  }

  .ol-overviewmap-box {
    border: 1px dashed rgba(0, 0, 0, 0.5);
    filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
    will-change: filter;
    cursor: move;
  }

  .ol-zoomslider {
    grid-area: zoom-slider;
    height: 128px;
  }

  .ol-zoomslider button {
    position: relative;
    height: 8px;
    display: block;
    border-radius: inherit;
  }

  .ol-zoom-extent {
    grid-area: zoom-extent;
    align-self: end;
  }

  /* icons & controls styles */
  .ol-overviewmap button span:empty {
    display: contents;
  }

  .ol-overviewmap button span:empty::before {
    mask: var(--vaadin-map-icon-overview-map-collapse, var(--_vaadin-icon-chevron-down)) 50% /
      var(--vaadin-icon-visual-size, 100%) no-repeat;
  }

  .ol-overviewmap.ol-collapsed button {
    rotate: 180deg;
  }

  .ol-overviewmap button span:empty::before,
  .ol-zoom-in:empty::before,
  .ol-zoom-out:empty::before,
  .ol-compass:empty::before,
  .ol-full-screen button:empty::before,
  .ol-full-screen-true:empty::before {
    content: '';
    display: block;
    background: currentColor;
    width: var(--vaadin-icon-size, 1lh);
    height: var(--vaadin-icon-size, 1lh);
    flex: none;
  }

  .ol-zoom-in:empty::before {
    mask: var(--vaadin-map-icon-zoom-in, var(--_vaadin-icon-plus)) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
  }

  .ol-zoom-out:empty::before {
    mask: var(--vaadin-map-icon-zoom-out, var(--_vaadin-icon-minus)) 50% / var(--vaadin-icon-visual-size, 100%)
      no-repeat;
  }

  .ol-zoom button.ol-zoom-in {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }

  .ol-zoom button.ol-zoom-out {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }

  .ol-control button,
  .ol-attribution:not(.ol-uncollapsible) ul {
    transition: 0.15s opacity;
    background: var(--vaadin-map-control-background, var(--vaadin-background-color));
    color: var(--vaadin-map-control-text-color, var(--vaadin-text-color-secondary));
    opacity: 0.65;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .ol-control:not(.ol-uncollapsible):hover {
    box-shadow: var(--vaadin-map-control-shadow, 0 3px 8px -1px rgba(0, 0, 0, 0.2));
  }

  .ol-attribution a {
    color: inherit;
    cursor: pointer;
  }

  .ol-control:hover button,
  .ol-control button:focus,
  .ol-attribution:hover ul {
    opacity: 1;
  }

  .ol-control button:hover {
    color: var(--vaadin-map-control-text-color-hover, var(--vaadin-text-color));
  }

  .ol-control button:focus-visible {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }

  .ol-overviewmap:not(.ol-collapsed),
  .ol-overviewmap:not(.ol-collapsed):hover {
    background: var(--vaadin-map-control-background, var(--vaadin-background-color));
    box-shadow: var(--vaadin-map-control-shadow, 0 3px 8px -1px rgba(0, 0, 0, 0.2));
    transition: 0.15s box-shadow;
  }
`;
function binarySearch(haystack, needle, comparator) {
  let mid, cmp;
  comparator = comparator || ascending;
  let low2 = 0;
  let high2 = haystack.length;
  let found = false;
  while (low2 < high2) {
    mid = low2 + (high2 - low2 >> 1);
    cmp = +comparator(haystack[mid], needle);
    if (cmp < 0) {
      low2 = mid + 1;
    } else {
      high2 = mid;
      found = !cmp;
    }
  }
  return found ? low2 : ~low2;
}
function ascending(a, b) {
  return a > b ? 1 : a < b ? -1 : 0;
}
function descending(a, b) {
  return a < b ? 1 : a > b ? -1 : 0;
}
function linearFindNearest(arr, target, direction) {
  if (arr[0] <= target) {
    return 0;
  }
  const n = arr.length;
  if (target <= arr[n - 1]) {
    return n - 1;
  }
  if (typeof direction === "function") {
    for (let i = 1; i < n; ++i) {
      const candidate = arr[i];
      if (candidate === target) {
        return i;
      }
      if (candidate < target) {
        if (direction(target, arr[i - 1], candidate) > 0) {
          return i - 1;
        }
        return i;
      }
    }
    return n - 1;
  }
  if (direction > 0) {
    for (let i = 1; i < n; ++i) {
      if (arr[i] < target) {
        return i - 1;
      }
    }
    return n - 1;
  }
  if (direction < 0) {
    for (let i = 1; i < n; ++i) {
      if (arr[i] <= target) {
        return i;
      }
    }
    return n - 1;
  }
  for (let i = 1; i < n; ++i) {
    if (arr[i] == target) {
      return i;
    }
    if (arr[i] < target) {
      if (arr[i - 1] - target < target - arr[i]) {
        return i - 1;
      }
      return i;
    }
  }
  return n - 1;
}
function reverseSubArray(arr, begin, end) {
  while (begin < end) {
    const tmp = arr[begin];
    arr[begin] = arr[end];
    arr[end] = tmp;
    ++begin;
    --end;
  }
}
function extend$3(arr, data) {
  const extension = Array.isArray(data) ? data : [data];
  const length = extension.length;
  for (let i = 0; i < length; i++) {
    arr[arr.length] = extension[i];
  }
}
function equals$2(arr1, arr2) {
  const len1 = arr1.length;
  if (len1 !== arr2.length) {
    return false;
  }
  for (let i = 0; i < len1; i++) {
    if (arr1[i] !== arr2[i]) {
      return false;
    }
  }
  return true;
}
function isSorted(arr, func, strict) {
  const compare = func || ascending;
  return arr.every(function(currentVal, index) {
    if (index === 0) {
      return true;
    }
    const res = compare(arr[index - 1], currentVal);
    return !(res > 0 || res === 0);
  });
}
const CLASS_HIDDEN = "ol-hidden";
const CLASS_UNSELECTABLE = "ol-unselectable";
const CLASS_CONTROL = "ol-control";
const CLASS_COLLAPSED = "ol-collapsed";
const fontRegEx = new RegExp(
  [
    "^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)",
    "(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)",
    "(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)",
    "(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?",
    "(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))",
    "(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))",
    `?\\s*([-,\\"\\'\\sa-z0-9]+?)\\s*$`
  ].join(""),
  "i"
);
const fontRegExMatchIndex = [
  "style",
  "variant",
  "weight",
  "size",
  "lineHeight",
  "family"
];
const fontWeights = {
  normal: 400,
  bold: 700
};
const getFontParameters = function(fontSpec) {
  const match2 = fontSpec.match(fontRegEx);
  if (!match2) {
    return null;
  }
  const style = (
    /** @type {FontParameters} */
    {
      lineHeight: "normal",
      size: "1.2em",
      style: "normal",
      weight: "400",
      variant: "normal"
    }
  );
  for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {
    const value = match2[i + 1];
    if (value !== void 0) {
      style[fontRegExMatchIndex[i]] = typeof value === "string" ? value.trim() : value;
    }
  }
  if (isNaN(Number(style.weight)) && style.weight in fontWeights) {
    style.weight = fontWeights[style.weight];
  }
  style.families = style.family.split(/,\s?/).map((f) => f.trim().replace(/^['"]|['"]$/g, ""));
  return style;
};
const ua = typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined" ? navigator.userAgent.toLowerCase() : "";
const SAFARI = ua.includes("safari") && !ua.includes("chrom");
SAFARI && (ua.includes("version/15.4") || /cpu (os|iphone os) 15_4 like mac os x/.test(ua));
const WEBKIT = ua.includes("webkit") && !ua.includes("edge");
const MAC = ua.includes("macintosh");
const DEVICE_PIXEL_RATIO = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
const WORKER_OFFSCREEN_CANVAS = typeof WorkerGlobalScope !== "undefined" && typeof OffscreenCanvas !== "undefined" && self instanceof WorkerGlobalScope;
const IMAGE_DECODE = typeof Image !== "undefined" && Image.prototype.decode;
const CREATE_IMAGE_BITMAP = typeof createImageBitmap === "function";
const PASSIVE_EVENT_LISTENERS = (function() {
  let passive = false;
  try {
    const options2 = Object.defineProperty({}, "passive", {
      get: function() {
        passive = true;
      }
    });
    window.addEventListener("_", null, options2);
    window.removeEventListener("_", null, options2);
  } catch {
  }
  return passive;
})();
function createCanvasContext2D(width, height, canvasPool2, settings) {
  let canvas;
  if (canvasPool2 && canvasPool2.length) {
    canvas = /** @type {HTMLCanvasElement} */
    canvasPool2.shift();
  } else if (WORKER_OFFSCREEN_CANVAS) {
    canvas = new OffscreenCanvas(width || 300, height || 300);
  } else {
    canvas = document.createElement("canvas");
  }
  if (width) {
    canvas.width = width;
  }
  if (height) {
    canvas.height = height;
  }
  return (
    /** @type {CanvasRenderingContext2D} */
    canvas.getContext("2d", settings)
  );
}
let sharedCanvasContext;
function getSharedCanvasContext2D() {
  if (!sharedCanvasContext) {
    sharedCanvasContext = createCanvasContext2D(1, 1);
  }
  return sharedCanvasContext;
}
function releaseCanvas(context) {
  const canvas = context.canvas;
  canvas.width = 1;
  canvas.height = 1;
  context.clearRect(0, 0, 1, 1);
}
function replaceNode(newNode, oldNode) {
  const parent = oldNode.parentNode;
  if (parent) {
    parent.replaceChild(newNode, oldNode);
  }
}
function removeChildren(node) {
  while (node.lastChild) {
    node.lastChild.remove();
  }
}
function replaceChildren(node, children) {
  const oldChildren = node.childNodes;
  for (let i = 0; true; ++i) {
    const oldChild = oldChildren[i];
    const newChild = children[i];
    if (!oldChild && !newChild) {
      break;
    }
    if (oldChild === newChild) {
      continue;
    }
    if (!oldChild) {
      node.appendChild(newChild);
      continue;
    }
    if (!newChild) {
      node.removeChild(oldChild);
      --i;
      continue;
    }
    node.insertBefore(newChild, oldChild);
  }
}
const EventType = {
  /**
   * Generic change event. Triggered when the revision counter is increased.
   * @event module:ol/events/Event~BaseEvent#change
   * @api
   */
  CHANGE: "change",
  /**
   * Generic error event. Triggered when an error occurs.
   * @event module:ol/events/Event~BaseEvent#error
   * @api
   */
  ERROR: "error",
  CONTEXTMENU: "contextmenu",
  CLICK: "click",
  DBLCLICK: "dblclick",
  KEYDOWN: "keydown",
  KEYPRESS: "keypress",
  LOAD: "load",
  TOUCHMOVE: "touchmove",
  WHEEL: "wheel"
};
function TRUE() {
  return true;
}
function FALSE() {
  return false;
}
function VOID() {
}
function memoizeOne(fn) {
  let lastResult;
  let lastArgs;
  let lastThis;
  return function() {
    const nextArgs = Array.prototype.slice.call(arguments);
    if (!lastArgs || this !== lastThis || !equals$2(nextArgs, lastArgs)) {
      lastThis = this;
      lastArgs = nextArgs;
      lastResult = fn.apply(this, arguments);
    }
    return lastResult;
  };
}
function toPromise(getter) {
  function promiseGetter() {
    let value;
    try {
      value = getter();
    } catch (err) {
      return Promise.reject(err);
    }
    if (value instanceof Promise) {
      return value;
    }
    return Promise.resolve(value);
  }
  return promiseGetter();
}
const MapEventType = {
  /**
   * Triggered after a map frame is rendered.
   * @event module:ol/MapEvent~MapEvent#postrender
   * @api
   */
  POSTRENDER: "postrender",
  /**
   * Triggered when the map starts moving.
   * @event module:ol/MapEvent~MapEvent#movestart
   * @api
   */
  MOVESTART: "movestart",
  /**
   * Triggered after the map is moved.
   * @event module:ol/MapEvent~MapEvent#moveend
   * @api
   */
  MOVEEND: "moveend",
  /**
   * Triggered when loading of additional map data (tiles, images, features) starts.
   * @event module:ol/MapEvent~MapEvent#loadstart
   * @api
   */
  LOADSTART: "loadstart",
  /**
   * Triggered when loading of additional map data has completed.
   * @event module:ol/MapEvent~MapEvent#loadend
   * @api
   */
  LOADEND: "loadend"
};
const ObjectEventType = {
  /**
   * Triggered when a property is changed.
   * @event module:ol/Object.ObjectEvent#propertychange
   * @api
   */
  PROPERTYCHANGE: "propertychange"
};
class Disposable {
  constructor() {
    this.disposed = false;
  }
  /**
   * Clean up.
   */
  dispose() {
    if (!this.disposed) {
      this.disposed = true;
      this.disposeInternal();
    }
  }
  /**
   * Extension point for disposable objects.
   * @protected
   */
  disposeInternal() {
  }
}
function clear(object) {
  for (const property in object) {
    delete object[property];
  }
}
function isEmpty$1(object) {
  let property;
  for (property in object) {
    return false;
  }
  return !property;
}
class BaseEvent {
  /**
   * @param {string} type Type.
   */
  constructor(type) {
    this.propagationStopped;
    this.defaultPrevented;
    this.type = type;
    this.target = null;
  }
  /**
   * Prevent default. This means that no emulated `click`, `singleclick` or `doubleclick` events
   * will be fired.
   * @api
   */
  preventDefault() {
    this.defaultPrevented = true;
  }
  /**
   * Stop event propagation.
   * @api
   */
  stopPropagation() {
    this.propagationStopped = true;
  }
}
class Target extends Disposable {
  /**
   * @param {*} [target] Default event target for dispatched events.
   */
  constructor(target) {
    super();
    this.eventTarget_ = target;
    this.pendingRemovals_ = null;
    this.dispatching_ = null;
    this.listeners_ = null;
  }
  /**
   * @param {string} type Type.
   * @param {import("../events.js").Listener} listener Listener.
   */
  addEventListener(type, listener) {
    if (!type || !listener) {
      return;
    }
    const listeners = this.listeners_ || (this.listeners_ = {});
    const listenersForType = listeners[type] || (listeners[type] = []);
    if (!listenersForType.includes(listener)) {
      listenersForType.push(listener);
    }
  }
  /**
   * Dispatches an event and calls all listeners listening for events
   * of this type. The event parameter can either be a string or an
   * Object with a `type` property.
   *
   * @param {import("./Event.js").default|string} event Event object.
   * @return {boolean|undefined} `false` if anyone called preventDefault on the
   *     event object or if any of the listeners returned false.
   * @api
   */
  dispatchEvent(event) {
    const isString2 = typeof event === "string";
    const type = isString2 ? event : event.type;
    const listeners = this.listeners_ && this.listeners_[type];
    if (!listeners) {
      return;
    }
    const evt = isString2 ? new BaseEvent(event) : (
      /** @type {Event} */
      event
    );
    if (!evt.target) {
      evt.target = this.eventTarget_ || this;
    }
    const dispatching = this.dispatching_ || (this.dispatching_ = {});
    const pendingRemovals = this.pendingRemovals_ || (this.pendingRemovals_ = {});
    if (!(type in dispatching)) {
      dispatching[type] = 0;
      pendingRemovals[type] = 0;
    }
    ++dispatching[type];
    let propagate;
    for (let i = 0, ii = listeners.length; i < ii; ++i) {
      if ("handleEvent" in listeners[i]) {
        propagate = /** @type {import("../events.js").ListenerObject} */
        listeners[i].handleEvent(evt);
      } else {
        propagate = /** @type {import("../events.js").ListenerFunction} */
        listeners[i].call(this, evt);
      }
      if (propagate === false || evt.propagationStopped) {
        propagate = false;
        break;
      }
    }
    if (--dispatching[type] === 0) {
      let pr = pendingRemovals[type];
      delete pendingRemovals[type];
      while (pr--) {
        this.removeEventListener(type, VOID);
      }
      delete dispatching[type];
    }
    return propagate;
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    this.listeners_ && clear(this.listeners_);
  }
  /**
   * Get the listeners for a specified event type. Listeners are returned in the
   * order that they will be called in.
   *
   * @param {string} type Type.
   * @return {Array<import("../events.js").Listener>|undefined} Listeners.
   */
  getListeners(type) {
    return this.listeners_ && this.listeners_[type] || void 0;
  }
  /**
   * @param {string} [type] Type. If not provided,
   *     `true` will be returned if this event target has any listeners.
   * @return {boolean} Has listeners.
   */
  hasListener(type) {
    if (!this.listeners_) {
      return false;
    }
    return type ? type in this.listeners_ : Object.keys(this.listeners_).length > 0;
  }
  /**
   * @param {string} type Type.
   * @param {import("../events.js").Listener} listener Listener.
   */
  removeEventListener(type, listener) {
    if (!this.listeners_) {
      return;
    }
    const listeners = this.listeners_[type];
    if (!listeners) {
      return;
    }
    const index = listeners.indexOf(listener);
    if (index !== -1) {
      if (this.pendingRemovals_ && type in this.pendingRemovals_) {
        listeners[index] = VOID;
        ++this.pendingRemovals_[type];
      } else {
        listeners.splice(index, 1);
        if (listeners.length === 0) {
          delete this.listeners_[type];
        }
      }
    }
  }
}
function listen(target, type, listener, thisArg, once) {
  if (once) {
    const originalListener = listener;
    listener = function(event) {
      target.removeEventListener(type, listener);
      return originalListener.call(thisArg ?? this, event);
    };
  } else if (thisArg && thisArg !== target) {
    listener = listener.bind(thisArg);
  }
  const eventsKey = {
    target,
    type,
    listener
  };
  target.addEventListener(type, listener);
  return eventsKey;
}
function listenOnce(target, type, listener, thisArg) {
  return listen(target, type, listener, thisArg, true);
}
function unlistenByKey(key2) {
  if (key2 && key2.target) {
    key2.target.removeEventListener(key2.type, key2.listener);
    clear(key2);
  }
}
class Observable extends Target {
  constructor() {
    super();
    this.on = /** @type {ObservableOnSignature<import("./events").EventsKey>} */
    this.onInternal;
    this.once = /** @type {ObservableOnSignature<import("./events").EventsKey>} */
    this.onceInternal;
    this.un = /** @type {ObservableOnSignature<void>} */
    this.unInternal;
    this.revision_ = 0;
  }
  /**
   * Increases the revision counter and dispatches a 'change' event.
   * @api
   */
  changed() {
    ++this.revision_;
    this.dispatchEvent(EventType.CHANGE);
  }
  /**
   * Get the version number for this object.  Each time the object is modified,
   * its version number will be incremented.
   * @return {number} Revision.
   * @api
   */
  getRevision() {
    return this.revision_;
  }
  /**
   * @param {string|Array<string>} type Type.
   * @param {function((Event|import("./events/Event").default)): ?} listener Listener.
   * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key.
   * @protected
   */
  onInternal(type, listener) {
    if (Array.isArray(type)) {
      const len = type.length;
      const keys = new Array(len);
      for (let i = 0; i < len; ++i) {
        keys[i] = listen(this, type[i], listener);
      }
      return keys;
    }
    return listen(
      this,
      /** @type {string} */
      type,
      listener
    );
  }
  /**
   * @param {string|Array<string>} type Type.
   * @param {function((Event|import("./events/Event").default)): ?} listener Listener.
   * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key.
   * @protected
   */
  onceInternal(type, listener) {
    let key2;
    if (Array.isArray(type)) {
      const len = type.length;
      key2 = new Array(len);
      for (let i = 0; i < len; ++i) {
        key2[i] = listenOnce(this, type[i], listener);
      }
    } else {
      key2 = listenOnce(
        this,
        /** @type {string} */
        type,
        listener
      );
    }
    listener.ol_key = key2;
    return key2;
  }
  /**
   * Unlisten for a certain type of event.
   * @param {string|Array<string>} type Type.
   * @param {function((Event|import("./events/Event").default)): ?} listener Listener.
   * @protected
   */
  unInternal(type, listener) {
    const key2 = (
      /** @type {Object} */
      listener.ol_key
    );
    if (key2) {
      unByKey(key2);
    } else if (Array.isArray(type)) {
      for (let i = 0, ii = type.length; i < ii; ++i) {
        this.removeEventListener(type[i], listener);
      }
    } else {
      this.removeEventListener(type, listener);
    }
  }
}
Observable.prototype.on;
Observable.prototype.once;
Observable.prototype.un;
function unByKey(key2) {
  if (Array.isArray(key2)) {
    for (let i = 0, ii = key2.length; i < ii; ++i) {
      unlistenByKey(key2[i]);
    }
  } else {
    unlistenByKey(
      /** @type {import("./events.js").EventsKey} */
      key2
    );
  }
}
function abstract() {
  throw new Error("Unimplemented abstract method.");
}
let uidCounter_ = 0;
function getUid(obj) {
  return obj.ol_uid || (obj.ol_uid = String(++uidCounter_));
}
class ObjectEvent extends BaseEvent {
  /**
   * @param {string} type The event type.
   * @param {string} key The property name.
   * @param {*} oldValue The old value for `key`.
   */
  constructor(type, key2, oldValue) {
    super(type);
    this.key = key2;
    this.oldValue = oldValue;
  }
}
class BaseObject extends Observable {
  /**
   * @param {Object<string, *>} [values] An object with key-value pairs.
   */
  constructor(values) {
    super();
    this.on;
    this.once;
    this.un;
    getUid(this);
    this.values_ = null;
    if (values !== void 0) {
      this.setProperties(values);
    }
  }
  /**
   * Gets a value.
   * @param {string} key Key name.
   * @return {*} Value.
   * @api
   */
  get(key2) {
    let value;
    if (this.values_ && this.values_.hasOwnProperty(key2)) {
      value = this.values_[key2];
    }
    return value;
  }
  /**
   * Get a list of object property names.
   * @return {Array<string>} List of property names.
   * @api
   */
  getKeys() {
    return this.values_ && Object.keys(this.values_) || [];
  }
  /**
   * Get an object of all property names and values.
   * @return {Object<string, *>} Object.
   * @api
   */
  getProperties() {
    return this.values_ && Object.assign({}, this.values_) || {};
  }
  /**
   * Get an object of all property names and values.
   * @return {Object<string, *>?} Object.
   */
  getPropertiesInternal() {
    return this.values_;
  }
  /**
   * @return {boolean} The object has properties.
   */
  hasProperties() {
    return !!this.values_;
  }
  /**
   * @param {string} key Key name.
   * @param {*} oldValue Old value.
   */
  notify(key2, oldValue) {
    let eventType;
    eventType = `change:${key2}`;
    if (this.hasListener(eventType)) {
      this.dispatchEvent(new ObjectEvent(eventType, key2, oldValue));
    }
    eventType = ObjectEventType.PROPERTYCHANGE;
    if (this.hasListener(eventType)) {
      this.dispatchEvent(new ObjectEvent(eventType, key2, oldValue));
    }
  }
  /**
   * @param {string} key Key name.
   * @param {import("./events.js").Listener} listener Listener.
   */
  addChangeListener(key2, listener) {
    this.addEventListener(`change:${key2}`, listener);
  }
  /**
   * @param {string} key Key name.
   * @param {import("./events.js").Listener} listener Listener.
   */
  removeChangeListener(key2, listener) {
    this.removeEventListener(`change:${key2}`, listener);
  }
  /**
   * Sets a value.
   * @param {string} key Key name.
   * @param {*} value Value.
   * @param {boolean} [silent] Update without triggering an event.
   * @api
   */
  set(key2, value, silent) {
    const values = this.values_ || (this.values_ = {});
    if (silent) {
      values[key2] = value;
    } else {
      const oldValue = values[key2];
      values[key2] = value;
      if (oldValue !== value) {
        this.notify(key2, oldValue);
      }
    }
  }
  /**
   * Sets a collection of key-value pairs.  Note that this changes any existing
   * properties and adds new ones (it does not remove any existing properties).
   * @param {Object<string, *>} values Values.
   * @param {boolean} [silent] Update without triggering an event.
   * @api
   */
  setProperties(values, silent) {
    for (const key2 in values) {
      this.set(key2, values[key2], silent);
    }
  }
  /**
   * Apply any properties from another object without triggering events.
   * @param {BaseObject} source The source object.
   * @protected
   */
  applyProperties(source) {
    if (!source.values_) {
      return;
    }
    Object.assign(this.values_ || (this.values_ = {}), source.values_);
  }
  /**
   * Unsets a property.
   * @param {string} key Key name.
   * @param {boolean} [silent] Unset without triggering an event.
   * @api
   */
  unset(key2, silent) {
    if (this.values_ && key2 in this.values_) {
      const oldValue = this.values_[key2];
      delete this.values_[key2];
      if (isEmpty$1(this.values_)) {
        this.values_ = null;
      }
      if (!silent) {
        this.notify(key2, oldValue);
      }
    }
  }
}
class Control extends BaseObject {
  /**
   * @param {Options} options Control options.
   */
  constructor(options2) {
    super();
    const element = options2.element;
    if (element && !options2.target && !element.style.pointerEvents) {
      element.style.pointerEvents = "auto";
    }
    this.element = element ? element : null;
    this.target_ = null;
    this.map_ = null;
    this.listenerKeys = [];
    if (options2.render) {
      this.render = options2.render;
    }
    if (options2.target) {
      this.setTarget(options2.target);
    }
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    this.element?.remove();
    super.disposeInternal();
  }
  /**
   * Get the map associated with this control.
   * @return {import("../Map.js").default|null} Map.
   * @api
   */
  getMap() {
    return this.map_;
  }
  /**
   * Remove the control from its current map and attach it to the new map.
   * Pass `null` to just remove the control from the current map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default|null} map Map.
   * @api
   */
  setMap(map) {
    if (this.map_) {
      this.element?.remove();
    }
    for (let i = 0, ii = this.listenerKeys.length; i < ii; ++i) {
      unlistenByKey(this.listenerKeys[i]);
    }
    this.listenerKeys.length = 0;
    this.map_ = map;
    if (map) {
      const target = this.target_ ?? map.getOverlayContainerStopEvent();
      if (this.element) {
        target.appendChild(this.element);
      }
      if (this.render !== VOID) {
        this.listenerKeys.push(
          listen(map, MapEventType.POSTRENDER, this.render, this)
        );
      }
      map.render();
    }
  }
  /**
   * Renders the control.
   * @param {import("../MapEvent.js").default} mapEvent Map event.
   * @api
   */
  render(mapEvent) {
  }
  /**
   * This function is used to set a target element for the control. It has no
   * effect if it is called after the control has been added to the map (i.e.
   * after `setMap` is called on the control). If no `target` is set in the
   * options passed to the control constructor and if `setTarget` is not called
   * then the control is added to the map's overlay container.
   * @param {HTMLElement|string} target Target.
   * @api
   */
  setTarget(target) {
    this.target_ = typeof target === "string" ? document.getElementById(target) : target;
  }
}
class Attribution extends Control {
  /**
   * @param {Options} [options] Attribution options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super({
      element: document.createElement("div"),
      render: options2.render,
      target: options2.target
    });
    this.ulElement_ = document.createElement("ul");
    this.collapsed_ = options2.collapsed !== void 0 ? options2.collapsed : true;
    this.userCollapsed_ = this.collapsed_;
    this.overrideCollapsible_ = options2.collapsible !== void 0;
    this.collapsible_ = options2.collapsible !== void 0 ? options2.collapsible : true;
    if (!this.collapsible_) {
      this.collapsed_ = false;
    }
    this.attributions_ = options2.attributions;
    const className = options2.className !== void 0 ? options2.className : "ol-attribution";
    const tipLabel = options2.tipLabel !== void 0 ? options2.tipLabel : "Attributions";
    const expandClassName = options2.expandClassName !== void 0 ? options2.expandClassName : className + "-expand";
    const collapseLabel = options2.collapseLabel !== void 0 ? options2.collapseLabel : "›";
    const collapseClassName = options2.collapseClassName !== void 0 ? options2.collapseClassName : className + "-collapse";
    if (typeof collapseLabel === "string") {
      this.collapseLabel_ = document.createElement("span");
      this.collapseLabel_.textContent = collapseLabel;
      this.collapseLabel_.className = collapseClassName;
    } else {
      this.collapseLabel_ = collapseLabel;
    }
    const label = options2.label !== void 0 ? options2.label : "i";
    if (typeof label === "string") {
      this.label_ = document.createElement("span");
      this.label_.textContent = label;
      this.label_.className = expandClassName;
    } else {
      this.label_ = label;
    }
    const activeLabel = this.collapsible_ && !this.collapsed_ ? this.collapseLabel_ : this.label_;
    this.toggleButton_ = document.createElement("button");
    this.toggleButton_.setAttribute("type", "button");
    this.toggleButton_.setAttribute("aria-expanded", String(!this.collapsed_));
    this.toggleButton_.title = tipLabel;
    this.toggleButton_.appendChild(activeLabel);
    this.toggleButton_.addEventListener(
      EventType.CLICK,
      this.handleClick_.bind(this),
      false
    );
    const cssClasses = className + " " + CLASS_UNSELECTABLE + " " + CLASS_CONTROL + (this.collapsed_ && this.collapsible_ ? " " + CLASS_COLLAPSED : "") + (this.collapsible_ ? "" : " ol-uncollapsible");
    const element = this.element;
    element.className = cssClasses;
    element.appendChild(this.toggleButton_);
    element.appendChild(this.ulElement_);
    this.renderedAttributions_ = [];
    this.renderedVisible_ = true;
  }
  /**
   * Collect a list of visible attributions and set the collapsible state.
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @return {Array<string>} Attributions.
   * @private
   */
  collectSourceAttributions_(frameState) {
    const layers = this.getMap().getAllLayers();
    const visibleAttributions = new Set(
      layers.flatMap((layer) => layer.getAttributions(frameState))
    );
    if (this.attributions_ !== void 0) {
      Array.isArray(this.attributions_) ? this.attributions_.forEach((item) => visibleAttributions.add(item)) : visibleAttributions.add(this.attributions_);
    }
    if (!this.overrideCollapsible_) {
      const collapsible = !layers.some(
        (layer) => layer.getSource()?.getAttributionsCollapsible() === false
      );
      this.setCollapsible(collapsible);
    }
    return Array.from(visibleAttributions);
  }
  /**
   * @private
   * @param {?import("../Map.js").FrameState} frameState Frame state.
   */
  async updateElement_(frameState) {
    if (!frameState) {
      if (this.renderedVisible_) {
        this.element.style.display = "none";
        this.renderedVisible_ = false;
      }
      return;
    }
    const attributions = await Promise.all(
      this.collectSourceAttributions_(frameState).map(
        (attribution) => toPromise(() => attribution)
      )
    );
    const visible = attributions.length > 0;
    if (this.renderedVisible_ != visible) {
      this.element.style.display = visible ? "" : "none";
      this.renderedVisible_ = visible;
    }
    if (equals$2(attributions, this.renderedAttributions_)) {
      return;
    }
    removeChildren(this.ulElement_);
    for (let i = 0, ii = attributions.length; i < ii; ++i) {
      const element = document.createElement("li");
      element.innerHTML = attributions[i];
      this.ulElement_.appendChild(element);
    }
    this.renderedAttributions_ = attributions;
  }
  /**
   * @param {MouseEvent} event The event to handle
   * @private
   */
  handleClick_(event) {
    event.preventDefault();
    this.handleToggle_();
    this.userCollapsed_ = this.collapsed_;
  }
  /**
   * @private
   */
  handleToggle_() {
    this.element.classList.toggle(CLASS_COLLAPSED);
    if (this.collapsed_) {
      replaceNode(this.collapseLabel_, this.label_);
    } else {
      replaceNode(this.label_, this.collapseLabel_);
    }
    this.collapsed_ = !this.collapsed_;
    this.toggleButton_.setAttribute("aria-expanded", String(!this.collapsed_));
  }
  /**
   * Return `true` if the attribution is collapsible, `false` otherwise.
   * @return {boolean} True if the widget is collapsible.
   * @api
   */
  getCollapsible() {
    return this.collapsible_;
  }
  /**
   * Set whether the attribution should be collapsible.
   * @param {boolean} collapsible True if the widget is collapsible.
   * @api
   */
  setCollapsible(collapsible) {
    if (this.collapsible_ === collapsible) {
      return;
    }
    this.collapsible_ = collapsible;
    this.element.classList.toggle("ol-uncollapsible");
    if (this.userCollapsed_) {
      this.handleToggle_();
    }
  }
  /**
   * Collapse or expand the attribution according to the passed parameter. Will
   * not do anything if the attribution isn't collapsible or if the current
   * collapsed state is already the one requested.
   * @param {boolean} collapsed True if the widget is collapsed.
   * @api
   */
  setCollapsed(collapsed) {
    this.userCollapsed_ = collapsed;
    if (!this.collapsible_ || this.collapsed_ === collapsed) {
      return;
    }
    this.handleToggle_();
  }
  /**
   * Return `true` when the attribution is currently collapsed or `false`
   * otherwise.
   * @return {boolean} True if the widget is collapsed.
   * @api
   */
  getCollapsed() {
    return this.collapsed_;
  }
  /**
   * Update the attribution element.
   * @param {import("../MapEvent.js").default} mapEvent Map event.
   * @override
   */
  render(mapEvent) {
    this.updateElement_(mapEvent.frameState);
  }
}
const MapProperty = {
  LAYERGROUP: "layergroup",
  SIZE: "size",
  TARGET: "target",
  VIEW: "view"
};
const Relationship = {
  UNKNOWN: 0,
  INTERSECTING: 1,
  ABOVE: 2,
  RIGHT: 4,
  BELOW: 8,
  LEFT: 16
};
function boundingExtent(coordinates2) {
  const extent = createEmpty();
  for (let i = 0, ii = coordinates2.length; i < ii; ++i) {
    extendCoordinate(extent, coordinates2[i]);
  }
  return extent;
}
function _boundingExtentXYs(xs, ys, dest) {
  const minX = Math.min.apply(null, xs);
  const minY = Math.min.apply(null, ys);
  const maxX = Math.max.apply(null, xs);
  const maxY = Math.max.apply(null, ys);
  return createOrUpdate$2(minX, minY, maxX, maxY, dest);
}
function buffer(extent, value, dest) {
  if (dest) {
    dest[0] = extent[0] - value;
    dest[1] = extent[1] - value;
    dest[2] = extent[2] + value;
    dest[3] = extent[3] + value;
    return dest;
  }
  return [
    extent[0] - value,
    extent[1] - value,
    extent[2] + value,
    extent[3] + value
  ];
}
function clone(extent, dest) {
  if (dest) {
    dest[0] = extent[0];
    dest[1] = extent[1];
    dest[2] = extent[2];
    dest[3] = extent[3];
    return dest;
  }
  return extent.slice();
}
function closestSquaredDistanceXY(extent, x, y) {
  let dx, dy;
  if (x < extent[0]) {
    dx = extent[0] - x;
  } else if (extent[2] < x) {
    dx = x - extent[2];
  } else {
    dx = 0;
  }
  if (y < extent[1]) {
    dy = extent[1] - y;
  } else if (extent[3] < y) {
    dy = y - extent[3];
  } else {
    dy = 0;
  }
  return dx * dx + dy * dy;
}
function containsCoordinate(extent, coordinate) {
  return containsXY(extent, coordinate[0], coordinate[1]);
}
function containsExtent(extent1, extent2) {
  return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] && extent1[1] <= extent2[1] && extent2[3] <= extent1[3];
}
function containsXY(extent, x, y) {
  return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];
}
function coordinateRelationship(extent, coordinate) {
  const minX = extent[0];
  const minY = extent[1];
  const maxX = extent[2];
  const maxY = extent[3];
  const x = coordinate[0];
  const y = coordinate[1];
  let relationship = Relationship.UNKNOWN;
  if (x < minX) {
    relationship = relationship | Relationship.LEFT;
  } else if (x > maxX) {
    relationship = relationship | Relationship.RIGHT;
  }
  if (y < minY) {
    relationship = relationship | Relationship.BELOW;
  } else if (y > maxY) {
    relationship = relationship | Relationship.ABOVE;
  }
  if (relationship === Relationship.UNKNOWN) {
    relationship = Relationship.INTERSECTING;
  }
  return relationship;
}
function createEmpty() {
  return [Infinity, Infinity, -Infinity, -Infinity];
}
function createOrUpdate$2(minX, minY, maxX, maxY, dest) {
  if (dest) {
    dest[0] = minX;
    dest[1] = minY;
    dest[2] = maxX;
    dest[3] = maxY;
    return dest;
  }
  return [minX, minY, maxX, maxY];
}
function createOrUpdateEmpty(dest) {
  return createOrUpdate$2(Infinity, Infinity, -Infinity, -Infinity, dest);
}
function createOrUpdateFromCoordinate(coordinate, dest) {
  const x = coordinate[0];
  const y = coordinate[1];
  return createOrUpdate$2(x, y, x, y, dest);
}
function createOrUpdateFromFlatCoordinates(flatCoordinates, offset2, end, stride, dest) {
  const extent = createOrUpdateEmpty(dest);
  return extendFlatCoordinates(extent, flatCoordinates, offset2, end, stride);
}
function equals$1(extent1, extent2) {
  return extent1[0] == extent2[0] && extent1[2] == extent2[2] && extent1[1] == extent2[1] && extent1[3] == extent2[3];
}
function extend$2(extent1, extent2) {
  if (extent2[0] < extent1[0]) {
    extent1[0] = extent2[0];
  }
  if (extent2[2] > extent1[2]) {
    extent1[2] = extent2[2];
  }
  if (extent2[1] < extent1[1]) {
    extent1[1] = extent2[1];
  }
  if (extent2[3] > extent1[3]) {
    extent1[3] = extent2[3];
  }
  return extent1;
}
function extendCoordinate(extent, coordinate) {
  if (coordinate[0] < extent[0]) {
    extent[0] = coordinate[0];
  }
  if (coordinate[0] > extent[2]) {
    extent[2] = coordinate[0];
  }
  if (coordinate[1] < extent[1]) {
    extent[1] = coordinate[1];
  }
  if (coordinate[1] > extent[3]) {
    extent[3] = coordinate[1];
  }
}
function extendFlatCoordinates(extent, flatCoordinates, offset2, end, stride) {
  for (; offset2 < end; offset2 += stride) {
    extendXY(extent, flatCoordinates[offset2], flatCoordinates[offset2 + 1]);
  }
  return extent;
}
function extendXY(extent, x, y) {
  extent[0] = Math.min(extent[0], x);
  extent[1] = Math.min(extent[1], y);
  extent[2] = Math.max(extent[2], x);
  extent[3] = Math.max(extent[3], y);
}
function forEachCorner(extent, callback) {
  let val;
  val = callback(getBottomLeft(extent));
  if (val) {
    return val;
  }
  val = callback(getBottomRight(extent));
  if (val) {
    return val;
  }
  val = callback(getTopRight(extent));
  if (val) {
    return val;
  }
  val = callback(getTopLeft(extent));
  if (val) {
    return val;
  }
  return false;
}
function getArea(extent) {
  let area = 0;
  if (!isEmpty(extent)) {
    area = getWidth(extent) * getHeight(extent);
  }
  return area;
}
function getBottomLeft(extent) {
  return [extent[0], extent[1]];
}
function getBottomRight(extent) {
  return [extent[2], extent[1]];
}
function getCenter(extent) {
  return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];
}
function getCorner(extent, corner) {
  let coordinate;
  if (corner === "bottom-left") {
    coordinate = getBottomLeft(extent);
  } else if (corner === "bottom-right") {
    coordinate = getBottomRight(extent);
  } else if (corner === "top-left") {
    coordinate = getTopLeft(extent);
  } else if (corner === "top-right") {
    coordinate = getTopRight(extent);
  } else {
    throw new Error("Invalid corner");
  }
  return coordinate;
}
function getForViewAndSize(center, resolution, rotation, size, dest) {
  const [x0, y0, x1, y1, x2, y2, x3, y3] = getRotatedViewport(
    center,
    resolution,
    rotation,
    size
  );
  return createOrUpdate$2(
    Math.min(x0, x1, x2, x3),
    Math.min(y0, y1, y2, y3),
    Math.max(x0, x1, x2, x3),
    Math.max(y0, y1, y2, y3),
    dest
  );
}
function getRotatedViewport(center, resolution, rotation, size) {
  const dx = resolution * size[0] / 2;
  const dy = resolution * size[1] / 2;
  const cosRotation = Math.cos(rotation);
  const sinRotation = Math.sin(rotation);
  const xCos = dx * cosRotation;
  const xSin = dx * sinRotation;
  const yCos = dy * cosRotation;
  const ySin = dy * sinRotation;
  const x = center[0];
  const y = center[1];
  return [
    x - xCos + ySin,
    y - xSin - yCos,
    x - xCos - ySin,
    y - xSin + yCos,
    x + xCos - ySin,
    y + xSin + yCos,
    x + xCos + ySin,
    y + xSin - yCos,
    x - xCos + ySin,
    y - xSin - yCos
  ];
}
function getHeight(extent) {
  return extent[3] - extent[1];
}
function getIntersection(extent1, extent2, dest) {
  const intersection = dest ? dest : createEmpty();
  if (intersects$1(extent1, extent2)) {
    if (extent1[0] > extent2[0]) {
      intersection[0] = extent1[0];
    } else {
      intersection[0] = extent2[0];
    }
    if (extent1[1] > extent2[1]) {
      intersection[1] = extent1[1];
    } else {
      intersection[1] = extent2[1];
    }
    if (extent1[2] < extent2[2]) {
      intersection[2] = extent1[2];
    } else {
      intersection[2] = extent2[2];
    }
    if (extent1[3] < extent2[3]) {
      intersection[3] = extent1[3];
    } else {
      intersection[3] = extent2[3];
    }
  } else {
    createOrUpdateEmpty(intersection);
  }
  return intersection;
}
function getTopLeft(extent) {
  return [extent[0], extent[3]];
}
function getTopRight(extent) {
  return [extent[2], extent[3]];
}
function getWidth(extent) {
  return extent[2] - extent[0];
}
function intersects$1(extent1, extent2) {
  return extent1[0] <= extent2[2] && extent1[2] >= extent2[0] && extent1[1] <= extent2[3] && extent1[3] >= extent2[1];
}
function isEmpty(extent) {
  return extent[2] < extent[0] || extent[3] < extent[1];
}
function returnOrUpdate(extent, dest) {
  if (dest) {
    dest[0] = extent[0];
    dest[1] = extent[1];
    dest[2] = extent[2];
    dest[3] = extent[3];
    return dest;
  }
  return extent;
}
function intersectsSegment(extent, start2, end) {
  let intersects2 = false;
  const startRel = coordinateRelationship(extent, start2);
  const endRel = coordinateRelationship(extent, end);
  if (startRel === Relationship.INTERSECTING || endRel === Relationship.INTERSECTING) {
    intersects2 = true;
  } else {
    const minX = extent[0];
    const minY = extent[1];
    const maxX = extent[2];
    const maxY = extent[3];
    const startX = start2[0];
    const startY = start2[1];
    const endX = end[0];
    const endY = end[1];
    const slope = (endY - startY) / (endX - startX);
    let x, y;
    if (!!(endRel & Relationship.ABOVE) && !(startRel & Relationship.ABOVE)) {
      x = endX - (endY - maxY) / slope;
      intersects2 = x >= minX && x <= maxX;
    }
    if (!intersects2 && !!(endRel & Relationship.RIGHT) && !(startRel & Relationship.RIGHT)) {
      y = endY - (endX - maxX) * slope;
      intersects2 = y >= minY && y <= maxY;
    }
    if (!intersects2 && !!(endRel & Relationship.BELOW) && !(startRel & Relationship.BELOW)) {
      x = endX - (endY - minY) / slope;
      intersects2 = x >= minX && x <= maxX;
    }
    if (!intersects2 && !!(endRel & Relationship.LEFT) && !(startRel & Relationship.LEFT)) {
      y = endY - (endX - minX) * slope;
      intersects2 = y >= minY && y <= maxY;
    }
  }
  return intersects2;
}
function applyTransform(extent, transformFn, dest, stops) {
  if (isEmpty(extent)) {
    return createOrUpdateEmpty(dest);
  }
  let coordinates2 = [];
  {
    coordinates2 = [
      extent[0],
      extent[1],
      extent[2],
      extent[1],
      extent[2],
      extent[3],
      extent[0],
      extent[3]
    ];
  }
  transformFn(coordinates2, coordinates2, 2);
  const xs = [];
  const ys = [];
  for (let i = 0, l = coordinates2.length; i < l; i += 2) {
    xs.push(coordinates2[i]);
    ys.push(coordinates2[i + 1]);
  }
  return _boundingExtentXYs(xs, ys, dest);
}
function wrapX$2(extent, projection) {
  const projectionExtent = projection.getExtent();
  const center = getCenter(extent);
  if (projection.canWrapX() && (center[0] < projectionExtent[0] || center[0] >= projectionExtent[2])) {
    const worldWidth = getWidth(projectionExtent);
    const worldsAway = Math.floor(
      (center[0] - projectionExtent[0]) / worldWidth
    );
    const offset2 = worldsAway * worldWidth;
    extent[0] -= offset2;
    extent[2] -= offset2;
  }
  return extent;
}
function wrapAndSliceX(extent, projection, multiWorld) {
  if (projection.canWrapX()) {
    const projectionExtent = projection.getExtent();
    if (!isFinite(extent[0]) || !isFinite(extent[2])) {
      return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]];
    }
    wrapX$2(extent, projection);
    const worldWidth = getWidth(projectionExtent);
    if (getWidth(extent) > worldWidth && !multiWorld) {
      return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]];
    }
    if (extent[0] < projectionExtent[0]) {
      return [
        [extent[0] + worldWidth, extent[1], projectionExtent[2], extent[3]],
        [projectionExtent[0], extent[1], extent[2], extent[3]]
      ];
    }
    if (extent[2] > projectionExtent[2]) {
      return [
        [extent[0], extent[1], projectionExtent[2], extent[3]],
        [projectionExtent[0], extent[1], extent[2] - worldWidth, extent[3]]
      ];
    }
  }
  return [extent];
}
function clamp(value, min2, max2) {
  return Math.min(Math.max(value, min2), max2);
}
function squaredSegmentDistance(x, y, x1, y1, x2, y2) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  if (dx !== 0 || dy !== 0) {
    const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
    if (t > 1) {
      x1 = x2;
      y1 = y2;
    } else if (t > 0) {
      x1 += dx * t;
      y1 += dy * t;
    }
  }
  return squaredDistance(x, y, x1, y1);
}
function squaredDistance(x1, y1, x2, y2) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  return dx * dx + dy * dy;
}
function solveLinearSystem(mat) {
  const n = mat.length;
  for (let i = 0; i < n; i++) {
    let maxRow = i;
    let maxEl = Math.abs(mat[i][i]);
    for (let r = i + 1; r < n; r++) {
      const absValue = Math.abs(mat[r][i]);
      if (absValue > maxEl) {
        maxEl = absValue;
        maxRow = r;
      }
    }
    if (maxEl === 0) {
      return null;
    }
    const tmp = mat[maxRow];
    mat[maxRow] = mat[i];
    mat[i] = tmp;
    for (let j = i + 1; j < n; j++) {
      const coef = -mat[j][i] / mat[i][i];
      for (let k = i; k < n + 1; k++) {
        if (i == k) {
          mat[j][k] = 0;
        } else {
          mat[j][k] += coef * mat[i][k];
        }
      }
    }
  }
  const x = new Array(n);
  for (let l = n - 1; l >= 0; l--) {
    x[l] = mat[l][n] / mat[l][l];
    for (let m = l - 1; m >= 0; m--) {
      mat[m][n] -= mat[m][l] * x[l];
    }
  }
  return x;
}
function toDegrees(angleInRadians) {
  return angleInRadians * 180 / Math.PI;
}
function toRadians(angleInDegrees) {
  return angleInDegrees * Math.PI / 180;
}
function modulo(a, b) {
  const r = a % b;
  return r * b < 0 ? r + b : r;
}
function lerp(a, b, x) {
  return a + x * (b - a);
}
function toFixed(n, decimals) {
  const factor = Math.pow(10, decimals);
  return Math.round(n * factor) / factor;
}
function round(n, decimals) {
  return Math.round(toFixed(n, decimals));
}
function floor(n, decimals) {
  return Math.floor(toFixed(n, decimals));
}
function ceil(n, decimals) {
  return Math.ceil(toFixed(n, decimals));
}
function wrap(n, min2, max2) {
  if (n >= min2 && n < max2) {
    return n;
  }
  const range2 = max2 - min2;
  return ((n - min2) % range2 + range2) % range2 + min2;
}
function compareVersions(v1, v2) {
  const s1 = ("" + v1).split(".");
  const s2 = ("" + v2).split(".");
  for (let i = 0; i < Math.max(s1.length, s2.length); i++) {
    const n1 = parseInt(s1[i] || "0", 10);
    const n2 = parseInt(s2[i] || "0", 10);
    if (n1 > n2) {
      return 1;
    }
    if (n2 > n1) {
      return -1;
    }
  }
  return 0;
}
function add$3(coordinate, delta) {
  coordinate[0] += +delta[0];
  coordinate[1] += +delta[1];
  return coordinate;
}
function equals(coordinate1, coordinate2) {
  let equals2 = true;
  for (let i = coordinate1.length - 1; i >= 0; --i) {
    if (coordinate1[i] != coordinate2[i]) {
      equals2 = false;
      break;
    }
  }
  return equals2;
}
function rotate$1(coordinate, angle) {
  const cosAngle = Math.cos(angle);
  const sinAngle = Math.sin(angle);
  const x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
  const y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
  coordinate[0] = x;
  coordinate[1] = y;
  return coordinate;
}
function scale$2(coordinate, scale2) {
  coordinate[0] *= scale2;
  coordinate[1] *= scale2;
  return coordinate;
}
function wrapX$1(coordinate, projection) {
  if (projection.canWrapX()) {
    const worldWidth = getWidth(projection.getExtent());
    const worldsAway = getWorldsAway(coordinate, projection, worldWidth);
    if (worldsAway) {
      coordinate[0] -= worldsAway * worldWidth;
    }
  }
  return coordinate;
}
function getWorldsAway(coordinate, projection, sourceExtentWidth) {
  const projectionExtent = projection.getExtent();
  let worldsAway = 0;
  if (projection.canWrapX() && (coordinate[0] < projectionExtent[0] || coordinate[0] > projectionExtent[2])) {
    sourceExtentWidth = sourceExtentWidth || getWidth(projectionExtent);
    worldsAway = Math.floor(
      (coordinate[0] - projectionExtent[0]) / sourceExtentWidth
    );
  }
  return worldsAway;
}
const PointerEventType = {
  POINTERMOVE: "pointermove",
  POINTERDOWN: "pointerdown"
};
function warn(...args) {
  console.warn(...args);
}
const METERS_PER_UNIT$1 = {
  // use the radius of the Normal sphere
  "radians": 6370997 / (2 * Math.PI),
  "degrees": 2 * Math.PI * 6370997 / 360,
  "ft": 0.3048,
  "m": 1,
  "us-ft": 1200 / 3937
};
let Projection$1 = class Projection2 {
  /**
   * @param {Options} options Projection options.
   */
  constructor(options2) {
    this.code_ = options2.code;
    this.units_ = /** @type {import("./Units.js").Units} */
    options2.units;
    this.extent_ = options2.extent !== void 0 ? options2.extent : null;
    this.worldExtent_ = options2.worldExtent !== void 0 ? options2.worldExtent : null;
    this.axisOrientation_ = options2.axisOrientation !== void 0 ? options2.axisOrientation : "enu";
    this.global_ = options2.global !== void 0 ? options2.global : false;
    this.canWrapX_ = !!(this.global_ && this.extent_);
    this.getPointResolutionFunc_ = options2.getPointResolution;
    this.defaultTileGrid_ = null;
    this.metersPerUnit_ = options2.metersPerUnit;
  }
  /**
   * @return {boolean} The projection is suitable for wrapping the x-axis
   */
  canWrapX() {
    return this.canWrapX_;
  }
  /**
   * Get the code for this projection, e.g. 'EPSG:4326'.
   * @return {string} Code.
   * @api
   */
  getCode() {
    return this.code_;
  }
  /**
   * Get the validity extent for this projection.
   * @return {import("../extent.js").Extent} Extent.
   * @api
   */
  getExtent() {
    return this.extent_;
  }
  /**
   * Get the units of this projection.
   * @return {import("./Units.js").Units} Units.
   * @api
   */
  getUnits() {
    return this.units_;
  }
  /**
   * Get the amount of meters per unit of this projection.  If the projection is
   * not configured with `metersPerUnit` or a units identifier, the return is
   * `undefined`.
   * @return {number|undefined} Meters.
   * @api
   */
  getMetersPerUnit() {
    return this.metersPerUnit_ || METERS_PER_UNIT$1[this.units_];
  }
  /**
   * Get the world extent for this projection.
   * @return {import("../extent.js").Extent} Extent.
   * @api
   */
  getWorldExtent() {
    return this.worldExtent_;
  }
  /**
   * Get the axis orientation of this projection.
   * Example values are:
   * enu - the default easting, northing, elevation.
   * neu - northing, easting, up - useful for "lat/long" geographic coordinates,
   *     or south orientated transverse mercator.
   * wnu - westing, northing, up - some planetary coordinate systems have
   *     "west positive" coordinate systems
   * @return {string} Axis orientation.
   * @api
   */
  getAxisOrientation() {
    return this.axisOrientation_;
  }
  /**
   * Is this projection a global projection which spans the whole world?
   * @return {boolean} Whether the projection is global.
   * @api
   */
  isGlobal() {
    return this.global_;
  }
  /**
   * Set if the projection is a global projection which spans the whole world
   * @param {boolean} global Whether the projection is global.
   * @api
   */
  setGlobal(global) {
    this.global_ = global;
    this.canWrapX_ = !!(global && this.extent_);
  }
  /**
   * @return {import("../tilegrid/TileGrid.js").default} The default tile grid.
   */
  getDefaultTileGrid() {
    return this.defaultTileGrid_;
  }
  /**
   * @param {import("../tilegrid/TileGrid.js").default} tileGrid The default tile grid.
   */
  setDefaultTileGrid(tileGrid) {
    this.defaultTileGrid_ = tileGrid;
  }
  /**
   * Set the validity extent for this projection.
   * @param {import("../extent.js").Extent} extent Extent.
   * @api
   */
  setExtent(extent) {
    this.extent_ = extent;
    this.canWrapX_ = !!(this.global_ && extent);
  }
  /**
   * Set the world extent for this projection.
   * @param {import("../extent.js").Extent} worldExtent World extent
   *     [minlon, minlat, maxlon, maxlat].
   * @api
   */
  setWorldExtent(worldExtent) {
    this.worldExtent_ = worldExtent;
  }
  /**
   * Set the getPointResolution function (see {@link module:ol/proj.getPointResolution}
   * for this projection.
   * @param {function(number, import("../coordinate.js").Coordinate):number} func Function
   * @api
   */
  setGetPointResolution(func) {
    this.getPointResolutionFunc_ = func;
  }
  /**
   * Get the custom point resolution function for this projection (if set).
   * @return {GetPointResolution|undefined} The custom point
   * resolution function (if set).
   */
  getPointResolutionFunc() {
    return this.getPointResolutionFunc_;
  }
};
const RADIUS$1 = 6378137;
const HALF_SIZE = Math.PI * RADIUS$1;
const EXTENT$1 = [-HALF_SIZE, -HALF_SIZE, HALF_SIZE, HALF_SIZE];
const WORLD_EXTENT = [-180, -85, 180, 85];
const MAX_SAFE_Y = RADIUS$1 * Math.log(Math.tan(Math.PI / 2));
class EPSG3857Projection extends Projection$1 {
  /**
   * @param {string} code Code.
   */
  constructor(code) {
    super({
      code,
      units: "m",
      extent: EXTENT$1,
      global: true,
      worldExtent: WORLD_EXTENT,
      getPointResolution: function(resolution, point) {
        return resolution / Math.cosh(point[1] / RADIUS$1);
      }
    });
  }
}
const PROJECTIONS$1 = [
  new EPSG3857Projection("EPSG:3857"),
  new EPSG3857Projection("EPSG:102100"),
  new EPSG3857Projection("EPSG:102113"),
  new EPSG3857Projection("EPSG:900913"),
  new EPSG3857Projection("http://www.opengis.net/def/crs/EPSG/0/3857"),
  new EPSG3857Projection("http://www.opengis.net/gml/srs/epsg.xml#3857")
];
function fromEPSG4326(input, output, dimension, stride) {
  const length = input.length;
  dimension = dimension > 1 ? dimension : 2;
  stride = stride ?? dimension;
  if (output === void 0) {
    if (dimension > 2) {
      output = input.slice();
    } else {
      output = new Array(length);
    }
  }
  for (let i = 0; i < length; i += stride) {
    output[i] = HALF_SIZE * input[i] / 180;
    let y = RADIUS$1 * Math.log(Math.tan(Math.PI * (+input[i + 1] + 90) / 360));
    if (y > MAX_SAFE_Y) {
      y = MAX_SAFE_Y;
    } else if (y < -MAX_SAFE_Y) {
      y = -MAX_SAFE_Y;
    }
    output[i + 1] = y;
  }
  return output;
}
function toEPSG4326(input, output, dimension, stride) {
  const length = input.length;
  dimension = dimension > 1 ? dimension : 2;
  stride = stride ?? dimension;
  if (output === void 0) {
    if (dimension > 2) {
      output = input.slice();
    } else {
      output = new Array(length);
    }
  }
  for (let i = 0; i < length; i += stride) {
    output[i] = 180 * input[i] / HALF_SIZE;
    output[i + 1] = 360 * Math.atan(Math.exp(input[i + 1] / RADIUS$1)) / Math.PI - 90;
  }
  return output;
}
const RADIUS = 6378137;
const EXTENT = [-180, -90, 180, 90];
const METERS_PER_UNIT = Math.PI * RADIUS / 180;
class EPSG4326Projection extends Projection$1 {
  /**
   * @param {string} code Code.
   * @param {string} [axisOrientation] Axis orientation.
   */
  constructor(code, axisOrientation) {
    super({
      code,
      units: "degrees",
      extent: EXTENT,
      axisOrientation,
      global: true,
      metersPerUnit: METERS_PER_UNIT,
      worldExtent: EXTENT
    });
  }
}
const PROJECTIONS = [
  new EPSG4326Projection("CRS:84"),
  new EPSG4326Projection("EPSG:4326", "neu"),
  new EPSG4326Projection("urn:ogc:def:crs:OGC:1.3:CRS84"),
  new EPSG4326Projection("urn:ogc:def:crs:OGC:2:84"),
  new EPSG4326Projection("http://www.opengis.net/def/crs/OGC/1.3/CRS84"),
  new EPSG4326Projection("http://www.opengis.net/gml/srs/epsg.xml#4326", "neu"),
  new EPSG4326Projection("http://www.opengis.net/def/crs/EPSG/0/4326", "neu")
];
let cache$1 = {};
function get$4(code) {
  return cache$1[code] || cache$1[code.replace(/urn:(x-)?ogc:def:crs:EPSG:(.*:)?(\w+)$/, "EPSG:$3")] || null;
}
function add$2(code, projection) {
  cache$1[code] = projection;
}
let transforms = {};
function add$1(source, destination, transformFn) {
  const sourceCode = source.getCode();
  const destinationCode = destination.getCode();
  if (!(sourceCode in transforms)) {
    transforms[sourceCode] = {};
  }
  transforms[sourceCode][destinationCode] = transformFn;
}
function get$3(sourceCode, destinationCode) {
  if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {
    return transforms[sourceCode][destinationCode];
  }
  return null;
}
const K0 = 0.9996;
const E = 669438e-8;
const E2 = E * E;
const E3 = E2 * E;
const E_P2 = E / (1 - E);
const SQRT_E = Math.sqrt(1 - E);
const _E = (1 - SQRT_E) / (1 + SQRT_E);
const _E2 = _E * _E;
const _E3 = _E2 * _E;
const _E4 = _E3 * _E;
const _E5 = _E4 * _E;
const M1 = 1 - E / 4 - 3 * E2 / 64 - 5 * E3 / 256;
const M2 = 3 * E / 8 + 3 * E2 / 32 + 45 * E3 / 1024;
const M3 = 15 * E2 / 256 + 45 * E3 / 1024;
const M4 = 35 * E3 / 3072;
const P2 = 3 / 2 * _E - 27 / 32 * _E3 + 269 / 512 * _E5;
const P3 = 21 / 16 * _E2 - 55 / 32 * _E4;
const P4 = 151 / 96 * _E3 - 417 / 128 * _E5;
const P5 = 1097 / 512 * _E4;
const R = 6378137;
function toLonLat(easting, northing, zone) {
  const x = easting - 5e5;
  const y = zone.north ? northing : northing - 1e7;
  const m = y / K0;
  const mu = m / (R * M1);
  const pRad = mu + P2 * Math.sin(2 * mu) + P3 * Math.sin(4 * mu) + P4 * Math.sin(6 * mu) + P5 * Math.sin(8 * mu);
  const pSin = Math.sin(pRad);
  const pSin2 = pSin * pSin;
  const pCos = Math.cos(pRad);
  const pTan = pSin / pCos;
  const pTan2 = pTan * pTan;
  const pTan4 = pTan2 * pTan2;
  const epSin = 1 - E * pSin2;
  const epSinSqrt = Math.sqrt(1 - E * pSin2);
  const n = R / epSinSqrt;
  const r = (1 - E) / epSin;
  const c = E_P2 * pCos ** 2;
  const c2 = c * c;
  const d = x / (n * K0);
  const d2 = d * d;
  const d3 = d2 * d;
  const d4 = d3 * d;
  const d5 = d4 * d;
  const d6 = d5 * d;
  const latitude = pRad - pTan / r * (d2 / 2 - d4 / 24 * (5 + 3 * pTan2 + 10 * c - 4 * c2 - 9 * E_P2)) + d6 / 720 * (61 + 90 * pTan2 + 298 * c + 45 * pTan4 - 252 * E_P2 - 3 * c2);
  let longitude = (d - d3 / 6 * (1 + 2 * pTan2 + c) + d5 / 120 * (5 - 2 * c + 28 * pTan2 - 3 * c2 + 8 * E_P2 + 24 * pTan4)) / pCos;
  longitude = wrap(
    longitude + toRadians(zoneToCentralLongitude(zone.number)),
    -Math.PI,
    Math.PI
  );
  return [toDegrees(longitude), toDegrees(latitude)];
}
const MIN_LATITUDE = -80;
const MAX_LATITUDE = 84;
const MIN_LONGITUDE = -180;
const MAX_LONGITUDE = 180;
function fromLonLat(longitude, latitude, zone) {
  longitude = wrap(longitude, MIN_LONGITUDE, MAX_LONGITUDE);
  if (latitude < MIN_LATITUDE) {
    latitude = MIN_LATITUDE;
  } else if (latitude > MAX_LATITUDE) {
    latitude = MAX_LATITUDE;
  }
  const latRad = toRadians(latitude);
  const latSin = Math.sin(latRad);
  const latCos = Math.cos(latRad);
  const latTan = latSin / latCos;
  const latTan2 = latTan * latTan;
  const latTan4 = latTan2 * latTan2;
  const lonRad = toRadians(longitude);
  const centralLon = zoneToCentralLongitude(zone.number);
  const centralLonRad = toRadians(centralLon);
  const n = R / Math.sqrt(1 - E * latSin ** 2);
  const c = E_P2 * latCos ** 2;
  const a = latCos * wrap(lonRad - centralLonRad, -Math.PI, Math.PI);
  const a22 = a * a;
  const a3 = a22 * a;
  const a4 = a3 * a;
  const a5 = a4 * a;
  const a6 = a5 * a;
  const m = R * (M1 * latRad - M2 * Math.sin(2 * latRad) + M3 * Math.sin(4 * latRad) - M4 * Math.sin(6 * latRad));
  const easting = K0 * n * (a + a3 / 6 * (1 - latTan2 + c) + a5 / 120 * (5 - 18 * latTan2 + latTan4 + 72 * c - 58 * E_P2)) + 5e5;
  let northing = K0 * (m + n * latTan * (a22 / 2 + a4 / 24 * (5 - latTan2 + 9 * c + 4 * c ** 2) + a6 / 720 * (61 - 58 * latTan2 + latTan4 + 600 * c - 330 * E_P2)));
  if (!zone.north) {
    northing += 1e7;
  }
  return [easting, northing];
}
function zoneToCentralLongitude(zone) {
  return (zone - 1) * 6 - 180 + 3;
}
const epsgRegExes = [
  /^EPSG:(\d+)$/,
  /^urn:ogc:def:crs:EPSG::(\d+)$/,
  /^http:\/\/www\.opengis\.net\/def\/crs\/EPSG\/0\/(\d+)$/
];
function zoneFromCode(code) {
  let epsgId = 0;
  for (const re2 of epsgRegExes) {
    const match2 = code.match(re2);
    if (match2) {
      epsgId = parseInt(match2[1]);
      break;
    }
  }
  if (!epsgId) {
    return null;
  }
  let number = 0;
  let north = false;
  if (epsgId > 32700 && epsgId < 32761) {
    number = epsgId - 32700;
  } else if (epsgId > 32600 && epsgId < 32661) {
    north = true;
    number = epsgId - 32600;
  }
  if (!number) {
    return null;
  }
  return { number, north };
}
function makeTransformFunction(transformer2, zone) {
  return function(input, output, dimension, stride) {
    const length = input.length;
    dimension = dimension > 1 ? dimension : 2;
    stride = stride ?? dimension;
    if (!output) {
      if (dimension > 2) {
        output = input.slice();
      } else {
        output = new Array(length);
      }
    }
    for (let i = 0; i < length; i += stride) {
      const x = input[i];
      const y = input[i + 1];
      const coord = transformer2(x, y, zone);
      output[i] = coord[0];
      output[i + 1] = coord[1];
    }
    return output;
  };
}
function makeProjection(code) {
  const zone = zoneFromCode(code);
  if (!zone) {
    return null;
  }
  return new Projection$1({ code, units: "m" });
}
function makeTransforms(projection) {
  const zone = zoneFromCode(projection.getCode());
  if (!zone) {
    return null;
  }
  return {
    forward: makeTransformFunction(fromLonLat, zone),
    inverse: makeTransformFunction(toLonLat, zone)
  };
}
const DEFAULT_RADIUS = 63710088e-1;
function getDistance(c1, c2, radius) {
  radius = radius || DEFAULT_RADIUS;
  const lat1 = toRadians(c1[1]);
  const lat2 = toRadians(c2[1]);
  const deltaLatBy2 = (lat2 - lat1) / 2;
  const deltaLonBy2 = toRadians(c2[0] - c1[0]) / 2;
  const a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * Math.cos(lat1) * Math.cos(lat2);
  return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
const transformFactories = [makeTransforms];
const projectionFactories = [makeProjection];
let showCoordinateWarning = true;
function disableCoordinateWarning(disable2) {
  showCoordinateWarning = false;
}
function cloneTransform(input, output) {
  if (output !== void 0) {
    for (let i = 0, ii = input.length; i < ii; ++i) {
      output[i] = input[i];
    }
    output = output;
  } else {
    output = input.slice();
  }
  return output;
}
function addProjection(projection) {
  add$2(projection.getCode(), projection);
  add$1(projection, projection, cloneTransform);
}
function addProjections(projections2) {
  projections2.forEach(addProjection);
}
function get$2(projectionLike) {
  if (!(typeof projectionLike === "string")) {
    return projectionLike;
  }
  const projection = get$4(projectionLike);
  if (projection) {
    return projection;
  }
  for (const makeProjection2 of projectionFactories) {
    const projection2 = makeProjection2(projectionLike);
    if (projection2) {
      return projection2;
    }
  }
  return null;
}
function getPointResolution(projection, resolution, point, units2) {
  projection = get$2(projection);
  let pointResolution;
  const getter = projection.getPointResolutionFunc();
  if (getter) {
    pointResolution = getter(resolution, point);
    if (units2 && units2 !== projection.getUnits()) {
      const metersPerUnit = projection.getMetersPerUnit();
      if (metersPerUnit) {
        pointResolution = pointResolution * metersPerUnit / METERS_PER_UNIT$1[units2];
      }
    }
  } else {
    const projUnits = projection.getUnits();
    if (projUnits == "degrees" && !units2 || units2 == "degrees") {
      pointResolution = resolution;
    } else {
      const toEPSG43262 = getTransformFromProjections(
        projection,
        get$2("EPSG:4326")
      );
      if (!toEPSG43262 && projUnits !== "degrees") {
        pointResolution = resolution * projection.getMetersPerUnit();
      } else {
        let vertices = [
          point[0] - resolution / 2,
          point[1],
          point[0] + resolution / 2,
          point[1],
          point[0],
          point[1] - resolution / 2,
          point[0],
          point[1] + resolution / 2
        ];
        vertices = toEPSG43262(vertices, vertices, 2);
        const width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4));
        const height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8));
        pointResolution = (width + height) / 2;
      }
      const metersPerUnit = units2 ? METERS_PER_UNIT$1[units2] : projection.getMetersPerUnit();
      if (metersPerUnit !== void 0) {
        pointResolution /= metersPerUnit;
      }
    }
  }
  return pointResolution;
}
function addEquivalentProjections(projections2) {
  addProjections(projections2);
  projections2.forEach(function(source) {
    projections2.forEach(function(destination) {
      if (source !== destination) {
        add$1(source, destination, cloneTransform);
      }
    });
  });
}
function addEquivalentTransforms(projections1, projections2, forwardTransform, inverseTransform) {
  projections1.forEach(function(projection1) {
    projections2.forEach(function(projection2) {
      add$1(projection1, projection2, forwardTransform);
      add$1(projection2, projection1, inverseTransform);
    });
  });
}
function createProjection(projection, defaultCode) {
  if (!projection) {
    return get$2(defaultCode);
  }
  if (typeof projection === "string") {
    return get$2(projection);
  }
  return (
    /** @type {Projection} */
    projection
  );
}
function createTransformFromCoordinateTransform(coordTransform) {
  return (
    /**
     * @param {Array<number>} input Input.
     * @param {Array<number>} [output] Output.
     * @param {number} [dimension] Dimensions that should be transformed.
     * @param {number} [stride] Stride.
     * @return {Array<number>} Output.
     */
    (function(input, output, dimension, stride) {
      const length = input.length;
      dimension = dimension !== void 0 ? dimension : 2;
      stride = stride ?? dimension;
      output = output !== void 0 ? output : new Array(length);
      for (let i = 0; i < length; i += stride) {
        const point = coordTransform(input.slice(i, i + dimension));
        const pointLength = point.length;
        for (let j = 0, jj = stride; j < jj; ++j) {
          output[i + j] = j >= pointLength ? input[i + j] : point[j];
        }
      }
      return output;
    })
  );
}
function addCoordinateTransforms(source, destination, forward2, inverse2) {
  const sourceProj = get$2(source);
  const destProj = get$2(destination);
  add$1(
    sourceProj,
    destProj,
    createTransformFromCoordinateTransform(forward2)
  );
  add$1(
    destProj,
    sourceProj,
    createTransformFromCoordinateTransform(inverse2)
  );
}
function equivalent$1(projection1, projection2) {
  if (projection1 === projection2) {
    return true;
  }
  const equalUnits = projection1.getUnits() === projection2.getUnits();
  if (projection1.getCode() === projection2.getCode()) {
    return equalUnits;
  }
  const transformFunc = getTransformFromProjections(projection1, projection2);
  return transformFunc === cloneTransform && equalUnits;
}
function getTransformFromProjections(source, destination) {
  const sourceCode = source.getCode();
  const destinationCode = destination.getCode();
  let transformFunc = get$3(sourceCode, destinationCode);
  if (transformFunc) {
    return transformFunc;
  }
  let sourceTransforms = null;
  let destinationTransforms = null;
  for (const makeTransforms2 of transformFactories) {
    if (!sourceTransforms) {
      sourceTransforms = makeTransforms2(source);
    }
    if (!destinationTransforms) {
      destinationTransforms = makeTransforms2(destination);
    }
  }
  if (!sourceTransforms && !destinationTransforms) {
    return null;
  }
  const intermediateCode = "EPSG:4326";
  if (!destinationTransforms) {
    const toDestination = get$3(intermediateCode, destinationCode);
    if (toDestination) {
      transformFunc = composeTransformFuncs(
        sourceTransforms.inverse,
        toDestination
      );
    }
  } else if (!sourceTransforms) {
    const fromSource = get$3(sourceCode, intermediateCode);
    if (fromSource) {
      transformFunc = composeTransformFuncs(
        fromSource,
        destinationTransforms.forward
      );
    }
  } else {
    transformFunc = composeTransformFuncs(
      sourceTransforms.inverse,
      destinationTransforms.forward
    );
  }
  if (transformFunc) {
    addProjection(source);
    addProjection(destination);
    add$1(source, destination, transformFunc);
  }
  return transformFunc;
}
function composeTransformFuncs(t1, t2) {
  return function(input, output, dimensions, stride) {
    output = t1(input, output, dimensions, stride);
    return t2(output, output, dimensions, stride);
  };
}
function getTransform(source, destination) {
  const sourceProjection = get$2(source);
  const destinationProjection = get$2(destination);
  return getTransformFromProjections(sourceProjection, destinationProjection);
}
function transform$1(coordinate, source, destination) {
  const transformFunc = getTransform(source, destination);
  if (!transformFunc) {
    const sourceCode = get$2(source).getCode();
    const destinationCode = get$2(destination).getCode();
    throw new Error(
      `No transform available between ${sourceCode} and ${destinationCode}`
    );
  }
  return transformFunc(coordinate, void 0, coordinate.length);
}
function transformExtent(extent, source, destination, stops) {
  const transformFunc = getTransform(source, destination);
  return applyTransform(extent, transformFunc, void 0);
}
let userProjection = null;
function setUserProjection$1(projection) {
  userProjection = get$2(projection);
}
function getUserProjection() {
  return userProjection;
}
function toUserCoordinate(coordinate, sourceProjection) {
  if (!userProjection) {
    return coordinate;
  }
  return transform$1(coordinate, sourceProjection, userProjection);
}
function fromUserCoordinate(coordinate, destProjection) {
  if (!userProjection) {
    if (showCoordinateWarning && !equals(coordinate, [0, 0]) && coordinate[0] >= -180 && coordinate[0] <= 180 && coordinate[1] >= -90 && coordinate[1] <= 90) {
      showCoordinateWarning = false;
      warn(
        "Call useGeographic() from ol/proj once to work with [longitude, latitude] coordinates."
      );
    }
    return coordinate;
  }
  return transform$1(coordinate, userProjection, destProjection);
}
function toUserExtent(extent, sourceProjection) {
  if (!userProjection) {
    return extent;
  }
  return transformExtent(extent, sourceProjection, userProjection);
}
function fromUserExtent(extent, destProjection) {
  if (!userProjection) {
    return extent;
  }
  return transformExtent(extent, userProjection, destProjection);
}
function toUserResolution(resolution, sourceProjection) {
  if (!userProjection) {
    return resolution;
  }
  const sourceMetersPerUnit = get$2(sourceProjection).getMetersPerUnit();
  const userMetersPerUnit = userProjection.getMetersPerUnit();
  return sourceMetersPerUnit && userMetersPerUnit ? resolution * sourceMetersPerUnit / userMetersPerUnit : resolution;
}
function createSafeCoordinateTransform(sourceProj, destProj, transform2) {
  return function(coord) {
    let transformed, worldsAway;
    if (sourceProj.canWrapX()) {
      const sourceExtent = sourceProj.getExtent();
      const sourceExtentWidth = getWidth(sourceExtent);
      coord = coord.slice(0);
      worldsAway = getWorldsAway(coord, sourceProj, sourceExtentWidth);
      if (worldsAway) {
        coord[0] = coord[0] - worldsAway * sourceExtentWidth;
      }
      coord[0] = clamp(coord[0], sourceExtent[0], sourceExtent[2]);
      coord[1] = clamp(coord[1], sourceExtent[1], sourceExtent[3]);
      transformed = transform2(coord);
    } else {
      transformed = transform2(coord);
    }
    if (worldsAway && destProj.canWrapX()) {
      transformed[0] += worldsAway * getWidth(destProj.getExtent());
    }
    return transformed;
  };
}
function addCommon() {
  addEquivalentProjections(PROJECTIONS$1);
  addEquivalentProjections(PROJECTIONS);
  addEquivalentTransforms(
    PROJECTIONS,
    PROJECTIONS$1,
    fromEPSG4326,
    toEPSG4326
  );
}
addCommon();
const CollectionEventType = {
  /**
   * Triggered when an item is added to the collection.
   * @event module:ol/Collection.CollectionEvent#add
   * @api
   */
  ADD: "add",
  /**
   * Triggered when an item is removed from the collection.
   * @event module:ol/Collection.CollectionEvent#remove
   * @api
   */
  REMOVE: "remove"
};
const Property$2 = {
  LENGTH: "length"
};
class CollectionEvent extends BaseEvent {
  /**
   * @param {import("./CollectionEventType.js").default} type Type.
   * @param {T} element Element.
   * @param {number} index The index of the added or removed element.
   */
  constructor(type, element, index) {
    super(type);
    this.element = element;
    this.index = index;
  }
}
class Collection extends BaseObject {
  /**
   * @param {Array<T>} [array] Array.
   * @param {Options} [options] Collection options.
   */
  constructor(array, options2) {
    super();
    this.on;
    this.once;
    this.un;
    options2 = options2 || {};
    this.unique_ = !!options2.unique;
    this.array_ = array ? array : [];
    if (this.unique_) {
      for (let i = 0, ii = this.array_.length; i < ii; ++i) {
        this.assertUnique_(this.array_[i], i);
      }
    }
    this.updateLength_();
  }
  /**
   * Remove all elements from the collection.
   * @api
   */
  clear() {
    while (this.getLength() > 0) {
      this.pop();
    }
  }
  /**
   * Add elements to the collection.  This pushes each item in the provided array
   * to the end of the collection.
   * @param {!Array<T>} arr Array.
   * @return {Collection<T>} This collection.
   * @api
   */
  extend(arr) {
    for (let i = 0, ii = arr.length; i < ii; ++i) {
      this.push(arr[i]);
    }
    return this;
  }
  /**
   * Iterate over each element, calling the provided callback.
   * @param {function(T, number, Array<T>): *} f The function to call
   *     for every element. This function takes 3 arguments (the element, the
   *     index and the array). The return value is ignored.
   * @api
   */
  forEach(f) {
    const array = this.array_;
    for (let i = 0, ii = array.length; i < ii; ++i) {
      f(array[i], i, array);
    }
  }
  /**
   * Get a reference to the underlying Array object. Warning: if the array
   * is mutated, no events will be dispatched by the collection, and the
   * collection's "length" property won't be in sync with the actual length
   * of the array.
   * @return {!Array<T>} Array.
   * @api
   */
  getArray() {
    return this.array_;
  }
  /**
   * Get the element at the provided index.
   * @param {number} index Index.
   * @return {T} Element.
   * @api
   */
  item(index) {
    return this.array_[index];
  }
  /**
   * Get the length of this collection.
   * @return {number} The length of the array.
   * @observable
   * @api
   */
  getLength() {
    return this.get(Property$2.LENGTH);
  }
  /**
   * Insert an element at the provided index.
   * @param {number} index Index.
   * @param {T} elem Element.
   * @api
   */
  insertAt(index, elem) {
    if (index < 0 || index > this.getLength()) {
      throw new Error("Index out of bounds: " + index);
    }
    if (this.unique_) {
      this.assertUnique_(elem);
    }
    this.array_.splice(index, 0, elem);
    this.updateLength_();
    this.dispatchEvent(
      new CollectionEvent(CollectionEventType.ADD, elem, index)
    );
  }
  /**
   * Remove the last element of the collection and return it.
   * Return `undefined` if the collection is empty.
   * @return {T|undefined} Element.
   * @api
   */
  pop() {
    return this.removeAt(this.getLength() - 1);
  }
  /**
   * Insert the provided element at the end of the collection.
   * @param {T} elem Element.
   * @return {number} New length of the collection.
   * @api
   */
  push(elem) {
    if (this.unique_) {
      this.assertUnique_(elem);
    }
    const n = this.getLength();
    this.insertAt(n, elem);
    return this.getLength();
  }
  /**
   * Remove the first occurrence of an element from the collection.
   * @param {T} elem Element.
   * @return {T|undefined} The removed element or undefined if none found.
   * @api
   */
  remove(elem) {
    const arr = this.array_;
    for (let i = 0, ii = arr.length; i < ii; ++i) {
      if (arr[i] === elem) {
        return this.removeAt(i);
      }
    }
    return void 0;
  }
  /**
   * Remove the element at the provided index and return it.
   * Return `undefined` if the collection does not contain this index.
   * @param {number} index Index.
   * @return {T|undefined} Value.
   * @api
   */
  removeAt(index) {
    if (index < 0 || index >= this.getLength()) {
      return void 0;
    }
    const prev = this.array_[index];
    this.array_.splice(index, 1);
    this.updateLength_();
    this.dispatchEvent(
      /** @type {CollectionEvent<T>} */
      new CollectionEvent(CollectionEventType.REMOVE, prev, index)
    );
    return prev;
  }
  /**
   * Set the element at the provided index.
   * @param {number} index Index.
   * @param {T} elem Element.
   * @api
   */
  setAt(index, elem) {
    const n = this.getLength();
    if (index >= n) {
      this.insertAt(index, elem);
      return;
    }
    if (index < 0) {
      throw new Error("Index out of bounds: " + index);
    }
    if (this.unique_) {
      this.assertUnique_(elem, index);
    }
    const prev = this.array_[index];
    this.array_[index] = elem;
    this.dispatchEvent(
      /** @type {CollectionEvent<T>} */
      new CollectionEvent(CollectionEventType.REMOVE, prev, index)
    );
    this.dispatchEvent(
      /** @type {CollectionEvent<T>} */
      new CollectionEvent(CollectionEventType.ADD, elem, index)
    );
  }
  /**
   * @private
   */
  updateLength_() {
    this.set(Property$2.LENGTH, this.array_.length);
  }
  /**
   * @private
   * @param {T} elem Element.
   * @param {number} [except] Optional index to ignore.
   */
  assertUnique_(elem, except) {
    for (let i = 0, ii = this.array_.length; i < ii; ++i) {
      if (this.array_[i] === elem && i !== except) {
        throw new Error("Duplicate item added to a unique collection");
      }
    }
  }
}
class MapEvent extends BaseEvent {
  /**
   * @param {string} type Event type.
   * @param {import("./Map.js").default} map Map.
   * @param {?import("./Map.js").FrameState} [frameState] Frame state.
   */
  constructor(type, map, frameState) {
    super(type);
    this.map = map;
    this.frameState = frameState !== void 0 ? frameState : null;
  }
}
class MapBrowserEvent extends MapEvent {
  /**
   * @param {string} type Event type.
   * @param {import("./Map.js").default} map Map.
   * @param {EVENT} originalEvent Original event.
   * @param {boolean} [dragging] Is the map currently being dragged?
   * @param {import("./Map.js").FrameState} [frameState] Frame state.
   * @param {Array<PointerEvent>} [activePointers] Active pointers.
   */
  constructor(type, map, originalEvent, dragging, frameState, activePointers) {
    super(type, map, frameState);
    this.originalEvent = originalEvent;
    this.pixel_ = null;
    this.coordinate_ = null;
    this.dragging = dragging !== void 0 ? dragging : false;
    this.activePointers = activePointers;
  }
  /**
   * The map pixel relative to the viewport corresponding to the original event.
   * @type {import("./pixel.js").Pixel}
   * @api
   */
  get pixel() {
    if (!this.pixel_) {
      this.pixel_ = this.map.getEventPixel(this.originalEvent);
    }
    return this.pixel_;
  }
  set pixel(pixel) {
    this.pixel_ = pixel;
  }
  /**
   * The coordinate corresponding to the original browser event.  This will be in the user
   * projection if one is set.  Otherwise it will be in the view projection.
   * @type {import("./coordinate.js").Coordinate}
   * @api
   */
  get coordinate() {
    if (!this.coordinate_) {
      this.coordinate_ = this.map.getCoordinateFromPixel(this.pixel);
    }
    return this.coordinate_;
  }
  set coordinate(coordinate) {
    this.coordinate_ = coordinate;
  }
  /**
   * Prevents the default browser action.
   * See https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault.
   * @api
   * @override
   */
  preventDefault() {
    super.preventDefault();
    if ("preventDefault" in this.originalEvent) {
      this.originalEvent.preventDefault();
    }
  }
  /**
   * Prevents further propagation of the current event.
   * See https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation.
   * @api
   * @override
   */
  stopPropagation() {
    super.stopPropagation();
    if ("stopPropagation" in this.originalEvent) {
      this.originalEvent.stopPropagation();
    }
  }
}
const MapBrowserEventType = {
  /**
   * A true single click with no dragging and no double click. Note that this
   * event is delayed by 250 ms to ensure that it is not a double click.
   * @event module:ol/MapBrowserEvent~MapBrowserEvent#singleclick
   * @api
   */
  SINGLECLICK: "singleclick",
  /**
   * A click with no dragging. A double click will fire two of this.
   * @event module:ol/MapBrowserEvent~MapBrowserEvent#click
   * @api
   */
  CLICK: EventType.CLICK,
  /**
   * A true double click, with no dragging.
   * @event module:ol/MapBrowserEvent~MapBrowserEvent#dblclick
   * @api
   */
  DBLCLICK: EventType.DBLCLICK,
  /**
   * Triggered when a pointer is dragged.
   * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointerdrag
   * @api
   */
  POINTERDRAG: "pointerdrag",
  /**
   * Triggered when a pointer is moved. Note that on touch devices this is
   * triggered when the map is panned, so is not the same as mousemove.
   * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointermove
   * @api
   */
  POINTERMOVE: "pointermove",
  POINTERDOWN: "pointerdown",
  POINTERUP: "pointerup",
  POINTEROVER: "pointerover",
  POINTEROUT: "pointerout",
  POINTERENTER: "pointerenter",
  POINTERLEAVE: "pointerleave",
  POINTERCANCEL: "pointercancel"
};
class MapBrowserEventHandler extends Target {
  /**
   * @param {import("./Map.js").default} map The map with the viewport to listen to events on.
   * @param {number} [moveTolerance] The minimal distance the pointer must travel to trigger a move.
   */
  constructor(map, moveTolerance) {
    super(map);
    this.map_ = map;
    this.clickTimeoutId_;
    this.emulateClicks_ = false;
    this.dragging_ = false;
    this.dragListenerKeys_ = [];
    this.moveTolerance_ = moveTolerance === void 0 ? 1 : moveTolerance;
    this.down_ = null;
    const element = this.map_.getViewport();
    this.activePointers_ = [];
    this.trackedTouches_ = {};
    this.element_ = element;
    this.pointerdownListenerKey_ = listen(
      element,
      PointerEventType.POINTERDOWN,
      this.handlePointerDown_,
      this
    );
    this.originalPointerMoveEvent_;
    this.relayedListenerKey_ = listen(
      element,
      PointerEventType.POINTERMOVE,
      this.relayMoveEvent_,
      this
    );
    this.boundHandleTouchMove_ = this.handleTouchMove_.bind(this);
    this.element_.addEventListener(
      EventType.TOUCHMOVE,
      this.boundHandleTouchMove_,
      PASSIVE_EVENT_LISTENERS ? { passive: false } : false
    );
  }
  /**
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @private
   */
  emulateClick_(pointerEvent) {
    let newEvent = new MapBrowserEvent(
      MapBrowserEventType.CLICK,
      this.map_,
      pointerEvent
    );
    this.dispatchEvent(newEvent);
    if (this.clickTimeoutId_ !== void 0) {
      clearTimeout(this.clickTimeoutId_);
      this.clickTimeoutId_ = void 0;
      newEvent = new MapBrowserEvent(
        MapBrowserEventType.DBLCLICK,
        this.map_,
        pointerEvent
      );
      this.dispatchEvent(newEvent);
    } else {
      this.clickTimeoutId_ = setTimeout(() => {
        this.clickTimeoutId_ = void 0;
        const newEvent2 = new MapBrowserEvent(
          MapBrowserEventType.SINGLECLICK,
          this.map_,
          pointerEvent
        );
        this.dispatchEvent(newEvent2);
      }, 250);
    }
  }
  /**
   * Keeps track on how many pointers are currently active.
   *
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @private
   */
  updateActivePointers_(pointerEvent) {
    const event = pointerEvent;
    const id = event.pointerId;
    if (event.type == MapBrowserEventType.POINTERUP || event.type == MapBrowserEventType.POINTERCANCEL) {
      delete this.trackedTouches_[id];
      for (const pointerId in this.trackedTouches_) {
        if (this.trackedTouches_[pointerId].target !== event.target) {
          delete this.trackedTouches_[pointerId];
          break;
        }
      }
    } else if (event.type == MapBrowserEventType.POINTERDOWN || event.type == MapBrowserEventType.POINTERMOVE) {
      this.trackedTouches_[id] = event;
    }
    this.activePointers_ = Object.values(this.trackedTouches_);
  }
  /**
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @private
   */
  handlePointerUp_(pointerEvent) {
    this.updateActivePointers_(pointerEvent);
    const newEvent = new MapBrowserEvent(
      MapBrowserEventType.POINTERUP,
      this.map_,
      pointerEvent,
      void 0,
      void 0,
      this.activePointers_
    );
    this.dispatchEvent(newEvent);
    if (this.emulateClicks_ && !newEvent.defaultPrevented && !this.dragging_ && this.isMouseActionButton_(pointerEvent)) {
      this.emulateClick_(this.down_);
    }
    if (this.activePointers_.length === 0) {
      this.dragListenerKeys_.forEach(unlistenByKey);
      this.dragListenerKeys_.length = 0;
      this.dragging_ = false;
      this.down_ = null;
    }
  }
  /**
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @return {boolean} If the left mouse button was pressed.
   * @private
   */
  isMouseActionButton_(pointerEvent) {
    return pointerEvent.button === 0;
  }
  /**
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @private
   */
  handlePointerDown_(pointerEvent) {
    this.emulateClicks_ = this.activePointers_.length === 0;
    this.updateActivePointers_(pointerEvent);
    const newEvent = new MapBrowserEvent(
      MapBrowserEventType.POINTERDOWN,
      this.map_,
      pointerEvent,
      void 0,
      void 0,
      this.activePointers_
    );
    this.dispatchEvent(newEvent);
    this.down_ = new PointerEvent(pointerEvent.type, pointerEvent);
    Object.defineProperty(this.down_, "target", {
      writable: false,
      value: pointerEvent.target
    });
    if (this.dragListenerKeys_.length === 0) {
      const doc2 = this.map_.getOwnerDocument();
      this.dragListenerKeys_.push(
        listen(
          doc2,
          MapBrowserEventType.POINTERMOVE,
          this.handlePointerMove_,
          this
        ),
        listen(doc2, MapBrowserEventType.POINTERUP, this.handlePointerUp_, this),
        /* Note that the listener for `pointercancel is set up on
         * `pointerEventHandler_` and not `documentPointerEventHandler_` like
         * the `pointerup` and `pointermove` listeners.
         *
         * The reason for this is the following: `TouchSource.vacuumTouches_()`
         * issues `pointercancel` events, when there was no `touchend` for a
         * `touchstart`. Now, let's say a first `touchstart` is registered on
         * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.
         * But `documentPointerEventHandler_` doesn't know about the first
         * `touchstart`. If there is no `touchend` for the `touchstart`, we can
         * only receive a `touchcancel` from `pointerEventHandler_`, because it is
         * only registered there.
         */
        listen(
          this.element_,
          MapBrowserEventType.POINTERCANCEL,
          this.handlePointerUp_,
          this
        )
      );
      if (this.element_.getRootNode && this.element_.getRootNode() !== doc2) {
        this.dragListenerKeys_.push(
          listen(
            this.element_.getRootNode(),
            MapBrowserEventType.POINTERUP,
            this.handlePointerUp_,
            this
          )
        );
      }
    }
  }
  /**
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @private
   */
  handlePointerMove_(pointerEvent) {
    if (this.isMoving_(pointerEvent)) {
      this.updateActivePointers_(pointerEvent);
      this.dragging_ = true;
      const newEvent = new MapBrowserEvent(
        MapBrowserEventType.POINTERDRAG,
        this.map_,
        pointerEvent,
        this.dragging_,
        void 0,
        this.activePointers_
      );
      this.dispatchEvent(newEvent);
    }
  }
  /**
   * Wrap and relay a pointermove event.
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @private
   */
  relayMoveEvent_(pointerEvent) {
    this.originalPointerMoveEvent_ = pointerEvent;
    const dragging = !!(this.down_ && this.isMoving_(pointerEvent));
    this.dispatchEvent(
      new MapBrowserEvent(
        MapBrowserEventType.POINTERMOVE,
        this.map_,
        pointerEvent,
        dragging
      )
    );
  }
  /**
   * Flexible handling of a `touch-action: none` css equivalent: because calling
   * `preventDefault()` on a `pointermove` event does not stop native page scrolling
   * and zooming, we also listen for `touchmove` and call `preventDefault()` on it
   * when an interaction (currently `DragPan` handles the event.
   * @param {TouchEvent} event Event.
   * @private
   */
  handleTouchMove_(event) {
    const originalEvent = this.originalPointerMoveEvent_;
    if ((!originalEvent || originalEvent.defaultPrevented) && (typeof event.cancelable !== "boolean" || event.cancelable === true)) {
      event.preventDefault();
    }
  }
  /**
   * @param {PointerEvent} pointerEvent Pointer
   * event.
   * @return {boolean} Is moving.
   * @private
   */
  isMoving_(pointerEvent) {
    return this.dragging_ || Math.abs(pointerEvent.clientX - this.down_.clientX) > this.moveTolerance_ || Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_;
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    if (this.relayedListenerKey_) {
      unlistenByKey(this.relayedListenerKey_);
      this.relayedListenerKey_ = null;
    }
    this.element_.removeEventListener(
      EventType.TOUCHMOVE,
      this.boundHandleTouchMove_
    );
    if (this.pointerdownListenerKey_) {
      unlistenByKey(this.pointerdownListenerKey_);
      this.pointerdownListenerKey_ = null;
    }
    this.dragListenerKeys_.forEach(unlistenByKey);
    this.dragListenerKeys_.length = 0;
    this.element_ = null;
    super.disposeInternal();
  }
}
const TileState = {
  IDLE: 0,
  LOADING: 1,
  LOADED: 2,
  /**
   * Indicates that tile loading failed
   * @type {number}
   */
  ERROR: 3,
  EMPTY: 4
};
function assert(assertion, errorMessage) {
  if (!assertion) {
    throw new Error(errorMessage);
  }
}
const DROP = Infinity;
class PriorityQueue {
  /**
   * @param {function(T): number} priorityFunction Priority function.
   * @param {function(T): string} keyFunction Key function.
   */
  constructor(priorityFunction, keyFunction) {
    this.priorityFunction_ = priorityFunction;
    this.keyFunction_ = keyFunction;
    this.elements_ = [];
    this.priorities_ = [];
    this.queuedElements_ = {};
  }
  /**
   * FIXME empty description for jsdoc
   */
  clear() {
    this.elements_.length = 0;
    this.priorities_.length = 0;
    clear(this.queuedElements_);
  }
  /**
   * Remove and return the highest-priority element. O(log N).
   * @return {T} Element.
   */
  dequeue() {
    const elements = this.elements_;
    const priorities = this.priorities_;
    const element = elements[0];
    if (elements.length == 1) {
      elements.length = 0;
      priorities.length = 0;
    } else {
      elements[0] = /** @type {T} */
      elements.pop();
      priorities[0] = /** @type {number} */
      priorities.pop();
      this.siftUp_(0);
    }
    const elementKey = this.keyFunction_(element);
    delete this.queuedElements_[elementKey];
    return element;
  }
  /**
   * Enqueue an element. O(log N).
   * @param {T} element Element.
   * @return {boolean} The element was added to the queue.
   */
  enqueue(element) {
    assert(
      !(this.keyFunction_(element) in this.queuedElements_),
      "Tried to enqueue an `element` that was already added to the queue"
    );
    const priority = this.priorityFunction_(element);
    if (priority != DROP) {
      this.elements_.push(element);
      this.priorities_.push(priority);
      this.queuedElements_[this.keyFunction_(element)] = true;
      this.siftDown_(0, this.elements_.length - 1);
      return true;
    }
    return false;
  }
  /**
   * @return {number} Count.
   */
  getCount() {
    return this.elements_.length;
  }
  /**
   * Gets the index of the left child of the node at the given index.
   * @param {number} index The index of the node to get the left child for.
   * @return {number} The index of the left child.
   * @private
   */
  getLeftChildIndex_(index) {
    return index * 2 + 1;
  }
  /**
   * Gets the index of the right child of the node at the given index.
   * @param {number} index The index of the node to get the right child for.
   * @return {number} The index of the right child.
   * @private
   */
  getRightChildIndex_(index) {
    return index * 2 + 2;
  }
  /**
   * Gets the index of the parent of the node at the given index.
   * @param {number} index The index of the node to get the parent for.
   * @return {number} The index of the parent.
   * @private
   */
  getParentIndex_(index) {
    return index - 1 >> 1;
  }
  /**
   * Make this a heap. O(N).
   * @private
   */
  heapify_() {
    let i;
    for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {
      this.siftUp_(i);
    }
  }
  /**
   * @return {boolean} Is empty.
   */
  isEmpty() {
    return this.elements_.length === 0;
  }
  /**
   * @param {string} key Key.
   * @return {boolean} Is key queued.
   */
  isKeyQueued(key2) {
    return key2 in this.queuedElements_;
  }
  /**
   * @param {T} element Element.
   * @return {boolean} Is queued.
   */
  isQueued(element) {
    return this.isKeyQueued(this.keyFunction_(element));
  }
  /**
   * @param {number} index The index of the node to move down.
   * @private
   */
  siftUp_(index) {
    const elements = this.elements_;
    const priorities = this.priorities_;
    const count = elements.length;
    const element = elements[index];
    const priority = priorities[index];
    const startIndex = index;
    while (index < count >> 1) {
      const lIndex = this.getLeftChildIndex_(index);
      const rIndex = this.getRightChildIndex_(index);
      const smallerChildIndex = rIndex < count && priorities[rIndex] < priorities[lIndex] ? rIndex : lIndex;
      elements[index] = elements[smallerChildIndex];
      priorities[index] = priorities[smallerChildIndex];
      index = smallerChildIndex;
    }
    elements[index] = element;
    priorities[index] = priority;
    this.siftDown_(startIndex, index);
  }
  /**
   * @param {number} startIndex The index of the root.
   * @param {number} index The index of the node to move up.
   * @private
   */
  siftDown_(startIndex, index) {
    const elements = this.elements_;
    const priorities = this.priorities_;
    const element = elements[index];
    const priority = priorities[index];
    while (index > startIndex) {
      const parentIndex = this.getParentIndex_(index);
      if (priorities[parentIndex] > priority) {
        elements[index] = elements[parentIndex];
        priorities[index] = priorities[parentIndex];
        index = parentIndex;
      } else {
        break;
      }
    }
    elements[index] = element;
    priorities[index] = priority;
  }
  /**
   * FIXME empty description for jsdoc
   */
  reprioritize() {
    const priorityFunction = this.priorityFunction_;
    const elements = this.elements_;
    const priorities = this.priorities_;
    let index = 0;
    const n = elements.length;
    let element, i, priority;
    for (i = 0; i < n; ++i) {
      element = elements[i];
      priority = priorityFunction(element);
      if (priority == DROP) {
        delete this.queuedElements_[this.keyFunction_(element)];
      } else {
        priorities[index] = priority;
        elements[index++] = element;
      }
    }
    elements.length = index;
    priorities.length = index;
    this.heapify_();
  }
}
class TileQueue extends PriorityQueue {
  /**
   * @param {PriorityFunction} tilePriorityFunction Tile priority function.
   * @param {function(): ?} tileChangeCallback Function called on each tile change event.
   */
  constructor(tilePriorityFunction, tileChangeCallback) {
    super(
      (element) => tilePriorityFunction.apply(null, element),
      (element) => element[0].getKey()
    );
    this.boundHandleTileChange_ = this.handleTileChange.bind(this);
    this.tileChangeCallback_ = tileChangeCallback;
    this.tilesLoading_ = 0;
    this.tilesLoadingKeys_ = {};
  }
  /**
   * @param {TileQueueElement} element Element.
   * @return {boolean} The element was added to the queue.
   * @override
   */
  enqueue(element) {
    const added = super.enqueue(element);
    if (added) {
      const tile = element[0];
      tile.addEventListener(EventType.CHANGE, this.boundHandleTileChange_);
    }
    return added;
  }
  /**
   * @return {number} Number of tiles loading.
   */
  getTilesLoading() {
    return this.tilesLoading_;
  }
  /**
   * @param {import("./events/Event.js").default} event Event.
   * @protected
   */
  handleTileChange(event) {
    const tile = (
      /** @type {import("./Tile.js").default} */
      event.target
    );
    const state = tile.getState();
    if (state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) {
      if (state !== TileState.ERROR) {
        tile.removeEventListener(EventType.CHANGE, this.boundHandleTileChange_);
      }
      const tileKey = tile.getKey();
      if (tileKey in this.tilesLoadingKeys_) {
        delete this.tilesLoadingKeys_[tileKey];
        --this.tilesLoading_;
      }
      this.tileChangeCallback_();
    }
  }
  /**
   * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
   * @param {number} maxNewLoads Maximum number of new tiles to load.
   */
  loadMoreTiles(maxTotalLoading, maxNewLoads) {
    let newLoads = 0;
    while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads && this.getCount() > 0) {
      const tile = this.dequeue()[0];
      const tileKey = tile.getKey();
      const state = tile.getState();
      if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
        this.tilesLoadingKeys_[tileKey] = true;
        ++this.tilesLoading_;
        ++newLoads;
        tile.load();
      }
    }
  }
}
function getTilePriority(frameState, tile, tileSourceKey, tileCenter, tileResolution) {
  if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {
    return DROP;
  }
  if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) {
    return DROP;
  }
  const center = frameState.viewState.center;
  const deltaX = tileCenter[0] - center[0];
  const deltaY = tileCenter[1] - center[1];
  return 65536 * Math.log(tileResolution) + Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
}
const ViewHint = {
  ANIMATING: 0,
  INTERACTING: 1
};
const ViewProperty = {
  CENTER: "center",
  RESOLUTION: "resolution",
  ROTATION: "rotation"
};
function createExtent(extent, onlyCenter, smooth) {
  return (
    /**
     * @param {import("./coordinate.js").Coordinate|undefined} center Center.
     * @param {number|undefined} resolution Resolution.
     * @param {import("./size.js").Size} size Viewport size; unused if `onlyCenter` was specified.
     * @param {boolean} [isMoving] True if an interaction or animation is in progress.
     * @param {Array<number>} [centerShift] Shift between map center and viewport center.
     * @return {import("./coordinate.js").Coordinate|undefined} Center.
     */
    (function(center, resolution, size, isMoving, centerShift) {
      if (!center) {
        return void 0;
      }
      if (!resolution && !onlyCenter) {
        return center;
      }
      const viewWidth = onlyCenter ? 0 : size[0] * resolution;
      const viewHeight = onlyCenter ? 0 : size[1] * resolution;
      const shiftX = centerShift ? centerShift[0] : 0;
      const shiftY = centerShift ? centerShift[1] : 0;
      let minX = extent[0] + viewWidth / 2 + shiftX;
      let maxX = extent[2] - viewWidth / 2 + shiftX;
      let minY = extent[1] + viewHeight / 2 + shiftY;
      let maxY = extent[3] - viewHeight / 2 + shiftY;
      if (minX > maxX) {
        minX = (maxX + minX) / 2;
        maxX = minX;
      }
      if (minY > maxY) {
        minY = (maxY + minY) / 2;
        maxY = minY;
      }
      let x = clamp(center[0], minX, maxX);
      let y = clamp(center[1], minY, maxY);
      if (isMoving && smooth && resolution) {
        const ratio = 30 * resolution;
        x += -ratio * Math.log(1 + Math.max(0, minX - center[0]) / ratio) + ratio * Math.log(1 + Math.max(0, center[0] - maxX) / ratio);
        y += -ratio * Math.log(1 + Math.max(0, minY - center[1]) / ratio) + ratio * Math.log(1 + Math.max(0, center[1] - maxY) / ratio);
      }
      return [x, y];
    })
  );
}
function none$1(center) {
  return center;
}
function easeIn(t) {
  return Math.pow(t, 3);
}
function easeOut(t) {
  return 1 - easeIn(1 - t);
}
function inAndOut(t) {
  return 3 * t * t - 2 * t * t * t;
}
function linear(t) {
  return t;
}
new Array(6);
function create() {
  return [1, 0, 0, 1, 0, 0];
}
function setFromArray(transform1, transform2) {
  transform1[0] = transform2[0];
  transform1[1] = transform2[1];
  transform1[2] = transform2[2];
  transform1[3] = transform2[3];
  transform1[4] = transform2[4];
  transform1[5] = transform2[5];
  return transform1;
}
function apply(transform2, coordinate) {
  const x = coordinate[0];
  const y = coordinate[1];
  coordinate[0] = transform2[0] * x + transform2[2] * y + transform2[4];
  coordinate[1] = transform2[1] * x + transform2[3] * y + transform2[5];
  return coordinate;
}
function compose(transform2, dx1, dy1, sx, sy, angle, dx2, dy2) {
  const sin2 = Math.sin(angle);
  const cos2 = Math.cos(angle);
  transform2[0] = sx * cos2;
  transform2[1] = sy * sin2;
  transform2[2] = -sx * sin2;
  transform2[3] = sy * cos2;
  transform2[4] = dx2 * sx * cos2 - dy2 * sx * sin2 + dx1;
  transform2[5] = dx2 * sy * sin2 + dy2 * sy * cos2 + dy1;
  return transform2;
}
function makeInverse(target, source) {
  const det = determinant(source);
  assert(det !== 0, "Transformation matrix cannot be inverted");
  const a = source[0];
  const b = source[1];
  const c = source[2];
  const d = source[3];
  const e = source[4];
  const f = source[5];
  target[0] = d / det;
  target[1] = -b / det;
  target[2] = -c / det;
  target[3] = a / det;
  target[4] = (c * f - d * e) / det;
  target[5] = -(a * f - b * e) / det;
  return target;
}
function determinant(mat) {
  return mat[0] * mat[3] - mat[1] * mat[2];
}
const matrixPrecision = [1e5, 1e5, 1e5, 1e5, 2, 2];
function toString$1(mat) {
  const transformString = "matrix(" + mat.join(", ") + ")";
  return transformString;
}
function fromString$1(cssTransform) {
  const values = cssTransform.substring(7, cssTransform.length - 1).split(",");
  return values.map(parseFloat);
}
function equivalent(cssTransform1, cssTransform2) {
  const mat1 = fromString$1(cssTransform1);
  const mat2 = fromString$1(cssTransform2);
  for (let i = 0; i < 6; ++i) {
    if (Math.round((mat1[i] - mat2[i]) * matrixPrecision[i]) !== 0) {
      return false;
    }
  }
  return true;
}
function transform2D(flatCoordinates, offset2, end, stride, transform2, dest, destinationStride) {
  dest = dest ? dest : [];
  destinationStride = destinationStride ? destinationStride : 2;
  let i = 0;
  for (let j = offset2; j < end; j += stride) {
    const x = flatCoordinates[j];
    const y = flatCoordinates[j + 1];
    dest[i++] = transform2[0] * x + transform2[2] * y + transform2[4];
    dest[i++] = transform2[1] * x + transform2[3] * y + transform2[5];
    for (let k = 2; k < destinationStride; k++) {
      dest[i++] = flatCoordinates[j + k];
    }
  }
  if (dest && dest.length != i) {
    dest.length = i;
  }
  return dest;
}
function rotate(flatCoordinates, offset2, end, stride, angle, anchor, dest) {
  dest = dest ? dest : [];
  const cos2 = Math.cos(angle);
  const sin2 = Math.sin(angle);
  const anchorX = anchor[0];
  const anchorY = anchor[1];
  let i = 0;
  for (let j = offset2; j < end; j += stride) {
    const deltaX = flatCoordinates[j] - anchorX;
    const deltaY = flatCoordinates[j + 1] - anchorY;
    dest[i++] = anchorX + deltaX * cos2 - deltaY * sin2;
    dest[i++] = anchorY + deltaX * sin2 + deltaY * cos2;
    for (let k = j + 2; k < j + stride; ++k) {
      dest[i++] = flatCoordinates[k];
    }
  }
  if (dest && dest.length != i) {
    dest.length = i;
  }
  return dest;
}
function scale$1(flatCoordinates, offset2, end, stride, sx, sy, anchor, dest) {
  dest = dest ? dest : [];
  const anchorX = anchor[0];
  const anchorY = anchor[1];
  let i = 0;
  for (let j = offset2; j < end; j += stride) {
    const deltaX = flatCoordinates[j] - anchorX;
    const deltaY = flatCoordinates[j + 1] - anchorY;
    dest[i++] = anchorX + sx * deltaX;
    dest[i++] = anchorY + sy * deltaY;
    for (let k = j + 2; k < j + stride; ++k) {
      dest[i++] = flatCoordinates[k];
    }
  }
  if (dest && dest.length != i) {
    dest.length = i;
  }
  return dest;
}
function translate(flatCoordinates, offset2, end, stride, deltaX, deltaY, dest) {
  dest = dest ? dest : [];
  let i = 0;
  for (let j = offset2; j < end; j += stride) {
    dest[i++] = flatCoordinates[j] + deltaX;
    dest[i++] = flatCoordinates[j + 1] + deltaY;
    for (let k = j + 2; k < j + stride; ++k) {
      dest[i++] = flatCoordinates[k];
    }
  }
  if (dest && dest.length != i) {
    dest.length = i;
  }
  return dest;
}
const tmpTransform$1 = create();
const tmpPoint = [NaN, NaN];
class Geometry extends BaseObject {
  constructor() {
    super();
    this.extent_ = createEmpty();
    this.extentRevision_ = -1;
    this.simplifiedGeometryMaxMinSquaredTolerance = 0;
    this.simplifiedGeometryRevision = 0;
    this.simplifyTransformedInternal = memoizeOne(
      (revision, squaredTolerance, transform2) => {
        if (!transform2) {
          return this.getSimplifiedGeometry(squaredTolerance);
        }
        const clone2 = this.clone();
        clone2.applyTransform(transform2);
        return clone2.getSimplifiedGeometry(squaredTolerance);
      }
    );
  }
  /**
   * Get a transformed and simplified version of the geometry.
   * @abstract
   * @param {number} squaredTolerance Squared tolerance.
   * @param {import("../proj.js").TransformFunction} [transform] Optional transform function.
   * @return {Geometry} Simplified geometry.
   */
  simplifyTransformed(squaredTolerance, transform2) {
    return this.simplifyTransformedInternal(
      this.getRevision(),
      squaredTolerance,
      transform2
    );
  }
  /**
   * Make a complete copy of the geometry.
   * @abstract
   * @return {!Geometry} Clone.
   */
  clone() {
    return abstract();
  }
  /**
   * @abstract
   * @param {number} x X.
   * @param {number} y Y.
   * @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @return {number} Minimum squared distance.
   */
  closestPointXY(x, y, closestPoint, minSquaredDistance) {
    return abstract();
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   * @return {boolean} Contains (x, y).
   */
  containsXY(x, y) {
    return this.closestPointXY(x, y, tmpPoint, Number.MIN_VALUE) === 0;
  }
  /**
   * Return the closest point of the geometry to the passed point as
   * {@link module:ol/coordinate~Coordinate coordinate}.
   * @param {import("../coordinate.js").Coordinate} point Point.
   * @param {import("../coordinate.js").Coordinate} [closestPoint] Closest point.
   * @return {import("../coordinate.js").Coordinate} Closest point.
   * @api
   */
  getClosestPoint(point, closestPoint) {
    closestPoint = closestPoint ? closestPoint : [NaN, NaN];
    this.closestPointXY(point[0], point[1], closestPoint, Infinity);
    return closestPoint;
  }
  /**
   * Returns true if this geometry includes the specified coordinate. If the
   * coordinate is on the boundary of the geometry, returns false.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @return {boolean} Contains coordinate.
   * @api
   */
  intersectsCoordinate(coordinate) {
    return this.containsXY(coordinate[0], coordinate[1]);
  }
  /**
   * @abstract
   * @param {import("../extent.js").Extent} extent Extent.
   * @protected
   * @return {import("../extent.js").Extent} extent Extent.
   */
  computeExtent(extent) {
    return abstract();
  }
  /**
   * Get the extent of the geometry.
   * @param {import("../extent.js").Extent} [extent] Extent.
   * @return {import("../extent.js").Extent} extent Extent.
   * @api
   */
  getExtent(extent) {
    if (this.extentRevision_ != this.getRevision()) {
      const extent2 = this.computeExtent(this.extent_);
      if (isNaN(extent2[0]) || isNaN(extent2[1])) {
        createOrUpdateEmpty(extent2);
      }
      this.extentRevision_ = this.getRevision();
    }
    return returnOrUpdate(this.extent_, extent);
  }
  /**
   * Rotate the geometry around a given coordinate. This modifies the geometry
   * coordinates in place.
   * @abstract
   * @param {number} angle Rotation angle in radians.
   * @param {import("../coordinate.js").Coordinate} anchor The rotation center.
   * @api
   */
  rotate(angle, anchor) {
    abstract();
  }
  /**
   * Scale the geometry (with an optional origin).  This modifies the geometry
   * coordinates in place.
   * @abstract
   * @param {number} sx The scaling factor in the x-direction.
   * @param {number} [sy] The scaling factor in the y-direction (defaults to sx).
   * @param {import("../coordinate.js").Coordinate} [anchor] The scale origin (defaults to the center
   *     of the geometry extent).
   * @api
   */
  scale(sx, sy, anchor) {
    abstract();
  }
  /**
   * Create a simplified version of this geometry.  For linestrings, this uses
   * the [Douglas Peucker](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm)
   * algorithm.  For polygons, a quantization-based
   * simplification is used to preserve topology.
   * @param {number} tolerance The tolerance distance for simplification.
   * @return {Geometry} A new, simplified version of the original geometry.
   * @api
   */
  simplify(tolerance) {
    return this.getSimplifiedGeometry(tolerance * tolerance);
  }
  /**
   * Create a simplified version of this geometry using the Douglas Peucker
   * algorithm.
   * See https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm.
   * @abstract
   * @param {number} squaredTolerance Squared tolerance.
   * @return {Geometry} Simplified geometry.
   */
  getSimplifiedGeometry(squaredTolerance) {
    return abstract();
  }
  /**
   * Get the type of this geometry.
   * @abstract
   * @return {Type} Geometry type.
   */
  getType() {
    return abstract();
  }
  /**
   * Apply a transform function to the coordinates of the geometry.
   * The geometry is modified in place.
   * If you do not want the geometry modified in place, first `clone()` it and
   * then use this function on the clone.
   * @abstract
   * @param {import("../proj.js").TransformFunction} transformFn Transform function.
   * Called with a flat array of geometry coordinates.
   */
  applyTransform(transformFn) {
    abstract();
  }
  /**
   * Test if the geometry and the passed extent intersect.
   * @abstract
   * @param {import("../extent.js").Extent} extent Extent.
   * @return {boolean} `true` if the geometry and the extent intersect.
   */
  intersectsExtent(extent) {
    return abstract();
  }
  /**
   * Translate the geometry.  This modifies the geometry coordinates in place.  If
   * instead you want a new geometry, first `clone()` this geometry.
   * @abstract
   * @param {number} deltaX Delta X.
   * @param {number} deltaY Delta Y.
   * @api
   */
  translate(deltaX, deltaY) {
    abstract();
  }
  /**
   * Transform each coordinate of the geometry from one coordinate reference
   * system to another. The geometry is modified in place.
   * For example, a line will be transformed to a line and a circle to a circle.
   * If you do not want the geometry modified in place, first `clone()` it and
   * then use this function on the clone.
   *
   * @param {import("../proj.js").ProjectionLike} source The current projection.  Can be a
   *     string identifier or a {@link module:ol/proj/Projection~Projection} object.
   * @param {import("../proj.js").ProjectionLike} destination The desired projection.  Can be a
   *     string identifier or a {@link module:ol/proj/Projection~Projection} object.
   * @return {this} This geometry.  Note that original geometry is
   *     modified in place.
   * @api
   */
  transform(source, destination) {
    const sourceProj = get$2(source);
    const transformFn = sourceProj.getUnits() == "tile-pixels" ? function(inCoordinates, outCoordinates, stride) {
      const pixelExtent = sourceProj.getExtent();
      const projectedExtent = sourceProj.getWorldExtent();
      const scale2 = getHeight(projectedExtent) / getHeight(pixelExtent);
      compose(
        tmpTransform$1,
        projectedExtent[0],
        projectedExtent[3],
        scale2,
        -scale2,
        0,
        0,
        0
      );
      const transformed = transform2D(
        inCoordinates,
        0,
        inCoordinates.length,
        stride,
        tmpTransform$1,
        outCoordinates
      );
      const projTransform = getTransform(sourceProj, destination);
      if (projTransform) {
        return projTransform(transformed, transformed, stride);
      }
      return transformed;
    } : getTransform(sourceProj, destination);
    this.applyTransform(transformFn);
    return this;
  }
}
class SimpleGeometry extends Geometry {
  constructor() {
    super();
    this.layout = "XY";
    this.stride = 2;
    this.flatCoordinates;
  }
  /**
   * @param {import("../extent.js").Extent} extent Extent.
   * @protected
   * @return {import("../extent.js").Extent} extent Extent.
   * @override
   */
  computeExtent(extent) {
    return createOrUpdateFromFlatCoordinates(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      extent
    );
  }
  /**
   * @abstract
   * @return {Array<*> | null} Coordinates.
   */
  getCoordinates() {
    return abstract();
  }
  /**
   * Return the first coordinate of the geometry.
   * @return {import("../coordinate.js").Coordinate} First coordinate.
   * @api
   */
  getFirstCoordinate() {
    return this.flatCoordinates.slice(0, this.stride);
  }
  /**
   * @return {Array<number>} Flat coordinates.
   */
  getFlatCoordinates() {
    return this.flatCoordinates;
  }
  /**
   * Return the last coordinate of the geometry.
   * @return {import("../coordinate.js").Coordinate} Last point.
   * @api
   */
  getLastCoordinate() {
    return this.flatCoordinates.slice(
      this.flatCoordinates.length - this.stride
    );
  }
  /**
   * Return the {@link import("./Geometry.js").GeometryLayout layout} of the geometry.
   * @return {import("./Geometry.js").GeometryLayout} Layout.
   * @api
   */
  getLayout() {
    return this.layout;
  }
  /**
   * Create a simplified version of this geometry using the Douglas Peucker algorithm.
   * @param {number} squaredTolerance Squared tolerance.
   * @return {SimpleGeometry} Simplified geometry.
   * @override
   */
  getSimplifiedGeometry(squaredTolerance) {
    if (this.simplifiedGeometryRevision !== this.getRevision()) {
      this.simplifiedGeometryMaxMinSquaredTolerance = 0;
      this.simplifiedGeometryRevision = this.getRevision();
    }
    if (squaredTolerance < 0 || this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance) {
      return this;
    }
    const simplifiedGeometry = this.getSimplifiedGeometryInternal(squaredTolerance);
    const simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();
    if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {
      return simplifiedGeometry;
    }
    this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
    return this;
  }
  /**
   * @param {number} squaredTolerance Squared tolerance.
   * @return {SimpleGeometry} Simplified geometry.
   * @protected
   */
  getSimplifiedGeometryInternal(squaredTolerance) {
    return this;
  }
  /**
   * @return {number} Stride.
   */
  getStride() {
    return this.stride;
  }
  /**
   * @param {import("./Geometry.js").GeometryLayout} layout Layout.
   * @param {Array<number>} flatCoordinates Flat coordinates.
   */
  setFlatCoordinates(layout, flatCoordinates) {
    this.stride = getStrideForLayout(layout);
    this.layout = layout;
    this.flatCoordinates = flatCoordinates;
  }
  /**
   * @abstract
   * @param {!Array<*>} coordinates Coordinates.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   */
  setCoordinates(coordinates2, layout) {
    abstract();
  }
  /**
   * @param {import("./Geometry.js").GeometryLayout|undefined} layout Layout.
   * @param {Array<*>} coordinates Coordinates.
   * @param {number} nesting Nesting.
   * @protected
   */
  setLayout(layout, coordinates2, nesting) {
    let stride;
    if (layout) {
      stride = getStrideForLayout(layout);
    } else {
      for (let i = 0; i < nesting; ++i) {
        if (coordinates2.length === 0) {
          this.layout = "XY";
          this.stride = 2;
          return;
        }
        coordinates2 = /** @type {Array<unknown>} */
        coordinates2[0];
      }
      stride = coordinates2.length;
      layout = getLayoutForStride(stride);
    }
    this.layout = layout;
    this.stride = stride;
  }
  /**
   * Apply a transform function to the coordinates of the geometry.
   * The geometry is modified in place.
   * If you do not want the geometry modified in place, first `clone()` it and
   * then use this function on the clone.
   * @param {import("../proj.js").TransformFunction} transformFn Transform function.
   * Called with a flat array of geometry coordinates.
   * @api
   * @override
   */
  applyTransform(transformFn) {
    if (this.flatCoordinates) {
      transformFn(
        this.flatCoordinates,
        this.flatCoordinates,
        this.layout.startsWith("XYZ") ? 3 : 2,
        this.stride
      );
      this.changed();
    }
  }
  /**
   * Rotate the geometry around a given coordinate. This modifies the geometry
   * coordinates in place.
   * @param {number} angle Rotation angle in counter-clockwise radians.
   * @param {import("../coordinate.js").Coordinate} anchor The rotation center.
   * @api
   * @override
   */
  rotate(angle, anchor) {
    const flatCoordinates = this.getFlatCoordinates();
    if (flatCoordinates) {
      const stride = this.getStride();
      rotate(
        flatCoordinates,
        0,
        flatCoordinates.length,
        stride,
        angle,
        anchor,
        flatCoordinates
      );
      this.changed();
    }
  }
  /**
   * Scale the geometry (with an optional origin).  This modifies the geometry
   * coordinates in place.
   * @param {number} sx The scaling factor in the x-direction.
   * @param {number} [sy] The scaling factor in the y-direction (defaults to sx).
   * @param {import("../coordinate.js").Coordinate} [anchor] The scale origin (defaults to the center
   *     of the geometry extent).
   * @api
   * @override
   */
  scale(sx, sy, anchor) {
    if (sy === void 0) {
      sy = sx;
    }
    if (!anchor) {
      anchor = getCenter(this.getExtent());
    }
    const flatCoordinates = this.getFlatCoordinates();
    if (flatCoordinates) {
      const stride = this.getStride();
      scale$1(
        flatCoordinates,
        0,
        flatCoordinates.length,
        stride,
        sx,
        sy,
        anchor,
        flatCoordinates
      );
      this.changed();
    }
  }
  /**
   * Translate the geometry.  This modifies the geometry coordinates in place.  If
   * instead you want a new geometry, first `clone()` this geometry.
   * @param {number} deltaX Delta X.
   * @param {number} deltaY Delta Y.
   * @api
   * @override
   */
  translate(deltaX, deltaY) {
    const flatCoordinates = this.getFlatCoordinates();
    if (flatCoordinates) {
      const stride = this.getStride();
      translate(
        flatCoordinates,
        0,
        flatCoordinates.length,
        stride,
        deltaX,
        deltaY,
        flatCoordinates
      );
      this.changed();
    }
  }
}
function getLayoutForStride(stride) {
  let layout;
  if (stride == 2) {
    layout = "XY";
  } else if (stride == 3) {
    layout = "XYZ";
  } else if (stride == 4) {
    layout = "XYZM";
  }
  return (
    /** @type {import("./Geometry.js").GeometryLayout} */
    layout
  );
}
function getStrideForLayout(layout) {
  let stride;
  if (layout == "XY") {
    stride = 2;
  } else if (layout == "XYZ" || layout == "XYM") {
    stride = 3;
  } else if (layout == "XYZM") {
    stride = 4;
  }
  return (
    /** @type {number} */
    stride
  );
}
function transformGeom2D(simpleGeometry, transform2, dest) {
  const flatCoordinates = simpleGeometry.getFlatCoordinates();
  if (!flatCoordinates) {
    return null;
  }
  const stride = simpleGeometry.getStride();
  return transform2D(
    flatCoordinates,
    0,
    flatCoordinates.length,
    stride,
    transform2,
    dest
  );
}
function linearRing(flatCoordinates, offset2, end, stride) {
  let twiceArea = 0;
  const x0 = flatCoordinates[end - stride];
  const y0 = flatCoordinates[end - stride + 1];
  let dx1 = 0;
  let dy1 = 0;
  for (; offset2 < end; offset2 += stride) {
    const dx2 = flatCoordinates[offset2] - x0;
    const dy2 = flatCoordinates[offset2 + 1] - y0;
    twiceArea += dy1 * dx2 - dx1 * dy2;
    dx1 = dx2;
    dy1 = dy2;
  }
  return twiceArea / 2;
}
function linearRings(flatCoordinates, offset2, ends, stride) {
  let area = 0;
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    area += linearRing(flatCoordinates, offset2, end, stride);
    offset2 = end;
  }
  return area;
}
function assignClosest(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {
  const x1 = flatCoordinates[offset1];
  const y1 = flatCoordinates[offset1 + 1];
  const dx = flatCoordinates[offset2] - x1;
  const dy = flatCoordinates[offset2 + 1] - y1;
  let offset3;
  if (dx === 0 && dy === 0) {
    offset3 = offset1;
  } else {
    const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
    if (t > 1) {
      offset3 = offset2;
    } else if (t > 0) {
      for (let i = 0; i < stride; ++i) {
        closestPoint[i] = lerp(
          flatCoordinates[offset1 + i],
          flatCoordinates[offset2 + i],
          t
        );
      }
      closestPoint.length = stride;
      return;
    } else {
      offset3 = offset1;
    }
  }
  for (let i = 0; i < stride; ++i) {
    closestPoint[i] = flatCoordinates[offset3 + i];
  }
  closestPoint.length = stride;
}
function maxSquaredDelta(flatCoordinates, offset2, end, stride, max2) {
  let x1 = flatCoordinates[offset2];
  let y1 = flatCoordinates[offset2 + 1];
  for (offset2 += stride; offset2 < end; offset2 += stride) {
    const x2 = flatCoordinates[offset2];
    const y2 = flatCoordinates[offset2 + 1];
    const squaredDelta = squaredDistance(x1, y1, x2, y2);
    if (squaredDelta > max2) {
      max2 = squaredDelta;
    }
    x1 = x2;
    y1 = y2;
  }
  return max2;
}
function arrayMaxSquaredDelta(flatCoordinates, offset2, ends, stride, max2) {
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    max2 = maxSquaredDelta(flatCoordinates, offset2, end, stride, max2);
    offset2 = end;
  }
  return max2;
}
function assignClosestPoint(flatCoordinates, offset2, end, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint2) {
  if (offset2 == end) {
    return minSquaredDistance;
  }
  let i, squaredDistance$1;
  if (maxDelta === 0) {
    squaredDistance$1 = squaredDistance(
      x,
      y,
      flatCoordinates[offset2],
      flatCoordinates[offset2 + 1]
    );
    if (squaredDistance$1 < minSquaredDistance) {
      for (i = 0; i < stride; ++i) {
        closestPoint[i] = flatCoordinates[offset2 + i];
      }
      closestPoint.length = stride;
      return squaredDistance$1;
    }
    return minSquaredDistance;
  }
  tmpPoint2 = tmpPoint2 ? tmpPoint2 : [NaN, NaN];
  let index = offset2 + stride;
  while (index < end) {
    assignClosest(
      flatCoordinates,
      index - stride,
      index,
      stride,
      x,
      y,
      tmpPoint2
    );
    squaredDistance$1 = squaredDistance(x, y, tmpPoint2[0], tmpPoint2[1]);
    if (squaredDistance$1 < minSquaredDistance) {
      minSquaredDistance = squaredDistance$1;
      for (i = 0; i < stride; ++i) {
        closestPoint[i] = tmpPoint2[i];
      }
      closestPoint.length = stride;
      index += stride;
    } else {
      index += stride * Math.max(
        (Math.sqrt(squaredDistance$1) - Math.sqrt(minSquaredDistance)) / maxDelta | 0,
        1
      );
    }
  }
  if (isRing) {
    assignClosest(
      flatCoordinates,
      end - stride,
      offset2,
      stride,
      x,
      y,
      tmpPoint2
    );
    squaredDistance$1 = squaredDistance(x, y, tmpPoint2[0], tmpPoint2[1]);
    if (squaredDistance$1 < minSquaredDistance) {
      minSquaredDistance = squaredDistance$1;
      for (i = 0; i < stride; ++i) {
        closestPoint[i] = tmpPoint2[i];
      }
      closestPoint.length = stride;
    }
  }
  return minSquaredDistance;
}
function assignClosestArrayPoint(flatCoordinates, offset2, ends, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint2) {
  tmpPoint2 = tmpPoint2 ? tmpPoint2 : [NaN, NaN];
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    minSquaredDistance = assignClosestPoint(
      flatCoordinates,
      offset2,
      end,
      stride,
      maxDelta,
      isRing,
      x,
      y,
      closestPoint,
      minSquaredDistance,
      tmpPoint2
    );
    offset2 = end;
  }
  return minSquaredDistance;
}
function deflateCoordinate(flatCoordinates, offset2, coordinate, stride) {
  for (let i = 0, ii = coordinate.length; i < ii; ++i) {
    flatCoordinates[offset2++] = coordinate[i];
  }
  return offset2;
}
function deflateCoordinates(flatCoordinates, offset2, coordinates2, stride) {
  for (let i = 0, ii = coordinates2.length; i < ii; ++i) {
    const coordinate = coordinates2[i];
    for (let j = 0; j < stride; ++j) {
      flatCoordinates[offset2++] = coordinate[j];
    }
  }
  return offset2;
}
function deflateCoordinatesArray(flatCoordinates, offset2, coordinatess, stride, ends) {
  ends = ends ? ends : [];
  let i = 0;
  for (let j = 0, jj = coordinatess.length; j < jj; ++j) {
    const end = deflateCoordinates(
      flatCoordinates,
      offset2,
      coordinatess[j],
      stride
    );
    ends[i++] = end;
    offset2 = end;
  }
  ends.length = i;
  return ends;
}
function inflateCoordinates(flatCoordinates, offset2, end, stride, coordinates2) {
  coordinates2 = coordinates2 !== void 0 ? coordinates2 : [];
  let i = 0;
  for (let j = offset2; j < end; j += stride) {
    coordinates2[i++] = flatCoordinates.slice(j, j + stride);
  }
  coordinates2.length = i;
  return coordinates2;
}
function inflateCoordinatesArray(flatCoordinates, offset2, ends, stride, coordinatess) {
  coordinatess = coordinatess !== void 0 ? coordinatess : [];
  let i = 0;
  for (let j = 0, jj = ends.length; j < jj; ++j) {
    const end = ends[j];
    coordinatess[i++] = inflateCoordinates(
      flatCoordinates,
      offset2,
      end,
      stride,
      coordinatess[i]
    );
    offset2 = end;
  }
  coordinatess.length = i;
  return coordinatess;
}
function inflateMultiCoordinatesArray(flatCoordinates, offset2, endss, stride, coordinatesss) {
  coordinatesss = coordinatesss !== void 0 ? coordinatesss : [];
  let i = 0;
  for (let j = 0, jj = endss.length; j < jj; ++j) {
    const ends = endss[j];
    coordinatesss[i++] = ends.length === 1 && ends[0] === offset2 ? [] : inflateCoordinatesArray(
      flatCoordinates,
      offset2,
      ends,
      stride,
      coordinatesss[i]
    );
    offset2 = ends[ends.length - 1];
  }
  coordinatesss.length = i;
  return coordinatesss;
}
function douglasPeucker(flatCoordinates, offset2, end, stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
  const n = (end - offset2) / stride;
  if (n < 3) {
    for (; offset2 < end; offset2 += stride) {
      simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset2];
      simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset2 + 1];
    }
    return simplifiedOffset;
  }
  const markers = new Array(n);
  markers[0] = 1;
  markers[n - 1] = 1;
  const stack = [offset2, end - stride];
  let index = 0;
  while (stack.length > 0) {
    const last = stack.pop();
    const first = stack.pop();
    let maxSquaredDistance = 0;
    const x1 = flatCoordinates[first];
    const y1 = flatCoordinates[first + 1];
    const x2 = flatCoordinates[last];
    const y2 = flatCoordinates[last + 1];
    for (let i = first + stride; i < last; i += stride) {
      const x = flatCoordinates[i];
      const y = flatCoordinates[i + 1];
      const squaredDistance2 = squaredSegmentDistance(x, y, x1, y1, x2, y2);
      if (squaredDistance2 > maxSquaredDistance) {
        index = i;
        maxSquaredDistance = squaredDistance2;
      }
    }
    if (maxSquaredDistance > squaredTolerance) {
      markers[(index - offset2) / stride] = 1;
      if (first + stride < index) {
        stack.push(first, index);
      }
      if (index + stride < last) {
        stack.push(index, last);
      }
    }
  }
  for (let i = 0; i < n; ++i) {
    if (markers[i]) {
      simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset2 + i * stride];
      simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset2 + i * stride + 1];
    }
  }
  return simplifiedOffset;
}
function douglasPeuckerArray(flatCoordinates, offset2, ends, stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    simplifiedOffset = douglasPeucker(
      flatCoordinates,
      offset2,
      end,
      stride,
      squaredTolerance,
      simplifiedFlatCoordinates,
      simplifiedOffset
    );
    simplifiedEnds.push(simplifiedOffset);
    offset2 = end;
  }
  return simplifiedOffset;
}
function snap(value, tolerance) {
  return tolerance * Math.round(value / tolerance);
}
function quantize(flatCoordinates, offset2, end, stride, tolerance, simplifiedFlatCoordinates, simplifiedOffset) {
  if (offset2 == end) {
    return simplifiedOffset;
  }
  let x1 = snap(flatCoordinates[offset2], tolerance);
  let y1 = snap(flatCoordinates[offset2 + 1], tolerance);
  offset2 += stride;
  simplifiedFlatCoordinates[simplifiedOffset++] = x1;
  simplifiedFlatCoordinates[simplifiedOffset++] = y1;
  let x2, y2;
  do {
    x2 = snap(flatCoordinates[offset2], tolerance);
    y2 = snap(flatCoordinates[offset2 + 1], tolerance);
    offset2 += stride;
    if (offset2 == end) {
      simplifiedFlatCoordinates[simplifiedOffset++] = x2;
      simplifiedFlatCoordinates[simplifiedOffset++] = y2;
      return simplifiedOffset;
    }
  } while (x2 == x1 && y2 == y1);
  while (offset2 < end) {
    const x3 = snap(flatCoordinates[offset2], tolerance);
    const y3 = snap(flatCoordinates[offset2 + 1], tolerance);
    offset2 += stride;
    if (x3 == x2 && y3 == y2) {
      continue;
    }
    const dx1 = x2 - x1;
    const dy1 = y2 - y1;
    const dx2 = x3 - x1;
    const dy2 = y3 - y1;
    if (dx1 * dy2 == dy1 * dx2 && (dx1 < 0 && dx2 < dx1 || dx1 == dx2 || dx1 > 0 && dx2 > dx1) && (dy1 < 0 && dy2 < dy1 || dy1 == dy2 || dy1 > 0 && dy2 > dy1)) {
      x2 = x3;
      y2 = y3;
      continue;
    }
    simplifiedFlatCoordinates[simplifiedOffset++] = x2;
    simplifiedFlatCoordinates[simplifiedOffset++] = y2;
    x1 = x2;
    y1 = y2;
    x2 = x3;
    y2 = y3;
  }
  simplifiedFlatCoordinates[simplifiedOffset++] = x2;
  simplifiedFlatCoordinates[simplifiedOffset++] = y2;
  return simplifiedOffset;
}
function quantizeArray(flatCoordinates, offset2, ends, stride, tolerance, simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    simplifiedOffset = quantize(
      flatCoordinates,
      offset2,
      end,
      stride,
      tolerance,
      simplifiedFlatCoordinates,
      simplifiedOffset
    );
    simplifiedEnds.push(simplifiedOffset);
    offset2 = end;
  }
  return simplifiedOffset;
}
class LinearRing extends SimpleGeometry {
  /**
   * @param {Array<import("../coordinate.js").Coordinate>|Array<number>} coordinates Coordinates.
   *     For internal use, flat coordinates in combination with `layout` are also accepted.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   */
  constructor(coordinates2, layout) {
    super();
    this.maxDelta_ = -1;
    this.maxDeltaRevision_ = -1;
    if (layout !== void 0 && !Array.isArray(coordinates2[0])) {
      this.setFlatCoordinates(
        layout,
        /** @type {Array<number>} */
        coordinates2
      );
    } else {
      this.setCoordinates(
        /** @type {Array<import("../coordinate.js").Coordinate>} */
        coordinates2,
        layout
      );
    }
  }
  /**
   * Make a complete copy of the geometry.
   * @return {!LinearRing} Clone.
   * @api
   * @override
   */
  clone() {
    return new LinearRing(this.flatCoordinates.slice(), this.layout);
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   * @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @return {number} Minimum squared distance.
   * @override
   */
  closestPointXY(x, y, closestPoint, minSquaredDistance) {
    if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
      return minSquaredDistance;
    }
    if (this.maxDeltaRevision_ != this.getRevision()) {
      this.maxDelta_ = Math.sqrt(
        maxSquaredDelta(
          this.flatCoordinates,
          0,
          this.flatCoordinates.length,
          this.stride,
          0
        )
      );
      this.maxDeltaRevision_ = this.getRevision();
    }
    return assignClosestPoint(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      this.maxDelta_,
      true,
      x,
      y,
      closestPoint,
      minSquaredDistance
    );
  }
  /**
   * Return the area of the linear ring on projected plane.
   * @return {number} Area (on projected plane).
   * @api
   */
  getArea() {
    return linearRing(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride
    );
  }
  /**
   * Return the coordinates of the linear ring.
   * @return {Array<import("../coordinate.js").Coordinate>} Coordinates.
   * @api
   * @override
   */
  getCoordinates() {
    return inflateCoordinates(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride
    );
  }
  /**
   * @param {number} squaredTolerance Squared tolerance.
   * @return {LinearRing} Simplified LinearRing.
   * @protected
   * @override
   */
  getSimplifiedGeometryInternal(squaredTolerance) {
    const simplifiedFlatCoordinates = [];
    simplifiedFlatCoordinates.length = douglasPeucker(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      squaredTolerance,
      simplifiedFlatCoordinates,
      0
    );
    return new LinearRing(simplifiedFlatCoordinates, "XY");
  }
  /**
   * Get the type of this geometry.
   * @return {import("./Geometry.js").Type} Geometry type.
   * @api
   * @override
   */
  getType() {
    return "LinearRing";
  }
  /**
   * Test if the geometry and the passed extent intersect.
   * @param {import("../extent.js").Extent} extent Extent.
   * @return {boolean} `true` if the geometry and the extent intersect.
   * @api
   * @override
   */
  intersectsExtent(extent) {
    return false;
  }
  /**
   * Set the coordinates of the linear ring.
   * @param {!Array<import("../coordinate.js").Coordinate>} coordinates Coordinates.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   * @api
   * @override
   */
  setCoordinates(coordinates2, layout) {
    this.setLayout(layout, coordinates2, 1);
    if (!this.flatCoordinates) {
      this.flatCoordinates = [];
    }
    this.flatCoordinates.length = deflateCoordinates(
      this.flatCoordinates,
      0,
      coordinates2,
      this.stride
    );
    this.changed();
  }
}
let Point$1 = class Point3 extends SimpleGeometry {
  /**
   * @param {import("../coordinate.js").Coordinate} coordinates Coordinates.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   */
  constructor(coordinates2, layout) {
    super();
    this.setCoordinates(coordinates2, layout);
  }
  /**
   * Make a complete copy of the geometry.
   * @return {!Point} Clone.
   * @api
   * @override
   */
  clone() {
    const point = new Point3(this.flatCoordinates.slice(), this.layout);
    point.applyProperties(this);
    return point;
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   * @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @return {number} Minimum squared distance.
   * @override
   */
  closestPointXY(x, y, closestPoint, minSquaredDistance) {
    const flatCoordinates = this.flatCoordinates;
    const squaredDistance$1 = squaredDistance(
      x,
      y,
      flatCoordinates[0],
      flatCoordinates[1]
    );
    if (squaredDistance$1 < minSquaredDistance) {
      const stride = this.stride;
      for (let i = 0; i < stride; ++i) {
        closestPoint[i] = flatCoordinates[i];
      }
      closestPoint.length = stride;
      return squaredDistance$1;
    }
    return minSquaredDistance;
  }
  /**
   * Return the coordinate of the point.
   * @return {import("../coordinate.js").Coordinate} Coordinates.
   * @api
   * @override
   */
  getCoordinates() {
    return this.flatCoordinates.slice();
  }
  /**
   * @param {import("../extent.js").Extent} extent Extent.
   * @protected
   * @return {import("../extent.js").Extent} extent Extent.
   * @override
   */
  computeExtent(extent) {
    return createOrUpdateFromCoordinate(this.flatCoordinates, extent);
  }
  /**
   * Get the type of this geometry.
   * @return {import("./Geometry.js").Type} Geometry type.
   * @api
   * @override
   */
  getType() {
    return "Point";
  }
  /**
   * Test if the geometry and the passed extent intersect.
   * @param {import("../extent.js").Extent} extent Extent.
   * @return {boolean} `true` if the geometry and the extent intersect.
   * @api
   * @override
   */
  intersectsExtent(extent) {
    return containsXY(extent, this.flatCoordinates[0], this.flatCoordinates[1]);
  }
  /**
   * @param {!Array<*>} coordinates Coordinates.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   * @api
   * @override
   */
  setCoordinates(coordinates2, layout) {
    this.setLayout(layout, coordinates2, 0);
    if (!this.flatCoordinates) {
      this.flatCoordinates = [];
    }
    this.flatCoordinates.length = deflateCoordinate(
      this.flatCoordinates,
      0,
      coordinates2,
      this.stride
    );
    this.changed();
  }
};
function linearRingContainsExtent(flatCoordinates, offset2, end, stride, extent) {
  const outside = forEachCorner(
    extent,
    /**
     * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate.
     * @return {boolean} Contains (x, y).
     */
    function(coordinate) {
      return !linearRingContainsXY(
        flatCoordinates,
        offset2,
        end,
        stride,
        coordinate[0],
        coordinate[1]
      );
    }
  );
  return !outside;
}
function linearRingContainsXY(flatCoordinates, offset2, end, stride, x, y) {
  let wn = 0;
  let x1 = flatCoordinates[end - stride];
  let y1 = flatCoordinates[end - stride + 1];
  for (; offset2 < end; offset2 += stride) {
    const x2 = flatCoordinates[offset2];
    const y2 = flatCoordinates[offset2 + 1];
    if (y1 <= y) {
      if (y2 > y && (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1) > 0) {
        wn++;
      }
    } else if (y2 <= y && (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1) < 0) {
      wn--;
    }
    x1 = x2;
    y1 = y2;
  }
  return wn !== 0;
}
function linearRingsContainsXY(flatCoordinates, offset2, ends, stride, x, y) {
  if (ends.length === 0) {
    return false;
  }
  if (!linearRingContainsXY(flatCoordinates, offset2, ends[0], stride, x, y)) {
    return false;
  }
  for (let i = 1, ii = ends.length; i < ii; ++i) {
    if (linearRingContainsXY(flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {
      return false;
    }
  }
  return true;
}
function getInteriorPointOfArray(flatCoordinates, offset2, ends, stride, flatCenters, flatCentersOffset, dest) {
  let i, ii, x, x1, x2, y1, y2;
  const y = flatCenters[flatCentersOffset + 1];
  const intersections = [];
  for (let r = 0, rr = ends.length; r < rr; ++r) {
    const end = ends[r];
    x1 = flatCoordinates[end - stride];
    y1 = flatCoordinates[end - stride + 1];
    for (i = offset2; i < end; i += stride) {
      x2 = flatCoordinates[i];
      y2 = flatCoordinates[i + 1];
      if (y <= y1 && y2 <= y || y1 <= y && y <= y2) {
        x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;
        intersections.push(x);
      }
      x1 = x2;
      y1 = y2;
    }
  }
  let pointX = NaN;
  let maxSegmentLength = -Infinity;
  intersections.sort(ascending);
  x1 = intersections[0];
  for (i = 1, ii = intersections.length; i < ii; ++i) {
    x2 = intersections[i];
    const segmentLength = Math.abs(x2 - x1);
    if (segmentLength > maxSegmentLength) {
      x = (x1 + x2) / 2;
      if (linearRingsContainsXY(flatCoordinates, offset2, ends, stride, x, y)) {
        pointX = x;
        maxSegmentLength = segmentLength;
      }
    }
    x1 = x2;
  }
  if (isNaN(pointX)) {
    pointX = flatCenters[flatCentersOffset];
  }
  if (dest) {
    dest.push(pointX, y, maxSegmentLength);
    return dest;
  }
  return [pointX, y, maxSegmentLength];
}
function getInteriorPointsOfMultiArray(flatCoordinates, offset2, endss, stride, flatCenters) {
  let interiorPoints = [];
  for (let i = 0, ii = endss.length; i < ii; ++i) {
    const ends = endss[i];
    interiorPoints = getInteriorPointOfArray(
      flatCoordinates,
      offset2,
      ends,
      stride,
      flatCenters,
      2 * i,
      interiorPoints
    );
    offset2 = ends[ends.length - 1];
  }
  return interiorPoints;
}
function forEach(flatCoordinates, offset2, end, stride, callback) {
  let ret;
  offset2 += stride;
  for (; offset2 < end; offset2 += stride) {
    ret = callback(
      flatCoordinates.slice(offset2 - stride, offset2),
      flatCoordinates.slice(offset2, offset2 + stride)
    );
    if (ret) {
      return ret;
    }
  }
  return false;
}
function intersectsLineString(flatCoordinates, offset2, end, stride, extent, coordinatesExtent) {
  coordinatesExtent = coordinatesExtent ?? extendFlatCoordinates(createEmpty(), flatCoordinates, offset2, end, stride);
  if (!intersects$1(extent, coordinatesExtent)) {
    return false;
  }
  if (coordinatesExtent[0] >= extent[0] && coordinatesExtent[2] <= extent[2] || coordinatesExtent[1] >= extent[1] && coordinatesExtent[3] <= extent[3]) {
    return true;
  }
  return forEach(
    flatCoordinates,
    offset2,
    end,
    stride,
    /**
     * @param {import("../../coordinate.js").Coordinate} point1 Start point.
     * @param {import("../../coordinate.js").Coordinate} point2 End point.
     * @return {boolean} `true` if the segment and the extent intersect,
     *     `false` otherwise.
     */
    function(point1, point2) {
      return intersectsSegment(extent, point1, point2);
    }
  );
}
function intersectsLinearRing(flatCoordinates, offset2, end, stride, extent) {
  if (intersectsLineString(flatCoordinates, offset2, end, stride, extent)) {
    return true;
  }
  if (linearRingContainsXY(
    flatCoordinates,
    offset2,
    end,
    stride,
    extent[0],
    extent[1]
  )) {
    return true;
  }
  if (linearRingContainsXY(
    flatCoordinates,
    offset2,
    end,
    stride,
    extent[0],
    extent[3]
  )) {
    return true;
  }
  if (linearRingContainsXY(
    flatCoordinates,
    offset2,
    end,
    stride,
    extent[2],
    extent[1]
  )) {
    return true;
  }
  if (linearRingContainsXY(
    flatCoordinates,
    offset2,
    end,
    stride,
    extent[2],
    extent[3]
  )) {
    return true;
  }
  return false;
}
function intersectsLinearRingArray(flatCoordinates, offset2, ends, stride, extent) {
  if (!intersectsLinearRing(flatCoordinates, offset2, ends[0], stride, extent)) {
    return false;
  }
  if (ends.length === 1) {
    return true;
  }
  for (let i = 1, ii = ends.length; i < ii; ++i) {
    if (linearRingContainsExtent(
      flatCoordinates,
      ends[i - 1],
      ends[i],
      stride,
      extent
    )) {
      if (!intersectsLineString(
        flatCoordinates,
        ends[i - 1],
        ends[i],
        stride,
        extent
      )) {
        return false;
      }
    }
  }
  return true;
}
function coordinates(flatCoordinates, offset2, end, stride) {
  while (offset2 < end - stride) {
    for (let i = 0; i < stride; ++i) {
      const tmp = flatCoordinates[offset2 + i];
      flatCoordinates[offset2 + i] = flatCoordinates[end - stride + i];
      flatCoordinates[end - stride + i] = tmp;
    }
    offset2 += stride;
    end -= stride;
  }
}
function linearRingIsClockwise(flatCoordinates, offset2, end, stride) {
  let edge = 0;
  let x1 = flatCoordinates[end - stride];
  let y1 = flatCoordinates[end - stride + 1];
  for (; offset2 < end; offset2 += stride) {
    const x2 = flatCoordinates[offset2];
    const y2 = flatCoordinates[offset2 + 1];
    edge += (x2 - x1) * (y2 + y1);
    x1 = x2;
    y1 = y2;
  }
  return edge === 0 ? void 0 : edge > 0;
}
function linearRingsAreOriented(flatCoordinates, offset2, ends, stride, right) {
  right = right !== void 0 ? right : false;
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    const isClockwise = linearRingIsClockwise(
      flatCoordinates,
      offset2,
      end,
      stride
    );
    if (i === 0) {
      if (right && isClockwise || !right && !isClockwise) {
        return false;
      }
    } else {
      if (right && !isClockwise || !right && isClockwise) {
        return false;
      }
    }
    offset2 = end;
  }
  return true;
}
function orientLinearRings(flatCoordinates, offset2, ends, stride, right) {
  right = right !== void 0 ? right : false;
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    const isClockwise = linearRingIsClockwise(
      flatCoordinates,
      offset2,
      end,
      stride
    );
    const reverse = i === 0 ? right && isClockwise || !right && !isClockwise : right && !isClockwise || !right && isClockwise;
    if (reverse) {
      coordinates(flatCoordinates, offset2, end, stride);
    }
    offset2 = end;
  }
  return offset2;
}
function inflateEnds(flatCoordinates, ends) {
  const endss = [];
  let offset2 = 0;
  let prevEndIndex = 0;
  let startOrientation;
  for (let i = 0, ii = ends.length; i < ii; ++i) {
    const end = ends[i];
    const orientation = linearRingIsClockwise(flatCoordinates, offset2, end, 2);
    if (startOrientation === void 0) {
      startOrientation = orientation;
    }
    if (orientation === startOrientation) {
      endss.push(ends.slice(prevEndIndex, i + 1));
    } else {
      if (endss.length === 0) {
        continue;
      }
      endss[endss.length - 1].push(ends[prevEndIndex]);
    }
    prevEndIndex = i + 1;
    offset2 = end;
  }
  return endss;
}
class Polygon extends SimpleGeometry {
  /**
   * @param {!Array<Array<import("../coordinate.js").Coordinate>>|!Array<number>} coordinates
   *     Array of linear rings that define the polygon. The first linear ring of the
   *     array defines the outer-boundary or surface of the polygon. Each subsequent
   *     linear ring defines a hole in the surface of the polygon. A linear ring is
   *     an array of vertices' coordinates where the first coordinate and the last are
   *     equivalent. (For internal use, flat coordinates in combination with
   *     `layout` and `ends` are also accepted.)
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   * @param {Array<number>} [ends] Ends (for internal use with flat coordinates).
   */
  constructor(coordinates2, layout, ends) {
    super();
    this.ends_ = [];
    this.flatInteriorPointRevision_ = -1;
    this.flatInteriorPoint_ = null;
    this.maxDelta_ = -1;
    this.maxDeltaRevision_ = -1;
    this.orientedRevision_ = -1;
    this.orientedFlatCoordinates_ = null;
    if (layout !== void 0 && ends) {
      this.setFlatCoordinates(
        layout,
        /** @type {Array<number>} */
        coordinates2
      );
      this.ends_ = ends;
    } else {
      this.setCoordinates(
        /** @type {Array<Array<import("../coordinate.js").Coordinate>>} */
        coordinates2,
        layout
      );
    }
  }
  /**
   * Append the passed linear ring to this polygon.
   * @param {LinearRing} linearRing Linear ring.
   * @api
   */
  appendLinearRing(linearRing2) {
    if (!this.flatCoordinates) {
      this.flatCoordinates = linearRing2.getFlatCoordinates().slice();
    } else {
      extend$3(this.flatCoordinates, linearRing2.getFlatCoordinates());
    }
    this.ends_.push(this.flatCoordinates.length);
    this.changed();
  }
  /**
   * Make a complete copy of the geometry.
   * @return {!Polygon} Clone.
   * @api
   * @override
   */
  clone() {
    const polygon = new Polygon(
      this.flatCoordinates.slice(),
      this.layout,
      this.ends_.slice()
    );
    polygon.applyProperties(this);
    return polygon;
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   * @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @return {number} Minimum squared distance.
   * @override
   */
  closestPointXY(x, y, closestPoint, minSquaredDistance) {
    if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
      return minSquaredDistance;
    }
    if (this.maxDeltaRevision_ != this.getRevision()) {
      this.maxDelta_ = Math.sqrt(
        arrayMaxSquaredDelta(
          this.flatCoordinates,
          0,
          this.ends_,
          this.stride,
          0
        )
      );
      this.maxDeltaRevision_ = this.getRevision();
    }
    return assignClosestArrayPoint(
      this.flatCoordinates,
      0,
      this.ends_,
      this.stride,
      this.maxDelta_,
      true,
      x,
      y,
      closestPoint,
      minSquaredDistance
    );
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   * @return {boolean} Contains (x, y).
   * @override
   */
  containsXY(x, y) {
    return linearRingsContainsXY(
      this.getOrientedFlatCoordinates(),
      0,
      this.ends_,
      this.stride,
      x,
      y
    );
  }
  /**
   * Return the area of the polygon on projected plane.
   * @return {number} Area (on projected plane).
   * @api
   */
  getArea() {
    return linearRings(
      this.getOrientedFlatCoordinates(),
      0,
      this.ends_,
      this.stride
    );
  }
  /**
   * Get the coordinate array for this geometry.  This array has the structure
   * of a GeoJSON coordinate array for polygons.
   *
   * @param {boolean} [right] Orient coordinates according to the right-hand
   *     rule (counter-clockwise for exterior and clockwise for interior rings).
   *     If `false`, coordinates will be oriented according to the left-hand rule
   *     (clockwise for exterior and counter-clockwise for interior rings).
   *     By default, coordinate orientation will depend on how the geometry was
   *     constructed.
   * @return {Array<Array<import("../coordinate.js").Coordinate>>} Coordinates.
   * @api
   * @override
   */
  getCoordinates(right) {
    let flatCoordinates;
    if (right !== void 0) {
      flatCoordinates = this.getOrientedFlatCoordinates().slice();
      orientLinearRings(flatCoordinates, 0, this.ends_, this.stride, right);
    } else {
      flatCoordinates = this.flatCoordinates;
    }
    return inflateCoordinatesArray(flatCoordinates, 0, this.ends_, this.stride);
  }
  /**
   * @return {Array<number>} Ends.
   */
  getEnds() {
    return this.ends_;
  }
  /**
   * @return {Array<number>} Interior point.
   */
  getFlatInteriorPoint() {
    if (this.flatInteriorPointRevision_ != this.getRevision()) {
      const flatCenter = getCenter(this.getExtent());
      this.flatInteriorPoint_ = getInteriorPointOfArray(
        this.getOrientedFlatCoordinates(),
        0,
        this.ends_,
        this.stride,
        flatCenter,
        0
      );
      this.flatInteriorPointRevision_ = this.getRevision();
    }
    return (
      /** @type {import("../coordinate.js").Coordinate} */
      this.flatInteriorPoint_
    );
  }
  /**
   * Return an interior point of the polygon.
   * @return {Point} Interior point as XYM coordinate, where M is the
   * length of the horizontal intersection that the point belongs to.
   * @api
   */
  getInteriorPoint() {
    return new Point$1(this.getFlatInteriorPoint(), "XYM");
  }
  /**
   * Return the number of rings of the polygon,  this includes the exterior
   * ring and any interior rings.
   *
   * @return {number} Number of rings.
   * @api
   */
  getLinearRingCount() {
    return this.ends_.length;
  }
  /**
   * Return the Nth linear ring of the polygon geometry. Return `null` if the
   * given index is out of range.
   * The exterior linear ring is available at index `0` and the interior rings
   * at index `1` and beyond.
   *
   * @param {number} index Index.
   * @return {LinearRing|null} Linear ring.
   * @api
   */
  getLinearRing(index) {
    if (index < 0 || this.ends_.length <= index) {
      return null;
    }
    return new LinearRing(
      this.flatCoordinates.slice(
        index === 0 ? 0 : this.ends_[index - 1],
        this.ends_[index]
      ),
      this.layout
    );
  }
  /**
   * Return the linear rings of the polygon.
   * @return {Array<LinearRing>} Linear rings.
   * @api
   */
  getLinearRings() {
    const layout = this.layout;
    const flatCoordinates = this.flatCoordinates;
    const ends = this.ends_;
    const linearRings2 = [];
    let offset2 = 0;
    for (let i = 0, ii = ends.length; i < ii; ++i) {
      const end = ends[i];
      const linearRing2 = new LinearRing(
        flatCoordinates.slice(offset2, end),
        layout
      );
      linearRings2.push(linearRing2);
      offset2 = end;
    }
    return linearRings2;
  }
  /**
   * @return {Array<number>} Oriented flat coordinates.
   */
  getOrientedFlatCoordinates() {
    if (this.orientedRevision_ != this.getRevision()) {
      const flatCoordinates = this.flatCoordinates;
      if (linearRingsAreOriented(flatCoordinates, 0, this.ends_, this.stride)) {
        this.orientedFlatCoordinates_ = flatCoordinates;
      } else {
        this.orientedFlatCoordinates_ = flatCoordinates.slice();
        this.orientedFlatCoordinates_.length = orientLinearRings(
          this.orientedFlatCoordinates_,
          0,
          this.ends_,
          this.stride
        );
      }
      this.orientedRevision_ = this.getRevision();
    }
    return (
      /** @type {Array<number>} */
      this.orientedFlatCoordinates_
    );
  }
  /**
   * @param {number} squaredTolerance Squared tolerance.
   * @return {Polygon} Simplified Polygon.
   * @protected
   * @override
   */
  getSimplifiedGeometryInternal(squaredTolerance) {
    const simplifiedFlatCoordinates = [];
    const simplifiedEnds = [];
    simplifiedFlatCoordinates.length = quantizeArray(
      this.flatCoordinates,
      0,
      this.ends_,
      this.stride,
      Math.sqrt(squaredTolerance),
      simplifiedFlatCoordinates,
      0,
      simplifiedEnds
    );
    return new Polygon(simplifiedFlatCoordinates, "XY", simplifiedEnds);
  }
  /**
   * Get the type of this geometry.
   * @return {import("./Geometry.js").Type} Geometry type.
   * @api
   * @override
   */
  getType() {
    return "Polygon";
  }
  /**
   * Test if the geometry and the passed extent intersect.
   * @param {import("../extent.js").Extent} extent Extent.
   * @return {boolean} `true` if the geometry and the extent intersect.
   * @api
   * @override
   */
  intersectsExtent(extent) {
    return intersectsLinearRingArray(
      this.getOrientedFlatCoordinates(),
      0,
      this.ends_,
      this.stride,
      extent
    );
  }
  /**
   * Set the coordinates of the polygon.
   * @param {!Array<Array<import("../coordinate.js").Coordinate>>} coordinates Coordinates.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   * @api
   * @override
   */
  setCoordinates(coordinates2, layout) {
    this.setLayout(layout, coordinates2, 2);
    if (!this.flatCoordinates) {
      this.flatCoordinates = [];
    }
    const ends = deflateCoordinatesArray(
      this.flatCoordinates,
      0,
      coordinates2,
      this.stride,
      this.ends_
    );
    this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
    this.changed();
  }
}
function fromExtent(extent) {
  if (isEmpty(extent)) {
    throw new Error("Cannot create polygon from empty extent");
  }
  const minX = extent[0];
  const minY = extent[1];
  const maxX = extent[2];
  const maxY = extent[3];
  const flatCoordinates = [
    minX,
    minY,
    minX,
    maxY,
    maxX,
    maxY,
    maxX,
    minY,
    minX,
    minY
  ];
  return new Polygon(flatCoordinates, "XY", [flatCoordinates.length]);
}
function getViewportClampedResolution(resolution, maxExtent, viewportSize, showFullExtent) {
  const xResolution = getWidth(maxExtent) / viewportSize[0];
  const yResolution = getHeight(maxExtent) / viewportSize[1];
  if (showFullExtent) {
    return Math.min(resolution, Math.max(xResolution, yResolution));
  }
  return Math.min(resolution, Math.min(xResolution, yResolution));
}
function getSmoothClampedResolution(resolution, maxResolution, minResolution) {
  let result = Math.min(resolution, maxResolution);
  const ratio = 50;
  result *= Math.log(1 + ratio * Math.max(0, resolution / maxResolution - 1)) / ratio + 1;
  if (minResolution) {
    result = Math.max(result, minResolution);
    result /= Math.log(1 + ratio * Math.max(0, minResolution / resolution - 1)) / ratio + 1;
  }
  return clamp(result, minResolution / 2, maxResolution * 2);
}
function createSnapToResolutions(resolutions, smooth, maxExtent, showFullExtent) {
  smooth = smooth !== void 0 ? smooth : true;
  return (
    /**
     * @param {number|undefined} resolution Resolution.
     * @param {number} direction Direction.
     * @param {import("./size.js").Size} size Viewport size.
     * @param {boolean} [isMoving] True if an interaction or animation is in progress.
     * @return {number|undefined} Resolution.
     */
    (function(resolution, direction, size, isMoving) {
      if (resolution !== void 0) {
        const maxResolution = resolutions[0];
        const minResolution = resolutions[resolutions.length - 1];
        const cappedMaxRes = maxExtent ? getViewportClampedResolution(
          maxResolution,
          maxExtent,
          size,
          showFullExtent
        ) : maxResolution;
        if (isMoving) {
          if (!smooth) {
            return clamp(resolution, minResolution, cappedMaxRes);
          }
          return getSmoothClampedResolution(
            resolution,
            cappedMaxRes,
            minResolution
          );
        }
        const capped = Math.min(cappedMaxRes, resolution);
        const z = Math.floor(linearFindNearest(resolutions, capped, direction));
        if (resolutions[z] > cappedMaxRes && z < resolutions.length - 1) {
          return resolutions[z + 1];
        }
        return resolutions[z];
      }
      return void 0;
    })
  );
}
function createSnapToPower(power, maxResolution, minResolution, smooth, maxExtent, showFullExtent) {
  smooth = smooth !== void 0 ? smooth : true;
  minResolution = minResolution !== void 0 ? minResolution : 0;
  return (
    /**
     * @param {number|undefined} resolution Resolution.
     * @param {number} direction Direction.
     * @param {import("./size.js").Size} size Viewport size.
     * @param {boolean} [isMoving] True if an interaction or animation is in progress.
     * @return {number|undefined} Resolution.
     */
    (function(resolution, direction, size, isMoving) {
      if (resolution !== void 0) {
        const cappedMaxRes = maxExtent ? getViewportClampedResolution(
          maxResolution,
          maxExtent,
          size,
          showFullExtent
        ) : maxResolution;
        if (isMoving) {
          if (!smooth) {
            return clamp(resolution, minResolution, cappedMaxRes);
          }
          return getSmoothClampedResolution(
            resolution,
            cappedMaxRes,
            minResolution
          );
        }
        const tolerance = 1e-9;
        const minZoomLevel = Math.ceil(
          Math.log(maxResolution / cappedMaxRes) / Math.log(power) - tolerance
        );
        const offset2 = -direction * (0.5 - tolerance) + 0.5;
        const capped = Math.min(cappedMaxRes, resolution);
        const cappedZoomLevel = Math.floor(
          Math.log(maxResolution / capped) / Math.log(power) + offset2
        );
        const zoomLevel = Math.max(minZoomLevel, cappedZoomLevel);
        const newResolution = maxResolution / Math.pow(power, zoomLevel);
        return clamp(newResolution, minResolution, cappedMaxRes);
      }
      return void 0;
    })
  );
}
function createMinMaxResolution(maxResolution, minResolution, smooth, maxExtent, showFullExtent) {
  smooth = smooth !== void 0 ? smooth : true;
  return (
    /**
     * @param {number|undefined} resolution Resolution.
     * @param {number} direction Direction.
     * @param {import("./size.js").Size} size Viewport size.
     * @param {boolean} [isMoving] True if an interaction or animation is in progress.
     * @return {number|undefined} Resolution.
     */
    (function(resolution, direction, size, isMoving) {
      if (resolution !== void 0) {
        const cappedMaxRes = maxExtent ? getViewportClampedResolution(
          maxResolution,
          maxExtent,
          size,
          showFullExtent
        ) : maxResolution;
        if (!smooth || !isMoving) {
          return clamp(resolution, minResolution, cappedMaxRes);
        }
        return getSmoothClampedResolution(
          resolution,
          cappedMaxRes,
          minResolution
        );
      }
      return void 0;
    })
  );
}
function disable(rotation) {
  if (rotation !== void 0) {
    return 0;
  }
  return void 0;
}
function none(rotation) {
  if (rotation !== void 0) {
    return rotation;
  }
  return void 0;
}
function createSnapToN(n) {
  const theta = 2 * Math.PI / n;
  return (
    /**
     * @param {number|undefined} rotation Rotation.
     * @param {boolean} [isMoving] True if an interaction or animation is in progress.
     * @return {number|undefined} Rotation.
     */
    (function(rotation, isMoving) {
      if (isMoving) {
        return rotation;
      }
      if (rotation !== void 0) {
        rotation = Math.floor(rotation / theta + 0.5) * theta;
        return rotation;
      }
      return void 0;
    })
  );
}
function createSnapToZero(tolerance) {
  const t = toRadians(5);
  return (
    /**
     * @param {number|undefined} rotation Rotation.
     * @param {boolean} [isMoving] True if an interaction or animation is in progress.
     * @return {number|undefined} Rotation.
     */
    (function(rotation, isMoving) {
      if (isMoving || rotation === void 0) {
        return rotation;
      }
      if (Math.abs(rotation) <= t) {
        return 0;
      }
      return rotation;
    })
  );
}
const DEFAULT_MAX_ZOOM = 42;
const DEFAULT_TILE_SIZE = 256;
const DEFAULT_MIN_ZOOM = 0;
class View extends BaseObject {
  /**
   * @param {ViewOptions} [options] View options.
   */
  constructor(options2) {
    super();
    this.on;
    this.once;
    this.un;
    options2 = Object.assign({}, options2);
    this.hints_ = [0, 0];
    this.animations_ = [];
    this.updateAnimationKey_;
    this.projection_ = createProjection(options2.projection, "EPSG:3857");
    this.viewportSize_ = [100, 100];
    this.targetCenter_ = null;
    this.targetResolution_;
    this.targetRotation_;
    this.nextCenter_ = null;
    this.nextResolution_;
    this.nextRotation_;
    this.cancelAnchor_ = void 0;
    if (options2.projection) {
      disableCoordinateWarning();
    }
    if (options2.center) {
      options2.center = fromUserCoordinate(options2.center, this.projection_);
    }
    if (options2.extent) {
      options2.extent = fromUserExtent(options2.extent, this.projection_);
    }
    this.applyOptions_(options2);
  }
  /**
   * Set up the view with the given options.
   * @param {ViewOptions} options View options.
   */
  applyOptions_(options2) {
    const properties = Object.assign({}, options2);
    for (const key2 in ViewProperty) {
      delete properties[key2];
    }
    this.setProperties(properties, true);
    const resolutionConstraintInfo = createResolutionConstraint(options2);
    this.maxResolution_ = resolutionConstraintInfo.maxResolution;
    this.minResolution_ = resolutionConstraintInfo.minResolution;
    this.zoomFactor_ = resolutionConstraintInfo.zoomFactor;
    this.resolutions_ = options2.resolutions;
    this.padding_ = options2.padding;
    this.minZoom_ = resolutionConstraintInfo.minZoom;
    const centerConstraint = createCenterConstraint(options2);
    const resolutionConstraint = resolutionConstraintInfo.constraint;
    const rotationConstraint = createRotationConstraint(options2);
    this.constraints_ = {
      center: centerConstraint,
      resolution: resolutionConstraint,
      rotation: rotationConstraint
    };
    this.setRotation(options2.rotation !== void 0 ? options2.rotation : 0);
    this.setCenterInternal(
      options2.center !== void 0 ? options2.center : null
    );
    if (options2.resolution !== void 0) {
      this.setResolution(options2.resolution);
    } else if (options2.zoom !== void 0) {
      this.setZoom(options2.zoom);
    }
  }
  /**
   * Padding (in css pixels).
   * If the map viewport is partially covered with other content (overlays) along
   * its edges, this setting allows to shift the center of the viewport away from that
   * content. The order of the values in the array is top, right, bottom, left.
   * The default is no padding, which is equivalent to `[0, 0, 0, 0]`.
   * @type {Array<number>|undefined}
   * @api
   */
  get padding() {
    return this.padding_;
  }
  set padding(padding) {
    let oldPadding = this.padding_;
    this.padding_ = padding;
    const center = this.getCenterInternal();
    if (center) {
      const newPadding = padding || [0, 0, 0, 0];
      oldPadding = oldPadding || [0, 0, 0, 0];
      const resolution = this.getResolution();
      const offsetX = resolution / 2 * (newPadding[3] - oldPadding[3] + oldPadding[1] - newPadding[1]);
      const offsetY = resolution / 2 * (newPadding[0] - oldPadding[0] + oldPadding[2] - newPadding[2]);
      this.setCenterInternal([center[0] + offsetX, center[1] - offsetY]);
    }
  }
  /**
   * Get an updated version of the view options used to construct the view.  The
   * current resolution (or zoom), center, and rotation are applied to any stored
   * options.  The provided options can be used to apply new min/max zoom or
   * resolution limits.
   * @param {ViewOptions} newOptions New options to be applied.
   * @return {ViewOptions} New options updated with the current view state.
   */
  getUpdatedOptions_(newOptions) {
    const options2 = this.getProperties();
    if (options2.resolution !== void 0) {
      options2.resolution = this.getResolution();
    } else {
      options2.zoom = this.getZoom();
    }
    options2.center = this.getCenterInternal();
    options2.rotation = this.getRotation();
    return Object.assign({}, options2, newOptions);
  }
  /**
   * Animate the view.  The view's center, zoom (or resolution), and rotation
   * can be animated for smooth transitions between view states.  For example,
   * to animate the view to a new zoom level:
   *
   *     view.animate({zoom: view.getZoom() + 1});
   *
   * By default, the animation lasts one second and uses in-and-out easing.  You
   * can customize this behavior by including `duration` (in milliseconds) and
   * `easing` options (see {@link module:ol/easing}).
   *
   * To chain together multiple animations, call the method with multiple
   * animation objects.  For example, to first zoom and then pan:
   *
   *     view.animate({zoom: 10}, {center: [0, 0]});
   *
   * If you provide a function as the last argument to the animate method, it
   * will get called at the end of an animation series.  The callback will be
   * called with `true` if the animation series completed on its own or `false`
   * if it was cancelled.
   *
   * Animations are cancelled by user interactions (e.g. dragging the map) or by
   * calling `view.setCenter()`, `view.setResolution()`, or `view.setRotation()`
   * (or another method that calls one of these).
   *
   * @param {...(AnimationOptions|function(boolean): void)} var_args Animation
   *     options.  Multiple animations can be run in series by passing multiple
   *     options objects.  To run multiple animations in parallel, call the method
   *     multiple times.  An optional callback can be provided as a final
   *     argument.  The callback will be called with a boolean indicating whether
   *     the animation completed without being cancelled.
   * @api
   */
  animate(var_args) {
    if (this.isDef() && !this.getAnimating()) {
      this.resolveConstraints(0);
    }
    const args = new Array(arguments.length);
    for (let i = 0; i < args.length; ++i) {
      let options2 = arguments[i];
      if (options2.center) {
        options2 = Object.assign({}, options2);
        options2.center = fromUserCoordinate(
          options2.center,
          this.getProjection()
        );
      }
      if (options2.anchor) {
        options2 = Object.assign({}, options2);
        options2.anchor = fromUserCoordinate(
          options2.anchor,
          this.getProjection()
        );
      }
      args[i] = options2;
    }
    this.animateInternal.apply(this, args);
  }
  /**
   * @param {...(AnimationOptions|function(boolean): void)} var_args Animation options.
   */
  animateInternal(var_args) {
    let animationCount = arguments.length;
    let callback;
    if (animationCount > 1 && typeof arguments[animationCount - 1] === "function") {
      callback = arguments[animationCount - 1];
      --animationCount;
    }
    let i = 0;
    for (; i < animationCount && !this.isDef(); ++i) {
      const state = arguments[i];
      if (state.center) {
        this.setCenterInternal(state.center);
      }
      if (state.zoom !== void 0) {
        this.setZoom(state.zoom);
      } else if (state.resolution) {
        this.setResolution(state.resolution);
      }
      if (state.rotation !== void 0) {
        this.setRotation(state.rotation);
      }
    }
    if (i === animationCount) {
      if (callback) {
        animationCallback(callback, true);
      }
      return;
    }
    let start2 = Date.now();
    let center = this.targetCenter_.slice();
    let resolution = this.targetResolution_;
    let rotation = this.targetRotation_;
    const series = [];
    for (; i < animationCount; ++i) {
      const options2 = (
        /** @type {AnimationOptions} */
        arguments[i]
      );
      const animation = {
        start: start2,
        complete: false,
        anchor: options2.anchor,
        duration: options2.duration !== void 0 ? options2.duration : 1e3,
        easing: options2.easing || inAndOut,
        callback
      };
      if (options2.center) {
        animation.sourceCenter = center;
        animation.targetCenter = options2.center.slice();
        center = animation.targetCenter;
      }
      if (options2.zoom !== void 0) {
        animation.sourceResolution = resolution;
        animation.targetResolution = this.getResolutionForZoom(options2.zoom);
        resolution = animation.targetResolution;
      } else if (options2.resolution) {
        animation.sourceResolution = resolution;
        animation.targetResolution = options2.resolution;
        resolution = animation.targetResolution;
      }
      if (options2.rotation !== void 0) {
        animation.sourceRotation = rotation;
        const delta = modulo(options2.rotation - rotation + Math.PI, 2 * Math.PI) - Math.PI;
        animation.targetRotation = rotation + delta;
        rotation = animation.targetRotation;
      }
      if (isNoopAnimation(animation)) {
        animation.complete = true;
      } else {
        start2 += animation.duration;
      }
      series.push(animation);
    }
    this.animations_.push(series);
    this.setHint(ViewHint.ANIMATING, 1);
    this.updateAnimations_();
  }
  /**
   * Determine if the view is being animated.
   * @return {boolean} The view is being animated.
   * @api
   */
  getAnimating() {
    return this.hints_[ViewHint.ANIMATING] > 0;
  }
  /**
   * Determine if the user is interacting with the view, such as panning or zooming.
   * @return {boolean} The view is being interacted with.
   * @api
   */
  getInteracting() {
    return this.hints_[ViewHint.INTERACTING] > 0;
  }
  /**
   * Cancel any ongoing animations.
   * @api
   */
  cancelAnimations() {
    this.setHint(ViewHint.ANIMATING, -this.hints_[ViewHint.ANIMATING]);
    let anchor;
    for (let i = 0, ii = this.animations_.length; i < ii; ++i) {
      const series = this.animations_[i];
      if (series[0].callback) {
        animationCallback(series[0].callback, false);
      }
      if (!anchor) {
        for (let j = 0, jj = series.length; j < jj; ++j) {
          const animation = series[j];
          if (!animation.complete) {
            anchor = animation.anchor;
            break;
          }
        }
      }
    }
    this.animations_.length = 0;
    this.cancelAnchor_ = anchor;
    this.nextCenter_ = null;
    this.nextResolution_ = NaN;
    this.nextRotation_ = NaN;
  }
  /**
   * Update all animations.
   */
  updateAnimations_() {
    if (this.updateAnimationKey_ !== void 0) {
      cancelAnimationFrame(this.updateAnimationKey_);
      this.updateAnimationKey_ = void 0;
    }
    if (!this.getAnimating()) {
      return;
    }
    const now = Date.now();
    let more = false;
    for (let i = this.animations_.length - 1; i >= 0; --i) {
      const series = this.animations_[i];
      let seriesComplete = true;
      for (let j = 0, jj = series.length; j < jj; ++j) {
        const animation = series[j];
        if (animation.complete) {
          continue;
        }
        const elapsed = now - animation.start;
        let fraction = animation.duration > 0 ? elapsed / animation.duration : 1;
        if (fraction >= 1) {
          animation.complete = true;
          fraction = 1;
        } else {
          seriesComplete = false;
        }
        const progress = animation.easing(fraction);
        if (animation.sourceCenter) {
          const x0 = animation.sourceCenter[0];
          const y0 = animation.sourceCenter[1];
          const x1 = animation.targetCenter[0];
          const y1 = animation.targetCenter[1];
          this.nextCenter_ = animation.targetCenter;
          const x = x0 + progress * (x1 - x0);
          const y = y0 + progress * (y1 - y0);
          this.targetCenter_ = [x, y];
        }
        if (animation.sourceResolution && animation.targetResolution) {
          const resolution = progress === 1 ? animation.targetResolution : animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);
          if (animation.anchor) {
            const size = this.getViewportSize_(this.getRotation());
            const constrainedResolution = this.constraints_.resolution(
              resolution,
              0,
              size,
              true
            );
            this.targetCenter_ = this.calculateCenterZoom(
              constrainedResolution,
              animation.anchor
            );
          }
          this.nextResolution_ = animation.targetResolution;
          this.targetResolution_ = resolution;
          this.applyTargetState_(true);
        }
        if (animation.sourceRotation !== void 0 && animation.targetRotation !== void 0) {
          const rotation = progress === 1 ? modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI : animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation);
          if (animation.anchor) {
            const constrainedRotation = this.constraints_.rotation(
              rotation,
              true
            );
            this.targetCenter_ = this.calculateCenterRotate(
              constrainedRotation,
              animation.anchor
            );
          }
          this.nextRotation_ = animation.targetRotation;
          this.targetRotation_ = rotation;
        }
        this.applyTargetState_(true);
        more = true;
        if (!animation.complete) {
          break;
        }
      }
      if (seriesComplete) {
        this.animations_[i] = null;
        this.setHint(ViewHint.ANIMATING, -1);
        this.nextCenter_ = null;
        this.nextResolution_ = NaN;
        this.nextRotation_ = NaN;
        const callback = series[0].callback;
        if (callback) {
          animationCallback(callback, true);
        }
      }
    }
    this.animations_ = this.animations_.filter(Boolean);
    if (more && this.updateAnimationKey_ === void 0) {
      this.updateAnimationKey_ = requestAnimationFrame(
        this.updateAnimations_.bind(this)
      );
    }
  }
  /**
   * @param {number} rotation Target rotation.
   * @param {import("./coordinate.js").Coordinate} anchor Rotation anchor.
   * @return {import("./coordinate.js").Coordinate|undefined} Center for rotation and anchor.
   */
  calculateCenterRotate(rotation, anchor) {
    let center;
    const currentCenter = this.getCenterInternal();
    if (currentCenter !== void 0) {
      center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]];
      rotate$1(center, rotation - this.getRotation());
      add$3(center, anchor);
    }
    return center;
  }
  /**
   * @param {number} resolution Target resolution.
   * @param {import("./coordinate.js").Coordinate} anchor Zoom anchor.
   * @return {import("./coordinate.js").Coordinate|undefined} Center for resolution and anchor.
   */
  calculateCenterZoom(resolution, anchor) {
    let center;
    const currentCenter = this.getCenterInternal();
    const currentResolution = this.getResolution();
    if (currentCenter !== void 0 && currentResolution !== void 0) {
      const x = anchor[0] - resolution * (anchor[0] - currentCenter[0]) / currentResolution;
      const y = anchor[1] - resolution * (anchor[1] - currentCenter[1]) / currentResolution;
      center = [x, y];
    }
    return center;
  }
  /**
   * Returns the current viewport size.
   * @private
   * @param {number} [rotation] Take into account the rotation of the viewport when giving the size
   * @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
   */
  getViewportSize_(rotation) {
    const size = this.viewportSize_;
    if (rotation) {
      const w = size[0];
      const h = size[1];
      return [
        Math.abs(w * Math.cos(rotation)) + Math.abs(h * Math.sin(rotation)),
        Math.abs(w * Math.sin(rotation)) + Math.abs(h * Math.cos(rotation))
      ];
    }
    return size;
  }
  /**
   * Stores the viewport size on the view. The viewport size is not read every time from the DOM
   * to avoid performance hit and layout reflow.
   * This should be done on map size change.
   * Note: the constraints are not resolved during an animation to avoid stopping it
   * @param {import("./size.js").Size} [size] Viewport size; if undefined, [100, 100] is assumed
   */
  setViewportSize(size) {
    this.viewportSize_ = Array.isArray(size) ? size.slice() : [100, 100];
    if (!this.getAnimating()) {
      this.resolveConstraints(0);
    }
  }
  /**
   * Get the view center.
   * @return {import("./coordinate.js").Coordinate|undefined} The center of the view.
   * @observable
   * @api
   */
  getCenter() {
    const center = this.getCenterInternal();
    if (!center) {
      return center;
    }
    return toUserCoordinate(center, this.getProjection());
  }
  /**
   * Get the view center without transforming to user projection.
   * @return {import("./coordinate.js").Coordinate|undefined} The center of the view.
   */
  getCenterInternal() {
    return (
      /** @type {import("./coordinate.js").Coordinate|undefined} */
      this.get(ViewProperty.CENTER)
    );
  }
  /**
   * @return {Constraints} Constraints.
   */
  getConstraints() {
    return this.constraints_;
  }
  /**
   * @return {boolean} Resolution constraint is set
   */
  getConstrainResolution() {
    return this.get("constrainResolution");
  }
  /**
   * @param {Array<number>} [hints] Destination array.
   * @return {Array<number>} Hint.
   */
  getHints(hints) {
    if (hints !== void 0) {
      hints[0] = this.hints_[0];
      hints[1] = this.hints_[1];
      return hints;
    }
    return this.hints_.slice();
  }
  /**
   * Calculate the extent for the current view state and the passed box size.
   * @param {import("./size.js").Size} [size] The pixel dimensions of the box
   * into which the calculated extent should fit. Defaults to the size of the
   * map the view is associated with.
   * If no map or multiple maps are connected to the view, provide the desired
   * box size (e.g. `map.getSize()`).
   * @return {import("./extent.js").Extent} Extent.
   * @api
   */
  calculateExtent(size) {
    const extent = this.calculateExtentInternal(size);
    return toUserExtent(extent, this.getProjection());
  }
  /**
   * @param {import("./size.js").Size} [size] Box pixel size. If not provided,
   * the map's last known viewport size will be used.
   * @return {import("./extent.js").Extent} Extent.
   */
  calculateExtentInternal(size) {
    size = size || this.getViewportSizeMinusPadding_();
    const center = (
      /** @type {!import("./coordinate.js").Coordinate} */
      this.getCenterInternal()
    );
    assert(center, "The view center is not defined");
    const resolution = (
      /** @type {!number} */
      this.getResolution()
    );
    assert(resolution !== void 0, "The view resolution is not defined");
    const rotation = (
      /** @type {!number} */
      this.getRotation()
    );
    assert(rotation !== void 0, "The view rotation is not defined");
    return getForViewAndSize(center, resolution, rotation, size);
  }
  /**
   * Get the maximum resolution of the view.
   * @return {number} The maximum resolution of the view.
   * @api
   */
  getMaxResolution() {
    return this.maxResolution_;
  }
  /**
   * Get the minimum resolution of the view.
   * @return {number} The minimum resolution of the view.
   * @api
   */
  getMinResolution() {
    return this.minResolution_;
  }
  /**
   * Get the maximum zoom level for the view.
   * @return {number} The maximum zoom level.
   * @api
   */
  getMaxZoom() {
    return (
      /** @type {number} */
      this.getZoomForResolution(this.minResolution_)
    );
  }
  /**
   * Set a new maximum zoom level for the view.
   * @param {number} zoom The maximum zoom level.
   * @api
   */
  setMaxZoom(zoom) {
    this.applyOptions_(this.getUpdatedOptions_({ maxZoom: zoom }));
  }
  /**
   * Get the minimum zoom level for the view.
   * @return {number} The minimum zoom level.
   * @api
   */
  getMinZoom() {
    return (
      /** @type {number} */
      this.getZoomForResolution(this.maxResolution_)
    );
  }
  /**
   * Set a new minimum zoom level for the view.
   * @param {number} zoom The minimum zoom level.
   * @api
   */
  setMinZoom(zoom) {
    this.applyOptions_(this.getUpdatedOptions_({ minZoom: zoom }));
  }
  /**
   * Set whether the view should allow intermediary zoom levels.
   * @param {boolean} enabled Whether the resolution is constrained.
   * @api
   */
  setConstrainResolution(enabled) {
    this.applyOptions_(this.getUpdatedOptions_({ constrainResolution: enabled }));
  }
  /**
   * Get the view projection.
   * @return {import("./proj/Projection.js").default} The projection of the view.
   * @api
   */
  getProjection() {
    return this.projection_;
  }
  /**
   * Get the view resolution.
   * @return {number|undefined} The resolution of the view.
   * @observable
   * @api
   */
  getResolution() {
    return (
      /** @type {number|undefined} */
      this.get(ViewProperty.RESOLUTION)
    );
  }
  /**
   * Get the resolutions for the view. This returns the array of resolutions
   * passed to the constructor of the View, or undefined if none were given.
   * @return {Array<number>|undefined} The resolutions of the view.
   * @api
   */
  getResolutions() {
    return this.resolutions_;
  }
  /**
   * Get the resolution for a provided extent (in map units) and size (in pixels).
   * @param {import("./extent.js").Extent} extent Extent.
   * @param {import("./size.js").Size} [size] Box pixel size.
   * @return {number} The resolution at which the provided extent will render at
   *     the given size.
   * @api
   */
  getResolutionForExtent(extent, size) {
    return this.getResolutionForExtentInternal(
      fromUserExtent(extent, this.getProjection()),
      size
    );
  }
  /**
   * Get the resolution for a provided extent (in map units) and size (in pixels).
   * @param {import("./extent.js").Extent} extent Extent.
   * @param {import("./size.js").Size} [size] Box pixel size.
   * @return {number} The resolution at which the provided extent will render at
   *     the given size.
   */
  getResolutionForExtentInternal(extent, size) {
    size = size || this.getViewportSizeMinusPadding_();
    const xResolution = getWidth(extent) / size[0];
    const yResolution = getHeight(extent) / size[1];
    return Math.max(xResolution, yResolution);
  }
  /**
   * Return a function that returns a value between 0 and 1 for a
   * resolution. Exponential scaling is assumed.
   * @param {number} [power] Power.
   * @return {function(number): number} Resolution for value function.
   */
  getResolutionForValueFunction(power) {
    power = power || 2;
    const maxResolution = this.getConstrainedResolution(this.maxResolution_);
    const minResolution = this.minResolution_;
    const max2 = Math.log(maxResolution / minResolution) / Math.log(power);
    return (
      /**
       * @param {number} value Value.
       * @return {number} Resolution.
       */
      (function(value) {
        const resolution = maxResolution / Math.pow(power, value * max2);
        return resolution;
      })
    );
  }
  /**
   * Get the view rotation.
   * @return {number} The rotation of the view in radians.
   * @observable
   * @api
   */
  getRotation() {
    return (
      /** @type {number} */
      this.get(ViewProperty.ROTATION)
    );
  }
  /**
   * Return a function that returns a resolution for a value between
   * 0 and 1. Exponential scaling is assumed.
   * @param {number} [power] Power.
   * @return {function(number): number} Value for resolution function.
   */
  getValueForResolutionFunction(power) {
    const logPower = Math.log(power || 2);
    const maxResolution = this.getConstrainedResolution(this.maxResolution_);
    const minResolution = this.minResolution_;
    const max2 = Math.log(maxResolution / minResolution) / logPower;
    return (
      /**
       * @param {number} resolution Resolution.
       * @return {number} Value.
       */
      (function(resolution) {
        const value = Math.log(maxResolution / resolution) / logPower / max2;
        return value;
      })
    );
  }
  /**
   * Returns the size of the viewport minus padding.
   * @private
   * @param {number} [rotation] Take into account the rotation of the viewport when giving the size
   * @return {import("./size.js").Size} Viewport size reduced by the padding.
   */
  getViewportSizeMinusPadding_(rotation) {
    let size = this.getViewportSize_(rotation);
    const padding = this.padding_;
    if (padding) {
      size = [
        size[0] - padding[1] - padding[3],
        size[1] - padding[0] - padding[2]
      ];
    }
    return size;
  }
  /**
   * @return {State} View state.
   */
  getState() {
    const projection = this.getProjection();
    const resolution = this.getResolution();
    const rotation = this.getRotation();
    let center = (
      /** @type {import("./coordinate.js").Coordinate} */
      this.getCenterInternal()
    );
    const padding = this.padding_;
    if (padding) {
      const reducedSize = this.getViewportSizeMinusPadding_();
      center = calculateCenterOn(
        center,
        this.getViewportSize_(),
        [reducedSize[0] / 2 + padding[3], reducedSize[1] / 2 + padding[0]],
        resolution,
        rotation
      );
    }
    return {
      center: center.slice(0),
      projection: projection !== void 0 ? projection : null,
      resolution,
      nextCenter: this.nextCenter_,
      nextResolution: this.nextResolution_,
      nextRotation: this.nextRotation_,
      rotation,
      zoom: this.getZoom()
    };
  }
  /**
   * @return {ViewStateLayerStateExtent} Like `FrameState`, but just `viewState` and `extent`.
   */
  getViewStateAndExtent() {
    return {
      viewState: this.getState(),
      extent: this.calculateExtent()
    };
  }
  /**
   * Get the current zoom level. This method may return non-integer zoom levels
   * if the view does not constrain the resolution, or if an interaction or
   * animation is underway.
   * @return {number|undefined} Zoom.
   * @api
   */
  getZoom() {
    let zoom;
    const resolution = this.getResolution();
    if (resolution !== void 0) {
      zoom = this.getZoomForResolution(resolution);
    }
    return zoom;
  }
  /**
   * Get the zoom level for a resolution.
   * @param {number} resolution The resolution.
   * @return {number|undefined} The zoom level for the provided resolution.
   * @api
   */
  getZoomForResolution(resolution) {
    let offset2 = this.minZoom_ || 0;
    let max2, zoomFactor;
    if (this.resolutions_) {
      const nearest = linearFindNearest(this.resolutions_, resolution, 1);
      offset2 = nearest;
      max2 = this.resolutions_[nearest];
      if (nearest == this.resolutions_.length - 1) {
        zoomFactor = 2;
      } else {
        zoomFactor = max2 / this.resolutions_[nearest + 1];
      }
    } else {
      max2 = this.maxResolution_;
      zoomFactor = this.zoomFactor_;
    }
    return offset2 + Math.log(max2 / resolution) / Math.log(zoomFactor);
  }
  /**
   * Get the resolution for a zoom level.
   * @param {number} zoom Zoom level.
   * @return {number} The view resolution for the provided zoom level.
   * @api
   */
  getResolutionForZoom(zoom) {
    if (this.resolutions_?.length) {
      if (this.resolutions_.length === 1) {
        return this.resolutions_[0];
      }
      const baseLevel = clamp(
        Math.floor(zoom),
        0,
        this.resolutions_.length - 2
      );
      const zoomFactor = this.resolutions_[baseLevel] / this.resolutions_[baseLevel + 1];
      return this.resolutions_[baseLevel] / Math.pow(zoomFactor, clamp(zoom - baseLevel, 0, 1));
    }
    return this.maxResolution_ / Math.pow(this.zoomFactor_, zoom - this.minZoom_);
  }
  /**
   * Fit the given geometry or extent based on the given map size and border.
   * The size is pixel dimensions of the box to fit the extent into.
   * In most cases you will want to use the map size, that is `map.getSize()`.
   * Takes care of the map angle.
   * @param {import("./geom/SimpleGeometry.js").default|import("./extent.js").Extent} geometryOrExtent The geometry or
   *     extent to fit the view to.
   * @param {FitOptions} [options] Options.
   * @api
   */
  fit(geometryOrExtent, options2) {
    let geometry;
    assert(
      Array.isArray(geometryOrExtent) || typeof /** @type {?} */
      geometryOrExtent.getSimplifiedGeometry === "function",
      "Invalid extent or geometry provided as `geometry`"
    );
    if (Array.isArray(geometryOrExtent)) {
      assert(
        !isEmpty(geometryOrExtent),
        "Cannot fit empty extent provided as `geometry`"
      );
      const extent = fromUserExtent(geometryOrExtent, this.getProjection());
      geometry = fromExtent(extent);
    } else if (geometryOrExtent.getType() === "Circle") {
      const extent = fromUserExtent(
        geometryOrExtent.getExtent(),
        this.getProjection()
      );
      geometry = fromExtent(extent);
      geometry.rotate(this.getRotation(), getCenter(extent));
    } else {
      const userProjection2 = getUserProjection();
      if (userProjection2) {
        geometry = /** @type {import("./geom/SimpleGeometry.js").default} */
        geometryOrExtent.clone().transform(userProjection2, this.getProjection());
      } else {
        geometry = geometryOrExtent;
      }
    }
    this.fitInternal(geometry, options2);
  }
  /**
   * Calculate rotated extent
   * @param {import("./geom/SimpleGeometry.js").default} geometry The geometry.
   * @return {import("./extent").Extent} The rotated extent for the geometry.
   */
  rotatedExtentForGeometry(geometry) {
    const rotation = this.getRotation();
    const cosAngle = Math.cos(rotation);
    const sinAngle = Math.sin(-rotation);
    const coords = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    let minRotX = Infinity;
    let minRotY = Infinity;
    let maxRotX = -Infinity;
    let maxRotY = -Infinity;
    for (let i = 0, ii = coords.length; i < ii; i += stride) {
      const rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;
      const rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;
      minRotX = Math.min(minRotX, rotX);
      minRotY = Math.min(minRotY, rotY);
      maxRotX = Math.max(maxRotX, rotX);
      maxRotY = Math.max(maxRotY, rotY);
    }
    return [minRotX, minRotY, maxRotX, maxRotY];
  }
  /**
   * @param {import("./geom/SimpleGeometry.js").default} geometry The geometry.
   * @param {FitOptions} [options] Options.
   */
  fitInternal(geometry, options2) {
    options2 = options2 || {};
    let size = options2.size;
    if (!size) {
      size = this.getViewportSizeMinusPadding_();
    }
    const padding = options2.padding !== void 0 ? options2.padding : [0, 0, 0, 0];
    const nearest = options2.nearest !== void 0 ? options2.nearest : false;
    let minResolution;
    if (options2.minResolution !== void 0) {
      minResolution = options2.minResolution;
    } else if (options2.maxZoom !== void 0) {
      minResolution = this.getResolutionForZoom(options2.maxZoom);
    } else {
      minResolution = 0;
    }
    const rotatedExtent = this.rotatedExtentForGeometry(geometry);
    let resolution = this.getResolutionForExtentInternal(rotatedExtent, [
      size[0] - padding[1] - padding[3],
      size[1] - padding[0] - padding[2]
    ]);
    resolution = isNaN(resolution) ? minResolution : Math.max(resolution, minResolution);
    resolution = this.getConstrainedResolution(resolution, nearest ? 0 : 1);
    const rotation = this.getRotation();
    const sinAngle = Math.sin(rotation);
    const cosAngle = Math.cos(rotation);
    const centerRot = getCenter(rotatedExtent);
    centerRot[0] += (padding[1] - padding[3]) / 2 * resolution;
    centerRot[1] += (padding[0] - padding[2]) / 2 * resolution;
    const centerX = centerRot[0] * cosAngle - centerRot[1] * sinAngle;
    const centerY = centerRot[1] * cosAngle + centerRot[0] * sinAngle;
    const center = this.getConstrainedCenter([centerX, centerY], resolution);
    const callback = options2.callback ? options2.callback : VOID;
    if (options2.duration !== void 0) {
      this.animateInternal(
        {
          resolution,
          center,
          duration: options2.duration,
          easing: options2.easing
        },
        callback
      );
    } else {
      this.targetResolution_ = resolution;
      this.targetCenter_ = center;
      this.applyTargetState_(false, true);
      animationCallback(callback, true);
    }
  }
  /**
   * Center on coordinate and view position.
   * @param {import("./coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("./size.js").Size} size Box pixel size.
   * @param {import("./pixel.js").Pixel} position Position on the view to center on.
   * @api
   */
  centerOn(coordinate, size, position) {
    this.centerOnInternal(
      fromUserCoordinate(coordinate, this.getProjection()),
      size,
      position
    );
  }
  /**
   * @param {import("./coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("./size.js").Size} size Box pixel size.
   * @param {import("./pixel.js").Pixel} position Position on the view to center on.
   */
  centerOnInternal(coordinate, size, position) {
    this.setCenterInternal(
      calculateCenterOn(
        coordinate,
        size,
        position,
        this.getResolution(),
        this.getRotation()
      )
    );
  }
  /**
   * Calculates the shift between map and viewport center.
   * @param {import("./coordinate.js").Coordinate} center Center.
   * @param {number} resolution Resolution.
   * @param {number} rotation Rotation.
   * @param {import("./size.js").Size} size Size.
   * @return {Array<number>|undefined} Center shift.
   */
  calculateCenterShift(center, resolution, rotation, size) {
    let centerShift;
    const padding = this.padding_;
    if (padding && center) {
      const reducedSize = this.getViewportSizeMinusPadding_(-rotation);
      const shiftedCenter = calculateCenterOn(
        center,
        size,
        [reducedSize[0] / 2 + padding[3], reducedSize[1] / 2 + padding[0]],
        resolution,
        rotation
      );
      centerShift = [
        center[0] - shiftedCenter[0],
        center[1] - shiftedCenter[1]
      ];
    }
    return centerShift;
  }
  /**
   * @return {boolean} Is defined.
   */
  isDef() {
    return !!this.getCenterInternal() && this.getResolution() !== void 0;
  }
  /**
   * Adds relative coordinates to the center of the view. Any extent constraint will apply.
   * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add.
   * @api
   */
  adjustCenter(deltaCoordinates) {
    const center = toUserCoordinate(this.targetCenter_, this.getProjection());
    this.setCenter([
      center[0] + deltaCoordinates[0],
      center[1] + deltaCoordinates[1]
    ]);
  }
  /**
   * Adds relative coordinates to the center of the view. Any extent constraint will apply.
   * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add.
   */
  adjustCenterInternal(deltaCoordinates) {
    const center = this.targetCenter_;
    this.setCenterInternal([
      center[0] + deltaCoordinates[0],
      center[1] + deltaCoordinates[1]
    ]);
  }
  /**
   * Multiply the view resolution by a ratio, optionally using an anchor. Any resolution
   * constraint will apply.
   * @param {number} ratio The ratio to apply on the view resolution.
   * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation.
   * @api
   */
  adjustResolution(ratio, anchor) {
    anchor = anchor && fromUserCoordinate(anchor, this.getProjection());
    this.adjustResolutionInternal(ratio, anchor);
  }
  /**
   * Multiply the view resolution by a ratio, optionally using an anchor. Any resolution
   * constraint will apply.
   * @param {number} ratio The ratio to apply on the view resolution.
   * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation.
   */
  adjustResolutionInternal(ratio, anchor) {
    const isMoving = this.getAnimating() || this.getInteracting();
    const size = this.getViewportSize_(this.getRotation());
    const newResolution = this.constraints_.resolution(
      this.targetResolution_ * ratio,
      0,
      size,
      isMoving
    );
    if (anchor) {
      this.targetCenter_ = this.calculateCenterZoom(newResolution, anchor);
    }
    this.targetResolution_ *= ratio;
    this.applyTargetState_();
  }
  /**
   * Adds a value to the view zoom level, optionally using an anchor. Any resolution
   * constraint will apply.
   * @param {number} delta Relative value to add to the zoom level.
   * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation.
   * @api
   */
  adjustZoom(delta, anchor) {
    this.adjustResolution(Math.pow(this.zoomFactor_, -delta), anchor);
  }
  /**
   * Adds a value to the view rotation, optionally using an anchor. Any rotation
   * constraint will apply.
   * @param {number} delta Relative value to add to the zoom rotation, in radians.
   * @param {import("./coordinate.js").Coordinate} [anchor] The rotation center.
   * @api
   */
  adjustRotation(delta, anchor) {
    if (anchor) {
      anchor = fromUserCoordinate(anchor, this.getProjection());
    }
    this.adjustRotationInternal(delta, anchor);
  }
  /**
   * @param {number} delta Relative value to add to the zoom rotation, in radians.
   * @param {import("./coordinate.js").Coordinate} [anchor] The rotation center.
   */
  adjustRotationInternal(delta, anchor) {
    const isMoving = this.getAnimating() || this.getInteracting();
    const newRotation = this.constraints_.rotation(
      this.targetRotation_ + delta,
      isMoving
    );
    if (anchor) {
      this.targetCenter_ = this.calculateCenterRotate(newRotation, anchor);
    }
    this.targetRotation_ += delta;
    this.applyTargetState_();
  }
  /**
   * Set the center of the current view. Any extent constraint will apply.
   * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view.
   * @observable
   * @api
   */
  setCenter(center) {
    this.setCenterInternal(
      center ? fromUserCoordinate(center, this.getProjection()) : center
    );
  }
  /**
   * Set the center using the view projection (not the user projection).
   * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view.
   */
  setCenterInternal(center) {
    this.targetCenter_ = center;
    this.applyTargetState_();
  }
  /**
   * @param {import("./ViewHint.js").default} hint Hint.
   * @param {number} delta Delta.
   * @return {number} New value.
   */
  setHint(hint, delta) {
    this.hints_[hint] += delta;
    this.changed();
    return this.hints_[hint];
  }
  /**
   * Set the resolution for this view. Any resolution constraint will apply.
   * @param {number|undefined} resolution The resolution of the view.
   * @observable
   * @api
   */
  setResolution(resolution) {
    this.targetResolution_ = resolution;
    this.applyTargetState_();
  }
  /**
   * Set the rotation for this view. Any rotation constraint will apply.
   * @param {number} rotation The rotation of the view in radians.
   * @observable
   * @api
   */
  setRotation(rotation) {
    this.targetRotation_ = rotation;
    this.applyTargetState_();
  }
  /**
   * Zoom to a specific zoom level. Any resolution constrain will apply.
   * @param {number} zoom Zoom level.
   * @api
   */
  setZoom(zoom) {
    this.setResolution(this.getResolutionForZoom(zoom));
  }
  /**
   * Recompute rotation/resolution/center based on target values.
   * Note: we have to compute rotation first, then resolution and center considering that
   * parameters can influence one another in case a view extent constraint is present.
   * @param {boolean} [doNotCancelAnims] Do not cancel animations.
   * @param {boolean} [forceMoving] Apply constraints as if the view is moving.
   * @private
   */
  applyTargetState_(doNotCancelAnims, forceMoving) {
    const isMoving = this.getAnimating() || this.getInteracting() || forceMoving;
    const newRotation = this.constraints_.rotation(
      this.targetRotation_,
      isMoving
    );
    const size = this.getViewportSize_(newRotation);
    const newResolution = this.constraints_.resolution(
      this.targetResolution_,
      0,
      size,
      isMoving
    );
    const newCenter = this.constraints_.center(
      this.targetCenter_,
      newResolution,
      size,
      isMoving,
      this.calculateCenterShift(
        this.targetCenter_,
        newResolution,
        newRotation,
        size
      )
    );
    if (this.get(ViewProperty.ROTATION) !== newRotation) {
      this.set(ViewProperty.ROTATION, newRotation);
    }
    if (this.get(ViewProperty.RESOLUTION) !== newResolution) {
      this.set(ViewProperty.RESOLUTION, newResolution);
      this.set("zoom", this.getZoom(), true);
    }
    if (!newCenter || !this.get(ViewProperty.CENTER) || !equals(this.get(ViewProperty.CENTER), newCenter)) {
      this.set(ViewProperty.CENTER, newCenter);
    }
    if (this.getAnimating() && !doNotCancelAnims) {
      this.cancelAnimations();
    }
    this.cancelAnchor_ = void 0;
  }
  /**
   * If any constraints need to be applied, an animation will be triggered.
   * This is typically done on interaction end.
   * Note: calling this with a duration of 0 will apply the constrained values straight away,
   * without animation.
   * @param {number} [duration] The animation duration in ms.
   * @param {number} [resolutionDirection] Which direction to zoom.
   * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation.
   */
  resolveConstraints(duration, resolutionDirection, anchor) {
    duration = duration !== void 0 ? duration : 200;
    const direction = resolutionDirection || 0;
    const newRotation = this.constraints_.rotation(this.targetRotation_);
    const size = this.getViewportSize_(newRotation);
    const newResolution = this.constraints_.resolution(
      this.targetResolution_,
      direction,
      size
    );
    const newCenter = this.constraints_.center(
      this.targetCenter_,
      newResolution,
      size,
      false,
      this.calculateCenterShift(
        this.targetCenter_,
        newResolution,
        newRotation,
        size
      )
    );
    if (duration === 0 && !this.cancelAnchor_) {
      this.targetResolution_ = newResolution;
      this.targetRotation_ = newRotation;
      this.targetCenter_ = newCenter;
      this.applyTargetState_();
      return;
    }
    anchor = anchor || (duration === 0 ? this.cancelAnchor_ : void 0);
    this.cancelAnchor_ = void 0;
    if (this.getResolution() !== newResolution || this.getRotation() !== newRotation || !this.getCenterInternal() || !equals(this.getCenterInternal(), newCenter)) {
      if (this.getAnimating()) {
        this.cancelAnimations();
      }
      this.animateInternal({
        rotation: newRotation,
        center: newCenter,
        resolution: newResolution,
        duration,
        easing: easeOut,
        anchor
      });
    }
  }
  /**
   * Notify the View that an interaction has started.
   * The view state will be resolved to a stable one if needed
   * (depending on its constraints).
   * @api
   */
  beginInteraction() {
    this.resolveConstraints(0);
    this.setHint(ViewHint.INTERACTING, 1);
  }
  /**
   * Notify the View that an interaction has ended. The view state will be resolved
   * to a stable one if needed (depending on its constraints).
   * @param {number} [duration] Animation duration in ms.
   * @param {number} [resolutionDirection] Which direction to zoom.
   * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation.
   * @api
   */
  endInteraction(duration, resolutionDirection, anchor) {
    anchor = anchor && fromUserCoordinate(anchor, this.getProjection());
    this.endInteractionInternal(duration, resolutionDirection, anchor);
  }
  /**
   * Notify the View that an interaction has ended. The view state will be resolved
   * to a stable one if needed (depending on its constraints).
   * @param {number} [duration] Animation duration in ms.
   * @param {number} [resolutionDirection] Which direction to zoom.
   * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation.
   */
  endInteractionInternal(duration, resolutionDirection, anchor) {
    if (!this.getInteracting()) {
      return;
    }
    this.setHint(ViewHint.INTERACTING, -1);
    this.resolveConstraints(duration, resolutionDirection, anchor);
  }
  /**
   * Get a valid position for the view center according to the current constraints.
   * @param {import("./coordinate.js").Coordinate|undefined} targetCenter Target center position.
   * @param {number} [targetResolution] Target resolution. If not supplied, the current one will be used.
   * This is useful to guess a valid center position at a different zoom level.
   * @return {import("./coordinate.js").Coordinate|undefined} Valid center position.
   */
  getConstrainedCenter(targetCenter, targetResolution) {
    const size = this.getViewportSize_(this.getRotation());
    return this.constraints_.center(
      targetCenter,
      targetResolution || this.getResolution(),
      size
    );
  }
  /**
   * Get a valid zoom level according to the current view constraints.
   * @param {number|undefined} targetZoom Target zoom.
   * @param {number} [direction] Indicate which resolution should be used
   * by a renderer if the view resolution does not match any resolution of the tile source.
   * If 0, the nearest resolution will be used. If 1, the nearest lower resolution
   * will be used. If -1, the nearest higher resolution will be used.
   * @return {number|undefined} Valid zoom level.
   */
  getConstrainedZoom(targetZoom, direction) {
    const targetRes = this.getResolutionForZoom(targetZoom);
    return this.getZoomForResolution(
      this.getConstrainedResolution(targetRes, direction)
    );
  }
  /**
   * Get a valid resolution according to the current view constraints.
   * @param {number|undefined} targetResolution Target resolution.
   * @param {number} [direction] Indicate which resolution should be used
   * by a renderer if the view resolution does not match any resolution of the tile source.
   * If 0, the nearest resolution will be used. If 1, the nearest lower resolution
   * will be used. If -1, the nearest higher resolution will be used.
   * @return {number|undefined} Valid resolution.
   */
  getConstrainedResolution(targetResolution, direction) {
    direction = direction || 0;
    const size = this.getViewportSize_(this.getRotation());
    return this.constraints_.resolution(targetResolution, direction, size);
  }
}
function animationCallback(callback, returnValue) {
  setTimeout(function() {
    callback(returnValue);
  }, 0);
}
function createCenterConstraint(options2) {
  if (options2.extent !== void 0) {
    const smooth = options2.smoothExtentConstraint !== void 0 ? options2.smoothExtentConstraint : true;
    return createExtent(options2.extent, options2.constrainOnlyCenter, smooth);
  }
  const projection = createProjection(options2.projection, "EPSG:3857");
  if (options2.multiWorld !== true && projection.isGlobal()) {
    const extent = projection.getExtent().slice();
    extent[0] = -Infinity;
    extent[2] = Infinity;
    return createExtent(extent, false, false);
  }
  return none$1;
}
function createResolutionConstraint(options2) {
  let resolutionConstraint;
  let maxResolution;
  let minResolution;
  const defaultMaxZoom = 28;
  const defaultZoomFactor = 2;
  let minZoom = options2.minZoom !== void 0 ? options2.minZoom : DEFAULT_MIN_ZOOM;
  let maxZoom = options2.maxZoom !== void 0 ? options2.maxZoom : defaultMaxZoom;
  const zoomFactor = options2.zoomFactor !== void 0 ? options2.zoomFactor : defaultZoomFactor;
  const multiWorld = options2.multiWorld !== void 0 ? options2.multiWorld : false;
  const smooth = options2.smoothResolutionConstraint !== void 0 ? options2.smoothResolutionConstraint : true;
  const showFullExtent = options2.showFullExtent !== void 0 ? options2.showFullExtent : false;
  const projection = createProjection(options2.projection, "EPSG:3857");
  const projExtent = projection.getExtent();
  let constrainOnlyCenter = options2.constrainOnlyCenter;
  let extent = options2.extent;
  if (!multiWorld && !extent && projection.isGlobal()) {
    constrainOnlyCenter = false;
    extent = projExtent;
  }
  if (options2.resolutions !== void 0) {
    const resolutions = options2.resolutions;
    maxResolution = resolutions[minZoom];
    minResolution = resolutions[maxZoom] !== void 0 ? resolutions[maxZoom] : resolutions[resolutions.length - 1];
    if (options2.constrainResolution) {
      resolutionConstraint = createSnapToResolutions(
        resolutions,
        smooth,
        !constrainOnlyCenter && extent,
        showFullExtent
      );
    } else {
      resolutionConstraint = createMinMaxResolution(
        maxResolution,
        minResolution,
        smooth,
        !constrainOnlyCenter && extent,
        showFullExtent
      );
    }
  } else {
    const size = !projExtent ? (
      // use an extent that can fit the whole world if need be
      360 * METERS_PER_UNIT$1.degrees / projection.getMetersPerUnit()
    ) : Math.max(getWidth(projExtent), getHeight(projExtent));
    const defaultMaxResolution = size / DEFAULT_TILE_SIZE / Math.pow(defaultZoomFactor, DEFAULT_MIN_ZOOM);
    const defaultMinResolution = defaultMaxResolution / Math.pow(defaultZoomFactor, defaultMaxZoom - DEFAULT_MIN_ZOOM);
    maxResolution = options2.maxResolution;
    if (maxResolution !== void 0) {
      minZoom = 0;
    } else {
      maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom);
    }
    minResolution = options2.minResolution;
    if (minResolution === void 0) {
      if (options2.maxZoom !== void 0) {
        if (options2.maxResolution !== void 0) {
          minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);
        } else {
          minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom);
        }
      } else {
        minResolution = defaultMinResolution;
      }
    }
    maxZoom = minZoom + Math.floor(
      Math.log(maxResolution / minResolution) / Math.log(zoomFactor)
    );
    minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);
    if (options2.constrainResolution) {
      resolutionConstraint = createSnapToPower(
        zoomFactor,
        maxResolution,
        minResolution,
        smooth,
        !constrainOnlyCenter && extent,
        showFullExtent
      );
    } else {
      resolutionConstraint = createMinMaxResolution(
        maxResolution,
        minResolution,
        smooth,
        !constrainOnlyCenter && extent,
        showFullExtent
      );
    }
  }
  return {
    constraint: resolutionConstraint,
    maxResolution,
    minResolution,
    minZoom,
    zoomFactor
  };
}
function createRotationConstraint(options2) {
  const enableRotation = options2.enableRotation !== void 0 ? options2.enableRotation : true;
  if (enableRotation) {
    const constrainRotation = options2.constrainRotation;
    if (constrainRotation === void 0 || constrainRotation === true) {
      return createSnapToZero();
    }
    if (constrainRotation === false) {
      return none;
    }
    if (typeof constrainRotation === "number") {
      return createSnapToN(constrainRotation);
    }
    return none;
  }
  return disable;
}
function isNoopAnimation(animation) {
  if (animation.sourceCenter && animation.targetCenter) {
    if (!equals(animation.sourceCenter, animation.targetCenter)) {
      return false;
    }
  }
  if (animation.sourceResolution !== animation.targetResolution) {
    return false;
  }
  if (animation.sourceRotation !== animation.targetRotation) {
    return false;
  }
  return true;
}
function calculateCenterOn(coordinate, size, position, resolution, rotation) {
  const cosAngle = Math.cos(-rotation);
  let sinAngle = Math.sin(-rotation);
  let rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
  let rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
  rotX += (size[0] / 2 - position[0]) * resolution;
  rotY += (position[1] - size[1] / 2) * resolution;
  sinAngle = -sinAngle;
  const centerX = rotX * cosAngle - rotY * sinAngle;
  const centerY = rotY * cosAngle + rotX * sinAngle;
  return [centerX, centerY];
}
class Rotate extends Control {
  /**
   * @param {Options} [options] Rotate options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super({
      element: document.createElement("div"),
      render: options2.render,
      target: options2.target
    });
    const className = options2.className !== void 0 ? options2.className : "ol-rotate";
    const label = options2.label !== void 0 ? options2.label : "⇧";
    const compassClassName = options2.compassClassName !== void 0 ? options2.compassClassName : "ol-compass";
    this.label_ = null;
    if (typeof label === "string") {
      this.label_ = document.createElement("span");
      this.label_.className = compassClassName;
      this.label_.textContent = label;
    } else {
      this.label_ = label;
      this.label_.classList.add(compassClassName);
    }
    const tipLabel = options2.tipLabel ? options2.tipLabel : "Reset rotation";
    const button = document.createElement("button");
    button.className = className + "-reset";
    button.setAttribute("type", "button");
    button.title = tipLabel;
    button.appendChild(this.label_);
    button.addEventListener(
      EventType.CLICK,
      this.handleClick_.bind(this),
      false
    );
    const cssClasses = className + " " + CLASS_UNSELECTABLE + " " + CLASS_CONTROL;
    const element = this.element;
    element.className = cssClasses;
    element.appendChild(button);
    this.callResetNorth_ = options2.resetNorth ? options2.resetNorth : void 0;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 250;
    this.autoHide_ = options2.autoHide !== void 0 ? options2.autoHide : true;
    this.rotation_ = void 0;
    if (this.autoHide_) {
      this.element.classList.add(CLASS_HIDDEN);
    }
  }
  /**
   * @param {MouseEvent} event The event to handle
   * @private
   */
  handleClick_(event) {
    event.preventDefault();
    if (this.callResetNorth_ !== void 0) {
      this.callResetNorth_();
    } else {
      this.resetNorth_();
    }
  }
  /**
   * @private
   */
  resetNorth_() {
    const map = this.getMap();
    const view = map.getView();
    if (!view) {
      return;
    }
    const rotation = view.getRotation();
    if (rotation !== void 0) {
      if (this.duration_ > 0 && rotation % (2 * Math.PI) !== 0) {
        view.animate({
          rotation: 0,
          duration: this.duration_,
          easing: easeOut
        });
      } else {
        view.setRotation(0);
      }
    }
  }
  /**
   * Update the rotate control element.
   * @param {import("../MapEvent.js").default} mapEvent Map event.
   * @override
   */
  render(mapEvent) {
    const frameState = mapEvent.frameState;
    if (!frameState) {
      return;
    }
    const rotation = frameState.viewState.rotation;
    if (rotation != this.rotation_) {
      const transform2 = "rotate(" + rotation + "rad)";
      if (this.autoHide_) {
        const contains2 = this.element.classList.contains(CLASS_HIDDEN);
        if (!contains2 && rotation === 0) {
          this.element.classList.add(CLASS_HIDDEN);
        } else if (contains2 && rotation !== 0) {
          this.element.classList.remove(CLASS_HIDDEN);
        }
      }
      this.label_.style.transform = transform2;
    }
    this.rotation_ = rotation;
  }
}
class Zoom extends Control {
  /**
   * @param {Options} [options] Zoom options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super({
      element: document.createElement("div"),
      target: options2.target
    });
    const className = options2.className !== void 0 ? options2.className : "ol-zoom";
    const delta = options2.delta !== void 0 ? options2.delta : 1;
    const zoomInClassName = options2.zoomInClassName !== void 0 ? options2.zoomInClassName : className + "-in";
    const zoomOutClassName = options2.zoomOutClassName !== void 0 ? options2.zoomOutClassName : className + "-out";
    const zoomInLabel = options2.zoomInLabel !== void 0 ? options2.zoomInLabel : "+";
    const zoomOutLabel = options2.zoomOutLabel !== void 0 ? options2.zoomOutLabel : "–";
    const zoomInTipLabel = options2.zoomInTipLabel !== void 0 ? options2.zoomInTipLabel : "Zoom in";
    const zoomOutTipLabel = options2.zoomOutTipLabel !== void 0 ? options2.zoomOutTipLabel : "Zoom out";
    const inElement = document.createElement("button");
    inElement.className = zoomInClassName;
    inElement.setAttribute("type", "button");
    inElement.title = zoomInTipLabel;
    inElement.appendChild(
      typeof zoomInLabel === "string" ? document.createTextNode(zoomInLabel) : zoomInLabel
    );
    inElement.addEventListener(
      EventType.CLICK,
      this.handleClick_.bind(this, delta),
      false
    );
    const outElement = document.createElement("button");
    outElement.className = zoomOutClassName;
    outElement.setAttribute("type", "button");
    outElement.title = zoomOutTipLabel;
    outElement.appendChild(
      typeof zoomOutLabel === "string" ? document.createTextNode(zoomOutLabel) : zoomOutLabel
    );
    outElement.addEventListener(
      EventType.CLICK,
      this.handleClick_.bind(this, -delta),
      false
    );
    const cssClasses = className + " " + CLASS_UNSELECTABLE + " " + CLASS_CONTROL;
    const element = this.element;
    element.className = cssClasses;
    element.appendChild(inElement);
    element.appendChild(outElement);
    this.duration_ = options2.duration !== void 0 ? options2.duration : 250;
  }
  /**
   * @param {number} delta Zoom delta.
   * @param {MouseEvent} event The event to handle
   * @private
   */
  handleClick_(delta, event) {
    event.preventDefault();
    this.zoomByDelta_(delta);
  }
  /**
   * @param {number} delta Zoom delta.
   * @private
   */
  zoomByDelta_(delta) {
    const map = this.getMap();
    const view = map.getView();
    if (!view) {
      return;
    }
    const currentZoom = view.getZoom();
    if (currentZoom !== void 0) {
      const newZoom = view.getConstrainedZoom(currentZoom + delta);
      if (this.duration_ > 0) {
        if (view.getAnimating()) {
          view.cancelAnimations();
        }
        view.animate({
          zoom: newZoom,
          duration: this.duration_,
          easing: easeOut
        });
      } else {
        view.setZoom(newZoom);
      }
    }
  }
}
function defaults$1(options2) {
  options2 = options2 ? options2 : {};
  const controls = new Collection();
  const zoomControl = options2.zoom !== void 0 ? options2.zoom : true;
  if (zoomControl) {
    controls.push(new Zoom(options2.zoomOptions));
  }
  const rotateControl = options2.rotate !== void 0 ? options2.rotate : true;
  if (rotateControl) {
    controls.push(new Rotate(options2.rotateOptions));
  }
  const attributionControl = options2.attribution !== void 0 ? options2.attribution : true;
  if (attributionControl) {
    controls.push(new Attribution(options2.attributionOptions));
  }
  return controls;
}
class Kinetic {
  /**
   * @param {number} decay Rate of decay (must be negative).
   * @param {number} minVelocity Minimum velocity (pixels/millisecond).
   * @param {number} delay Delay to consider to calculate the kinetic
   *     initial values (milliseconds).
   */
  constructor(decay, minVelocity, delay) {
    this.decay_ = decay;
    this.minVelocity_ = minVelocity;
    this.delay_ = delay;
    this.points_ = [];
    this.angle_ = 0;
    this.initialVelocity_ = 0;
  }
  /**
   * FIXME empty description for jsdoc
   */
  begin() {
    this.points_.length = 0;
    this.angle_ = 0;
    this.initialVelocity_ = 0;
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   */
  update(x, y) {
    this.points_.push(x, y, Date.now());
  }
  /**
   * @return {boolean} Whether we should do kinetic animation.
   */
  end() {
    if (this.points_.length < 6) {
      return false;
    }
    const delay = Date.now() - this.delay_;
    const lastIndex = this.points_.length - 3;
    if (this.points_[lastIndex + 2] < delay) {
      return false;
    }
    let firstIndex = lastIndex - 3;
    while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {
      firstIndex -= 3;
    }
    const duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];
    if (duration < 1e3 / 60) {
      return false;
    }
    const dx = this.points_[lastIndex] - this.points_[firstIndex];
    const dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];
    this.angle_ = Math.atan2(dy, dx);
    this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;
    return this.initialVelocity_ > this.minVelocity_;
  }
  /**
   * @return {number} Total distance travelled (pixels).
   */
  getDistance() {
    return (this.minVelocity_ - this.initialVelocity_) / this.decay_;
  }
  /**
   * @return {number} Angle of the kinetic panning animation (radians).
   */
  getAngle() {
    return this.angle_;
  }
}
const InteractionProperty = {
  ACTIVE: "active"
};
class Interaction extends BaseObject {
  /**
   * @param {InteractionOptions} [options] Options.
   */
  constructor(options2) {
    super();
    this.on;
    this.once;
    this.un;
    if (options2 && options2.handleEvent) {
      this.handleEvent = options2.handleEvent;
    }
    this.map_ = null;
    this.setActive(true);
  }
  /**
   * Return whether the interaction is currently active.
   * @return {boolean} `true` if the interaction is active, `false` otherwise.
   * @observable
   * @api
   */
  getActive() {
    return (
      /** @type {boolean} */
      this.get(InteractionProperty.ACTIVE)
    );
  }
  /**
   * Get the map associated with this interaction.
   * @return {import("../Map.js").default|null} Map.
   * @api
   */
  getMap() {
    return this.map_;
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event}.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @api
   */
  handleEvent(mapBrowserEvent) {
    return true;
  }
  /**
   * Activate or deactivate the interaction.
   * @param {boolean} active Active.
   * @observable
   * @api
   */
  setActive(active) {
    this.set(InteractionProperty.ACTIVE, active);
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default|null} map Map.
   */
  setMap(map) {
    this.map_ = map;
  }
}
function pan(view, delta, duration) {
  const currentCenter = view.getCenterInternal();
  if (currentCenter) {
    const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]];
    view.animateInternal({
      duration: duration !== void 0 ? duration : 250,
      easing: linear,
      center: view.getConstrainedCenter(center)
    });
  }
}
function zoomByDelta(view, delta, anchor, duration) {
  const currentZoom = view.getZoom();
  if (currentZoom === void 0) {
    return;
  }
  const newZoom = view.getConstrainedZoom(currentZoom + delta);
  const newResolution = view.getResolutionForZoom(newZoom);
  if (view.getAnimating()) {
    view.cancelAnimations();
  }
  view.animate({
    resolution: newResolution,
    anchor,
    duration: duration !== void 0 ? duration : 250,
    easing: easeOut
  });
}
class DoubleClickZoom extends Interaction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    super();
    options2 = options2 ? options2 : {};
    this.delta_ = options2.delta ? options2.delta : 1;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 250;
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} (if it was a
   * doubleclick) and eventually zooms the map.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @override
   */
  handleEvent(mapBrowserEvent) {
    let stopEvent = false;
    if (mapBrowserEvent.type == MapBrowserEventType.DBLCLICK) {
      const browserEvent = (
        /** @type {MouseEvent} */
        mapBrowserEvent.originalEvent
      );
      const map = mapBrowserEvent.map;
      const anchor = mapBrowserEvent.coordinate;
      const delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;
      const view = map.getView();
      zoomByDelta(view, delta, anchor, this.duration_);
      browserEvent.preventDefault();
      stopEvent = true;
    }
    return !stopEvent;
  }
}
function all$1(var_args) {
  const conditions = arguments;
  return function(event) {
    let pass = true;
    for (let i = 0, ii = conditions.length; i < ii; ++i) {
      pass = pass && conditions[i](event);
      if (!pass) {
        break;
      }
    }
    return pass;
  };
}
const altShiftKeysOnly = function(mapBrowserEvent) {
  const originalEvent = mapBrowserEvent.originalEvent;
  return originalEvent.altKey && !(originalEvent.metaKey || originalEvent.ctrlKey) && originalEvent.shiftKey;
};
const focus = function(event) {
  const targetElement = event.map.getTargetElement();
  const rootNode = targetElement.getRootNode();
  const activeElement = event.map.getOwnerDocument().activeElement;
  return rootNode instanceof ShadowRoot ? rootNode.host.contains(activeElement) : targetElement.contains(activeElement);
};
const focusWithTabindex = function(event) {
  const targetElement = event.map.getTargetElement();
  const rootNode = targetElement.getRootNode();
  const tabIndexCandidate = rootNode instanceof ShadowRoot ? rootNode.host : targetElement;
  return tabIndexCandidate.hasAttribute("tabindex") ? focus(event) : true;
};
const always$1 = TRUE;
const mouseActionButton = function(mapBrowserEvent) {
  const originalEvent = mapBrowserEvent.originalEvent;
  return "pointerId" in originalEvent && originalEvent.button == 0 && !(WEBKIT && MAC && originalEvent.ctrlKey);
};
const noModifierKeys = function(mapBrowserEvent) {
  const originalEvent = (
    /** @type {KeyboardEvent|MouseEvent|TouchEvent} */
    mapBrowserEvent.originalEvent
  );
  return !originalEvent.altKey && !(originalEvent.metaKey || originalEvent.ctrlKey) && !originalEvent.shiftKey;
};
const platformModifierKey = function(mapBrowserEvent) {
  const originalEvent = mapBrowserEvent.originalEvent;
  return MAC ? originalEvent.metaKey : originalEvent.ctrlKey;
};
const shiftKeyOnly = function(mapBrowserEvent) {
  const originalEvent = mapBrowserEvent.originalEvent;
  return !originalEvent.altKey && !(originalEvent.metaKey || originalEvent.ctrlKey) && originalEvent.shiftKey;
};
const targetNotEditable = function(mapBrowserEvent) {
  const originalEvent = mapBrowserEvent.originalEvent;
  const tagName = (
    /** @type {Element} */
    originalEvent.target.tagName
  );
  return tagName !== "INPUT" && tagName !== "SELECT" && tagName !== "TEXTAREA" && // `isContentEditable` is only available on `HTMLElement`, but it may also be a
  // different type like `SVGElement`.
  // @ts-ignore
  !originalEvent.target.isContentEditable;
};
const mouseOnly = function(mapBrowserEvent) {
  const pointerEvent = mapBrowserEvent.originalEvent;
  return "pointerId" in pointerEvent && pointerEvent.pointerType == "mouse";
};
const primaryAction = function(mapBrowserEvent) {
  const pointerEvent = mapBrowserEvent.originalEvent;
  return "pointerId" in pointerEvent && pointerEvent.isPrimary && pointerEvent.button === 0;
};
class PointerInteraction extends Interaction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super(
      /** @type {import("./Interaction.js").InteractionOptions} */
      options2
    );
    if (options2.handleDownEvent) {
      this.handleDownEvent = options2.handleDownEvent;
    }
    if (options2.handleDragEvent) {
      this.handleDragEvent = options2.handleDragEvent;
    }
    if (options2.handleMoveEvent) {
      this.handleMoveEvent = options2.handleMoveEvent;
    }
    if (options2.handleUpEvent) {
      this.handleUpEvent = options2.handleUpEvent;
    }
    if (options2.stopDown) {
      this.stopDown = options2.stopDown;
    }
    this.handlingDownUpSequence = false;
    this.targetPointers = [];
  }
  /**
   * Returns the current number of pointers involved in the interaction,
   * e.g. `2` when two fingers are used.
   * @return {number} The number of pointers.
   * @api
   */
  getPointerCount() {
    return this.targetPointers.length;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @protected
   */
  handleDownEvent(mapBrowserEvent) {
    return false;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @protected
   */
  handleDragEvent(mapBrowserEvent) {
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} and may call into
   * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
   * detected.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @api
   * @override
   */
  handleEvent(mapBrowserEvent) {
    if (!mapBrowserEvent.originalEvent) {
      return true;
    }
    let stopEvent = false;
    this.updateTrackedPointers_(mapBrowserEvent);
    if (this.handlingDownUpSequence) {
      if (mapBrowserEvent.type == MapBrowserEventType.POINTERDRAG) {
        this.handleDragEvent(mapBrowserEvent);
        mapBrowserEvent.originalEvent.preventDefault();
      } else if (mapBrowserEvent.type == MapBrowserEventType.POINTERUP) {
        const handledUp = this.handleUpEvent(mapBrowserEvent);
        this.handlingDownUpSequence = handledUp && this.targetPointers.length > 0;
      }
    } else {
      if (mapBrowserEvent.type == MapBrowserEventType.POINTERDOWN) {
        const handled = this.handleDownEvent(mapBrowserEvent);
        this.handlingDownUpSequence = handled;
        stopEvent = this.stopDown(handled);
      } else if (mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE) {
        this.handleMoveEvent(mapBrowserEvent);
      }
    }
    return !stopEvent;
  }
  /**
   * Handle pointer move events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @protected
   */
  handleMoveEvent(mapBrowserEvent) {
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @protected
   */
  handleUpEvent(mapBrowserEvent) {
    return false;
  }
  /**
   * This function is used to determine if "down" events should be propagated
   * to other interactions or should be stopped.
   * @param {boolean} handled Was the event handled by the interaction?
   * @return {boolean} Should the `down` event be stopped?
   */
  stopDown(handled) {
    return handled;
  }
  /**
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @private
   */
  updateTrackedPointers_(mapBrowserEvent) {
    if (mapBrowserEvent.activePointers) {
      this.targetPointers = mapBrowserEvent.activePointers;
    }
  }
}
function centroid(pointerEvents) {
  const length = pointerEvents.length;
  let clientX = 0;
  let clientY = 0;
  for (let i = 0; i < length; i++) {
    clientX += pointerEvents[i].clientX;
    clientY += pointerEvents[i].clientY;
  }
  return { clientX: clientX / length, clientY: clientY / length };
}
class DragPan extends PointerInteraction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    super({
      stopDown: FALSE
    });
    options2 = options2 ? options2 : {};
    this.kinetic_ = options2.kinetic;
    this.lastCentroid = null;
    this.lastPointersCount_;
    this.panning_ = false;
    const condition = options2.condition ? options2.condition : all$1(noModifierKeys, primaryAction);
    this.condition_ = options2.onFocusOnly ? all$1(focusWithTabindex, condition) : condition;
    this.noKinetic_ = false;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    const map = mapBrowserEvent.map;
    if (!this.panning_) {
      this.panning_ = true;
      map.getView().beginInteraction();
    }
    const targetPointers = this.targetPointers;
    const centroid$1 = map.getEventPixel(centroid(targetPointers));
    if (targetPointers.length == this.lastPointersCount_) {
      if (this.kinetic_) {
        this.kinetic_.update(centroid$1[0], centroid$1[1]);
      }
      if (this.lastCentroid) {
        const delta = [
          this.lastCentroid[0] - centroid$1[0],
          centroid$1[1] - this.lastCentroid[1]
        ];
        const map2 = mapBrowserEvent.map;
        const view = map2.getView();
        scale$2(delta, view.getResolution());
        rotate$1(delta, view.getRotation());
        view.adjustCenterInternal(delta);
      }
    } else if (this.kinetic_) {
      this.kinetic_.begin();
    }
    this.lastCentroid = centroid$1;
    this.lastPointersCount_ = targetPointers.length;
    mapBrowserEvent.originalEvent.preventDefault();
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    const map = mapBrowserEvent.map;
    const view = map.getView();
    if (this.targetPointers.length === 0) {
      if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
        const distance = this.kinetic_.getDistance();
        const angle = this.kinetic_.getAngle();
        const center = view.getCenterInternal();
        const centerpx = map.getPixelFromCoordinateInternal(center);
        const dest = map.getCoordinateFromPixelInternal([
          centerpx[0] - distance * Math.cos(angle),
          centerpx[1] - distance * Math.sin(angle)
        ]);
        view.animateInternal({
          center: view.getConstrainedCenter(dest),
          duration: 500,
          easing: easeOut
        });
      }
      if (this.panning_) {
        this.panning_ = false;
        view.endInteraction();
      }
      return false;
    }
    if (this.kinetic_) {
      this.kinetic_.begin();
    }
    this.lastCentroid = null;
    return true;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
      const map = mapBrowserEvent.map;
      const view = map.getView();
      this.lastCentroid = null;
      if (view.getAnimating()) {
        view.cancelAnimations();
      }
      if (this.kinetic_) {
        this.kinetic_.begin();
      }
      this.noKinetic_ = this.targetPointers.length > 1;
      return true;
    }
    return false;
  }
}
class DragRotate extends PointerInteraction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super({
      stopDown: FALSE
    });
    this.condition_ = options2.condition ? options2.condition : altShiftKeysOnly;
    this.lastAngle_ = void 0;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 250;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    if (!mouseOnly(mapBrowserEvent)) {
      return;
    }
    const map = mapBrowserEvent.map;
    const view = map.getView();
    if (view.getConstraints().rotation === disable) {
      return;
    }
    const size = map.getSize();
    const offset2 = mapBrowserEvent.pixel;
    const theta = Math.atan2(size[1] / 2 - offset2[1], offset2[0] - size[0] / 2);
    if (this.lastAngle_ !== void 0) {
      const delta = theta - this.lastAngle_;
      view.adjustRotationInternal(-delta);
    }
    this.lastAngle_ = theta;
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    if (!mouseOnly(mapBrowserEvent)) {
      return true;
    }
    const map = mapBrowserEvent.map;
    const view = map.getView();
    view.endInteraction(this.duration_);
    return false;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    if (!mouseOnly(mapBrowserEvent)) {
      return false;
    }
    if (mouseActionButton(mapBrowserEvent) && this.condition_(mapBrowserEvent)) {
      const map = mapBrowserEvent.map;
      map.getView().beginInteraction();
      this.lastAngle_ = void 0;
      return true;
    }
    return false;
  }
}
class RenderBox extends Disposable {
  /**
   * @param {string} className CSS class name.
   */
  constructor(className) {
    super();
    this.geometry_ = null;
    this.element_ = document.createElement("div");
    this.element_.style.position = "absolute";
    this.element_.style.pointerEvents = "auto";
    this.element_.className = "ol-box " + className;
    this.map_ = null;
    this.startPixel_ = null;
    this.endPixel_ = null;
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    this.setMap(null);
  }
  /**
   * @private
   */
  render_() {
    const startPixel = this.startPixel_;
    const endPixel = this.endPixel_;
    const px = "px";
    const style = this.element_.style;
    style.left = Math.min(startPixel[0], endPixel[0]) + px;
    style.top = Math.min(startPixel[1], endPixel[1]) + px;
    style.width = Math.abs(endPixel[0] - startPixel[0]) + px;
    style.height = Math.abs(endPixel[1] - startPixel[1]) + px;
  }
  /**
   * @param {import("../Map.js").default|null} map Map.
   */
  setMap(map) {
    if (this.map_) {
      this.map_.getOverlayContainer().removeChild(this.element_);
      const style = this.element_.style;
      style.left = "inherit";
      style.top = "inherit";
      style.width = "inherit";
      style.height = "inherit";
    }
    this.map_ = map;
    if (this.map_) {
      this.map_.getOverlayContainer().appendChild(this.element_);
    }
  }
  /**
   * @param {import("../pixel.js").Pixel} startPixel Start pixel.
   * @param {import("../pixel.js").Pixel} endPixel End pixel.
   */
  setPixels(startPixel, endPixel) {
    this.startPixel_ = startPixel;
    this.endPixel_ = endPixel;
    this.createOrUpdateGeometry();
    this.render_();
  }
  /**
   * Creates or updates the cached geometry.
   */
  createOrUpdateGeometry() {
    if (!this.map_) {
      return;
    }
    const startPixel = this.startPixel_;
    const endPixel = this.endPixel_;
    const pixels = [
      startPixel,
      [startPixel[0], endPixel[1]],
      endPixel,
      [endPixel[0], startPixel[1]]
    ];
    const coordinates2 = pixels.map(
      this.map_.getCoordinateFromPixelInternal,
      this.map_
    );
    coordinates2[4] = coordinates2[0].slice();
    if (!this.geometry_) {
      this.geometry_ = new Polygon([coordinates2]);
    } else {
      this.geometry_.setCoordinates([coordinates2]);
    }
  }
  /**
   * @return {import("../geom/Polygon.js").default} Geometry.
   */
  getGeometry() {
    return this.geometry_;
  }
}
const DragBoxEventType = {
  /**
   * Triggered upon drag box start.
   * @event DragBoxEvent#boxstart
   * @api
   */
  BOXSTART: "boxstart",
  /**
   * Triggered on drag when box is active.
   * @event DragBoxEvent#boxdrag
   * @api
   */
  BOXDRAG: "boxdrag",
  /**
   * Triggered upon drag box end.
   * @event DragBoxEvent#boxend
   * @api
   */
  BOXEND: "boxend",
  /**
   * Triggered upon drag box canceled.
   * @event DragBoxEvent#boxcancel
   * @api
   */
  BOXCANCEL: "boxcancel"
};
class DragBoxEvent extends BaseEvent {
  /**
   * @param {string} type The event type.
   * @param {import("../coordinate.js").Coordinate} coordinate The event coordinate.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Originating event.
   */
  constructor(type, coordinate, mapBrowserEvent) {
    super(type);
    this.coordinate = coordinate;
    this.mapBrowserEvent = mapBrowserEvent;
  }
}
class DragBox extends PointerInteraction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    super();
    this.on;
    this.once;
    this.un;
    options2 = options2 ?? {};
    this.box_ = new RenderBox(options2.className || "ol-dragbox");
    this.minArea_ = options2.minArea ?? 64;
    if (options2.onBoxEnd) {
      this.onBoxEnd = options2.onBoxEnd;
    }
    this.startPixel_ = null;
    this.condition_ = options2.condition ?? mouseActionButton;
    this.boxEndCondition_ = options2.boxEndCondition ?? this.defaultBoxEndCondition;
  }
  /**
   * The default condition for determining whether the boxend event
   * should fire.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent The originating MapBrowserEvent
   *     leading to the box end.
   * @param {import("../pixel.js").Pixel} startPixel The starting pixel of the box.
   * @param {import("../pixel.js").Pixel} endPixel The end pixel of the box.
   * @return {boolean} Whether or not the boxend condition should be fired.
   */
  defaultBoxEndCondition(mapBrowserEvent, startPixel, endPixel) {
    const width = endPixel[0] - startPixel[0];
    const height = endPixel[1] - startPixel[1];
    return width * width + height * height >= this.minArea_;
  }
  /**
   * Returns geometry of last drawn box.
   * @return {import("../geom/Polygon.js").default} Geometry.
   * @api
   */
  getGeometry() {
    return this.box_.getGeometry();
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    if (!this.startPixel_) {
      return;
    }
    this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel);
    this.dispatchEvent(
      new DragBoxEvent(
        DragBoxEventType.BOXDRAG,
        mapBrowserEvent.coordinate,
        mapBrowserEvent
      )
    );
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    if (!this.startPixel_) {
      return false;
    }
    const completeBox = this.boxEndCondition_(
      mapBrowserEvent,
      this.startPixel_,
      mapBrowserEvent.pixel
    );
    if (completeBox) {
      this.onBoxEnd(mapBrowserEvent);
    }
    this.dispatchEvent(
      new DragBoxEvent(
        completeBox ? DragBoxEventType.BOXEND : DragBoxEventType.BOXCANCEL,
        mapBrowserEvent.coordinate,
        mapBrowserEvent
      )
    );
    this.box_.setMap(null);
    this.startPixel_ = null;
    return false;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.condition_(mapBrowserEvent)) {
      this.startPixel_ = mapBrowserEvent.pixel;
      this.box_.setMap(mapBrowserEvent.map);
      this.box_.setPixels(this.startPixel_, this.startPixel_);
      this.dispatchEvent(
        new DragBoxEvent(
          DragBoxEventType.BOXSTART,
          mapBrowserEvent.coordinate,
          mapBrowserEvent
        )
      );
      return true;
    }
    return false;
  }
  /**
   * Function to execute just before `onboxend` is fired
   * @param {import("../MapBrowserEvent.js").default} event Event.
   */
  onBoxEnd(event) {
  }
  /**
   * Activate or deactivate the interaction.
   * @param {boolean} active Active.
   * @observable
   * @api
   * @override
   */
  setActive(active) {
    if (!active) {
      this.box_.setMap(null);
      if (this.startPixel_) {
        this.dispatchEvent(
          new DragBoxEvent(DragBoxEventType.BOXCANCEL, this.startPixel_, null)
        );
        this.startPixel_ = null;
      }
    }
    super.setActive(active);
  }
  /**
   * @param {import("../Map.js").default|null} map Map.
   * @override
   */
  setMap(map) {
    const oldMap = this.getMap();
    if (oldMap) {
      this.box_.setMap(null);
      if (this.startPixel_) {
        this.dispatchEvent(
          new DragBoxEvent(DragBoxEventType.BOXCANCEL, this.startPixel_, null)
        );
        this.startPixel_ = null;
      }
    }
    super.setMap(map);
  }
}
class DragZoom extends DragBox {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    const condition = options2.condition ? options2.condition : shiftKeyOnly;
    super({
      condition,
      className: options2.className || "ol-dragzoom",
      minArea: options2.minArea
    });
    this.duration_ = options2.duration !== void 0 ? options2.duration : 200;
    this.out_ = options2.out !== void 0 ? options2.out : false;
  }
  /**
   * Function to execute just before `onboxend` is fired
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @override
   */
  onBoxEnd(event) {
    const map = this.getMap();
    const view = (
      /** @type {!import("../View.js").default} */
      map.getView()
    );
    let geometry = this.getGeometry();
    if (this.out_) {
      const rotatedExtent = view.rotatedExtentForGeometry(geometry);
      const resolution = view.getResolutionForExtentInternal(rotatedExtent);
      const factor = view.getResolution() / resolution;
      geometry = geometry.clone();
      geometry.scale(factor * factor);
    }
    view.fitInternal(geometry, {
      duration: this.duration_,
      easing: easeOut
    });
  }
}
const Key = {
  LEFT: "ArrowLeft",
  UP: "ArrowUp",
  RIGHT: "ArrowRight",
  DOWN: "ArrowDown"
};
class KeyboardPan extends Interaction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    super();
    options2 = options2 || {};
    this.defaultCondition_ = function(mapBrowserEvent) {
      return noModifierKeys(mapBrowserEvent) && targetNotEditable(mapBrowserEvent);
    };
    this.condition_ = options2.condition !== void 0 ? options2.condition : this.defaultCondition_;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 100;
    this.pixelDelta_ = options2.pixelDelta !== void 0 ? options2.pixelDelta : 128;
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} if it was a
   * `KeyEvent`, and decides the direction to pan to (if an arrow key was
   * pressed).
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @override
   */
  handleEvent(mapBrowserEvent) {
    let stopEvent = false;
    if (mapBrowserEvent.type == EventType.KEYDOWN) {
      const keyEvent = (
        /** @type {KeyboardEvent} */
        mapBrowserEvent.originalEvent
      );
      const key2 = keyEvent.key;
      if (this.condition_(mapBrowserEvent) && (key2 == Key.DOWN || key2 == Key.LEFT || key2 == Key.RIGHT || key2 == Key.UP)) {
        const map = mapBrowserEvent.map;
        const view = map.getView();
        const mapUnitsDelta = view.getResolution() * this.pixelDelta_;
        let deltaX = 0, deltaY = 0;
        if (key2 == Key.DOWN) {
          deltaY = -mapUnitsDelta;
        } else if (key2 == Key.LEFT) {
          deltaX = -mapUnitsDelta;
        } else if (key2 == Key.RIGHT) {
          deltaX = mapUnitsDelta;
        } else {
          deltaY = mapUnitsDelta;
        }
        const delta = [deltaX, deltaY];
        rotate$1(delta, view.getRotation());
        pan(view, delta, this.duration_);
        keyEvent.preventDefault();
        stopEvent = true;
      }
    }
    return !stopEvent;
  }
}
class KeyboardZoom extends Interaction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    super();
    options2 = options2 ? options2 : {};
    this.condition_ = options2.condition ? options2.condition : function(mapBrowserEvent) {
      return !platformModifierKey(mapBrowserEvent) && targetNotEditable(mapBrowserEvent);
    };
    this.delta_ = options2.delta ? options2.delta : 1;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 100;
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} if it was a
   * `KeyEvent`, and decides whether to zoom in or out (depending on whether the
   * key pressed was '+' or '-').
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @override
   */
  handleEvent(mapBrowserEvent) {
    let stopEvent = false;
    if (mapBrowserEvent.type == EventType.KEYDOWN || mapBrowserEvent.type == EventType.KEYPRESS) {
      const keyEvent = (
        /** @type {KeyboardEvent} */
        mapBrowserEvent.originalEvent
      );
      const key2 = keyEvent.key;
      if (this.condition_(mapBrowserEvent) && (key2 === "+" || key2 === "-")) {
        const map = mapBrowserEvent.map;
        const delta = key2 === "+" ? this.delta_ : -this.delta_;
        const view = map.getView();
        zoomByDelta(view, delta, void 0, this.duration_);
        keyEvent.preventDefault();
        stopEvent = true;
      }
    }
    return !stopEvent;
  }
}
const DELTA_LINE_MULTIPLIER = 40;
const DELTA_PAGE_MULTIPLIER = 300;
class MouseWheelZoom extends Interaction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super(
      /** @type {import("./Interaction.js").InteractionOptions} */
      options2
    );
    this.totalDelta_ = 0;
    this.lastDelta_ = 0;
    this.maxDelta_ = options2.maxDelta !== void 0 ? options2.maxDelta : 1;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 250;
    this.timeout_ = options2.timeout !== void 0 ? options2.timeout : 80;
    this.useAnchor_ = options2.useAnchor !== void 0 ? options2.useAnchor : true;
    this.constrainResolution_ = options2.constrainResolution !== void 0 ? options2.constrainResolution : false;
    const condition = options2.condition ? options2.condition : always$1;
    this.condition_ = options2.onFocusOnly ? all$1(focusWithTabindex, condition) : condition;
    this.lastAnchor_ = null;
    this.startTime_ = void 0;
    this.timeoutId_;
    this.mode_ = void 0;
    this.trackpadEventGap_ = 400;
    this.trackpadTimeoutId_;
    this.deltaPerZoom_ = 300;
  }
  /**
   * @private
   */
  endInteraction_() {
    this.trackpadTimeoutId_ = void 0;
    const map = this.getMap();
    if (!map) {
      return;
    }
    const view = map.getView();
    view.endInteraction(
      void 0,
      this.lastDelta_ ? this.lastDelta_ > 0 ? 1 : -1 : 0,
      this.lastAnchor_ ? map.getCoordinateFromPixel(this.lastAnchor_) : null
    );
  }
  /**
   * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} (if it was a mousewheel-event) and eventually
   * zooms the map.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   * @return {boolean} `false` to stop event propagation.
   * @override
   */
  handleEvent(mapBrowserEvent) {
    if (!this.condition_(mapBrowserEvent)) {
      return true;
    }
    const type = mapBrowserEvent.type;
    if (type !== EventType.WHEEL) {
      return true;
    }
    const map = mapBrowserEvent.map;
    const wheelEvent = (
      /** @type {WheelEvent} */
      mapBrowserEvent.originalEvent
    );
    wheelEvent.preventDefault();
    if (this.useAnchor_) {
      this.lastAnchor_ = mapBrowserEvent.pixel;
    }
    let delta = wheelEvent.deltaY;
    switch (wheelEvent.deltaMode) {
      case WheelEvent.DOM_DELTA_LINE:
        delta *= DELTA_LINE_MULTIPLIER;
        break;
      case WheelEvent.DOM_DELTA_PAGE:
        delta *= DELTA_PAGE_MULTIPLIER;
        break;
    }
    if (delta === 0) {
      return false;
    }
    this.lastDelta_ = delta;
    const now = Date.now();
    if (this.startTime_ === void 0) {
      this.startTime_ = now;
    }
    if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) {
      this.mode_ = Math.abs(delta) < 4 ? "trackpad" : "wheel";
    }
    const view = map.getView();
    if (this.mode_ === "trackpad" && !(view.getConstrainResolution() || this.constrainResolution_)) {
      if (this.trackpadTimeoutId_) {
        clearTimeout(this.trackpadTimeoutId_);
      } else {
        if (view.getAnimating()) {
          view.cancelAnimations();
        }
        view.beginInteraction();
      }
      this.trackpadTimeoutId_ = setTimeout(
        this.endInteraction_.bind(this),
        this.timeout_
      );
      view.adjustZoom(
        -delta / this.deltaPerZoom_,
        this.lastAnchor_ ? map.getCoordinateFromPixel(this.lastAnchor_) : null
      );
      this.startTime_ = now;
      return false;
    }
    this.totalDelta_ += delta;
    const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
    clearTimeout(this.timeoutId_);
    this.timeoutId_ = setTimeout(
      this.handleWheelZoom_.bind(this, map),
      timeLeft
    );
    return false;
  }
  /**
   * @private
   * @param {import("../Map.js").default} map Map.
   */
  handleWheelZoom_(map) {
    const view = map.getView();
    if (view.getAnimating()) {
      view.cancelAnimations();
    }
    let delta = -clamp(
      this.totalDelta_,
      -this.maxDelta_ * this.deltaPerZoom_,
      this.maxDelta_ * this.deltaPerZoom_
    ) / this.deltaPerZoom_;
    if (view.getConstrainResolution() || this.constrainResolution_) {
      delta = delta ? delta > 0 ? 1 : -1 : 0;
    }
    zoomByDelta(
      view,
      delta,
      this.lastAnchor_ ? map.getCoordinateFromPixel(this.lastAnchor_) : null,
      this.duration_
    );
    this.mode_ = void 0;
    this.totalDelta_ = 0;
    this.lastAnchor_ = null;
    this.startTime_ = void 0;
    this.timeoutId_ = void 0;
  }
  /**
   * Enable or disable using the mouse's location as an anchor when zooming
   * @param {boolean} useAnchor true to zoom to the mouse's location, false
   * to zoom to the center of the map
   * @api
   */
  setMouseAnchor(useAnchor) {
    this.useAnchor_ = useAnchor;
    if (!useAnchor) {
      this.lastAnchor_ = null;
    }
  }
}
class PinchRotate extends PointerInteraction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    const pointerOptions = (
      /** @type {import("./Pointer.js").Options} */
      options2
    );
    if (!pointerOptions.stopDown) {
      pointerOptions.stopDown = FALSE;
    }
    super(pointerOptions);
    this.anchor_ = null;
    this.lastAngle_ = void 0;
    this.rotating_ = false;
    this.rotationDelta_ = 0;
    this.threshold_ = options2.threshold !== void 0 ? options2.threshold : 0.3;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 250;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    let rotationDelta = 0;
    const touch0 = this.targetPointers[0];
    const touch1 = this.targetPointers[1];
    const angle = Math.atan2(
      touch1.clientY - touch0.clientY,
      touch1.clientX - touch0.clientX
    );
    if (this.lastAngle_ !== void 0) {
      const delta = angle - this.lastAngle_;
      this.rotationDelta_ += delta;
      if (!this.rotating_ && Math.abs(this.rotationDelta_) > this.threshold_) {
        this.rotating_ = true;
      }
      rotationDelta = delta;
    }
    this.lastAngle_ = angle;
    const map = mapBrowserEvent.map;
    const view = map.getView();
    if (view.getConstraints().rotation === disable) {
      return;
    }
    this.anchor_ = map.getCoordinateFromPixelInternal(
      map.getEventPixel(centroid(this.targetPointers))
    );
    if (this.rotating_) {
      map.render();
      view.adjustRotationInternal(rotationDelta, this.anchor_);
    }
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    if (this.targetPointers.length < 2) {
      const map = mapBrowserEvent.map;
      const view = map.getView();
      view.endInteraction(this.duration_);
      return false;
    }
    return true;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.targetPointers.length >= 2) {
      const map = mapBrowserEvent.map;
      this.anchor_ = null;
      this.lastAngle_ = void 0;
      this.rotating_ = false;
      this.rotationDelta_ = 0;
      if (!this.handlingDownUpSequence) {
        map.getView().beginInteraction();
      }
      return true;
    }
    return false;
  }
}
class PinchZoom extends PointerInteraction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    const pointerOptions = (
      /** @type {import("./Pointer.js").Options} */
      options2
    );
    if (!pointerOptions.stopDown) {
      pointerOptions.stopDown = FALSE;
    }
    super(pointerOptions);
    this.anchor_ = null;
    this.duration_ = options2.duration !== void 0 ? options2.duration : 400;
    this.lastDistance_ = void 0;
    this.lastScaleDelta_ = 1;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @override
   */
  handleDragEvent(mapBrowserEvent) {
    let scaleDelta = 1;
    const touch0 = this.targetPointers[0];
    const touch1 = this.targetPointers[1];
    const dx = touch0.clientX - touch1.clientX;
    const dy = touch0.clientY - touch1.clientY;
    const distance = Math.sqrt(dx * dx + dy * dy);
    if (this.lastDistance_ !== void 0) {
      scaleDelta = this.lastDistance_ / distance;
    }
    this.lastDistance_ = distance;
    const map = mapBrowserEvent.map;
    const view = map.getView();
    if (scaleDelta != 1) {
      this.lastScaleDelta_ = scaleDelta;
    }
    this.anchor_ = map.getCoordinateFromPixelInternal(
      map.getEventPixel(centroid(this.targetPointers))
    );
    map.render();
    view.adjustResolutionInternal(scaleDelta, this.anchor_);
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(mapBrowserEvent) {
    if (this.targetPointers.length < 2) {
      const map = mapBrowserEvent.map;
      const view = map.getView();
      const direction = this.lastScaleDelta_ > 1 ? 1 : -1;
      view.endInteraction(this.duration_, direction);
      return false;
    }
    return true;
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(mapBrowserEvent) {
    if (this.targetPointers.length >= 2) {
      const map = mapBrowserEvent.map;
      this.anchor_ = null;
      this.lastDistance_ = void 0;
      this.lastScaleDelta_ = 1;
      if (!this.handlingDownUpSequence) {
        map.getView().beginInteraction();
      }
      return true;
    }
    return false;
  }
}
function defaults(options2) {
  options2 = options2 ? options2 : {};
  const interactions = new Collection();
  const kinetic = new Kinetic(-5e-3, 0.05, 100);
  const altShiftDragRotate = options2.altShiftDragRotate !== void 0 ? options2.altShiftDragRotate : true;
  if (altShiftDragRotate) {
    interactions.push(new DragRotate());
  }
  const doubleClickZoom = options2.doubleClickZoom !== void 0 ? options2.doubleClickZoom : true;
  if (doubleClickZoom) {
    interactions.push(
      new DoubleClickZoom({
        delta: options2.zoomDelta,
        duration: options2.zoomDuration
      })
    );
  }
  const dragPan = options2.dragPan !== void 0 ? options2.dragPan : true;
  if (dragPan) {
    interactions.push(
      new DragPan({
        onFocusOnly: options2.onFocusOnly,
        kinetic
      })
    );
  }
  const pinchRotate = options2.pinchRotate !== void 0 ? options2.pinchRotate : true;
  if (pinchRotate) {
    interactions.push(new PinchRotate());
  }
  const pinchZoom = options2.pinchZoom !== void 0 ? options2.pinchZoom : true;
  if (pinchZoom) {
    interactions.push(
      new PinchZoom({
        duration: options2.zoomDuration
      })
    );
  }
  const keyboard = options2.keyboard !== void 0 ? options2.keyboard : true;
  if (keyboard) {
    interactions.push(new KeyboardPan());
    interactions.push(
      new KeyboardZoom({
        delta: options2.zoomDelta,
        duration: options2.zoomDuration
      })
    );
  }
  const mouseWheelZoom = options2.mouseWheelZoom !== void 0 ? options2.mouseWheelZoom : true;
  if (mouseWheelZoom) {
    interactions.push(
      new MouseWheelZoom({
        onFocusOnly: options2.onFocusOnly,
        duration: options2.zoomDuration
      })
    );
  }
  const shiftDragZoom = options2.shiftDragZoom !== void 0 ? options2.shiftDragZoom : true;
  if (shiftDragZoom) {
    interactions.push(
      new DragZoom({
        duration: options2.zoomDuration
      })
    );
  }
  return interactions;
}
const LayerProperty = {
  OPACITY: "opacity",
  VISIBLE: "visible",
  EXTENT: "extent",
  Z_INDEX: "zIndex",
  MAX_RESOLUTION: "maxResolution",
  MIN_RESOLUTION: "minResolution",
  MAX_ZOOM: "maxZoom",
  MIN_ZOOM: "minZoom",
  SOURCE: "source",
  MAP: "map"
};
class BaseLayer extends BaseObject {
  /**
   * @param {Options} options Layer options.
   */
  constructor(options2) {
    super();
    this.on;
    this.once;
    this.un;
    this.background_ = options2.background;
    const properties = Object.assign({}, options2);
    if (typeof options2.properties === "object") {
      delete properties.properties;
      Object.assign(properties, options2.properties);
    }
    properties[LayerProperty.OPACITY] = options2.opacity !== void 0 ? options2.opacity : 1;
    assert(
      typeof properties[LayerProperty.OPACITY] === "number",
      "Layer opacity must be a number"
    );
    properties[LayerProperty.VISIBLE] = options2.visible !== void 0 ? options2.visible : true;
    properties[LayerProperty.Z_INDEX] = options2.zIndex;
    properties[LayerProperty.MAX_RESOLUTION] = options2.maxResolution !== void 0 ? options2.maxResolution : Infinity;
    properties[LayerProperty.MIN_RESOLUTION] = options2.minResolution !== void 0 ? options2.minResolution : 0;
    properties[LayerProperty.MIN_ZOOM] = options2.minZoom !== void 0 ? options2.minZoom : -Infinity;
    properties[LayerProperty.MAX_ZOOM] = options2.maxZoom !== void 0 ? options2.maxZoom : Infinity;
    this.className_ = properties.className !== void 0 ? properties.className : "ol-layer";
    delete properties.className;
    this.setProperties(properties);
    this.state_ = null;
  }
  /**
   * Get the background for this layer.
   * @return {BackgroundColor|false} Layer background.
   */
  getBackground() {
    return this.background_;
  }
  /**
   * @return {string} CSS class name.
   */
  getClassName() {
    return this.className_;
  }
  /**
   * This method is not meant to be called by layers or layer renderers because the state
   * is incorrect if the layer is included in a layer group.
   *
   * @param {boolean} [managed] Layer is managed.
   * @return {import("./Layer.js").State} Layer state.
   */
  getLayerState(managed) {
    const state = this.state_ || /** @type {?} */
    {
      layer: this,
      managed: managed === void 0 ? true : managed
    };
    const zIndex = this.getZIndex();
    state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
    state.visible = this.getVisible();
    state.extent = this.getExtent();
    state.zIndex = zIndex === void 0 && !state.managed ? Infinity : zIndex;
    state.maxResolution = this.getMaxResolution();
    state.minResolution = Math.max(this.getMinResolution(), 0);
    state.minZoom = this.getMinZoom();
    state.maxZoom = this.getMaxZoom();
    this.state_ = state;
    return state;
  }
  /**
   * @abstract
   * @param {Array<import("./Layer.js").default>} [array] Array of layers (to be
   *     modified in place).
   * @return {Array<import("./Layer.js").default>} Array of layers.
   */
  getLayersArray(array) {
    return abstract();
  }
  /**
   * @abstract
   * @param {Array<import("./Layer.js").State>} [states] Optional list of layer
   *     states (to be modified in place).
   * @return {Array<import("./Layer.js").State>} List of layer states.
   */
  getLayerStatesArray(states2) {
    return abstract();
  }
  /**
   * Return the {@link module:ol/extent~Extent extent} of the layer or `undefined` if it
   * will be visible regardless of extent.
   * @return {import("../extent.js").Extent|undefined} The layer extent.
   * @observable
   * @api
   */
  getExtent() {
    return (
      /** @type {import("../extent.js").Extent|undefined} */
      this.get(LayerProperty.EXTENT)
    );
  }
  /**
   * Return the maximum resolution of the layer. Returns Infinity if
   * the layer has no maximum resolution set.
   * @return {number} The maximum resolution of the layer.
   * @observable
   * @api
   */
  getMaxResolution() {
    return (
      /** @type {number} */
      this.get(LayerProperty.MAX_RESOLUTION)
    );
  }
  /**
   * Return the minimum resolution of the layer. Returns 0 if
   * the layer has no minimum resolution set.
   * @return {number} The minimum resolution of the layer.
   * @observable
   * @api
   */
  getMinResolution() {
    return (
      /** @type {number} */
      this.get(LayerProperty.MIN_RESOLUTION)
    );
  }
  /**
   * Return the minimum zoom level of the layer. Returns -Infinity if
   * the layer has no minimum zoom set.
   * @return {number} The minimum zoom level of the layer.
   * @observable
   * @api
   */
  getMinZoom() {
    return (
      /** @type {number} */
      this.get(LayerProperty.MIN_ZOOM)
    );
  }
  /**
   * Return the maximum zoom level of the layer. Returns Infinity if
   * the layer has no maximum zoom set.
   * @return {number} The maximum zoom level of the layer.
   * @observable
   * @api
   */
  getMaxZoom() {
    return (
      /** @type {number} */
      this.get(LayerProperty.MAX_ZOOM)
    );
  }
  /**
   * Return the opacity of the layer (between 0 and 1).
   * @return {number} The opacity of the layer.
   * @observable
   * @api
   */
  getOpacity() {
    return (
      /** @type {number} */
      this.get(LayerProperty.OPACITY)
    );
  }
  /**
   * @abstract
   * @return {import("../source/Source.js").State} Source state.
   */
  getSourceState() {
    return abstract();
  }
  /**
   * Return the value of this layer's `visible` property. To find out whether the layer
   * is visible on a map, use `isVisible()` instead.
   * @return {boolean} The value of the `visible` property of the layer.
   * @observable
   * @api
   */
  getVisible() {
    return (
      /** @type {boolean} */
      this.get(LayerProperty.VISIBLE)
    );
  }
  /**
   * Return the Z-index of the layer, which is used to order layers before
   * rendering. Returns undefined if the layer is unmanaged.
   * @return {number|undefined} The Z-index of the layer.
   * @observable
   * @api
   */
  getZIndex() {
    return (
      /** @type {number|undefined} */
      this.get(LayerProperty.Z_INDEX)
    );
  }
  /**
   * Sets the background color.
   * @param {BackgroundColor} [background] Background color.
   */
  setBackground(background2) {
    this.background_ = background2;
    this.changed();
  }
  /**
   * Set the extent at which the layer is visible.  If `undefined`, the layer
   * will be visible at all extents.
   * @param {import("../extent.js").Extent|undefined} extent The extent of the layer.
   * @observable
   * @api
   */
  setExtent(extent) {
    this.set(LayerProperty.EXTENT, extent);
  }
  /**
   * Set the maximum resolution at which the layer is visible.
   * @param {number} maxResolution The maximum resolution of the layer.
   * @observable
   * @api
   */
  setMaxResolution(maxResolution) {
    this.set(LayerProperty.MAX_RESOLUTION, maxResolution);
  }
  /**
   * Set the minimum resolution at which the layer is visible.
   * @param {number} minResolution The minimum resolution of the layer.
   * @observable
   * @api
   */
  setMinResolution(minResolution) {
    this.set(LayerProperty.MIN_RESOLUTION, minResolution);
  }
  /**
   * Set the maximum zoom (exclusive) at which the layer is visible.
   * Note that the zoom levels for layer visibility are based on the
   * view zoom level, which may be different from a tile source zoom level.
   * @param {number} maxZoom The maximum zoom of the layer.
   * @observable
   * @api
   */
  setMaxZoom(maxZoom) {
    this.set(LayerProperty.MAX_ZOOM, maxZoom);
  }
  /**
   * Set the minimum zoom (inclusive) at which the layer is visible.
   * Note that the zoom levels for layer visibility are based on the
   * view zoom level, which may be different from a tile source zoom level.
   * @param {number} minZoom The minimum zoom of the layer.
   * @observable
   * @api
   */
  setMinZoom(minZoom) {
    this.set(LayerProperty.MIN_ZOOM, minZoom);
  }
  /**
   * Set the opacity of the layer, allowed values range from 0 to 1.
   * @param {number} opacity The opacity of the layer.
   * @observable
   * @api
   */
  setOpacity(opacity) {
    assert(typeof opacity === "number", "Layer opacity must be a number");
    this.set(LayerProperty.OPACITY, opacity);
  }
  /**
   * Set the visibility of the layer (`true` or `false`).
   * @param {boolean} visible The visibility of the layer.
   * @observable
   * @api
   */
  setVisible(visible) {
    this.set(LayerProperty.VISIBLE, visible);
  }
  /**
   * Set Z-index of the layer, which is used to order layers before rendering.
   * The default Z-index is 0.
   * @param {number} zindex The z-index of the layer.
   * @observable
   * @api
   */
  setZIndex(zindex) {
    this.set(LayerProperty.Z_INDEX, zindex);
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    if (this.state_) {
      this.state_.layer = null;
      this.state_ = null;
    }
    super.disposeInternal();
  }
}
class GroupEvent extends BaseEvent {
  /**
   * @param {GroupEventType} type The event type.
   * @param {BaseLayer} layer The layer.
   */
  constructor(type, layer) {
    super(type);
    this.layer = layer;
  }
}
const Property$1 = {
  LAYERS: "layers"
};
class LayerGroup extends BaseLayer {
  /**
   * @param {Options} [options] Layer options.
   */
  constructor(options2) {
    options2 = options2 || {};
    const baseOptions = (
      /** @type {Options} */
      Object.assign({}, options2)
    );
    delete baseOptions.layers;
    let layers = options2.layers;
    super(baseOptions);
    this.on;
    this.once;
    this.un;
    this.layersListenerKeys_ = [];
    this.listenerKeys_ = {};
    this.addChangeListener(Property$1.LAYERS, this.handleLayersChanged_);
    if (layers) {
      if (Array.isArray(layers)) {
        layers = new Collection(layers.slice(), { unique: true });
      } else {
        assert(
          typeof /** @type {?} */
          layers.getArray === "function",
          "Expected `layers` to be an array or a `Collection`"
        );
      }
    } else {
      layers = new Collection(void 0, { unique: true });
    }
    this.setLayers(layers);
  }
  /**
   * @private
   */
  handleLayerChange_() {
    this.changed();
  }
  /**
   * @private
   */
  handleLayersChanged_() {
    this.layersListenerKeys_.forEach(unlistenByKey);
    this.layersListenerKeys_.length = 0;
    const layers = this.getLayers();
    this.layersListenerKeys_.push(
      listen(layers, CollectionEventType.ADD, this.handleLayersAdd_, this),
      listen(
        layers,
        CollectionEventType.REMOVE,
        this.handleLayersRemove_,
        this
      )
    );
    for (const id in this.listenerKeys_) {
      this.listenerKeys_[id].forEach(unlistenByKey);
    }
    clear(this.listenerKeys_);
    const layersArray = layers.getArray();
    for (let i = 0, ii = layersArray.length; i < ii; i++) {
      const layer = layersArray[i];
      this.registerLayerListeners_(layer);
      this.dispatchEvent(new GroupEvent("addlayer", layer));
    }
    this.changed();
  }
  /**
   * @param {BaseLayer} layer The layer.
   */
  registerLayerListeners_(layer) {
    const listenerKeys = [
      listen(
        layer,
        ObjectEventType.PROPERTYCHANGE,
        this.handleLayerChange_,
        this
      ),
      listen(layer, EventType.CHANGE, this.handleLayerChange_, this)
    ];
    if (layer instanceof LayerGroup) {
      listenerKeys.push(
        listen(layer, "addlayer", this.handleLayerGroupAdd_, this),
        listen(layer, "removelayer", this.handleLayerGroupRemove_, this)
      );
    }
    this.listenerKeys_[getUid(layer)] = listenerKeys;
  }
  /**
   * @param {GroupEvent} event The layer group event.
   */
  handleLayerGroupAdd_(event) {
    this.dispatchEvent(new GroupEvent("addlayer", event.layer));
  }
  /**
   * @param {GroupEvent} event The layer group event.
   */
  handleLayerGroupRemove_(event) {
    this.dispatchEvent(new GroupEvent("removelayer", event.layer));
  }
  /**
   * @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
   * @private
   */
  handleLayersAdd_(collectionEvent) {
    const layer = collectionEvent.element;
    this.registerLayerListeners_(layer);
    this.dispatchEvent(new GroupEvent("addlayer", layer));
    this.changed();
  }
  /**
   * @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
   * @private
   */
  handleLayersRemove_(collectionEvent) {
    const layer = collectionEvent.element;
    const key2 = getUid(layer);
    this.listenerKeys_[key2].forEach(unlistenByKey);
    delete this.listenerKeys_[key2];
    this.dispatchEvent(new GroupEvent("removelayer", layer));
    this.changed();
  }
  /**
   * Returns the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
   * in this group.
   * @return {!Collection<import("./Base.js").default>} Collection of
   *   {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
   * @observable
   * @api
   */
  getLayers() {
    return (
      /** @type {!Collection<import("./Base.js").default>} */
      this.get(Property$1.LAYERS)
    );
  }
  /**
   * Set the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
   * in this group.
   * @param {!Collection<import("./Base.js").default>} layers Collection of
   *   {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
   * @observable
   * @api
   */
  setLayers(layers) {
    const collection = this.getLayers();
    if (collection) {
      const currentLayers = collection.getArray();
      for (let i = 0, ii = currentLayers.length; i < ii; ++i) {
        this.dispatchEvent(new GroupEvent("removelayer", currentLayers[i]));
      }
    }
    this.set(Property$1.LAYERS, layers);
  }
  /**
   * @param {Array<import("./Layer.js").default>} [array] Array of layers (to be modified in place).
   * @return {Array<import("./Layer.js").default>} Array of layers.
   * @override
   */
  getLayersArray(array) {
    array = array !== void 0 ? array : [];
    this.getLayers().forEach(function(layer) {
      layer.getLayersArray(array);
    });
    return array;
  }
  /**
   * Get the layer states list and use this groups z-index as the default
   * for all layers in this and nested groups, if it is unset at this point.
   * If dest is not provided and this group's z-index is undefined
   * 0 is used a the default z-index.
   * @param {Array<import("./Layer.js").State>} [dest] Optional list
   * of layer states (to be modified in place).
   * @return {Array<import("./Layer.js").State>} List of layer states.
   * @override
   */
  getLayerStatesArray(dest) {
    const states2 = dest !== void 0 ? dest : [];
    const pos = states2.length;
    this.getLayers().forEach(function(layer) {
      layer.getLayerStatesArray(states2);
    });
    const ownLayerState = this.getLayerState();
    let defaultZIndex = ownLayerState.zIndex;
    if (!dest && ownLayerState.zIndex === void 0) {
      defaultZIndex = 0;
    }
    for (let i = pos, ii = states2.length; i < ii; i++) {
      const layerState = states2[i];
      layerState.opacity *= ownLayerState.opacity;
      layerState.visible = layerState.visible && ownLayerState.visible;
      layerState.maxResolution = Math.min(
        layerState.maxResolution,
        ownLayerState.maxResolution
      );
      layerState.minResolution = Math.max(
        layerState.minResolution,
        ownLayerState.minResolution
      );
      layerState.minZoom = Math.max(layerState.minZoom, ownLayerState.minZoom);
      layerState.maxZoom = Math.min(layerState.maxZoom, ownLayerState.maxZoom);
      if (ownLayerState.extent !== void 0) {
        if (layerState.extent !== void 0) {
          layerState.extent = getIntersection(
            layerState.extent,
            ownLayerState.extent
          );
        } else {
          layerState.extent = ownLayerState.extent;
        }
      }
      if (layerState.zIndex === void 0) {
        layerState.zIndex = defaultZIndex;
      }
    }
    return states2;
  }
  /**
   * @return {import("../source/Source.js").State} Source state.
   * @override
   */
  getSourceState() {
    return "ready";
  }
}
const RenderEventType = {
  /**
   * Triggered before a layer is rendered.
   * @event module:ol/render/Event~RenderEvent#prerender
   * @api
   */
  PRERENDER: "prerender",
  /**
   * Triggered after a layer is rendered.
   * @event module:ol/render/Event~RenderEvent#postrender
   * @api
   */
  POSTRENDER: "postrender",
  /**
   * Triggered before layers are composed.  When dispatched by the map, the event object will not have
   * a `context` set.  When dispatched by a layer, the event object will have a `context` set.  Only
   * WebGL layers currently dispatch this event.
   * @event module:ol/render/Event~RenderEvent#precompose
   * @api
   */
  PRECOMPOSE: "precompose",
  /**
   * Triggered after layers are composed.  When dispatched by the map, the event object will not have
   * a `context` set.  When dispatched by a layer, the event object will have a `context` set.  Only
   * WebGL layers currently dispatch this event.
   * @event module:ol/render/Event~RenderEvent#postcompose
   * @api
   */
  POSTCOMPOSE: "postcompose",
  /**
   * Triggered when rendering is complete, i.e. all sources and tiles have
   * finished loading for the current viewport, and all tiles are faded in.
   * The event object will not have a `context` set.
   * @event module:ol/render/Event~RenderEvent#rendercomplete
   * @api
   */
  RENDERCOMPLETE: "rendercomplete"
};
class Layer extends BaseLayer {
  /**
   * @param {Options<SourceType>} options Layer options.
   */
  constructor(options2) {
    const baseOptions = Object.assign({}, options2);
    delete baseOptions.source;
    super(baseOptions);
    this.on;
    this.once;
    this.un;
    this.mapPrecomposeKey_ = null;
    this.mapRenderKey_ = null;
    this.sourceChangeKey_ = null;
    this.renderer_ = null;
    this.sourceReady_ = false;
    this.rendered = false;
    if (options2.render) {
      this.render = options2.render;
    }
    if (options2.map) {
      this.setMap(options2.map);
    }
    this.addChangeListener(
      LayerProperty.SOURCE,
      this.handleSourcePropertyChange_
    );
    const source = options2.source ? (
      /** @type {SourceType} */
      options2.source
    ) : null;
    this.setSource(source);
  }
  /**
   * @param {Array<import("./Layer.js").default>} [array] Array of layers (to be modified in place).
   * @return {Array<import("./Layer.js").default>} Array of layers.
   * @override
   */
  getLayersArray(array) {
    array = array ? array : [];
    array.push(this);
    return array;
  }
  /**
   * @param {Array<import("./Layer.js").State>} [states] Optional list of layer states (to be modified in place).
   * @return {Array<import("./Layer.js").State>} List of layer states.
   * @override
   */
  getLayerStatesArray(states2) {
    states2 = states2 ? states2 : [];
    states2.push(this.getLayerState());
    return states2;
  }
  /**
   * Get the layer source.
   * @return {SourceType|null} The layer source (or `null` if not yet set).
   * @observable
   * @api
   */
  getSource() {
    return (
      /** @type {SourceType} */
      this.get(LayerProperty.SOURCE) || null
    );
  }
  /**
   * @return {SourceType|null} The source being rendered.
   */
  getRenderSource() {
    return this.getSource();
  }
  /**
   * @return {import("../source/Source.js").State} Source state.
   * @override
   */
  getSourceState() {
    const source = this.getSource();
    return !source ? "undefined" : source.getState();
  }
  /**
   * @private
   */
  handleSourceChange_() {
    this.changed();
    if (this.sourceReady_ || this.getSource().getState() !== "ready") {
      return;
    }
    this.sourceReady_ = true;
    this.dispatchEvent("sourceready");
  }
  /**
   * @private
   */
  handleSourcePropertyChange_() {
    if (this.sourceChangeKey_) {
      unlistenByKey(this.sourceChangeKey_);
      this.sourceChangeKey_ = null;
    }
    this.sourceReady_ = false;
    const source = this.getSource();
    if (source) {
      this.sourceChangeKey_ = listen(
        source,
        EventType.CHANGE,
        this.handleSourceChange_,
        this
      );
      if (source.getState() === "ready") {
        this.sourceReady_ = true;
        setTimeout(() => {
          this.dispatchEvent("sourceready");
        }, 0);
      }
    }
    this.changed();
  }
  /**
   * @param {import("../pixel").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../Feature").FeatureLike>>} Promise that resolves with
   * an array of features.
   */
  getFeatures(pixel) {
    if (!this.renderer_) {
      return Promise.resolve([]);
    }
    return this.renderer_.getFeatures(pixel);
  }
  /**
   * @param {import("../pixel").Pixel} pixel Pixel.
   * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data.
   */
  getData(pixel) {
    if (!this.renderer_ || !this.rendered) {
      return null;
    }
    return this.renderer_.getData(pixel);
  }
  /**
   * The layer is visible on the map view, i.e. within its min/max resolution or zoom and
   * extent, not set to `visible: false`, and not inside a layer group that is set
   * to `visible: false`.
   * @param {View|import("../View.js").ViewStateLayerStateExtent} [view] View or {@link import("../Map.js").FrameState}.
   * Only required when the layer is not added to a map.
   * @return {boolean} The layer is visible in the map view.
   * @api
   */
  isVisible(view) {
    let frameState;
    const map = this.getMapInternal();
    if (!view && map) {
      view = map.getView();
    }
    if (view instanceof View) {
      frameState = {
        viewState: view.getState(),
        extent: view.calculateExtent()
      };
    } else {
      frameState = view;
    }
    if (!frameState.layerStatesArray && map) {
      frameState.layerStatesArray = map.getLayerGroup().getLayerStatesArray();
    }
    let layerState;
    if (frameState.layerStatesArray) {
      layerState = frameState.layerStatesArray.find(
        (layerState2) => layerState2.layer === this
      );
      if (!layerState) {
        return false;
      }
    } else {
      layerState = this.getLayerState();
    }
    const layerExtent = this.getExtent();
    return inView(layerState, frameState.viewState) && (!layerExtent || intersects$1(layerExtent, frameState.extent));
  }
  /**
   * Get the attributions of the source of this layer for the given view.
   * @param {View|import("../View.js").ViewStateLayerStateExtent} [view] View or {@link import("../Map.js").FrameState}.
   * Only required when the layer is not added to a map.
   * @return {Array<string>} Attributions for this layer at the given view.
   * @api
   */
  getAttributions(view) {
    if (!this.isVisible(view)) {
      return [];
    }
    const getAttributions = this.getSource()?.getAttributions();
    if (!getAttributions) {
      return [];
    }
    const frameState = view instanceof View ? view.getViewStateAndExtent() : view;
    let attributions = getAttributions(frameState);
    if (!Array.isArray(attributions)) {
      attributions = [attributions];
    }
    return attributions;
  }
  /**
   * In charge to manage the rendering of the layer. One layer type is
   * bounded with one layer renderer.
   * @param {?import("../Map.js").FrameState} frameState Frame state.
   * @param {HTMLElement} target Target which the renderer may (but need not) use
   * for rendering its content.
   * @return {HTMLElement|null} The rendered element.
   */
  render(frameState, target) {
    const layerRenderer = this.getRenderer();
    if (layerRenderer.prepareFrame(frameState)) {
      this.rendered = true;
      return layerRenderer.renderFrame(frameState, target);
    }
    return null;
  }
  /**
   * Called when a layer is not visible during a map render.
   */
  unrender() {
    this.rendered = false;
  }
  /** @return {string} Declutter */
  getDeclutter() {
    return void 0;
  }
  /**
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @param {import("../layer/Layer.js").State} layerState Layer state.
   */
  renderDeclutter(frameState, layerState) {
  }
  /**
   * When the renderer follows a layout -> render approach, do the final rendering here.
   * @param {import('../Map.js').FrameState} frameState Frame state
   */
  renderDeferred(frameState) {
    const layerRenderer = this.getRenderer();
    if (!layerRenderer) {
      return;
    }
    layerRenderer.renderDeferred(frameState);
  }
  /**
   * For use inside the library only.
   * @param {import("../Map.js").default|null} map Map.
   */
  setMapInternal(map) {
    if (!map) {
      this.unrender();
    }
    this.set(LayerProperty.MAP, map);
  }
  /**
   * For use inside the library only.
   * @return {import("../Map.js").default|null} Map.
   */
  getMapInternal() {
    return this.get(LayerProperty.MAP);
  }
  /**
   * Sets the layer to be rendered on top of other layers on a map. The map will
   * not manage this layer in its layers collection. This
   * is useful for temporary layers. To remove an unmanaged layer from the map,
   * use `#setMap(null)`.
   *
   * To add the layer to a map and have it managed by the map, use
   * {@link module:ol/Map~Map#addLayer} instead.
   * @param {import("../Map.js").default|null} map Map.
   * @api
   */
  setMap(map) {
    if (this.mapPrecomposeKey_) {
      unlistenByKey(this.mapPrecomposeKey_);
      this.mapPrecomposeKey_ = null;
    }
    if (!map) {
      this.changed();
    }
    if (this.mapRenderKey_) {
      unlistenByKey(this.mapRenderKey_);
      this.mapRenderKey_ = null;
    }
    if (map) {
      this.mapPrecomposeKey_ = listen(
        map,
        RenderEventType.PRECOMPOSE,
        this.handlePrecompose_,
        this
      );
      this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
      this.changed();
    }
  }
  /**
   * @param {import("../events/Event.js").default} renderEvent Render event
   * @private
   */
  handlePrecompose_(renderEvent) {
    const layerStatesArray = (
      /** @type {import("../render/Event.js").default} */
      renderEvent.frameState.layerStatesArray
    );
    const layerState = this.getLayerState(false);
    assert(
      !layerStatesArray.some(
        (arrayLayerState) => arrayLayerState.layer === layerState.layer
      ),
      "A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both."
    );
    layerStatesArray.push(layerState);
  }
  /**
   * Set the layer source.
   * @param {SourceType|null} source The layer source.
   * @observable
   * @api
   */
  setSource(source) {
    this.set(LayerProperty.SOURCE, source);
  }
  /**
   * Get the renderer for this layer.
   * @return {RendererType|null} The layer renderer.
   */
  getRenderer() {
    if (!this.renderer_) {
      this.renderer_ = this.createRenderer();
    }
    return this.renderer_;
  }
  /**
   * @return {boolean} The layer has a renderer.
   */
  hasRenderer() {
    return !!this.renderer_;
  }
  /**
   * Create a renderer for this layer.
   * @return {RendererType} A layer renderer.
   * @protected
   */
  createRenderer() {
    return null;
  }
  /**
   * This will clear the renderer so that a new one can be created next time it is needed
   */
  clearRenderer() {
    if (this.renderer_) {
      this.renderer_.dispose();
      delete this.renderer_;
    }
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    this.clearRenderer();
    this.setSource(null);
    super.disposeInternal();
  }
}
function inView(layerState, viewState) {
  if (!layerState.visible) {
    return false;
  }
  const resolution = viewState.resolution;
  if (resolution < layerState.minResolution || resolution >= layerState.maxResolution) {
    return false;
  }
  const zoom = viewState.zoom;
  return zoom > layerState.minZoom && zoom <= layerState.maxZoom;
}
function quickselect(arr, k, left = 0, right = arr.length - 1, compare = defaultCompare) {
  while (right > left) {
    if (right - left > 600) {
      const n = right - left + 1;
      const m = k - left + 1;
      const z = Math.log(n);
      const s = 0.5 * Math.exp(2 * z / 3);
      const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
      const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
      const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
      quickselect(arr, k, newLeft, newRight, compare);
    }
    const t = arr[k];
    let i = left;
    let j = right;
    swap(arr, left, k);
    if (compare(arr[right], t) > 0) swap(arr, left, right);
    while (i < j) {
      swap(arr, i, j);
      i++;
      j--;
      while (compare(arr[i], t) < 0) i++;
      while (compare(arr[j], t) > 0) j--;
    }
    if (compare(arr[left], t) === 0) swap(arr, left, j);
    else {
      j++;
      swap(arr, j, right);
    }
    if (j <= k) left = j + 1;
    if (k <= j) right = j - 1;
  }
}
function swap(arr, i, j) {
  const tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp;
}
function defaultCompare(a, b) {
  return a < b ? -1 : a > b ? 1 : 0;
}
let RBush$1 = class RBush2 {
  constructor(maxEntries = 9) {
    this._maxEntries = Math.max(4, maxEntries);
    this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
    this.clear();
  }
  all() {
    return this._all(this.data, []);
  }
  search(bbox) {
    let node = this.data;
    const result = [];
    if (!intersects(bbox, node)) return result;
    const toBBox = this.toBBox;
    const nodesToSearch = [];
    while (node) {
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        const childBBox = node.leaf ? toBBox(child) : child;
        if (intersects(bbox, childBBox)) {
          if (node.leaf) result.push(child);
          else if (contains(bbox, childBBox)) this._all(child, result);
          else nodesToSearch.push(child);
        }
      }
      node = nodesToSearch.pop();
    }
    return result;
  }
  collides(bbox) {
    let node = this.data;
    if (!intersects(bbox, node)) return false;
    const nodesToSearch = [];
    while (node) {
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        const childBBox = node.leaf ? this.toBBox(child) : child;
        if (intersects(bbox, childBBox)) {
          if (node.leaf || contains(bbox, childBBox)) return true;
          nodesToSearch.push(child);
        }
      }
      node = nodesToSearch.pop();
    }
    return false;
  }
  load(data) {
    if (!(data && data.length)) return this;
    if (data.length < this._minEntries) {
      for (let i = 0; i < data.length; i++) {
        this.insert(data[i]);
      }
      return this;
    }
    let node = this._build(data.slice(), 0, data.length - 1, 0);
    if (!this.data.children.length) {
      this.data = node;
    } else if (this.data.height === node.height) {
      this._splitRoot(this.data, node);
    } else {
      if (this.data.height < node.height) {
        const tmpNode = this.data;
        this.data = node;
        node = tmpNode;
      }
      this._insert(node, this.data.height - node.height - 1, true);
    }
    return this;
  }
  insert(item) {
    if (item) this._insert(item, this.data.height - 1);
    return this;
  }
  clear() {
    this.data = createNode([]);
    return this;
  }
  remove(item, equalsFn) {
    if (!item) return this;
    let node = this.data;
    const bbox = this.toBBox(item);
    const path = [];
    const indexes = [];
    let i, parent, goingUp;
    while (node || path.length) {
      if (!node) {
        node = path.pop();
        parent = path[path.length - 1];
        i = indexes.pop();
        goingUp = true;
      }
      if (node.leaf) {
        const index = findItem(item, node.children, equalsFn);
        if (index !== -1) {
          node.children.splice(index, 1);
          path.push(node);
          this._condense(path);
          return this;
        }
      }
      if (!goingUp && !node.leaf && contains(node, bbox)) {
        path.push(node);
        indexes.push(i);
        i = 0;
        parent = node;
        node = node.children[0];
      } else if (parent) {
        i++;
        node = parent.children[i];
        goingUp = false;
      } else node = null;
    }
    return this;
  }
  toBBox(item) {
    return item;
  }
  compareMinX(a, b) {
    return a.minX - b.minX;
  }
  compareMinY(a, b) {
    return a.minY - b.minY;
  }
  toJSON() {
    return this.data;
  }
  fromJSON(data) {
    this.data = data;
    return this;
  }
  _all(node, result) {
    const nodesToSearch = [];
    while (node) {
      if (node.leaf) result.push(...node.children);
      else nodesToSearch.push(...node.children);
      node = nodesToSearch.pop();
    }
    return result;
  }
  _build(items, left, right, height) {
    const N = right - left + 1;
    let M5 = this._maxEntries;
    let node;
    if (N <= M5) {
      node = createNode(items.slice(left, right + 1));
      calcBBox(node, this.toBBox);
      return node;
    }
    if (!height) {
      height = Math.ceil(Math.log(N) / Math.log(M5));
      M5 = Math.ceil(N / Math.pow(M5, height - 1));
    }
    node = createNode([]);
    node.leaf = false;
    node.height = height;
    const N2 = Math.ceil(N / M5);
    const N1 = N2 * Math.ceil(Math.sqrt(M5));
    multiSelect(items, left, right, N1, this.compareMinX);
    for (let i = left; i <= right; i += N1) {
      const right2 = Math.min(i + N1 - 1, right);
      multiSelect(items, i, right2, N2, this.compareMinY);
      for (let j = i; j <= right2; j += N2) {
        const right3 = Math.min(j + N2 - 1, right2);
        node.children.push(this._build(items, j, right3, height - 1));
      }
    }
    calcBBox(node, this.toBBox);
    return node;
  }
  _chooseSubtree(bbox, node, level, path) {
    while (true) {
      path.push(node);
      if (node.leaf || path.length - 1 === level) break;
      let minArea = Infinity;
      let minEnlargement = Infinity;
      let targetNode;
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        const area = bboxArea(child);
        const enlargement = enlargedArea(bbox, child) - area;
        if (enlargement < minEnlargement) {
          minEnlargement = enlargement;
          minArea = area < minArea ? area : minArea;
          targetNode = child;
        } else if (enlargement === minEnlargement) {
          if (area < minArea) {
            minArea = area;
            targetNode = child;
          }
        }
      }
      node = targetNode || node.children[0];
    }
    return node;
  }
  _insert(item, level, isNode) {
    const bbox = isNode ? item : this.toBBox(item);
    const insertPath = [];
    const node = this._chooseSubtree(bbox, this.data, level, insertPath);
    node.children.push(item);
    extend$1(node, bbox);
    while (level >= 0) {
      if (insertPath[level].children.length > this._maxEntries) {
        this._split(insertPath, level);
        level--;
      } else break;
    }
    this._adjustParentBBoxes(bbox, insertPath, level);
  }
  // split overflowed node into two
  _split(insertPath, level) {
    const node = insertPath[level];
    const M5 = node.children.length;
    const m = this._minEntries;
    this._chooseSplitAxis(node, m, M5);
    const splitIndex = this._chooseSplitIndex(node, m, M5);
    const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
    newNode.height = node.height;
    newNode.leaf = node.leaf;
    calcBBox(node, this.toBBox);
    calcBBox(newNode, this.toBBox);
    if (level) insertPath[level - 1].children.push(newNode);
    else this._splitRoot(node, newNode);
  }
  _splitRoot(node, newNode) {
    this.data = createNode([node, newNode]);
    this.data.height = node.height + 1;
    this.data.leaf = false;
    calcBBox(this.data, this.toBBox);
  }
  _chooseSplitIndex(node, m, M5) {
    let index;
    let minOverlap = Infinity;
    let minArea = Infinity;
    for (let i = m; i <= M5 - m; i++) {
      const bbox1 = distBBox(node, 0, i, this.toBBox);
      const bbox2 = distBBox(node, i, M5, this.toBBox);
      const overlap = intersectionArea(bbox1, bbox2);
      const area = bboxArea(bbox1) + bboxArea(bbox2);
      if (overlap < minOverlap) {
        minOverlap = overlap;
        index = i;
        minArea = area < minArea ? area : minArea;
      } else if (overlap === minOverlap) {
        if (area < minArea) {
          minArea = area;
          index = i;
        }
      }
    }
    return index || M5 - m;
  }
  // sorts node children by the best axis for split
  _chooseSplitAxis(node, m, M5) {
    const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
    const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
    const xMargin = this._allDistMargin(node, m, M5, compareMinX);
    const yMargin = this._allDistMargin(node, m, M5, compareMinY);
    if (xMargin < yMargin) node.children.sort(compareMinX);
  }
  // total margin of all possible split distributions where each node is at least m full
  _allDistMargin(node, m, M5, compare) {
    node.children.sort(compare);
    const toBBox = this.toBBox;
    const leftBBox = distBBox(node, 0, m, toBBox);
    const rightBBox = distBBox(node, M5 - m, M5, toBBox);
    let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
    for (let i = m; i < M5 - m; i++) {
      const child = node.children[i];
      extend$1(leftBBox, node.leaf ? toBBox(child) : child);
      margin += bboxMargin(leftBBox);
    }
    for (let i = M5 - m - 1; i >= m; i--) {
      const child = node.children[i];
      extend$1(rightBBox, node.leaf ? toBBox(child) : child);
      margin += bboxMargin(rightBBox);
    }
    return margin;
  }
  _adjustParentBBoxes(bbox, path, level) {
    for (let i = level; i >= 0; i--) {
      extend$1(path[i], bbox);
    }
  }
  _condense(path) {
    for (let i = path.length - 1, siblings; i >= 0; i--) {
      if (path[i].children.length === 0) {
        if (i > 0) {
          siblings = path[i - 1].children;
          siblings.splice(siblings.indexOf(path[i]), 1);
        } else this.clear();
      } else calcBBox(path[i], this.toBBox);
    }
  }
};
function findItem(item, items, equalsFn) {
  if (!equalsFn) return items.indexOf(item);
  for (let i = 0; i < items.length; i++) {
    if (equalsFn(item, items[i])) return i;
  }
  return -1;
}
function calcBBox(node, toBBox) {
  distBBox(node, 0, node.children.length, toBBox, node);
}
function distBBox(node, k, p, toBBox, destNode) {
  if (!destNode) destNode = createNode(null);
  destNode.minX = Infinity;
  destNode.minY = Infinity;
  destNode.maxX = -Infinity;
  destNode.maxY = -Infinity;
  for (let i = k; i < p; i++) {
    const child = node.children[i];
    extend$1(destNode, node.leaf ? toBBox(child) : child);
  }
  return destNode;
}
function extend$1(a, b) {
  a.minX = Math.min(a.minX, b.minX);
  a.minY = Math.min(a.minY, b.minY);
  a.maxX = Math.max(a.maxX, b.maxX);
  a.maxY = Math.max(a.maxY, b.maxY);
  return a;
}
function compareNodeMinX(a, b) {
  return a.minX - b.minX;
}
function compareNodeMinY(a, b) {
  return a.minY - b.minY;
}
function bboxArea(a) {
  return (a.maxX - a.minX) * (a.maxY - a.minY);
}
function bboxMargin(a) {
  return a.maxX - a.minX + (a.maxY - a.minY);
}
function enlargedArea(a, b) {
  return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
}
function intersectionArea(a, b) {
  const minX = Math.max(a.minX, b.minX);
  const minY = Math.max(a.minY, b.minY);
  const maxX = Math.min(a.maxX, b.maxX);
  const maxY = Math.min(a.maxY, b.maxY);
  return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
}
function contains(a, b) {
  return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
}
function intersects(a, b) {
  return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
}
function createNode(children) {
  return {
    children,
    height: 1,
    leaf: true,
    minX: Infinity,
    minY: Infinity,
    maxX: -Infinity,
    maxY: -Infinity
  };
}
function multiSelect(arr, left, right, n, compare) {
  const stack = [left, right];
  while (stack.length) {
    right = stack.pop();
    left = stack.pop();
    if (right - left <= n) continue;
    const mid = left + Math.ceil((right - left) / n / 2) * n;
    quickselect(arr, mid, left, right, compare);
    stack.push(left, mid, mid, right);
  }
}
const NO_COLOR = [NaN, NaN, NaN, 0];
let colorParseContext;
function getColorParseContext() {
  if (!colorParseContext) {
    colorParseContext = createCanvasContext2D(1, 1, void 0, {
      willReadFrequently: true,
      desynchronized: true
    });
  }
  return colorParseContext;
}
const rgbModernRegEx = /^rgba?\(\s*(\d+%?)\s+(\d+%?)\s+(\d+%?)(?:\s*\/\s*(\d+%|\d*\.\d+|[01]))?\s*\)$/i;
const rgbLegacyAbsoluteRegEx = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*(\d+%|\d*\.\d+|[01]))?\s*\)$/i;
const rgbLegacyPercentageRegEx = /^rgba?\(\s*(\d+%)\s*,\s*(\d+%)\s*,\s*(\d+%)(?:\s*,\s*(\d+%|\d*\.\d+|[01]))?\s*\)$/i;
const hexRegEx = /^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i;
function toColorComponent(s, divider) {
  return s.endsWith("%") ? Number(s.substring(0, s.length - 1)) / divider : Number(s);
}
function throwInvalidColor(color2) {
  throw new Error('failed to parse "' + color2 + '" as color');
}
function parseRgba(color2) {
  if (color2.toLowerCase().startsWith("rgb")) {
    const rgb = color2.match(rgbLegacyAbsoluteRegEx) || color2.match(rgbModernRegEx) || color2.match(rgbLegacyPercentageRegEx);
    if (rgb) {
      const alpha = rgb[4];
      const rgbDivider = 100 / 255;
      return [
        clamp(toColorComponent(rgb[1], rgbDivider) + 0.5 | 0, 0, 255),
        clamp(toColorComponent(rgb[2], rgbDivider) + 0.5 | 0, 0, 255),
        clamp(toColorComponent(rgb[3], rgbDivider) + 0.5 | 0, 0, 255),
        alpha !== void 0 ? clamp(toColorComponent(alpha, 100), 0, 1) : 1
      ];
    }
    throwInvalidColor(color2);
  }
  if (color2.startsWith("#")) {
    if (hexRegEx.test(color2)) {
      const hex = color2.substring(1);
      const step = hex.length <= 4 ? 1 : 2;
      const colorFromHex = [0, 0, 0, 255];
      for (let i = 0, ii = hex.length; i < ii; i += step) {
        let colorComponent = parseInt(hex.substring(i, i + step), 16);
        if (step === 1) {
          colorComponent += colorComponent << 4;
        }
        colorFromHex[i / step] = colorComponent;
      }
      colorFromHex[3] = colorFromHex[3] / 255;
      return colorFromHex;
    }
    throwInvalidColor(color2);
  }
  const context = getColorParseContext();
  context.fillStyle = "#abcdef";
  let invalidCheckFillStyle = context.fillStyle;
  context.fillStyle = color2;
  if (context.fillStyle === invalidCheckFillStyle) {
    context.fillStyle = "#fedcba";
    invalidCheckFillStyle = context.fillStyle;
    context.fillStyle = color2;
    if (context.fillStyle === invalidCheckFillStyle) {
      throwInvalidColor(color2);
    }
  }
  const colorString = context.fillStyle;
  if (colorString.startsWith("#") || colorString.startsWith("rgba")) {
    return parseRgba(colorString);
  }
  context.clearRect(0, 0, 1, 1);
  context.fillRect(0, 0, 1, 1);
  const colorFromImage = Array.from(context.getImageData(0, 0, 1, 1).data);
  colorFromImage[3] = toFixed(colorFromImage[3] / 255, 3);
  return colorFromImage;
}
function asString(color2) {
  if (typeof color2 === "string") {
    return color2;
  }
  return toString(color2);
}
const MAX_CACHE_SIZE = 1024;
const cache = {};
let cacheSize = 0;
function withAlpha(color2) {
  if (color2.length === 4) {
    return color2;
  }
  const output = color2.slice();
  output[3] = 1;
  return output;
}
function b1(v) {
  return v > 31308e-7 ? Math.pow(v, 1 / 2.4) * 269.025 - 14.025 : v * 3294.6;
}
function b2(v) {
  return v > 0.2068965 ? Math.pow(v, 3) : (v - 4 / 29) * (108 / 841);
}
function a1(v) {
  return v > 10.314724 ? Math.pow((v + 14.025) / 269.025, 2.4) : v / 3294.6;
}
function a2(v) {
  return v > 88564e-7 ? Math.pow(v, 1 / 3) : v / (108 / 841) + 4 / 29;
}
function rgbaToLcha(color2) {
  const r = a1(color2[0]);
  const g = a1(color2[1]);
  const b = a1(color2[2]);
  const y = a2(r * 0.222488403 + g * 0.716873169 + b * 0.06060791);
  const l = 500 * (a2(r * 0.452247074 + g * 0.399439023 + b * 0.148375274) - y);
  const q = 200 * (y - a2(r * 0.016863605 + g * 0.117638439 + b * 0.865350722));
  const h = Math.atan2(q, l) * (180 / Math.PI);
  return [
    116 * y - 16,
    Math.sqrt(l * l + q * q),
    h < 0 ? h + 360 : h,
    color2[3]
  ];
}
function lchaToRgba(color2) {
  const l = (color2[0] + 16) / 116;
  const c = color2[1];
  const h = color2[2] * Math.PI / 180;
  const y = b2(l);
  const x = b2(l + c / 500 * Math.cos(h));
  const z = b2(l - c / 200 * Math.sin(h));
  const r = b1(x * 3.021973625 - y * 1.617392459 - z * 0.404875592);
  const g = b1(x * -0.943766287 + y * 1.916279586 + z * 0.027607165);
  const b = b1(x * 0.069407491 - y * 0.22898585 + z * 1.159737864);
  return [
    clamp(r + 0.5 | 0, 0, 255),
    clamp(g + 0.5 | 0, 0, 255),
    clamp(b + 0.5 | 0, 0, 255),
    color2[3]
  ];
}
function fromString(s) {
  if (s === "none") {
    return NO_COLOR;
  }
  if (cache.hasOwnProperty(s)) {
    return cache[s];
  }
  if (cacheSize >= MAX_CACHE_SIZE) {
    let i = 0;
    for (const key2 in cache) {
      if ((i++ & 3) === 0) {
        delete cache[key2];
        --cacheSize;
      }
    }
  }
  const color2 = parseRgba(s);
  if (color2.length !== 4) {
    throwInvalidColor(s);
  }
  for (const c of color2) {
    if (isNaN(c)) {
      throwInvalidColor(s);
    }
  }
  cache[s] = color2;
  ++cacheSize;
  return color2;
}
function asArray(color2) {
  if (Array.isArray(color2)) {
    return color2;
  }
  return fromString(color2);
}
function toString(color2) {
  let r = color2[0];
  if (r != (r | 0)) {
    r = r + 0.5 | 0;
  }
  let g = color2[1];
  if (g != (g | 0)) {
    g = g + 0.5 | 0;
  }
  let b = color2[2];
  if (b != (b | 0)) {
    b = b + 0.5 | 0;
  }
  const a = color2[3] === void 0 ? 1 : Math.round(color2[3] * 1e3) / 1e3;
  return "rgba(" + r + "," + g + "," + b + "," + a + ")";
}
function hasArea(size) {
  return size[0] > 0 && size[1] > 0;
}
function scale(size, ratio, dest) {
  if (dest === void 0) {
    dest = [0, 0];
  }
  dest[0] = size[0] * ratio + 0.5 | 0;
  dest[1] = size[1] * ratio + 0.5 | 0;
  return dest;
}
function toSize(size, dest) {
  if (Array.isArray(size)) {
    return size;
  }
  if (dest === void 0) {
    dest = [size, size];
  } else {
    dest[0] = size;
    dest[1] = size;
  }
  return dest;
}
let numTypes = 0;
const BooleanType = 1 << numTypes++;
const NumberType = 1 << numTypes++;
const StringType = 1 << numTypes++;
const ColorType = 1 << numTypes++;
const NumberArrayType = 1 << numTypes++;
const SizeType = 1 << numTypes++;
const AnyType = Math.pow(2, numTypes) - 1;
const typeNames = {
  [BooleanType]: "boolean",
  [NumberType]: "number",
  [StringType]: "string",
  [ColorType]: "color",
  [NumberArrayType]: "number[]",
  [SizeType]: "size"
};
const namedTypes = Object.keys(typeNames).map(Number).sort(ascending);
function isSpecific(type) {
  return type in typeNames;
}
function typeName(type) {
  const names2 = [];
  for (const namedType of namedTypes) {
    if (includesType(type, namedType)) {
      names2.push(typeNames[namedType]);
    }
  }
  if (names2.length === 0) {
    return "untyped";
  }
  if (names2.length < 3) {
    return names2.join(" or ");
  }
  return names2.slice(0, -1).join(", ") + ", or " + names2[names2.length - 1];
}
function includesType(broad, specific) {
  return (broad & specific) === specific;
}
function isType(type, expected) {
  return type === expected;
}
class LiteralExpression {
  /**
   * @param {number} type The value type.
   * @param {LiteralValue} value The literal value.
   */
  constructor(type, value) {
    if (!isSpecific(type)) {
      throw new Error(
        `literal expressions must have a specific type, got ${typeName(type)}`
      );
    }
    this.type = type;
    this.value = value;
  }
}
class CallExpression {
  /**
   * @param {number} type The return type.
   * @param {string} operator The operator.
   * @param {...Expression} args The arguments.
   */
  constructor(type, operator, ...args) {
    this.type = type;
    this.operator = operator;
    this.args = args;
  }
}
function newParsingContext() {
  return {
    variables: /* @__PURE__ */ new Set(),
    properties: /* @__PURE__ */ new Set(),
    featureId: false,
    geometryType: false,
    mapState: false
  };
}
function parse$1(encoded, expectedType, context) {
  switch (typeof encoded) {
    case "boolean": {
      if (isType(expectedType, StringType)) {
        return new LiteralExpression(StringType, encoded ? "true" : "false");
      }
      if (!includesType(expectedType, BooleanType)) {
        throw new Error(
          `got a boolean, but expected ${typeName(expectedType)}`
        );
      }
      return new LiteralExpression(BooleanType, encoded);
    }
    case "number": {
      if (isType(expectedType, SizeType)) {
        return new LiteralExpression(SizeType, toSize(encoded));
      }
      if (isType(expectedType, BooleanType)) {
        return new LiteralExpression(BooleanType, !!encoded);
      }
      if (isType(expectedType, StringType)) {
        return new LiteralExpression(StringType, encoded.toString());
      }
      if (!includesType(expectedType, NumberType)) {
        throw new Error(`got a number, but expected ${typeName(expectedType)}`);
      }
      return new LiteralExpression(NumberType, encoded);
    }
    case "string": {
      if (isType(expectedType, ColorType)) {
        return new LiteralExpression(ColorType, fromString(encoded));
      }
      if (isType(expectedType, BooleanType)) {
        return new LiteralExpression(BooleanType, !!encoded);
      }
      if (!includesType(expectedType, StringType)) {
        throw new Error(`got a string, but expected ${typeName(expectedType)}`);
      }
      return new LiteralExpression(StringType, encoded);
    }
  }
  if (!Array.isArray(encoded)) {
    throw new Error("expression must be an array or a primitive value");
  }
  if (encoded.length === 0) {
    throw new Error("empty expression");
  }
  if (typeof encoded[0] === "string") {
    return parseCallExpression(encoded, expectedType, context);
  }
  for (const item of encoded) {
    if (typeof item !== "number") {
      throw new Error("expected an array of numbers");
    }
  }
  if (isType(expectedType, SizeType)) {
    if (encoded.length !== 2) {
      throw new Error(
        `expected an array of two values for a size, got ${encoded.length}`
      );
    }
    return new LiteralExpression(SizeType, encoded);
  }
  if (isType(expectedType, ColorType)) {
    if (encoded.length === 3) {
      return new LiteralExpression(ColorType, [...encoded, 1]);
    }
    if (encoded.length === 4) {
      return new LiteralExpression(ColorType, encoded);
    }
    throw new Error(
      `expected an array of 3 or 4 values for a color, got ${encoded.length}`
    );
  }
  if (!includesType(expectedType, NumberArrayType)) {
    throw new Error(
      `got an array of numbers, but expected ${typeName(expectedType)}`
    );
  }
  return new LiteralExpression(NumberArrayType, encoded);
}
const Ops = {
  Get: "get",
  Var: "var",
  Concat: "concat",
  GeometryType: "geometry-type",
  LineMetric: "line-metric",
  Any: "any",
  All: "all",
  Not: "!",
  Resolution: "resolution",
  Zoom: "zoom",
  Time: "time",
  Equal: "==",
  NotEqual: "!=",
  GreaterThan: ">",
  GreaterThanOrEqualTo: ">=",
  LessThan: "<",
  LessThanOrEqualTo: "<=",
  Multiply: "*",
  Divide: "/",
  Add: "+",
  Subtract: "-",
  Clamp: "clamp",
  Mod: "%",
  Pow: "^",
  Abs: "abs",
  Floor: "floor",
  Ceil: "ceil",
  Round: "round",
  Sin: "sin",
  Cos: "cos",
  Atan: "atan",
  Sqrt: "sqrt",
  Match: "match",
  Between: "between",
  Interpolate: "interpolate",
  Coalesce: "coalesce",
  Case: "case",
  In: "in",
  Number: "number",
  String: "string",
  Array: "array",
  Color: "color",
  Id: "id",
  Band: "band",
  Palette: "palette",
  ToString: "to-string",
  Has: "has"
};
const parsers = {
  [Ops.Get]: createCallExpressionParser(hasArgsCount(1, Infinity), withGetArgs),
  [Ops.Var]: createCallExpressionParser(hasArgsCount(1, 1), withVarArgs),
  [Ops.Has]: createCallExpressionParser(hasArgsCount(1, Infinity), withGetArgs),
  [Ops.Id]: createCallExpressionParser(usesFeatureId, withNoArgs),
  [Ops.Concat]: createCallExpressionParser(
    hasArgsCount(2, Infinity),
    withArgsOfType(StringType)
  ),
  [Ops.GeometryType]: createCallExpressionParser(usesGeometryType, withNoArgs),
  [Ops.LineMetric]: createCallExpressionParser(withNoArgs),
  [Ops.Resolution]: createCallExpressionParser(usesMapState, withNoArgs),
  [Ops.Zoom]: createCallExpressionParser(usesMapState, withNoArgs),
  [Ops.Time]: createCallExpressionParser(usesMapState, withNoArgs),
  [Ops.Any]: createCallExpressionParser(
    hasArgsCount(2, Infinity),
    withArgsOfType(BooleanType)
  ),
  [Ops.All]: createCallExpressionParser(
    hasArgsCount(2, Infinity),
    withArgsOfType(BooleanType)
  ),
  [Ops.Not]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(BooleanType)
  ),
  [Ops.Equal]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(AnyType)
  ),
  [Ops.NotEqual]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(AnyType)
  ),
  [Ops.GreaterThan]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.GreaterThanOrEqualTo]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.LessThan]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.LessThanOrEqualTo]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.Multiply]: createCallExpressionParser(
    hasArgsCount(2, Infinity),
    withArgsOfReturnType
  ),
  [Ops.Coalesce]: createCallExpressionParser(
    hasArgsCount(2, Infinity),
    withArgsOfReturnType
  ),
  [Ops.Divide]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.Add]: createCallExpressionParser(
    hasArgsCount(2, Infinity),
    withArgsOfType(NumberType)
  ),
  [Ops.Subtract]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.Clamp]: createCallExpressionParser(
    hasArgsCount(3, 3),
    withArgsOfType(NumberType)
  ),
  [Ops.Mod]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.Pow]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.Abs]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Floor]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Ceil]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Round]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Sin]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Cos]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Atan]: createCallExpressionParser(
    hasArgsCount(1, 2),
    withArgsOfType(NumberType)
  ),
  [Ops.Sqrt]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(NumberType)
  ),
  [Ops.Match]: createCallExpressionParser(
    hasArgsCount(4, Infinity),
    hasEvenArgs,
    withMatchArgs
  ),
  [Ops.Between]: createCallExpressionParser(
    hasArgsCount(3, 3),
    withArgsOfType(NumberType)
  ),
  [Ops.Interpolate]: createCallExpressionParser(
    hasArgsCount(6, Infinity),
    hasEvenArgs,
    withInterpolateArgs
  ),
  [Ops.Case]: createCallExpressionParser(
    hasArgsCount(3, Infinity),
    hasOddArgs,
    withCaseArgs
  ),
  [Ops.In]: createCallExpressionParser(hasArgsCount(2, 2), withInArgs),
  [Ops.Number]: createCallExpressionParser(
    hasArgsCount(1, Infinity),
    withArgsOfType(AnyType)
  ),
  [Ops.String]: createCallExpressionParser(
    hasArgsCount(1, Infinity),
    withArgsOfType(AnyType)
  ),
  [Ops.Array]: createCallExpressionParser(
    hasArgsCount(1, Infinity),
    withArgsOfType(NumberType)
  ),
  [Ops.Color]: createCallExpressionParser(
    hasArgsCount(1, 4),
    withArgsOfType(NumberType)
  ),
  [Ops.Band]: createCallExpressionParser(
    hasArgsCount(1, 3),
    withArgsOfType(NumberType)
  ),
  [Ops.Palette]: createCallExpressionParser(
    hasArgsCount(2, 2),
    withPaletteArgs
  ),
  [Ops.ToString]: createCallExpressionParser(
    hasArgsCount(1, 1),
    withArgsOfType(BooleanType | NumberType | StringType | ColorType)
  )
};
function withGetArgs(encoded, returnType, context) {
  const argsCount = encoded.length - 1;
  const args = new Array(argsCount);
  for (let i = 0; i < argsCount; ++i) {
    const key2 = encoded[i + 1];
    switch (typeof key2) {
      case "number": {
        args[i] = new LiteralExpression(NumberType, key2);
        break;
      }
      case "string": {
        args[i] = new LiteralExpression(StringType, key2);
        break;
      }
      default: {
        throw new Error(
          `expected a string key or numeric array index for a get operation, got ${key2}`
        );
      }
    }
    if (i === 0) {
      context.properties.add(String(key2));
    }
  }
  return args;
}
function withVarArgs(encoded, returnType, context) {
  const name = encoded[1];
  if (typeof name !== "string") {
    throw new Error("expected a string argument for var operation");
  }
  context.variables.add(name);
  return [new LiteralExpression(StringType, name)];
}
function usesFeatureId(encoded, returnType, context) {
  context.featureId = true;
}
function usesGeometryType(encoded, returnType, context) {
  context.geometryType = true;
}
function usesMapState(encoded, returnType, context) {
  context.mapState = true;
}
function withNoArgs(encoded, returnType, context) {
  const operation = encoded[0];
  if (encoded.length !== 1) {
    throw new Error(`expected no arguments for ${operation} operation`);
  }
  return [];
}
function hasArgsCount(minArgs, maxArgs) {
  return function(encoded, returnType, context) {
    const operation = encoded[0];
    const argCount = encoded.length - 1;
    if (minArgs === maxArgs) {
      if (argCount !== minArgs) {
        const plural = minArgs === 1 ? "" : "s";
        throw new Error(
          `expected ${minArgs} argument${plural} for ${operation}, got ${argCount}`
        );
      }
    } else if (argCount < minArgs || argCount > maxArgs) {
      const range2 = maxArgs === Infinity ? `${minArgs} or more` : `${minArgs} to ${maxArgs}`;
      throw new Error(
        `expected ${range2} arguments for ${operation}, got ${argCount}`
      );
    }
  };
}
function withArgsOfReturnType(encoded, returnType, context) {
  const argCount = encoded.length - 1;
  const args = new Array(argCount);
  for (let i = 0; i < argCount; ++i) {
    const expression = parse$1(encoded[i + 1], returnType, context);
    args[i] = expression;
  }
  return args;
}
function withArgsOfType(argType) {
  return function(encoded, returnType, context) {
    const argCount = encoded.length - 1;
    const args = new Array(argCount);
    for (let i = 0; i < argCount; ++i) {
      const expression = parse$1(encoded[i + 1], argType, context);
      args[i] = expression;
    }
    return args;
  };
}
function hasOddArgs(encoded, returnType, context) {
  const operation = encoded[0];
  const argCount = encoded.length - 1;
  if (argCount % 2 === 0) {
    throw new Error(
      `expected an odd number of arguments for ${operation}, got ${argCount} instead`
    );
  }
}
function hasEvenArgs(encoded, returnType, context) {
  const operation = encoded[0];
  const argCount = encoded.length - 1;
  if (argCount % 2 === 1) {
    throw new Error(
      `expected an even number of arguments for operation ${operation}, got ${argCount} instead`
    );
  }
}
function withMatchArgs(encoded, returnType, context) {
  const argsCount = encoded.length - 1;
  const inputType = StringType | NumberType | BooleanType;
  const input = parse$1(encoded[1], inputType, context);
  const fallback = parse$1(encoded[encoded.length - 1], returnType, context);
  const args = new Array(argsCount - 2);
  for (let i = 0; i < argsCount - 2; i += 2) {
    try {
      const match2 = parse$1(encoded[i + 2], input.type, context);
      args[i] = match2;
    } catch (err) {
      throw new Error(
        `failed to parse argument ${i + 1} of match expression: ${err.message}`
      );
    }
    try {
      const output = parse$1(encoded[i + 3], fallback.type, context);
      args[i + 1] = output;
    } catch (err) {
      throw new Error(
        `failed to parse argument ${i + 2} of match expression: ${err.message}`
      );
    }
  }
  return [input, ...args, fallback];
}
function withInterpolateArgs(encoded, returnType, context) {
  const interpolationType = encoded[1];
  let base2;
  switch (interpolationType[0]) {
    case "linear":
      base2 = 1;
      break;
    case "exponential":
      const b = interpolationType[1];
      if (typeof b !== "number" || b <= 0) {
        throw new Error(
          `expected a number base for exponential interpolation, got ${JSON.stringify(b)} instead`
        );
      }
      base2 = b;
      break;
    default:
      throw new Error(
        `invalid interpolation type: ${JSON.stringify(interpolationType)}`
      );
  }
  const interpolation = new LiteralExpression(NumberType, base2);
  let input;
  try {
    input = parse$1(encoded[2], NumberType, context);
  } catch (err) {
    throw new Error(
      `failed to parse argument 1 in interpolate expression: ${err.message}`
    );
  }
  const args = new Array(encoded.length - 3);
  for (let i = 0; i < args.length; i += 2) {
    try {
      const stop2 = parse$1(encoded[i + 3], NumberType, context);
      args[i] = stop2;
    } catch (err) {
      throw new Error(
        `failed to parse argument ${i + 2} for interpolate expression: ${err.message}`
      );
    }
    try {
      const output = parse$1(encoded[i + 4], returnType, context);
      args[i + 1] = output;
    } catch (err) {
      throw new Error(
        `failed to parse argument ${i + 3} for interpolate expression: ${err.message}`
      );
    }
  }
  return [interpolation, input, ...args];
}
function withCaseArgs(encoded, returnType, context) {
  const fallback = parse$1(encoded[encoded.length - 1], returnType, context);
  const args = new Array(encoded.length - 1);
  for (let i = 0; i < args.length - 1; i += 2) {
    try {
      const condition = parse$1(encoded[i + 1], BooleanType, context);
      args[i] = condition;
    } catch (err) {
      throw new Error(
        `failed to parse argument ${i} of case expression: ${err.message}`
      );
    }
    try {
      const output = parse$1(encoded[i + 2], fallback.type, context);
      args[i + 1] = output;
    } catch (err) {
      throw new Error(
        `failed to parse argument ${i + 1} of case expression: ${err.message}`
      );
    }
  }
  args[args.length - 1] = fallback;
  return args;
}
function withInArgs(encoded, returnType, context) {
  let haystack = encoded[2];
  if (!Array.isArray(haystack)) {
    throw new Error(
      `the second argument for the "in" operator must be an array`
    );
  }
  let needleType;
  if (typeof haystack[0] === "string") {
    if (haystack[0] !== "literal") {
      throw new Error(
        `for the "in" operator, a string array should be wrapped in a "literal" operator to disambiguate from expressions`
      );
    }
    if (!Array.isArray(haystack[1])) {
      throw new Error(
        `failed to parse "in" expression: the literal operator must be followed by an array`
      );
    }
    haystack = haystack[1];
    needleType = StringType;
  } else {
    needleType = NumberType;
  }
  const args = new Array(haystack.length);
  for (let i = 0; i < args.length; i++) {
    try {
      const arg = parse$1(haystack[i], needleType, context);
      args[i] = arg;
    } catch (err) {
      throw new Error(
        `failed to parse haystack item ${i} for "in" expression: ${err.message}`
      );
    }
  }
  const needle = parse$1(encoded[1], needleType, context);
  return [needle, ...args];
}
function withPaletteArgs(encoded, returnType, context) {
  let index;
  try {
    index = parse$1(encoded[1], NumberType, context);
  } catch (err) {
    throw new Error(
      `failed to parse first argument in palette expression: ${err.message}`
    );
  }
  const colors = encoded[2];
  if (!Array.isArray(colors)) {
    throw new Error("the second argument of palette must be an array");
  }
  const parsedColors = new Array(colors.length);
  for (let i = 0; i < parsedColors.length; i++) {
    let color2;
    try {
      color2 = parse$1(colors[i], ColorType, context);
    } catch (err) {
      throw new Error(
        `failed to parse color at index ${i} in palette expression: ${err.message}`
      );
    }
    if (!(color2 instanceof LiteralExpression)) {
      throw new Error(
        `the palette color at index ${i} must be a literal value`
      );
    }
    parsedColors[i] = color2;
  }
  return [index, ...parsedColors];
}
function createCallExpressionParser(...validators) {
  return function(encoded, returnType, context) {
    const operator = encoded[0];
    let args;
    for (let i = 0; i < validators.length; i++) {
      const parsed = validators[i](encoded, returnType, context);
      if (i == validators.length - 1) {
        if (!parsed) {
          throw new Error(
            "expected last argument validator to return the parsed args"
          );
        }
        args = parsed;
      }
    }
    return new CallExpression(returnType, operator, ...args);
  };
}
function parseCallExpression(encoded, returnType, context) {
  const operator = encoded[0];
  const parser = parsers[operator];
  if (!parser) {
    throw new Error(`unknown operator: ${operator}`);
  }
  return parser(encoded, returnType, context);
}
function computeGeometryType(geometry) {
  if (!geometry) {
    return "";
  }
  const type = geometry.getType();
  switch (type) {
    case "Point":
    case "LineString":
    case "Polygon":
      return type;
    case "MultiPoint":
    case "MultiLineString":
    case "MultiPolygon":
      return (
        /** @type {'Point'|'LineString'|'Polygon'} */
        type.substring(5)
      );
    case "Circle":
      return "Polygon";
    case "GeometryCollection":
      return computeGeometryType(
        /** @type {import("../geom/GeometryCollection.js").default} */
        geometry.getGeometries()[0]
      );
    default:
      return "";
  }
}
function newEvaluationContext() {
  return {
    variables: {},
    properties: {},
    resolution: NaN,
    featureId: null,
    geometryType: ""
  };
}
function buildExpression(encoded, type, context) {
  const expression = parse$1(encoded, type, context);
  return compileExpression(expression);
}
function compileExpression(expression, context) {
  if (expression instanceof LiteralExpression) {
    if (expression.type === ColorType && typeof expression.value === "string") {
      const colorValue = fromString(expression.value);
      return function() {
        return colorValue;
      };
    }
    return function() {
      return expression.value;
    };
  }
  const operator = expression.operator;
  switch (operator) {
    case Ops.Number:
    case Ops.String:
    case Ops.Coalesce: {
      return compileAssertionExpression(expression);
    }
    case Ops.Get:
    case Ops.Var:
    case Ops.Has: {
      return compileAccessorExpression(expression);
    }
    case Ops.Id: {
      return (context2) => context2.featureId;
    }
    case Ops.GeometryType: {
      return (context2) => context2.geometryType;
    }
    case Ops.Concat: {
      const args = expression.args.map((e) => compileExpression(e));
      return (context2) => "".concat(...args.map((arg) => arg(context2).toString()));
    }
    case Ops.Resolution: {
      return (context2) => context2.resolution;
    }
    case Ops.Any:
    case Ops.All:
    case Ops.Between:
    case Ops.In:
    case Ops.Not: {
      return compileLogicalExpression(expression);
    }
    case Ops.Equal:
    case Ops.NotEqual:
    case Ops.LessThan:
    case Ops.LessThanOrEqualTo:
    case Ops.GreaterThan:
    case Ops.GreaterThanOrEqualTo: {
      return compileComparisonExpression(expression);
    }
    case Ops.Multiply:
    case Ops.Divide:
    case Ops.Add:
    case Ops.Subtract:
    case Ops.Clamp:
    case Ops.Mod:
    case Ops.Pow:
    case Ops.Abs:
    case Ops.Floor:
    case Ops.Ceil:
    case Ops.Round:
    case Ops.Sin:
    case Ops.Cos:
    case Ops.Atan:
    case Ops.Sqrt: {
      return compileNumericExpression(expression);
    }
    case Ops.Case: {
      return compileCaseExpression(expression);
    }
    case Ops.Match: {
      return compileMatchExpression(expression);
    }
    case Ops.Interpolate: {
      return compileInterpolateExpression(expression);
    }
    case Ops.ToString: {
      return compileConvertExpression(expression);
    }
    default: {
      throw new Error(`Unsupported operator ${operator}`);
    }
  }
}
function compileAssertionExpression(expression, context) {
  const type = expression.operator;
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  switch (type) {
    case Ops.Coalesce: {
      return (context2) => {
        for (let i = 0; i < length; ++i) {
          const value = args[i](context2);
          if (typeof value !== "undefined" && value !== null) {
            return value;
          }
        }
        throw new Error("Expected one of the values to be non-null");
      };
    }
    case Ops.Number:
    case Ops.String: {
      return (context2) => {
        for (let i = 0; i < length; ++i) {
          const value = args[i](context2);
          if (typeof value === type) {
            return value;
          }
        }
        throw new Error(`Expected one of the values to be a ${type}`);
      };
    }
    default: {
      throw new Error(`Unsupported assertion operator ${type}`);
    }
  }
}
function compileAccessorExpression(expression, context) {
  const nameExpression = (
    /** @type {LiteralExpression} */
    expression.args[0]
  );
  const name = (
    /** @type {string} */
    nameExpression.value
  );
  switch (expression.operator) {
    case Ops.Get: {
      return (context2) => {
        const args = expression.args;
        let value = context2.properties[name];
        for (let i = 1, ii = args.length; i < ii; ++i) {
          const keyExpression = (
            /** @type {LiteralExpression} */
            args[i]
          );
          const key2 = (
            /** @type {string|number} */
            keyExpression.value
          );
          value = value[key2];
        }
        return value;
      };
    }
    case Ops.Var: {
      return (context2) => context2.variables[name];
    }
    case Ops.Has: {
      return (context2) => {
        const args = expression.args;
        if (!(name in context2.properties)) {
          return false;
        }
        let value = context2.properties[name];
        for (let i = 1, ii = args.length; i < ii; ++i) {
          const keyExpression = (
            /** @type {LiteralExpression} */
            args[i]
          );
          const key2 = (
            /** @type {string|number} */
            keyExpression.value
          );
          if (!value || !Object.hasOwn(value, key2)) {
            return false;
          }
          value = value[key2];
        }
        return true;
      };
    }
    default: {
      throw new Error(`Unsupported accessor operator ${expression.operator}`);
    }
  }
}
function compileComparisonExpression(expression, context) {
  const op = expression.operator;
  const left = compileExpression(expression.args[0]);
  const right = compileExpression(expression.args[1]);
  switch (op) {
    case Ops.Equal: {
      return (context2) => left(context2) === right(context2);
    }
    case Ops.NotEqual: {
      return (context2) => left(context2) !== right(context2);
    }
    case Ops.LessThan: {
      return (context2) => left(context2) < right(context2);
    }
    case Ops.LessThanOrEqualTo: {
      return (context2) => left(context2) <= right(context2);
    }
    case Ops.GreaterThan: {
      return (context2) => left(context2) > right(context2);
    }
    case Ops.GreaterThanOrEqualTo: {
      return (context2) => left(context2) >= right(context2);
    }
    default: {
      throw new Error(`Unsupported comparison operator ${op}`);
    }
  }
}
function compileLogicalExpression(expression, context) {
  const op = expression.operator;
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  switch (op) {
    case Ops.Any: {
      return (context2) => {
        for (let i = 0; i < length; ++i) {
          if (args[i](context2)) {
            return true;
          }
        }
        return false;
      };
    }
    case Ops.All: {
      return (context2) => {
        for (let i = 0; i < length; ++i) {
          if (!args[i](context2)) {
            return false;
          }
        }
        return true;
      };
    }
    case Ops.Between: {
      return (context2) => {
        const value = args[0](context2);
        const min2 = args[1](context2);
        const max2 = args[2](context2);
        return value >= min2 && value <= max2;
      };
    }
    case Ops.In: {
      return (context2) => {
        const value = args[0](context2);
        for (let i = 1; i < length; ++i) {
          if (value === args[i](context2)) {
            return true;
          }
        }
        return false;
      };
    }
    case Ops.Not: {
      return (context2) => !args[0](context2);
    }
    default: {
      throw new Error(`Unsupported logical operator ${op}`);
    }
  }
}
function compileNumericExpression(expression, context) {
  const op = expression.operator;
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  switch (op) {
    case Ops.Multiply: {
      return (context2) => {
        let value = 1;
        for (let i = 0; i < length; ++i) {
          value *= args[i](context2);
        }
        return value;
      };
    }
    case Ops.Divide: {
      return (context2) => args[0](context2) / args[1](context2);
    }
    case Ops.Add: {
      return (context2) => {
        let value = 0;
        for (let i = 0; i < length; ++i) {
          value += args[i](context2);
        }
        return value;
      };
    }
    case Ops.Subtract: {
      return (context2) => args[0](context2) - args[1](context2);
    }
    case Ops.Clamp: {
      return (context2) => {
        const value = args[0](context2);
        const min2 = args[1](context2);
        if (value < min2) {
          return min2;
        }
        const max2 = args[2](context2);
        if (value > max2) {
          return max2;
        }
        return value;
      };
    }
    case Ops.Mod: {
      return (context2) => args[0](context2) % args[1](context2);
    }
    case Ops.Pow: {
      return (context2) => Math.pow(args[0](context2), args[1](context2));
    }
    case Ops.Abs: {
      return (context2) => Math.abs(args[0](context2));
    }
    case Ops.Floor: {
      return (context2) => Math.floor(args[0](context2));
    }
    case Ops.Ceil: {
      return (context2) => Math.ceil(args[0](context2));
    }
    case Ops.Round: {
      return (context2) => Math.round(args[0](context2));
    }
    case Ops.Sin: {
      return (context2) => Math.sin(args[0](context2));
    }
    case Ops.Cos: {
      return (context2) => Math.cos(args[0](context2));
    }
    case Ops.Atan: {
      if (length === 2) {
        return (context2) => Math.atan2(args[0](context2), args[1](context2));
      }
      return (context2) => Math.atan(args[0](context2));
    }
    case Ops.Sqrt: {
      return (context2) => Math.sqrt(args[0](context2));
    }
    default: {
      throw new Error(`Unsupported numeric operator ${op}`);
    }
  }
}
function compileCaseExpression(expression, context) {
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  return (context2) => {
    for (let i = 0; i < length - 1; i += 2) {
      const condition = args[i](context2);
      if (condition) {
        return args[i + 1](context2);
      }
    }
    return args[length - 1](context2);
  };
}
function compileMatchExpression(expression, context) {
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  return (context2) => {
    const value = args[0](context2);
    for (let i = 1; i < length - 1; i += 2) {
      if (value === args[i](context2)) {
        return args[i + 1](context2);
      }
    }
    return args[length - 1](context2);
  };
}
function compileInterpolateExpression(expression, context) {
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  return (context2) => {
    const base2 = args[0](context2);
    const value = args[1](context2);
    let previousInput;
    let previousOutput;
    for (let i = 2; i < length; i += 2) {
      const input = args[i](context2);
      let output = args[i + 1](context2);
      const isColor = Array.isArray(output);
      if (isColor) {
        output = withAlpha(output);
      }
      if (input >= value) {
        if (i === 2) {
          return output;
        }
        if (isColor) {
          return interpolateColor(
            base2,
            value,
            previousInput,
            previousOutput,
            input,
            output
          );
        }
        return interpolateNumber(
          base2,
          value,
          previousInput,
          previousOutput,
          input,
          output
        );
      }
      previousInput = input;
      previousOutput = output;
    }
    return previousOutput;
  };
}
function compileConvertExpression(expression, context) {
  const op = expression.operator;
  const length = expression.args.length;
  const args = new Array(length);
  for (let i = 0; i < length; ++i) {
    args[i] = compileExpression(expression.args[i]);
  }
  switch (op) {
    case Ops.ToString: {
      return (context2) => {
        const value = args[0](context2);
        if (expression.args[0].type === ColorType) {
          return toString(value);
        }
        return value.toString();
      };
    }
    default: {
      throw new Error(`Unsupported convert operator ${op}`);
    }
  }
}
function interpolateNumber(base2, value, input1, output1, input2, output2) {
  const delta = input2 - input1;
  if (delta === 0) {
    return output1;
  }
  const along = value - input1;
  const factor = base2 === 1 ? along / delta : (Math.pow(base2, along) - 1) / (Math.pow(base2, delta) - 1);
  return output1 + factor * (output2 - output1);
}
function interpolateColor(base2, value, input1, rgba1, input2, rgba2) {
  const delta = input2 - input1;
  if (delta === 0) {
    return rgba1;
  }
  const lcha1 = rgbaToLcha(rgba1);
  const lcha2 = rgbaToLcha(rgba2);
  let deltaHue = lcha2[2] - lcha1[2];
  if (deltaHue > 180) {
    deltaHue -= 360;
  } else if (deltaHue < -180) {
    deltaHue += 360;
  }
  const lcha = [
    interpolateNumber(base2, value, input1, lcha1[0], input2, lcha2[0]),
    interpolateNumber(base2, value, input1, lcha1[1], input2, lcha2[1]),
    lcha1[2] + interpolateNumber(base2, value, input1, 0, input2, deltaHue),
    interpolateNumber(base2, value, input1, rgba1[3], input2, rgba2[3])
  ];
  return lchaToRgba(lcha);
}
const ImageState = {
  IDLE: 0,
  LOADING: 1,
  LOADED: 2,
  ERROR: 3,
  EMPTY: 4
};
class ImageWrapper extends Target {
  /**
   * @param {import("./extent.js").Extent} extent Extent.
   * @param {number|Array<number>|undefined} resolution Resolution. If provided as array, x and y
   * resolution will be assumed.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("./ImageState.js").default|Loader} stateOrLoader State.
   */
  constructor(extent, resolution, pixelRatio, stateOrLoader) {
    super();
    this.extent = extent;
    this.pixelRatio_ = pixelRatio;
    this.resolution = resolution;
    this.state = typeof stateOrLoader === "function" ? ImageState.IDLE : stateOrLoader;
    this.image_ = null;
    this.loader = typeof stateOrLoader === "function" ? stateOrLoader : null;
  }
  /**
   * @protected
   */
  changed() {
    this.dispatchEvent(EventType.CHANGE);
  }
  /**
   * @return {import("./extent.js").Extent} Extent.
   */
  getExtent() {
    return this.extent;
  }
  /**
   * @return {import('./DataTile.js').ImageLike} Image.
   */
  getImage() {
    return this.image_;
  }
  /**
   * @return {number} PixelRatio.
   */
  getPixelRatio() {
    return this.pixelRatio_;
  }
  /**
   * @return {number|Array<number>} Resolution.
   */
  getResolution() {
    return (
      /** @type {number} */
      this.resolution
    );
  }
  /**
   * @return {import("./ImageState.js").default} State.
   */
  getState() {
    return this.state;
  }
  /**
   * Load not yet loaded URI.
   */
  load() {
    if (this.state == ImageState.IDLE) {
      if (this.loader) {
        this.state = ImageState.LOADING;
        this.changed();
        const resolution = this.getResolution();
        const requestResolution = Array.isArray(resolution) ? resolution[0] : resolution;
        toPromise(
          () => this.loader(
            this.getExtent(),
            requestResolution,
            this.getPixelRatio()
          )
        ).then((image) => {
          if ("image" in image) {
            this.image_ = image.image;
          }
          if ("extent" in image) {
            this.extent = image.extent;
          }
          if ("resolution" in image) {
            this.resolution = image.resolution;
          }
          if ("pixelRatio" in image) {
            this.pixelRatio_ = image.pixelRatio;
          }
          if (image instanceof HTMLImageElement || CREATE_IMAGE_BITMAP && image instanceof ImageBitmap || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement) {
            this.image_ = image;
          }
          this.state = ImageState.LOADED;
        }).catch((error2) => {
          this.state = ImageState.ERROR;
          console.error(error2);
        }).finally(() => this.changed());
      }
    }
  }
  /**
   * @param {import('./DataTile.js').ImageLike} image The image.
   */
  setImage(image) {
    this.image_ = image;
  }
  /**
   * @param {number|Array<number>} resolution Resolution.
   */
  setResolution(resolution) {
    this.resolution = resolution;
  }
}
function listenImage(image, loadHandler, errorHandler) {
  const img = (
    /** @type {HTMLImageElement} */
    image
  );
  let listening = true;
  let decoding = false;
  let loaded = false;
  const listenerKeys = [
    listenOnce(img, EventType.LOAD, function() {
      loaded = true;
      if (!decoding) {
        loadHandler();
      }
    })
  ];
  if (img.src && IMAGE_DECODE) {
    decoding = true;
    img.decode().then(function() {
      if (listening) {
        loadHandler();
      }
    }).catch(function(error2) {
      if (listening) {
        if (loaded) {
          loadHandler();
        } else {
          errorHandler();
        }
      }
    });
  } else {
    listenerKeys.push(listenOnce(img, EventType.ERROR, errorHandler));
  }
  return function unlisten() {
    listening = false;
    listenerKeys.forEach(unlistenByKey);
  };
}
function load(image, src) {
  return new Promise((resolve, reject) => {
    function handleLoad() {
      unlisten();
      resolve(image);
    }
    function handleError() {
      unlisten();
      reject(new Error("Image load error"));
    }
    function unlisten() {
      image.removeEventListener("load", handleLoad);
      image.removeEventListener("error", handleError);
    }
    image.addEventListener("load", handleLoad);
    image.addEventListener("error", handleError);
  });
}
function decodeFallback(image, src) {
  if (src) {
    image.src = src;
  }
  return image.src && IMAGE_DECODE ? new Promise(
    (resolve, reject) => image.decode().then(() => resolve(image)).catch(
      (e) => image.complete && image.width ? resolve(image) : reject(e)
    )
  ) : load(image);
}
function decode$1(image, src) {
  if (src) {
    image.src = src;
  }
  return image.src && IMAGE_DECODE && CREATE_IMAGE_BITMAP ? image.decode().then(() => createImageBitmap(image)).catch((e) => {
    if (image.complete && image.width) {
      return image;
    }
    throw e;
  }) : decodeFallback(image);
}
class IconImageCache {
  constructor() {
    this.cache_ = {};
    this.patternCache_ = {};
    this.cacheSize_ = 0;
    this.maxCacheSize_ = 1024;
  }
  /**
   * FIXME empty description for jsdoc
   */
  clear() {
    this.cache_ = {};
    this.patternCache_ = {};
    this.cacheSize_ = 0;
  }
  /**
   * @return {boolean} Can expire cache.
   */
  canExpireCache() {
    return this.cacheSize_ > this.maxCacheSize_;
  }
  /**
   * FIXME empty description for jsdoc
   */
  expire() {
    if (this.canExpireCache()) {
      let i = 0;
      for (const key2 in this.cache_) {
        const iconImage = this.cache_[key2];
        if ((i++ & 3) === 0 && !iconImage.hasListener()) {
          delete this.cache_[key2];
          delete this.patternCache_[key2];
          --this.cacheSize_;
        }
      }
    }
  }
  /**
   * @param {string} src Src.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../color.js").Color|string|null} color Color.
   * @return {import("./IconImage.js").default} Icon image.
   */
  get(src, crossOrigin, color2) {
    const key2 = getCacheKey$1(src, crossOrigin, color2);
    return key2 in this.cache_ ? this.cache_[key2] : null;
  }
  /**
   * @param {string} src Src.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../color.js").Color|string|null} color Color.
   * @return {CanvasPattern} Icon image.
   */
  getPattern(src, crossOrigin, color2) {
    const key2 = getCacheKey$1(src, crossOrigin, color2);
    return key2 in this.patternCache_ ? this.patternCache_[key2] : null;
  }
  /**
   * @param {string} src Src.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../color.js").Color|string|null} color Color.
   * @param {import("./IconImage.js").default|null} iconImage Icon image.
   * @param {boolean} [pattern] Also cache a `'repeat'` pattern with this `iconImage`.
   */
  set(src, crossOrigin, color2, iconImage, pattern) {
    const key2 = getCacheKey$1(src, crossOrigin, color2);
    const update = key2 in this.cache_;
    this.cache_[key2] = iconImage;
    if (pattern) {
      if (iconImage.getImageState() === ImageState.IDLE) {
        iconImage.load();
      }
      if (iconImage.getImageState() === ImageState.LOADING) {
        iconImage.ready().then(() => {
          this.patternCache_[key2] = getSharedCanvasContext2D().createPattern(
            iconImage.getImage(1),
            "repeat"
          );
        });
      } else {
        this.patternCache_[key2] = getSharedCanvasContext2D().createPattern(
          iconImage.getImage(1),
          "repeat"
        );
      }
    }
    if (!update) {
      ++this.cacheSize_;
    }
  }
  /**
   * Set the cache size of the icon cache. Default is `1024`. Change this value when
   * your map uses more than 1024 different icon images and you are not caching icon
   * styles on the application level.
   * @param {number} maxCacheSize Cache max size.
   * @api
   */
  setSize(maxCacheSize) {
    this.maxCacheSize_ = maxCacheSize;
    this.expire();
  }
}
function getCacheKey$1(src, crossOrigin, color2) {
  const colorString = color2 ? asArray(color2) : "null";
  return crossOrigin + ":" + src + ":" + colorString;
}
const shared = new IconImageCache();
let taintedTestContext = null;
class IconImage extends Target {
  /**
   * @param {HTMLImageElement|HTMLCanvasElement|ImageBitmap|null} image Image.
   * @param {string|undefined} src Src.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../ImageState.js").default|undefined} imageState Image state.
   * @param {import("../color.js").Color|string|null} color Color.
   */
  constructor(image, src, crossOrigin, imageState, color2) {
    super();
    this.hitDetectionImage_ = null;
    this.image_ = image;
    this.crossOrigin_ = crossOrigin;
    this.canvas_ = {};
    this.color_ = color2;
    this.imageState_ = imageState === void 0 ? ImageState.IDLE : imageState;
    this.size_ = image && image.width && image.height ? [image.width, image.height] : null;
    this.src_ = src;
    this.tainted_;
    this.ready_ = null;
  }
  /**
   * @private
   */
  initializeImage_() {
    this.image_ = new Image();
    if (this.crossOrigin_ !== null) {
      this.image_.crossOrigin = this.crossOrigin_;
    }
  }
  /**
   * @private
   * @return {boolean} The image canvas is tainted.
   */
  isTainted_() {
    if (this.tainted_ === void 0 && this.imageState_ === ImageState.LOADED) {
      if (!taintedTestContext) {
        taintedTestContext = createCanvasContext2D(1, 1, void 0, {
          willReadFrequently: true
        });
      }
      taintedTestContext.drawImage(this.image_, 0, 0);
      try {
        taintedTestContext.getImageData(0, 0, 1, 1);
        this.tainted_ = false;
      } catch {
        taintedTestContext = null;
        this.tainted_ = true;
      }
    }
    return this.tainted_ === true;
  }
  /**
   * @private
   */
  dispatchChangeEvent_() {
    this.dispatchEvent(EventType.CHANGE);
  }
  /**
   * @private
   */
  handleImageError_() {
    this.imageState_ = ImageState.ERROR;
    this.dispatchChangeEvent_();
  }
  /**
   * @private
   */
  handleImageLoad_() {
    this.imageState_ = ImageState.LOADED;
    this.size_ = [this.image_.width, this.image_.height];
    this.dispatchChangeEvent_();
  }
  /**
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLImageElement|HTMLCanvasElement|ImageBitmap} Image or Canvas element or image bitmap.
   */
  getImage(pixelRatio) {
    if (!this.image_) {
      this.initializeImage_();
    }
    this.replaceColor_(pixelRatio);
    return this.canvas_[pixelRatio] ? this.canvas_[pixelRatio] : this.image_;
  }
  /**
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} Image or Canvas element.
   */
  getPixelRatio(pixelRatio) {
    this.replaceColor_(pixelRatio);
    return this.canvas_[pixelRatio] ? pixelRatio : 1;
  }
  /**
   * @return {import("../ImageState.js").default} Image state.
   */
  getImageState() {
    return this.imageState_;
  }
  /**
   * @return {HTMLImageElement|HTMLCanvasElement|ImageBitmap} Image element.
   */
  getHitDetectionImage() {
    if (!this.image_) {
      this.initializeImage_();
    }
    if (!this.hitDetectionImage_) {
      if (this.isTainted_()) {
        const width = this.size_[0];
        const height = this.size_[1];
        const context = createCanvasContext2D(width, height);
        context.fillRect(0, 0, width, height);
        this.hitDetectionImage_ = context.canvas;
      } else {
        this.hitDetectionImage_ = this.image_;
      }
    }
    return this.hitDetectionImage_;
  }
  /**
   * Get the size of the icon (in pixels).
   * @return {import("../size.js").Size} Image size.
   */
  getSize() {
    return this.size_;
  }
  /**
   * @return {string|undefined} Image src.
   */
  getSrc() {
    return this.src_;
  }
  /**
   * Load not yet loaded URI.
   */
  load() {
    if (this.imageState_ !== ImageState.IDLE) {
      return;
    }
    if (!this.image_) {
      this.initializeImage_();
    }
    this.imageState_ = ImageState.LOADING;
    try {
      if (this.src_ !== void 0) {
        this.image_.src = this.src_;
      }
    } catch {
      this.handleImageError_();
    }
    if (this.image_ instanceof HTMLImageElement) {
      decodeFallback(this.image_, this.src_).then((image) => {
        this.image_ = image;
        this.handleImageLoad_();
      }).catch(this.handleImageError_.bind(this));
    }
  }
  /**
   * @param {number} pixelRatio Pixel ratio.
   * @private
   */
  replaceColor_(pixelRatio) {
    if (!this.color_ || this.canvas_[pixelRatio] || this.imageState_ !== ImageState.LOADED) {
      return;
    }
    const image = this.image_;
    const ctx = createCanvasContext2D(
      Math.ceil(image.width * pixelRatio),
      Math.ceil(image.height * pixelRatio)
    );
    const canvas = ctx.canvas;
    ctx.scale(pixelRatio, pixelRatio);
    ctx.drawImage(image, 0, 0);
    ctx.globalCompositeOperation = "multiply";
    ctx.fillStyle = asString(this.color_);
    ctx.fillRect(0, 0, canvas.width / pixelRatio, canvas.height / pixelRatio);
    ctx.globalCompositeOperation = "destination-in";
    ctx.drawImage(image, 0, 0);
    this.canvas_[pixelRatio] = canvas;
  }
  /**
   * @return {Promise<void>} Promise that resolves when the image is loaded.
   */
  ready() {
    if (!this.ready_) {
      this.ready_ = new Promise((resolve) => {
        if (this.imageState_ === ImageState.LOADED || this.imageState_ === ImageState.ERROR) {
          resolve();
        } else {
          const onChange = () => {
            if (this.imageState_ === ImageState.LOADED || this.imageState_ === ImageState.ERROR) {
              this.removeEventListener(EventType.CHANGE, onChange);
              resolve();
            }
          };
          this.addEventListener(EventType.CHANGE, onChange);
        }
      });
    }
    return this.ready_;
  }
}
function get$1(image, cacheKey, crossOrigin, imageState, color2, pattern) {
  let iconImage = cacheKey === void 0 ? void 0 : shared.get(cacheKey, crossOrigin, color2);
  if (!iconImage) {
    iconImage = new IconImage(
      image,
      image && "src" in image ? image.src || void 0 : cacheKey,
      crossOrigin,
      imageState,
      color2
    );
    shared.set(cacheKey, crossOrigin, color2, iconImage, pattern);
  }
  if (pattern && iconImage && !shared.getPattern(cacheKey, crossOrigin, color2)) {
    shared.set(cacheKey, crossOrigin, color2, iconImage, pattern);
  }
  return iconImage;
}
function asColorLike(color2) {
  if (!color2) {
    return null;
  }
  if (Array.isArray(color2)) {
    return toString(color2);
  }
  if (typeof color2 === "object" && "src" in color2) {
    return asCanvasPattern(color2);
  }
  return color2;
}
function asCanvasPattern(pattern) {
  if (!pattern.offset || !pattern.size) {
    return shared.getPattern(pattern.src, "anonymous", pattern.color);
  }
  const cacheKey = pattern.src + ":" + pattern.offset;
  const canvasPattern = shared.getPattern(
    cacheKey,
    void 0,
    pattern.color
  );
  if (canvasPattern) {
    return canvasPattern;
  }
  const iconImage = shared.get(pattern.src, "anonymous", null);
  if (iconImage.getImageState() !== ImageState.LOADED) {
    return null;
  }
  const patternCanvasContext = createCanvasContext2D(
    pattern.size[0],
    pattern.size[1]
  );
  patternCanvasContext.drawImage(
    iconImage.getImage(1),
    pattern.offset[0],
    pattern.offset[1],
    pattern.size[0],
    pattern.size[1],
    0,
    0,
    pattern.size[0],
    pattern.size[1]
  );
  get$1(
    patternCanvasContext.canvas,
    cacheKey,
    void 0,
    ImageState.LOADED,
    pattern.color,
    true
  );
  return shared.getPattern(cacheKey, void 0, pattern.color);
}
const defaultFont = "10px sans-serif";
const defaultFillStyle = "#000";
const defaultLineCap = "round";
const defaultLineDash = [];
const defaultLineDashOffset = 0;
const defaultLineJoin = "round";
const defaultMiterLimit = 10;
const defaultStrokeStyle = "#000";
const defaultTextAlign = "center";
const defaultTextBaseline = "middle";
const defaultPadding = [0, 0, 0, 0];
const defaultLineWidth = 1;
const checkedFonts = new BaseObject();
let measureContext = null;
let measureFont;
const textHeights = {};
const genericFontFamilies = /* @__PURE__ */ new Set([
  "serif",
  "sans-serif",
  "monospace",
  "cursive",
  "fantasy",
  "system-ui",
  "ui-serif",
  "ui-sans-serif",
  "ui-monospace",
  "ui-rounded",
  "emoji",
  "math",
  "fangsong"
]);
function getFontKey(style, weight, family) {
  return `${style} ${weight} 16px "${family}"`;
}
const registerFont = /* @__PURE__ */ (function() {
  const retries = 100;
  let timeout, fontFaceSet;
  async function isAvailable(fontSpec) {
    await fontFaceSet.ready;
    const fontFaces = await fontFaceSet.load(fontSpec);
    if (fontFaces.length === 0) {
      return false;
    }
    const font = getFontParameters(fontSpec);
    const checkFamily = font.families[0].toLowerCase();
    const checkWeight = font.weight;
    return fontFaces.some(
      /**
       * @param {import('../css.js').FontParameters} f Font.
       * @return {boolean} Font matches.
       */
      (f) => {
        const family = f.family.replace(/^['"]|['"]$/g, "").toLowerCase();
        const weight = fontWeights[f.weight] || f.weight;
        return family === checkFamily && f.style === font.style && weight == checkWeight;
      }
    );
  }
  async function check() {
    await fontFaceSet.ready;
    let done = true;
    const checkedFontsProperties = checkedFonts.getProperties();
    const fonts = Object.keys(checkedFontsProperties).filter(
      (key2) => checkedFontsProperties[key2] < retries
    );
    for (let i = fonts.length - 1; i >= 0; --i) {
      const font = fonts[i];
      let currentRetries = checkedFontsProperties[font];
      if (currentRetries < retries) {
        if (await isAvailable(font)) {
          clear(textHeights);
          checkedFonts.set(font, retries);
        } else {
          currentRetries += 10;
          checkedFonts.set(font, currentRetries, true);
          if (currentRetries < retries) {
            done = false;
          }
        }
      }
    }
    timeout = void 0;
    if (!done) {
      timeout = setTimeout(check, 100);
    }
  }
  return async function(fontSpec) {
    if (!fontFaceSet) {
      fontFaceSet = WORKER_OFFSCREEN_CANVAS ? self.fonts : document.fonts;
    }
    const font = getFontParameters(fontSpec);
    if (!font) {
      return;
    }
    const families = font.families;
    let needCheck = false;
    for (const family of families) {
      if (genericFontFamilies.has(family)) {
        continue;
      }
      const key2 = getFontKey(font.style, font.weight, family);
      if (checkedFonts.get(key2) !== void 0) {
        continue;
      }
      checkedFonts.set(key2, 0, true);
      needCheck = true;
    }
    if (needCheck) {
      clearTimeout(timeout);
      timeout = setTimeout(check, 100);
    }
  };
})();
const measureTextHeight = /* @__PURE__ */ (function() {
  let measureElement;
  return function(fontSpec) {
    let height = textHeights[fontSpec];
    if (height == void 0) {
      if (WORKER_OFFSCREEN_CANVAS) {
        const font = getFontParameters(fontSpec);
        const metrics = measureText(fontSpec, "Žg");
        const lineHeight = isNaN(Number(font.lineHeight)) ? 1.2 : Number(font.lineHeight);
        height = lineHeight * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
      } else {
        if (!measureElement) {
          measureElement = document.createElement("div");
          measureElement.innerHTML = "M";
          measureElement.style.minHeight = "0";
          measureElement.style.maxHeight = "none";
          measureElement.style.height = "auto";
          measureElement.style.padding = "0";
          measureElement.style.border = "none";
          measureElement.style.position = "absolute";
          measureElement.style.display = "block";
          measureElement.style.left = "-99999px";
        }
        measureElement.style.font = fontSpec;
        document.body.appendChild(measureElement);
        height = measureElement.offsetHeight;
        document.body.removeChild(measureElement);
      }
      textHeights[fontSpec] = height;
    }
    return height;
  };
})();
function measureText(font, text) {
  if (!measureContext) {
    measureContext = createCanvasContext2D(1, 1);
  }
  if (font != measureFont) {
    measureContext.font = font;
    measureFont = measureContext.font;
  }
  return measureContext.measureText(text);
}
function measureTextWidth(font, text) {
  return measureText(font, text).width;
}
function measureAndCacheTextWidth(font, text, cache2) {
  if (text in cache2) {
    return cache2[text];
  }
  const width = text.split("\n").reduce((prev, curr) => Math.max(prev, measureTextWidth(font, curr)), 0);
  cache2[text] = width;
  return width;
}
function getTextDimensions(baseStyle, chunks) {
  const widths = [];
  const heights = [];
  const lineWidths = [];
  let width = 0;
  let lineWidth = 0;
  let height = 0;
  let lineHeight = 0;
  for (let i = 0, ii = chunks.length; i <= ii; i += 2) {
    const text = chunks[i];
    if (text === "\n" || i === ii) {
      width = Math.max(width, lineWidth);
      lineWidths.push(lineWidth);
      lineWidth = 0;
      height += lineHeight;
      lineHeight = 0;
      continue;
    }
    const font = chunks[i + 1] || baseStyle.font;
    const currentWidth = measureTextWidth(font, text);
    widths.push(currentWidth);
    lineWidth += currentWidth;
    const currentHeight = measureTextHeight(font);
    heights.push(currentHeight);
    lineHeight = Math.max(lineHeight, currentHeight);
  }
  return { width, height, widths, heights, lineWidths };
}
function drawImageOrLabel(context, transform2, opacity, labelOrImage, originX, originY, w, h, x, y, scale2) {
  context.save();
  if (opacity !== 1) {
    if (context.globalAlpha === void 0) {
      context.globalAlpha = (context2) => context2.globalAlpha *= opacity;
    } else {
      context.globalAlpha *= opacity;
    }
  }
  if (transform2) {
    context.transform.apply(context, transform2);
  }
  if (
    /** @type {*} */
    labelOrImage.contextInstructions
  ) {
    context.translate(x, y);
    context.scale(scale2[0], scale2[1]);
    executeLabelInstructions(
      /** @type {Label} */
      labelOrImage,
      context
    );
  } else if (scale2[0] < 0 || scale2[1] < 0) {
    context.translate(x, y);
    context.scale(scale2[0], scale2[1]);
    context.drawImage(
      /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */
      labelOrImage,
      originX,
      originY,
      w,
      h,
      0,
      0,
      w,
      h
    );
  } else {
    context.drawImage(
      /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */
      labelOrImage,
      originX,
      originY,
      w,
      h,
      x,
      y,
      w * scale2[0],
      h * scale2[1]
    );
  }
  context.restore();
}
function executeLabelInstructions(label, context) {
  const contextInstructions = label.contextInstructions;
  for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) {
    if (Array.isArray(contextInstructions[i + 1])) {
      context[contextInstructions[i]].apply(
        context,
        contextInstructions[i + 1]
      );
    } else {
      context[contextInstructions[i]] = contextInstructions[i + 1];
    }
  }
}
class ImageStyle {
  /**
   * @param {Options} options Options.
   */
  constructor(options2) {
    this.opacity_ = options2.opacity;
    this.rotateWithView_ = options2.rotateWithView;
    this.rotation_ = options2.rotation;
    this.scale_ = options2.scale;
    this.scaleArray_ = toSize(options2.scale);
    this.displacement_ = options2.displacement;
    this.declutterMode_ = options2.declutterMode;
  }
  /**
   * Clones the style.
   * @return {ImageStyle} The cloned style.
   * @api
   */
  clone() {
    const scale2 = this.getScale();
    return new ImageStyle({
      opacity: this.getOpacity(),
      scale: Array.isArray(scale2) ? scale2.slice() : scale2,
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
      displacement: this.getDisplacement().slice(),
      declutterMode: this.getDeclutterMode()
    });
  }
  /**
   * Get the symbolizer opacity.
   * @return {number} Opacity.
   * @api
   */
  getOpacity() {
    return this.opacity_;
  }
  /**
   * Determine whether the symbolizer rotates with the map.
   * @return {boolean} Rotate with map.
   * @api
   */
  getRotateWithView() {
    return this.rotateWithView_;
  }
  /**
   * Get the symoblizer rotation.
   * @return {number} Rotation.
   * @api
   */
  getRotation() {
    return this.rotation_;
  }
  /**
   * Get the symbolizer scale.
   * @return {number|import("../size.js").Size} Scale.
   * @api
   */
  getScale() {
    return this.scale_;
  }
  /**
   * Get the symbolizer scale array.
   * @return {import("../size.js").Size} Scale array.
   */
  getScaleArray() {
    return this.scaleArray_;
  }
  /**
   * Get the displacement of the shape
   * @return {Array<number>} Shape's center displacement
   * @api
   */
  getDisplacement() {
    return this.displacement_;
  }
  /**
   * Get the declutter mode of the shape
   * @return {import("./Style.js").DeclutterMode} Shape's declutter mode
   * @api
   */
  getDeclutterMode() {
    return this.declutterMode_;
  }
  /**
   * Get the anchor point in pixels. The anchor determines the center point for the
   * symbolizer.
   * @abstract
   * @return {Array<number>} Anchor.
   */
  getAnchor() {
    return abstract();
  }
  /**
   * Get the image element for the symbolizer.
   * @abstract
   * @param {number} pixelRatio Pixel ratio.
   * @return {import('../DataTile.js').ImageLike} Image element.
   */
  getImage(pixelRatio) {
    return abstract();
  }
  /**
   * @abstract
   * @return {import('../DataTile.js').ImageLike} Image element.
   */
  getHitDetectionImage() {
    return abstract();
  }
  /**
   * Get the image pixel ratio.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} Pixel ratio.
   */
  getPixelRatio(pixelRatio) {
    return 1;
  }
  /**
   * @abstract
   * @return {import("../ImageState.js").default} Image state.
   */
  getImageState() {
    return abstract();
  }
  /**
   * @abstract
   * @return {import("../size.js").Size} Image size.
   */
  getImageSize() {
    return abstract();
  }
  /**
   * Get the origin of the symbolizer.
   * @abstract
   * @return {Array<number>} Origin.
   */
  getOrigin() {
    return abstract();
  }
  /**
   * Get the size of the symbolizer (in pixels).
   * @abstract
   * @return {import("../size.js").Size} Size.
   */
  getSize() {
    return abstract();
  }
  /**
   * Set the displacement.
   *
   * @param {Array<number>} displacement Displacement.
   * @api
   */
  setDisplacement(displacement) {
    this.displacement_ = displacement;
  }
  /**
   * Set the opacity.
   *
   * @param {number} opacity Opacity.
   * @api
   */
  setOpacity(opacity) {
    this.opacity_ = opacity;
  }
  /**
   * Set whether to rotate the style with the view.
   *
   * @param {boolean} rotateWithView Rotate with map.
   * @api
   */
  setRotateWithView(rotateWithView) {
    this.rotateWithView_ = rotateWithView;
  }
  /**
   * Set the rotation.
   *
   * @param {number} rotation Rotation.
   * @api
   */
  setRotation(rotation) {
    this.rotation_ = rotation;
  }
  /**
   * Set the scale.
   *
   * @param {number|import("../size.js").Size} scale Scale.
   * @api
   */
  setScale(scale2) {
    this.scale_ = scale2;
    this.scaleArray_ = toSize(scale2);
  }
  /**
   * @abstract
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   */
  listenImageChange(listener) {
    abstract();
  }
  /**
   * Load not yet loaded URI.
   * @abstract
   */
  load() {
    abstract();
  }
  /**
   * @abstract
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   */
  unlistenImageChange(listener) {
    abstract();
  }
  /**
   * @return {Promise<void>} `false` or Promise that resolves when the style is ready to use.
   */
  ready() {
    return Promise.resolve();
  }
}
class RegularShape extends ImageStyle {
  /**
   * @param {Options} options Options.
   */
  constructor(options2) {
    super({
      opacity: 1,
      rotateWithView: options2.rotateWithView !== void 0 ? options2.rotateWithView : false,
      rotation: options2.rotation !== void 0 ? options2.rotation : 0,
      scale: options2.scale !== void 0 ? options2.scale : 1,
      displacement: options2.displacement !== void 0 ? options2.displacement : [0, 0],
      declutterMode: options2.declutterMode
    });
    this.hitDetectionCanvas_ = null;
    this.fill_ = options2.fill !== void 0 ? options2.fill : null;
    this.origin_ = [0, 0];
    this.points_ = options2.points;
    this.radius = options2.radius;
    this.radius2_ = options2.radius2;
    this.angle_ = options2.angle !== void 0 ? options2.angle : 0;
    this.stroke_ = options2.stroke !== void 0 ? options2.stroke : null;
    this.size_;
    this.renderOptions_;
    this.imageState_ = this.fill_ && this.fill_.loading() ? ImageState.LOADING : ImageState.LOADED;
    if (this.imageState_ === ImageState.LOADING) {
      this.ready().then(() => this.imageState_ = ImageState.LOADED);
    }
    this.render();
  }
  /**
   * Clones the style.
   * @return {RegularShape} The cloned style.
   * @api
   * @override
   */
  clone() {
    const scale2 = this.getScale();
    const style = new RegularShape({
      fill: this.getFill() ? this.getFill().clone() : void 0,
      points: this.getPoints(),
      radius: this.getRadius(),
      radius2: this.getRadius2(),
      angle: this.getAngle(),
      stroke: this.getStroke() ? this.getStroke().clone() : void 0,
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
      scale: Array.isArray(scale2) ? scale2.slice() : scale2,
      displacement: this.getDisplacement().slice(),
      declutterMode: this.getDeclutterMode()
    });
    style.setOpacity(this.getOpacity());
    return style;
  }
  /**
   * Get the anchor point in pixels. The anchor determines the center point for the
   * symbolizer.
   * @return {Array<number>} Anchor.
   * @api
   * @override
   */
  getAnchor() {
    const size = this.size_;
    const displacement = this.getDisplacement();
    const scale2 = this.getScaleArray();
    return [
      size[0] / 2 - displacement[0] / scale2[0],
      size[1] / 2 + displacement[1] / scale2[1]
    ];
  }
  /**
   * Get the angle used in generating the shape.
   * @return {number} Shape's rotation in radians.
   * @api
   */
  getAngle() {
    return this.angle_;
  }
  /**
   * Get the fill style for the shape.
   * @return {import("./Fill.js").default|null} Fill style.
   * @api
   */
  getFill() {
    return this.fill_;
  }
  /**
   * Set the fill style.
   * @param {import("./Fill.js").default|null} fill Fill style.
   * @api
   */
  setFill(fill) {
    this.fill_ = fill;
    this.render();
  }
  /**
   * @return {HTMLCanvasElement} Image element.
   * @override
   */
  getHitDetectionImage() {
    if (!this.hitDetectionCanvas_) {
      this.hitDetectionCanvas_ = this.createHitDetectionCanvas_(
        this.renderOptions_
      );
    }
    return this.hitDetectionCanvas_;
  }
  /**
   * Get the image icon.
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLCanvasElement} Image or Canvas element.
   * @api
   * @override
   */
  getImage(pixelRatio) {
    const fillKey = this.fill_?.getKey();
    const cacheKey = `${pixelRatio},${this.angle_},${this.radius},${this.radius2_},${this.points_},${fillKey}` + Object.values(this.renderOptions_).join(",");
    let image = (
      /** @type {HTMLCanvasElement} */
      shared.get(cacheKey, null, null)?.getImage(1)
    );
    if (!image) {
      const renderOptions = this.renderOptions_;
      const size = Math.ceil(renderOptions.size * pixelRatio);
      const context = createCanvasContext2D(size, size);
      this.draw_(renderOptions, context, pixelRatio);
      image = context.canvas;
      shared.set(
        cacheKey,
        null,
        null,
        new IconImage(image, void 0, null, ImageState.LOADED, null)
      );
    }
    return image;
  }
  /**
   * Get the image pixel ratio.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} Pixel ratio.
   * @override
   */
  getPixelRatio(pixelRatio) {
    return pixelRatio;
  }
  /**
   * @return {import("../size.js").Size} Image size.
   * @override
   */
  getImageSize() {
    return this.size_;
  }
  /**
   * @return {import("../ImageState.js").default} Image state.
   * @override
   */
  getImageState() {
    return this.imageState_;
  }
  /**
   * Get the origin of the symbolizer.
   * @return {Array<number>} Origin.
   * @api
   * @override
   */
  getOrigin() {
    return this.origin_;
  }
  /**
   * Get the number of points for generating the shape.
   * @return {number} Number of points for stars and regular polygons.
   * @api
   */
  getPoints() {
    return this.points_;
  }
  /**
   * Get the (primary) radius for the shape.
   * @return {number} Radius.
   * @api
   */
  getRadius() {
    return this.radius;
  }
  /**
   * Get the secondary radius for the shape.
   * @return {number|undefined} Radius2.
   * @api
   */
  getRadius2() {
    return this.radius2_;
  }
  /**
   * Get the size of the symbolizer (in pixels).
   * @return {import("../size.js").Size} Size.
   * @api
   * @override
   */
  getSize() {
    return this.size_;
  }
  /**
   * Get the stroke style for the shape.
   * @return {import("./Stroke.js").default|null} Stroke style.
   * @api
   */
  getStroke() {
    return this.stroke_;
  }
  /**
   * Set the stroke style.
   * @param {import("./Stroke.js").default|null} stroke Stroke style.
   * @api
   */
  setStroke(stroke) {
    this.stroke_ = stroke;
    this.render();
  }
  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   * @override
   */
  listenImageChange(listener) {
  }
  /**
   * Load not yet loaded URI.
   * @override
   */
  load() {
  }
  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   * @override
   */
  unlistenImageChange(listener) {
  }
  /**
   * Calculate additional canvas size needed for the miter.
   * @param {string} lineJoin Line join
   * @param {number} strokeWidth Stroke width
   * @param {number} miterLimit Miter limit
   * @return {number} Additional canvas size needed
   * @private
   */
  calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit) {
    if (strokeWidth === 0 || this.points_ === Infinity || lineJoin !== "bevel" && lineJoin !== "miter") {
      return strokeWidth;
    }
    let r1 = this.radius;
    let r2 = this.radius2_ === void 0 ? r1 : this.radius2_;
    if (r1 < r2) {
      const tmp = r1;
      r1 = r2;
      r2 = tmp;
    }
    const points = this.radius2_ === void 0 ? this.points_ : this.points_ * 2;
    const alpha = 2 * Math.PI / points;
    const a = r2 * Math.sin(alpha);
    const b = Math.sqrt(r2 * r2 - a * a);
    const d = r1 - b;
    const e = Math.sqrt(a * a + d * d);
    const miterRatio = e / a;
    if (lineJoin === "miter" && miterRatio <= miterLimit) {
      return miterRatio * strokeWidth;
    }
    const k = strokeWidth / 2 / miterRatio;
    const l = strokeWidth / 2 * (d / e);
    const maxr = Math.sqrt((r1 + k) * (r1 + k) + l * l);
    const bevelAdd = maxr - r1;
    if (this.radius2_ === void 0 || lineJoin === "bevel") {
      return bevelAdd * 2;
    }
    const aa = r1 * Math.sin(alpha);
    const bb = Math.sqrt(r1 * r1 - aa * aa);
    const dd = r2 - bb;
    const ee = Math.sqrt(aa * aa + dd * dd);
    const innerMiterRatio = ee / aa;
    if (innerMiterRatio <= miterLimit) {
      const innerLength = innerMiterRatio * strokeWidth / 2 - r2 - r1;
      return 2 * Math.max(bevelAdd, innerLength);
    }
    return bevelAdd * 2;
  }
  /**
   * @return {RenderOptions}  The render options
   * @protected
   */
  createRenderOptions() {
    let lineCap = defaultLineCap;
    let lineJoin = defaultLineJoin;
    let miterLimit = 0;
    let lineDash = null;
    let lineDashOffset = 0;
    let strokeStyle;
    let strokeWidth = 0;
    if (this.stroke_) {
      strokeStyle = asColorLike(this.stroke_.getColor() ?? defaultStrokeStyle);
      strokeWidth = this.stroke_.getWidth() ?? defaultLineWidth;
      lineDash = this.stroke_.getLineDash();
      lineDashOffset = this.stroke_.getLineDashOffset() ?? 0;
      lineJoin = this.stroke_.getLineJoin() ?? defaultLineJoin;
      lineCap = this.stroke_.getLineCap() ?? defaultLineCap;
      miterLimit = this.stroke_.getMiterLimit() ?? defaultMiterLimit;
    }
    const add2 = this.calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit);
    const maxRadius = Math.max(this.radius, this.radius2_ || 0);
    const size = Math.ceil(2 * maxRadius + add2);
    return {
      strokeStyle,
      strokeWidth,
      size,
      lineCap,
      lineDash,
      lineDashOffset,
      lineJoin,
      miterLimit
    };
  }
  /**
   * @protected
   */
  render() {
    this.renderOptions_ = this.createRenderOptions();
    const size = this.renderOptions_.size;
    this.hitDetectionCanvas_ = null;
    this.size_ = [size, size];
  }
  /**
   * @private
   * @param {RenderOptions} renderOptions Render options.
   * @param {CanvasRenderingContext2D} context The rendering context.
   * @param {number} pixelRatio The pixel ratio.
   */
  draw_(renderOptions, context, pixelRatio) {
    context.scale(pixelRatio, pixelRatio);
    context.translate(renderOptions.size / 2, renderOptions.size / 2);
    this.createPath_(context);
    if (this.fill_) {
      let color2 = this.fill_.getColor();
      if (color2 === null) {
        color2 = defaultFillStyle;
      }
      context.fillStyle = asColorLike(color2);
      context.fill();
    }
    if (renderOptions.strokeStyle) {
      context.strokeStyle = renderOptions.strokeStyle;
      context.lineWidth = renderOptions.strokeWidth;
      if (renderOptions.lineDash) {
        context.setLineDash(renderOptions.lineDash);
        context.lineDashOffset = renderOptions.lineDashOffset;
      }
      context.lineCap = renderOptions.lineCap;
      context.lineJoin = renderOptions.lineJoin;
      context.miterLimit = renderOptions.miterLimit;
      context.stroke();
    }
  }
  /**
   * @private
   * @param {RenderOptions} renderOptions Render options.
   * @return {HTMLCanvasElement} Canvas containing the icon
   */
  createHitDetectionCanvas_(renderOptions) {
    let context;
    if (this.fill_) {
      let color2 = this.fill_.getColor();
      let opacity = 0;
      if (typeof color2 === "string") {
        color2 = asArray(color2);
      }
      if (color2 === null) {
        opacity = 1;
      } else if (Array.isArray(color2)) {
        opacity = color2.length === 4 ? color2[3] : 1;
      }
      if (opacity === 0) {
        context = createCanvasContext2D(renderOptions.size, renderOptions.size);
        this.drawHitDetectionCanvas_(renderOptions, context);
      }
    }
    return context ? context.canvas : this.getImage(1);
  }
  /**
   * @private
   * @param {CanvasRenderingContext2D} context The context to draw in.
   */
  createPath_(context) {
    let points = this.points_;
    const radius = this.radius;
    if (points === Infinity) {
      context.arc(0, 0, radius, 0, 2 * Math.PI);
    } else {
      const radius2 = this.radius2_ === void 0 ? radius : this.radius2_;
      if (this.radius2_ !== void 0) {
        points *= 2;
      }
      const startAngle = this.angle_ - Math.PI / 2;
      const step = 2 * Math.PI / points;
      for (let i = 0; i < points; i++) {
        const angle0 = startAngle + i * step;
        const radiusC = i % 2 === 0 ? radius : radius2;
        context.lineTo(radiusC * Math.cos(angle0), radiusC * Math.sin(angle0));
      }
      context.closePath();
    }
  }
  /**
   * @private
   * @param {RenderOptions} renderOptions Render options.
   * @param {CanvasRenderingContext2D} context The context.
   */
  drawHitDetectionCanvas_(renderOptions, context) {
    context.translate(renderOptions.size / 2, renderOptions.size / 2);
    this.createPath_(context);
    context.fillStyle = defaultFillStyle;
    context.fill();
    if (renderOptions.strokeStyle) {
      context.strokeStyle = renderOptions.strokeStyle;
      context.lineWidth = renderOptions.strokeWidth;
      if (renderOptions.lineDash) {
        context.setLineDash(renderOptions.lineDash);
        context.lineDashOffset = renderOptions.lineDashOffset;
      }
      context.lineJoin = renderOptions.lineJoin;
      context.miterLimit = renderOptions.miterLimit;
      context.stroke();
    }
  }
  /**
   * @override
   */
  ready() {
    return this.fill_ ? this.fill_.ready() : Promise.resolve();
  }
}
class CircleStyle extends RegularShape {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : { radius: 5 };
    super({
      points: Infinity,
      fill: options2.fill,
      radius: options2.radius,
      stroke: options2.stroke,
      scale: options2.scale !== void 0 ? options2.scale : 1,
      rotation: options2.rotation !== void 0 ? options2.rotation : 0,
      rotateWithView: options2.rotateWithView !== void 0 ? options2.rotateWithView : false,
      displacement: options2.displacement !== void 0 ? options2.displacement : [0, 0],
      declutterMode: options2.declutterMode
    });
  }
  /**
   * Clones the style.
   * @return {CircleStyle} The cloned style.
   * @api
   * @override
   */
  clone() {
    const scale2 = this.getScale();
    const style = new CircleStyle({
      fill: this.getFill() ? this.getFill().clone() : void 0,
      stroke: this.getStroke() ? this.getStroke().clone() : void 0,
      radius: this.getRadius(),
      scale: Array.isArray(scale2) ? scale2.slice() : scale2,
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
      displacement: this.getDisplacement().slice(),
      declutterMode: this.getDeclutterMode()
    });
    style.setOpacity(this.getOpacity());
    return style;
  }
  /**
   * Set the circle radius.
   *
   * @param {number} radius Circle radius.
   * @api
   */
  setRadius(radius) {
    this.radius = radius;
    this.render();
  }
}
class Fill {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 || {};
    this.patternImage_ = null;
    this.color_ = null;
    if (options2.color !== void 0) {
      this.setColor(options2.color);
    }
  }
  /**
   * Clones the style. The color is not cloned if it is a {@link module:ol/colorlike~ColorLike}.
   * @return {Fill} The cloned style.
   * @api
   */
  clone() {
    const color2 = this.getColor();
    return new Fill({
      color: Array.isArray(color2) ? color2.slice() : color2 || void 0
    });
  }
  /**
   * Get the fill color.
   * @return {import("../color.js").Color|import("../colorlike.js").ColorLike|import('../colorlike.js').PatternDescriptor|null} Color.
   * @api
   */
  getColor() {
    return this.color_;
  }
  /**
   * Set the color.
   *
   * @param {import("../color.js").Color|import("../colorlike.js").ColorLike|import('../colorlike.js').PatternDescriptor|null} color Color.
   * @api
   */
  setColor(color2) {
    if (color2 !== null && typeof color2 === "object" && "src" in color2) {
      const patternImage = get$1(
        null,
        color2.src,
        "anonymous",
        void 0,
        color2.offset ? null : color2.color ? color2.color : null,
        !(color2.offset && color2.size)
      );
      patternImage.ready().then(() => {
        this.patternImage_ = null;
      });
      if (patternImage.getImageState() === ImageState.IDLE) {
        patternImage.load();
      }
      if (patternImage.getImageState() === ImageState.LOADING) {
        this.patternImage_ = patternImage;
      }
    }
    this.color_ = color2;
  }
  /**
   * @return {string} Key of the fill for cache lookup.
   */
  getKey() {
    const fill = this.getColor();
    if (!fill) {
      return "";
    }
    return fill instanceof CanvasPattern || fill instanceof CanvasGradient ? getUid(fill) : typeof fill === "object" && "src" in fill ? fill.src + ":" + fill.offset : asArray(fill).toString();
  }
  /**
   * @return {boolean} The fill style is loading an image pattern.
   */
  loading() {
    return !!this.patternImage_;
  }
  /**
   * @return {Promise<void>} `false` or a promise that resolves when the style is ready to use.
   */
  ready() {
    return this.patternImage_ ? this.patternImage_.ready() : Promise.resolve();
  }
}
function calculateScale(width, height, wantedWidth, wantedHeight) {
  if (wantedWidth !== void 0 && wantedHeight !== void 0) {
    return [wantedWidth / width, wantedHeight / height];
  }
  if (wantedWidth !== void 0) {
    return wantedWidth / width;
  }
  if (wantedHeight !== void 0) {
    return wantedHeight / height;
  }
  return 1;
}
class Icon extends ImageStyle {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 || {};
    const opacity = options2.opacity !== void 0 ? options2.opacity : 1;
    const rotation = options2.rotation !== void 0 ? options2.rotation : 0;
    const scale2 = options2.scale !== void 0 ? options2.scale : 1;
    const rotateWithView = options2.rotateWithView !== void 0 ? options2.rotateWithView : false;
    super({
      opacity,
      rotation,
      scale: scale2,
      displacement: options2.displacement !== void 0 ? options2.displacement : [0, 0],
      rotateWithView,
      declutterMode: options2.declutterMode
    });
    this.anchor_ = options2.anchor !== void 0 ? options2.anchor : [0.5, 0.5];
    this.normalizedAnchor_ = null;
    this.anchorOrigin_ = options2.anchorOrigin !== void 0 ? options2.anchorOrigin : "top-left";
    this.anchorXUnits_ = options2.anchorXUnits !== void 0 ? options2.anchorXUnits : "fraction";
    this.anchorYUnits_ = options2.anchorYUnits !== void 0 ? options2.anchorYUnits : "fraction";
    this.crossOrigin_ = options2.crossOrigin !== void 0 ? options2.crossOrigin : null;
    const image = options2.img !== void 0 ? options2.img : null;
    let cacheKey = options2.src;
    assert(
      !(cacheKey !== void 0 && image),
      "`image` and `src` cannot be provided at the same time"
    );
    if ((cacheKey === void 0 || cacheKey.length === 0) && image) {
      cacheKey = /** @type {HTMLImageElement} */
      image.src || getUid(image);
    }
    assert(
      cacheKey !== void 0 && cacheKey.length > 0,
      "A defined and non-empty `src` or `image` must be provided"
    );
    assert(
      !((options2.width !== void 0 || options2.height !== void 0) && options2.scale !== void 0),
      "`width` or `height` cannot be provided together with `scale`"
    );
    let imageState;
    if (options2.src !== void 0) {
      imageState = ImageState.IDLE;
    } else if (image !== void 0) {
      if ("complete" in image) {
        if (image.complete) {
          imageState = image.src ? ImageState.LOADED : ImageState.IDLE;
        } else {
          imageState = ImageState.LOADING;
        }
      } else {
        imageState = ImageState.LOADED;
      }
    }
    this.color_ = options2.color !== void 0 ? asArray(options2.color) : null;
    this.iconImage_ = get$1(
      image,
      /** @type {string} */
      cacheKey,
      this.crossOrigin_,
      imageState,
      this.color_
    );
    this.offset_ = options2.offset !== void 0 ? options2.offset : [0, 0];
    this.offsetOrigin_ = options2.offsetOrigin !== void 0 ? options2.offsetOrigin : "top-left";
    this.origin_ = null;
    this.size_ = options2.size !== void 0 ? options2.size : null;
    this.initialOptions_;
    if (options2.width !== void 0 || options2.height !== void 0) {
      let width, height;
      if (options2.size) {
        [width, height] = options2.size;
      } else {
        const image2 = this.getImage(1);
        if (image2.width && image2.height) {
          width = image2.width;
          height = image2.height;
        } else if (image2 instanceof HTMLImageElement) {
          this.initialOptions_ = options2;
          const onload = () => {
            this.unlistenImageChange(onload);
            if (!this.initialOptions_) {
              return;
            }
            const imageSize = this.iconImage_.getSize();
            this.setScale(
              calculateScale(
                imageSize[0],
                imageSize[1],
                options2.width,
                options2.height
              )
            );
          };
          this.listenImageChange(onload);
          return;
        }
      }
      if (width !== void 0) {
        this.setScale(
          calculateScale(width, height, options2.width, options2.height)
        );
      }
    }
  }
  /**
   * Clones the style. The underlying Image/HTMLCanvasElement is not cloned.
   * @return {Icon} The cloned style.
   * @api
   * @override
   */
  clone() {
    let scale2, width, height;
    if (this.initialOptions_) {
      width = this.initialOptions_.width;
      height = this.initialOptions_.height;
    } else {
      scale2 = this.getScale();
      scale2 = Array.isArray(scale2) ? scale2.slice() : scale2;
    }
    return new Icon({
      anchor: this.anchor_.slice(),
      anchorOrigin: this.anchorOrigin_,
      anchorXUnits: this.anchorXUnits_,
      anchorYUnits: this.anchorYUnits_,
      color: this.color_ && this.color_.slice ? this.color_.slice() : this.color_ || void 0,
      crossOrigin: this.crossOrigin_,
      offset: this.offset_.slice(),
      offsetOrigin: this.offsetOrigin_,
      opacity: this.getOpacity(),
      rotateWithView: this.getRotateWithView(),
      rotation: this.getRotation(),
      scale: scale2,
      width,
      height,
      size: this.size_ !== null ? this.size_.slice() : void 0,
      src: this.getSrc(),
      displacement: this.getDisplacement().slice(),
      declutterMode: this.getDeclutterMode()
    });
  }
  /**
   * Get the anchor point in pixels. The anchor determines the center point for the
   * symbolizer.
   * @return {Array<number>} Anchor.
   * @api
   * @override
   */
  getAnchor() {
    let anchor = this.normalizedAnchor_;
    if (!anchor) {
      anchor = this.anchor_;
      const size = this.getSize();
      if (this.anchorXUnits_ == "fraction" || this.anchorYUnits_ == "fraction") {
        if (!size) {
          return null;
        }
        anchor = this.anchor_.slice();
        if (this.anchorXUnits_ == "fraction") {
          anchor[0] *= size[0];
        }
        if (this.anchorYUnits_ == "fraction") {
          anchor[1] *= size[1];
        }
      }
      if (this.anchorOrigin_ != "top-left") {
        if (!size) {
          return null;
        }
        if (anchor === this.anchor_) {
          anchor = this.anchor_.slice();
        }
        if (this.anchorOrigin_ == "top-right" || this.anchorOrigin_ == "bottom-right") {
          anchor[0] = -anchor[0] + size[0];
        }
        if (this.anchorOrigin_ == "bottom-left" || this.anchorOrigin_ == "bottom-right") {
          anchor[1] = -anchor[1] + size[1];
        }
      }
      this.normalizedAnchor_ = anchor;
    }
    const displacement = this.getDisplacement();
    const scale2 = this.getScaleArray();
    return [
      anchor[0] - displacement[0] / scale2[0],
      anchor[1] + displacement[1] / scale2[1]
    ];
  }
  /**
   * Set the anchor point. The anchor determines the center point for the
   * symbolizer.
   *
   * @param {Array<number>} anchor Anchor.
   * @api
   */
  setAnchor(anchor) {
    this.anchor_ = anchor;
    this.normalizedAnchor_ = null;
  }
  /**
   * Get the icon color.
   * @return {import("../color.js").Color} Color.
   * @api
   */
  getColor() {
    return this.color_;
  }
  /**
   * Get the image icon.
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLImageElement|HTMLCanvasElement|ImageBitmap} Image or Canvas element. If the Icon
   * style was configured with `src` or with a not let loaded `img`, an `ImageBitmap` will be returned.
   * @api
   * @override
   */
  getImage(pixelRatio) {
    return this.iconImage_.getImage(pixelRatio);
  }
  /**
   * Get the pixel ratio.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} The pixel ratio of the image.
   * @api
   * @override
   */
  getPixelRatio(pixelRatio) {
    return this.iconImage_.getPixelRatio(pixelRatio);
  }
  /**
   * @return {import("../size.js").Size} Image size.
   * @override
   */
  getImageSize() {
    return this.iconImage_.getSize();
  }
  /**
   * @return {import("../ImageState.js").default} Image state.
   * @override
   */
  getImageState() {
    return this.iconImage_.getImageState();
  }
  /**
   * @return {HTMLImageElement|HTMLCanvasElement|ImageBitmap} Image element.
   * @override
   */
  getHitDetectionImage() {
    return this.iconImage_.getHitDetectionImage();
  }
  /**
   * Get the origin of the symbolizer.
   * @return {Array<number>} Origin.
   * @api
   * @override
   */
  getOrigin() {
    if (this.origin_) {
      return this.origin_;
    }
    let offset2 = this.offset_;
    if (this.offsetOrigin_ != "top-left") {
      const size = this.getSize();
      const iconImageSize = this.iconImage_.getSize();
      if (!size || !iconImageSize) {
        return null;
      }
      offset2 = offset2.slice();
      if (this.offsetOrigin_ == "top-right" || this.offsetOrigin_ == "bottom-right") {
        offset2[0] = iconImageSize[0] - size[0] - offset2[0];
      }
      if (this.offsetOrigin_ == "bottom-left" || this.offsetOrigin_ == "bottom-right") {
        offset2[1] = iconImageSize[1] - size[1] - offset2[1];
      }
    }
    this.origin_ = offset2;
    return this.origin_;
  }
  /**
   * Get the image URL.
   * @return {string|undefined} Image src.
   * @api
   */
  getSrc() {
    return this.iconImage_.getSrc();
  }
  /**
   * Get the size of the icon (in pixels).
   * @return {import("../size.js").Size} Image size.
   * @api
   * @override
   */
  getSize() {
    return !this.size_ ? this.iconImage_.getSize() : this.size_;
  }
  /**
   * Get the width of the icon (in pixels). Will return undefined when the icon image is not yet loaded.
   * @return {number} Icon width (in pixels).
   * @api
   */
  getWidth() {
    const scale2 = this.getScaleArray();
    if (this.size_) {
      return this.size_[0] * scale2[0];
    }
    if (this.iconImage_.getImageState() == ImageState.LOADED) {
      return this.iconImage_.getSize()[0] * scale2[0];
    }
    return void 0;
  }
  /**
   * Get the height of the icon (in pixels). Will return undefined when the icon image is not yet loaded.
   * @return {number} Icon height (in pixels).
   * @api
   */
  getHeight() {
    const scale2 = this.getScaleArray();
    if (this.size_) {
      return this.size_[1] * scale2[1];
    }
    if (this.iconImage_.getImageState() == ImageState.LOADED) {
      return this.iconImage_.getSize()[1] * scale2[1];
    }
    return void 0;
  }
  /**
   * Set the scale.
   *
   * @param {number|import("../size.js").Size} scale Scale.
   * @api
   * @override
   */
  setScale(scale2) {
    delete this.initialOptions_;
    super.setScale(scale2);
  }
  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   * @override
   */
  listenImageChange(listener) {
    this.iconImage_.addEventListener(EventType.CHANGE, listener);
  }
  /**
   * Load not yet loaded URI.
   * When rendering a feature with an icon style, the vector renderer will
   * automatically call this method. However, you might want to call this
   * method yourself for preloading or other purposes.
   * @api
   * @override
   */
  load() {
    this.iconImage_.load();
  }
  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   * @override
   */
  unlistenImageChange(listener) {
    this.iconImage_.removeEventListener(EventType.CHANGE, listener);
  }
  /**
   * @override
   */
  ready() {
    return this.iconImage_.ready();
  }
}
class Stroke {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 || {};
    this.color_ = options2.color !== void 0 ? options2.color : null;
    this.lineCap_ = options2.lineCap;
    this.lineDash_ = options2.lineDash !== void 0 ? options2.lineDash : null;
    this.lineDashOffset_ = options2.lineDashOffset;
    this.lineJoin_ = options2.lineJoin;
    this.miterLimit_ = options2.miterLimit;
    this.width_ = options2.width;
  }
  /**
   * Clones the style.
   * @return {Stroke} The cloned style.
   * @api
   */
  clone() {
    const color2 = this.getColor();
    return new Stroke({
      color: Array.isArray(color2) ? color2.slice() : color2 || void 0,
      lineCap: this.getLineCap(),
      lineDash: this.getLineDash() ? this.getLineDash().slice() : void 0,
      lineDashOffset: this.getLineDashOffset(),
      lineJoin: this.getLineJoin(),
      miterLimit: this.getMiterLimit(),
      width: this.getWidth()
    });
  }
  /**
   * Get the stroke color.
   * @return {import("../color.js").Color|import("../colorlike.js").ColorLike} Color.
   * @api
   */
  getColor() {
    return this.color_;
  }
  /**
   * Get the line cap type for the stroke.
   * @return {CanvasLineCap|undefined} Line cap.
   * @api
   */
  getLineCap() {
    return this.lineCap_;
  }
  /**
   * Get the line dash style for the stroke.
   * @return {Array<number>|null} Line dash.
   * @api
   */
  getLineDash() {
    return this.lineDash_;
  }
  /**
   * Get the line dash offset for the stroke.
   * @return {number|undefined} Line dash offset.
   * @api
   */
  getLineDashOffset() {
    return this.lineDashOffset_;
  }
  /**
   * Get the line join type for the stroke.
   * @return {CanvasLineJoin|undefined} Line join.
   * @api
   */
  getLineJoin() {
    return this.lineJoin_;
  }
  /**
   * Get the miter limit for the stroke.
   * @return {number|undefined} Miter limit.
   * @api
   */
  getMiterLimit() {
    return this.miterLimit_;
  }
  /**
   * Get the stroke width.
   * @return {number|undefined} Width.
   * @api
   */
  getWidth() {
    return this.width_;
  }
  /**
   * Set the color.
   *
   * @param {import("../color.js").Color|import("../colorlike.js").ColorLike} color Color.
   * @api
   */
  setColor(color2) {
    this.color_ = color2;
  }
  /**
   * Set the line cap.
   *
   * @param {CanvasLineCap|undefined} lineCap Line cap.
   * @api
   */
  setLineCap(lineCap) {
    this.lineCap_ = lineCap;
  }
  /**
   * Set the line dash.
   *
   * @param {Array<number>|null} lineDash Line dash.
   * @api
   */
  setLineDash(lineDash) {
    this.lineDash_ = lineDash;
  }
  /**
   * Set the line dash offset.
   *
   * @param {number|undefined} lineDashOffset Line dash offset.
   * @api
   */
  setLineDashOffset(lineDashOffset) {
    this.lineDashOffset_ = lineDashOffset;
  }
  /**
   * Set the line join.
   *
   * @param {CanvasLineJoin|undefined} lineJoin Line join.
   * @api
   */
  setLineJoin(lineJoin) {
    this.lineJoin_ = lineJoin;
  }
  /**
   * Set the miter limit.
   *
   * @param {number|undefined} miterLimit Miter limit.
   * @api
   */
  setMiterLimit(miterLimit) {
    this.miterLimit_ = miterLimit;
  }
  /**
   * Set the width.
   *
   * @param {number|undefined} width Width.
   * @api
   */
  setWidth(width) {
    this.width_ = width;
  }
}
class Style {
  /**
   * @param {Options} [options] Style options.
   */
  constructor(options2) {
    options2 = options2 || {};
    this.geometry_ = null;
    this.geometryFunction_ = defaultGeometryFunction;
    if (options2.geometry !== void 0) {
      this.setGeometry(options2.geometry);
    }
    this.fill_ = options2.fill !== void 0 ? options2.fill : null;
    this.image_ = options2.image !== void 0 ? options2.image : null;
    this.renderer_ = options2.renderer !== void 0 ? options2.renderer : null;
    this.hitDetectionRenderer_ = options2.hitDetectionRenderer !== void 0 ? options2.hitDetectionRenderer : null;
    this.stroke_ = options2.stroke !== void 0 ? options2.stroke : null;
    this.text_ = options2.text !== void 0 ? options2.text : null;
    this.zIndex_ = options2.zIndex;
  }
  /**
   * Clones the style.
   * @return {Style} The cloned style.
   * @api
   */
  clone() {
    let geometry = this.getGeometry();
    if (geometry && typeof geometry === "object") {
      geometry = /** @type {import("../geom/Geometry.js").default} */
      geometry.clone();
    }
    return new Style({
      geometry: geometry ?? void 0,
      fill: this.getFill() ? this.getFill().clone() : void 0,
      image: this.getImage() ? this.getImage().clone() : void 0,
      renderer: this.getRenderer() ?? void 0,
      stroke: this.getStroke() ? this.getStroke().clone() : void 0,
      text: this.getText() ? this.getText().clone() : void 0,
      zIndex: this.getZIndex()
    });
  }
  /**
   * Get the custom renderer function that was configured with
   * {@link #setRenderer} or the `renderer` constructor option.
   * @return {RenderFunction|null} Custom renderer function.
   * @api
   */
  getRenderer() {
    return this.renderer_;
  }
  /**
   * Sets a custom renderer function for this style. When set, `fill`, `stroke`
   * and `image` options of the style will be ignored.
   * @param {RenderFunction|null} renderer Custom renderer function.
   * @api
   */
  setRenderer(renderer) {
    this.renderer_ = renderer;
  }
  /**
   * Sets a custom renderer function for this style used
   * in hit detection.
   * @param {RenderFunction|null} renderer Custom renderer function.
   * @api
   */
  setHitDetectionRenderer(renderer) {
    this.hitDetectionRenderer_ = renderer;
  }
  /**
   * Get the custom renderer function that was configured with
   * {@link #setHitDetectionRenderer} or the `hitDetectionRenderer` constructor option.
   * @return {RenderFunction|null} Custom renderer function.
   * @api
   */
  getHitDetectionRenderer() {
    return this.hitDetectionRenderer_;
  }
  /**
   * Get the geometry to be rendered.
   * @return {string|import("../geom/Geometry.js").default|GeometryFunction|null}
   * Feature property or geometry or function that returns the geometry that will
   * be rendered with this style.
   * @api
   */
  getGeometry() {
    return this.geometry_;
  }
  /**
   * Get the function used to generate a geometry for rendering.
   * @return {!GeometryFunction} Function that is called with a feature
   * and returns the geometry to render instead of the feature's geometry.
   * @api
   */
  getGeometryFunction() {
    return this.geometryFunction_;
  }
  /**
   * Get the fill style.
   * @return {import("./Fill.js").default|null} Fill style.
   * @api
   */
  getFill() {
    return this.fill_;
  }
  /**
   * Set the fill style.
   * @param {import("./Fill.js").default|null} fill Fill style.
   * @api
   */
  setFill(fill) {
    this.fill_ = fill;
  }
  /**
   * Get the image style.
   * @return {import("./Image.js").default|null} Image style.
   * @api
   */
  getImage() {
    return this.image_;
  }
  /**
   * Set the image style.
   * @param {import("./Image.js").default} image Image style.
   * @api
   */
  setImage(image) {
    this.image_ = image;
  }
  /**
   * Get the stroke style.
   * @return {import("./Stroke.js").default|null} Stroke style.
   * @api
   */
  getStroke() {
    return this.stroke_;
  }
  /**
   * Set the stroke style.
   * @param {import("./Stroke.js").default|null} stroke Stroke style.
   * @api
   */
  setStroke(stroke) {
    this.stroke_ = stroke;
  }
  /**
   * Get the text style.
   * @return {import("./Text.js").default|null} Text style.
   * @api
   */
  getText() {
    return this.text_;
  }
  /**
   * Set the text style.
   * @param {import("./Text.js").default} text Text style.
   * @api
   */
  setText(text) {
    this.text_ = text;
  }
  /**
   * Get the z-index for the style.
   * @return {number|undefined} ZIndex.
   * @api
   */
  getZIndex() {
    return this.zIndex_;
  }
  /**
   * Set a geometry that is rendered instead of the feature's geometry.
   *
   * @param {string|import("../geom/Geometry.js").default|GeometryFunction|null} geometry
   *     Feature property or geometry or function returning a geometry to render
   *     for this style.
   * @api
   */
  setGeometry(geometry) {
    if (typeof geometry === "function") {
      this.geometryFunction_ = geometry;
    } else if (typeof geometry === "string") {
      this.geometryFunction_ = function(feature) {
        return (
          /** @type {import("../geom/Geometry.js").default} */
          feature.get(geometry)
        );
      };
    } else if (!geometry) {
      this.geometryFunction_ = defaultGeometryFunction;
    } else if (geometry !== void 0) {
      this.geometryFunction_ = function() {
        return (
          /** @type {import("../geom/Geometry.js").default} */
          geometry
        );
      };
    }
    this.geometry_ = geometry;
  }
  /**
   * Set the z-index.
   *
   * @param {number|undefined} zIndex ZIndex.
   * @api
   */
  setZIndex(zIndex) {
    this.zIndex_ = zIndex;
  }
}
function toFunction(obj) {
  let styleFunction;
  if (typeof obj === "function") {
    styleFunction = obj;
  } else {
    let styles;
    if (Array.isArray(obj)) {
      styles = obj;
    } else {
      assert(
        typeof /** @type {?} */
        obj.getZIndex === "function",
        "Expected an `Style` or an array of `Style`"
      );
      const style = (
        /** @type {Style} */
        obj
      );
      styles = [style];
    }
    styleFunction = function() {
      return styles;
    };
  }
  return styleFunction;
}
let defaultStyles = null;
function createDefaultStyle(feature, resolution) {
  if (!defaultStyles) {
    const fill = new Fill({
      color: "rgba(255,255,255,0.4)"
    });
    const stroke = new Stroke({
      color: "#3399CC",
      width: 1.25
    });
    defaultStyles = [
      new Style({
        image: new CircleStyle({
          fill,
          stroke,
          radius: 5
        }),
        fill,
        stroke
      })
    ];
  }
  return defaultStyles;
}
function defaultGeometryFunction(feature) {
  return feature.getGeometry();
}
const DEFAULT_FILL_COLOR = "#333";
let Text$1 = class Text2 {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 || {};
    this.font_ = options2.font;
    this.rotation_ = options2.rotation;
    this.rotateWithView_ = options2.rotateWithView;
    this.keepUpright_ = options2.keepUpright;
    this.scale_ = options2.scale;
    this.scaleArray_ = toSize(options2.scale !== void 0 ? options2.scale : 1);
    this.text_ = options2.text;
    this.textAlign_ = options2.textAlign;
    this.justify_ = options2.justify;
    this.repeat_ = options2.repeat;
    this.textBaseline_ = options2.textBaseline;
    this.fill_ = options2.fill !== void 0 ? options2.fill : new Fill({ color: DEFAULT_FILL_COLOR });
    this.maxAngle_ = options2.maxAngle !== void 0 ? options2.maxAngle : Math.PI / 4;
    this.placement_ = options2.placement !== void 0 ? options2.placement : "point";
    this.overflow_ = !!options2.overflow;
    this.stroke_ = options2.stroke !== void 0 ? options2.stroke : null;
    this.offsetX_ = options2.offsetX !== void 0 ? options2.offsetX : 0;
    this.offsetY_ = options2.offsetY !== void 0 ? options2.offsetY : 0;
    this.backgroundFill_ = options2.backgroundFill ? options2.backgroundFill : null;
    this.backgroundStroke_ = options2.backgroundStroke ? options2.backgroundStroke : null;
    this.padding_ = options2.padding === void 0 ? null : options2.padding;
    this.declutterMode_ = options2.declutterMode;
  }
  /**
   * Clones the style.
   * @return {Text} The cloned style.
   * @api
   */
  clone() {
    const scale2 = this.getScale();
    return new Text2({
      font: this.getFont(),
      placement: this.getPlacement(),
      repeat: this.getRepeat(),
      maxAngle: this.getMaxAngle(),
      overflow: this.getOverflow(),
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
      keepUpright: this.getKeepUpright(),
      scale: Array.isArray(scale2) ? scale2.slice() : scale2,
      text: this.getText(),
      textAlign: this.getTextAlign(),
      justify: this.getJustify(),
      textBaseline: this.getTextBaseline(),
      fill: this.getFill() ? this.getFill().clone() : void 0,
      stroke: this.getStroke() ? this.getStroke().clone() : void 0,
      offsetX: this.getOffsetX(),
      offsetY: this.getOffsetY(),
      backgroundFill: this.getBackgroundFill() ? this.getBackgroundFill().clone() : void 0,
      backgroundStroke: this.getBackgroundStroke() ? this.getBackgroundStroke().clone() : void 0,
      padding: this.getPadding() || void 0,
      declutterMode: this.getDeclutterMode()
    });
  }
  /**
   * Get the `overflow` configuration.
   * @return {boolean} Let text overflow the length of the path they follow.
   * @api
   */
  getOverflow() {
    return this.overflow_;
  }
  /**
   * Get the font name.
   * @return {string|undefined} Font.
   * @api
   */
  getFont() {
    return this.font_;
  }
  /**
   * Get the maximum angle between adjacent characters.
   * @return {number} Angle in radians.
   * @api
   */
  getMaxAngle() {
    return this.maxAngle_;
  }
  /**
   * Get the label placement.
   * @return {TextPlacement} Text placement.
   * @api
   */
  getPlacement() {
    return this.placement_;
  }
  /**
   * Get the repeat interval of the text.
   * @return {number|undefined} Repeat interval in pixels.
   * @api
   */
  getRepeat() {
    return this.repeat_;
  }
  /**
   * Get the x-offset for the text.
   * @return {number} Horizontal text offset.
   * @api
   */
  getOffsetX() {
    return this.offsetX_;
  }
  /**
   * Get the y-offset for the text.
   * @return {number} Vertical text offset.
   * @api
   */
  getOffsetY() {
    return this.offsetY_;
  }
  /**
   * Get the fill style for the text.
   * @return {import("./Fill.js").default|null} Fill style.
   * @api
   */
  getFill() {
    return this.fill_;
  }
  /**
   * Determine whether the text rotates with the map.
   * @return {boolean|undefined} Rotate with map.
   * @api
   */
  getRotateWithView() {
    return this.rotateWithView_;
  }
  /**
   * Determine whether the text can be rendered upside down.
   * @return {boolean|undefined} Keep text upright.
   * @api
   */
  getKeepUpright() {
    return this.keepUpright_;
  }
  /**
   * Get the text rotation.
   * @return {number|undefined} Rotation.
   * @api
   */
  getRotation() {
    return this.rotation_;
  }
  /**
   * Get the text scale.
   * @return {number|import("../size.js").Size|undefined} Scale.
   * @api
   */
  getScale() {
    return this.scale_;
  }
  /**
   * Get the symbolizer scale array.
   * @return {import("../size.js").Size} Scale array.
   */
  getScaleArray() {
    return this.scaleArray_;
  }
  /**
   * Get the stroke style for the text.
   * @return {import("./Stroke.js").default|null} Stroke style.
   * @api
   */
  getStroke() {
    return this.stroke_;
  }
  /**
   * Get the text to be rendered.
   * @return {string|Array<string>|undefined} Text.
   * @api
   */
  getText() {
    return this.text_;
  }
  /**
   * Get the text alignment.
   * @return {CanvasTextAlign|undefined} Text align.
   * @api
   */
  getTextAlign() {
    return this.textAlign_;
  }
  /**
   * Get the justification.
   * @return {TextJustify|undefined} Justification.
   * @api
   */
  getJustify() {
    return this.justify_;
  }
  /**
   * Get the text baseline.
   * @return {CanvasTextBaseline|undefined} Text baseline.
   * @api
   */
  getTextBaseline() {
    return this.textBaseline_;
  }
  /**
   * Get the background fill style for the text.
   * @return {import("./Fill.js").default|null} Fill style.
   * @api
   */
  getBackgroundFill() {
    return this.backgroundFill_;
  }
  /**
   * Get the background stroke style for the text.
   * @return {import("./Stroke.js").default|null} Stroke style.
   * @api
   */
  getBackgroundStroke() {
    return this.backgroundStroke_;
  }
  /**
   * Get the padding for the text.
   * @return {Array<number>|null} Padding.
   * @api
   */
  getPadding() {
    return this.padding_;
  }
  /**
   * Get the declutter mode of the shape
   * @return {import("./Style.js").DeclutterMode} Shape's declutter mode
   * @api
   */
  getDeclutterMode() {
    return this.declutterMode_;
  }
  /**
   * Set the `overflow` property.
   *
   * @param {boolean} overflow Let text overflow the path that it follows.
   * @api
   */
  setOverflow(overflow) {
    this.overflow_ = overflow;
  }
  /**
   * Set the font.
   *
   * @param {string|undefined} font Font.
   * @api
   */
  setFont(font) {
    this.font_ = font;
  }
  /**
   * Set the maximum angle between adjacent characters.
   *
   * @param {number} maxAngle Angle in radians.
   * @api
   */
  setMaxAngle(maxAngle) {
    this.maxAngle_ = maxAngle;
  }
  /**
   * Set the x offset.
   *
   * @param {number} offsetX Horizontal text offset.
   * @api
   */
  setOffsetX(offsetX) {
    this.offsetX_ = offsetX;
  }
  /**
   * Set the y offset.
   *
   * @param {number} offsetY Vertical text offset.
   * @api
   */
  setOffsetY(offsetY) {
    this.offsetY_ = offsetY;
  }
  /**
   * Set the text placement.
   *
   * @param {TextPlacement} placement Placement.
   * @api
   */
  setPlacement(placement) {
    this.placement_ = placement;
  }
  /**
   * Set the repeat interval of the text.
   * @param {number|undefined} [repeat] Repeat interval in pixels.
   * @api
   */
  setRepeat(repeat) {
    this.repeat_ = repeat;
  }
  /**
   * Set whether to rotate the text with the view.
   *
   * @param {boolean} rotateWithView Rotate with map.
   * @api
   */
  setRotateWithView(rotateWithView) {
    this.rotateWithView_ = rotateWithView;
  }
  /**
   * Set whether the text can be rendered upside down.
   *
   * @param {boolean} keepUpright Keep text upright.
   * @api
   */
  setKeepUpright(keepUpright) {
    this.keepUpright_ = keepUpright;
  }
  /**
   * Set the fill.
   *
   * @param {import("./Fill.js").default|null} fill Fill style.
   * @api
   */
  setFill(fill) {
    this.fill_ = fill;
  }
  /**
   * Set the rotation.
   *
   * @param {number|undefined} rotation Rotation.
   * @api
   */
  setRotation(rotation) {
    this.rotation_ = rotation;
  }
  /**
   * Set the scale.
   *
   * @param {number|import("../size.js").Size|undefined} scale Scale.
   * @api
   */
  setScale(scale2) {
    this.scale_ = scale2;
    this.scaleArray_ = toSize(scale2 !== void 0 ? scale2 : 1);
  }
  /**
   * Set the stroke.
   *
   * @param {import("./Stroke.js").default|null} stroke Stroke style.
   * @api
   */
  setStroke(stroke) {
    this.stroke_ = stroke;
  }
  /**
   * Set the text.
   *
   * @param {string|Array<string>|undefined} text Text.
   * @api
   */
  setText(text) {
    this.text_ = text;
  }
  /**
   * Set the text alignment.
   *
   * @param {CanvasTextAlign|undefined} textAlign Text align.
   * @api
   */
  setTextAlign(textAlign) {
    this.textAlign_ = textAlign;
  }
  /**
   * Set the justification.
   *
   * @param {TextJustify|undefined} justify Justification.
   * @api
   */
  setJustify(justify) {
    this.justify_ = justify;
  }
  /**
   * Set the text baseline.
   *
   * @param {CanvasTextBaseline|undefined} textBaseline Text baseline.
   * @api
   */
  setTextBaseline(textBaseline) {
    this.textBaseline_ = textBaseline;
  }
  /**
   * Set the background fill.
   *
   * @param {import("./Fill.js").default|null} fill Fill style.
   * @api
   */
  setBackgroundFill(fill) {
    this.backgroundFill_ = fill;
  }
  /**
   * Set the background stroke.
   *
   * @param {import("./Stroke.js").default|null} stroke Stroke style.
   * @api
   */
  setBackgroundStroke(stroke) {
    this.backgroundStroke_ = stroke;
  }
  /**
   * Set the padding (`[top, right, bottom, left]`).
   *
   * @param {Array<number>|null} padding Padding.
   * @api
   */
  setPadding(padding) {
    this.padding_ = padding;
  }
};
function always(context) {
  return true;
}
function rulesToStyleFunction(rules) {
  const parsingContext = newParsingContext();
  const evaluator = buildRuleSet(rules, parsingContext);
  const evaluationContext = newEvaluationContext();
  return function(feature, resolution) {
    evaluationContext.properties = feature.getPropertiesInternal();
    evaluationContext.resolution = resolution;
    if (parsingContext.featureId) {
      const id = feature.getId();
      if (id !== void 0) {
        evaluationContext.featureId = id;
      } else {
        evaluationContext.featureId = null;
      }
    }
    if (parsingContext.geometryType) {
      evaluationContext.geometryType = computeGeometryType(
        feature.getGeometry()
      );
    }
    return evaluator(evaluationContext);
  };
}
function flatStylesToStyleFunction(flatStyles) {
  const parsingContext = newParsingContext();
  const length = flatStyles.length;
  const evaluators = new Array(length);
  for (let i = 0; i < length; ++i) {
    evaluators[i] = buildStyle(flatStyles[i], parsingContext);
  }
  const evaluationContext = newEvaluationContext();
  const styles = new Array(length);
  return function(feature, resolution) {
    evaluationContext.properties = feature.getPropertiesInternal();
    evaluationContext.resolution = resolution;
    if (parsingContext.featureId) {
      const id = feature.getId();
      if (id !== void 0) {
        evaluationContext.featureId = id;
      } else {
        evaluationContext.featureId = null;
      }
    }
    let nonNullCount = 0;
    for (let i = 0; i < length; ++i) {
      const style = evaluators[i](evaluationContext);
      if (style) {
        styles[nonNullCount] = style;
        nonNullCount += 1;
      }
    }
    styles.length = nonNullCount;
    return styles;
  };
}
function buildRuleSet(rules, context) {
  const length = rules.length;
  const compiledRules = new Array(length);
  for (let i = 0; i < length; ++i) {
    const rule = rules[i];
    const filter = "filter" in rule ? buildExpression(rule.filter, BooleanType, context) : always;
    let styles;
    if (Array.isArray(rule.style)) {
      const styleLength = rule.style.length;
      styles = new Array(styleLength);
      for (let j = 0; j < styleLength; ++j) {
        styles[j] = buildStyle(rule.style[j], context);
      }
    } else {
      styles = [buildStyle(rule.style, context)];
    }
    compiledRules[i] = { filter, styles };
  }
  return function(context2) {
    const styles = [];
    let someMatched = false;
    for (let i = 0; i < length; ++i) {
      const filterEvaluator = compiledRules[i].filter;
      if (!filterEvaluator(context2)) {
        continue;
      }
      if (rules[i].else && someMatched) {
        continue;
      }
      someMatched = true;
      for (const styleEvaluator of compiledRules[i].styles) {
        const style = styleEvaluator(context2);
        if (!style) {
          continue;
        }
        styles.push(style);
      }
    }
    return styles;
  };
}
function buildStyle(flatStyle, context) {
  const evaluateFill = buildFill(flatStyle, "", context);
  const evaluateStroke = buildStroke(flatStyle, "", context);
  const evaluateText = buildText(flatStyle, context);
  const evaluateImage = buildImage(flatStyle, context);
  const evaluateZIndex = numberEvaluator(flatStyle, "z-index", context);
  if (!evaluateFill && !evaluateStroke && !evaluateText && !evaluateImage && !isEmpty$1(flatStyle)) {
    throw new Error(
      "No fill, stroke, point, or text symbolizer properties in style: " + JSON.stringify(flatStyle)
    );
  }
  const style = new Style();
  return function(context2) {
    let empty = true;
    if (evaluateFill) {
      const fill = evaluateFill(context2);
      if (fill) {
        empty = false;
      }
      style.setFill(fill);
    }
    if (evaluateStroke) {
      const stroke = evaluateStroke(context2);
      if (stroke) {
        empty = false;
      }
      style.setStroke(stroke);
    }
    if (evaluateText) {
      const text = evaluateText(context2);
      if (text) {
        empty = false;
      }
      style.setText(text);
    }
    if (evaluateImage) {
      const image = evaluateImage(context2);
      if (image) {
        empty = false;
      }
      style.setImage(image);
    }
    if (evaluateZIndex) {
      style.setZIndex(evaluateZIndex(context2));
    }
    if (empty) {
      return null;
    }
    return style;
  };
}
function buildFill(flatStyle, prefix, context) {
  let evaluateColor;
  if (prefix + "fill-pattern-src" in flatStyle) {
    evaluateColor = patternEvaluator(flatStyle, prefix + "fill-", context);
  } else {
    if (flatStyle[prefix + "fill-color"] === "none") {
      return (context2) => null;
    }
    evaluateColor = colorLikeEvaluator(
      flatStyle,
      prefix + "fill-color",
      context
    );
  }
  if (!evaluateColor) {
    return null;
  }
  const fill = new Fill();
  return function(context2) {
    const color2 = evaluateColor(context2);
    if (color2 === NO_COLOR) {
      return null;
    }
    fill.setColor(color2);
    return fill;
  };
}
function buildStroke(flatStyle, prefix, context) {
  const evaluateWidth = numberEvaluator(
    flatStyle,
    prefix + "stroke-width",
    context
  );
  const evaluateColor = colorLikeEvaluator(
    flatStyle,
    prefix + "stroke-color",
    context
  );
  if (!evaluateWidth && !evaluateColor) {
    return null;
  }
  const evaluateLineCap = stringEvaluator(
    flatStyle,
    prefix + "stroke-line-cap",
    context
  );
  const evaluateLineJoin = stringEvaluator(
    flatStyle,
    prefix + "stroke-line-join",
    context
  );
  const evaluateLineDash = numberArrayEvaluator(
    flatStyle,
    prefix + "stroke-line-dash",
    context
  );
  const evaluateLineDashOffset = numberEvaluator(
    flatStyle,
    prefix + "stroke-line-dash-offset",
    context
  );
  const evaluateMiterLimit = numberEvaluator(
    flatStyle,
    prefix + "stroke-miter-limit",
    context
  );
  const stroke = new Stroke();
  return function(context2) {
    if (evaluateColor) {
      const color2 = evaluateColor(context2);
      if (color2 === NO_COLOR) {
        return null;
      }
      stroke.setColor(color2);
    }
    if (evaluateWidth) {
      stroke.setWidth(evaluateWidth(context2));
    }
    if (evaluateLineCap) {
      const lineCap = evaluateLineCap(context2);
      if (lineCap !== "butt" && lineCap !== "round" && lineCap !== "square") {
        throw new Error("Expected butt, round, or square line cap");
      }
      stroke.setLineCap(lineCap);
    }
    if (evaluateLineJoin) {
      const lineJoin = evaluateLineJoin(context2);
      if (lineJoin !== "bevel" && lineJoin !== "round" && lineJoin !== "miter") {
        throw new Error("Expected bevel, round, or miter line join");
      }
      stroke.setLineJoin(lineJoin);
    }
    if (evaluateLineDash) {
      stroke.setLineDash(evaluateLineDash(context2));
    }
    if (evaluateLineDashOffset) {
      stroke.setLineDashOffset(evaluateLineDashOffset(context2));
    }
    if (evaluateMiterLimit) {
      stroke.setMiterLimit(evaluateMiterLimit(context2));
    }
    return stroke;
  };
}
function buildText(flatStyle, context) {
  const prefix = "text-";
  const evaluateValue = stringEvaluator(flatStyle, prefix + "value", context);
  if (!evaluateValue) {
    return null;
  }
  const evaluateFill = buildFill(flatStyle, prefix, context);
  const evaluateBackgroundFill = buildFill(
    flatStyle,
    prefix + "background-",
    context
  );
  const evaluateStroke = buildStroke(flatStyle, prefix, context);
  const evaluateBackgroundStroke = buildStroke(
    flatStyle,
    prefix + "background-",
    context
  );
  const evaluateFont = stringEvaluator(flatStyle, prefix + "font", context);
  const evaluateMaxAngle = numberEvaluator(
    flatStyle,
    prefix + "max-angle",
    context
  );
  const evaluateOffsetX = numberEvaluator(
    flatStyle,
    prefix + "offset-x",
    context
  );
  const evaluateOffsetY = numberEvaluator(
    flatStyle,
    prefix + "offset-y",
    context
  );
  const evaluateOverflow = booleanEvaluator(
    flatStyle,
    prefix + "overflow",
    context
  );
  const evaluatePlacement = stringEvaluator(
    flatStyle,
    prefix + "placement",
    context
  );
  const evaluateRepeat = numberEvaluator(flatStyle, prefix + "repeat", context);
  const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + "scale", context);
  const evaluateRotateWithView = booleanEvaluator(
    flatStyle,
    prefix + "rotate-with-view",
    context
  );
  const evaluateRotation = numberEvaluator(
    flatStyle,
    prefix + "rotation",
    context
  );
  const evaluateAlign = stringEvaluator(flatStyle, prefix + "align", context);
  const evaluateJustify = stringEvaluator(
    flatStyle,
    prefix + "justify",
    context
  );
  const evaluateBaseline = stringEvaluator(
    flatStyle,
    prefix + "baseline",
    context
  );
  const evaluateKeepUpright = booleanEvaluator(
    flatStyle,
    prefix + "keep-upright",
    context
  );
  const evaluatePadding = numberArrayEvaluator(
    flatStyle,
    prefix + "padding",
    context
  );
  const declutterMode = optionalDeclutterMode(
    flatStyle,
    prefix + "declutter-mode"
  );
  const text = new Text$1({ declutterMode });
  return function(context2) {
    text.setText(evaluateValue(context2));
    if (evaluateFill) {
      text.setFill(evaluateFill(context2));
    }
    if (evaluateBackgroundFill) {
      text.setBackgroundFill(evaluateBackgroundFill(context2));
    }
    if (evaluateStroke) {
      text.setStroke(evaluateStroke(context2));
    }
    if (evaluateBackgroundStroke) {
      text.setBackgroundStroke(evaluateBackgroundStroke(context2));
    }
    if (evaluateFont) {
      text.setFont(evaluateFont(context2));
    }
    if (evaluateMaxAngle) {
      text.setMaxAngle(evaluateMaxAngle(context2));
    }
    if (evaluateOffsetX) {
      text.setOffsetX(evaluateOffsetX(context2));
    }
    if (evaluateOffsetY) {
      text.setOffsetY(evaluateOffsetY(context2));
    }
    if (evaluateOverflow) {
      text.setOverflow(evaluateOverflow(context2));
    }
    if (evaluatePlacement) {
      const placement = evaluatePlacement(context2);
      if (placement !== "point" && placement !== "line") {
        throw new Error("Expected point or line for text-placement");
      }
      text.setPlacement(placement);
    }
    if (evaluateRepeat) {
      text.setRepeat(evaluateRepeat(context2));
    }
    if (evaluateScale) {
      text.setScale(evaluateScale(context2));
    }
    if (evaluateRotateWithView) {
      text.setRotateWithView(evaluateRotateWithView(context2));
    }
    if (evaluateRotation) {
      text.setRotation(evaluateRotation(context2));
    }
    if (evaluateAlign) {
      const textAlign = evaluateAlign(context2);
      if (textAlign !== "left" && textAlign !== "center" && textAlign !== "right" && textAlign !== "end" && textAlign !== "start") {
        throw new Error(
          "Expected left, right, center, start, or end for text-align"
        );
      }
      text.setTextAlign(textAlign);
    }
    if (evaluateJustify) {
      const justify = evaluateJustify(context2);
      if (justify !== "left" && justify !== "right" && justify !== "center") {
        throw new Error("Expected left, right, or center for text-justify");
      }
      text.setJustify(justify);
    }
    if (evaluateBaseline) {
      const textBaseline = evaluateBaseline(context2);
      if (textBaseline !== "bottom" && textBaseline !== "top" && textBaseline !== "middle" && textBaseline !== "alphabetic" && textBaseline !== "hanging") {
        throw new Error(
          "Expected bottom, top, middle, alphabetic, or hanging for text-baseline"
        );
      }
      text.setTextBaseline(textBaseline);
    }
    if (evaluatePadding) {
      text.setPadding(evaluatePadding(context2));
    }
    if (evaluateKeepUpright) {
      text.setKeepUpright(evaluateKeepUpright(context2));
    }
    return text;
  };
}
function buildImage(flatStyle, context) {
  if ("icon-src" in flatStyle) {
    return buildIcon(flatStyle, context);
  }
  if ("shape-points" in flatStyle) {
    return buildShape(flatStyle, context);
  }
  if ("circle-radius" in flatStyle) {
    return buildCircle(flatStyle, context);
  }
  return null;
}
function buildIcon(flatStyle, context) {
  const prefix = "icon-";
  const srcName = prefix + "src";
  const src = requireString(flatStyle[srcName], srcName);
  const evaluateAnchor = coordinateEvaluator(
    flatStyle,
    prefix + "anchor",
    context
  );
  const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + "scale", context);
  const evaluateOpacity = numberEvaluator(
    flatStyle,
    prefix + "opacity",
    context
  );
  const evaluateDisplacement = coordinateEvaluator(
    flatStyle,
    prefix + "displacement",
    context
  );
  const evaluateRotation = numberEvaluator(
    flatStyle,
    prefix + "rotation",
    context
  );
  const evaluateRotateWithView = booleanEvaluator(
    flatStyle,
    prefix + "rotate-with-view",
    context
  );
  const anchorOrigin = optionalIconOrigin(flatStyle, prefix + "anchor-origin");
  const anchorXUnits = optionalIconAnchorUnits(
    flatStyle,
    prefix + "anchor-x-units"
  );
  const anchorYUnits = optionalIconAnchorUnits(
    flatStyle,
    prefix + "anchor-y-units"
  );
  const color2 = optionalColorLike(flatStyle, prefix + "color");
  const crossOrigin = optionalString(flatStyle, prefix + "cross-origin");
  const offset2 = optionalNumberArray(flatStyle, prefix + "offset");
  const offsetOrigin = optionalIconOrigin(flatStyle, prefix + "offset-origin");
  const width = optionalNumber(flatStyle, prefix + "width");
  const height = optionalNumber(flatStyle, prefix + "height");
  const size = optionalSize(flatStyle, prefix + "size");
  const declutterMode = optionalDeclutterMode(
    flatStyle,
    prefix + "declutter-mode"
  );
  const icon = new Icon({
    src,
    anchorOrigin,
    anchorXUnits,
    anchorYUnits,
    color: color2,
    crossOrigin,
    offset: offset2,
    offsetOrigin,
    height,
    width,
    size,
    declutterMode
  });
  return function(context2) {
    if (evaluateOpacity) {
      icon.setOpacity(evaluateOpacity(context2));
    }
    if (evaluateDisplacement) {
      icon.setDisplacement(evaluateDisplacement(context2));
    }
    if (evaluateRotation) {
      icon.setRotation(evaluateRotation(context2));
    }
    if (evaluateRotateWithView) {
      icon.setRotateWithView(evaluateRotateWithView(context2));
    }
    if (evaluateScale) {
      icon.setScale(evaluateScale(context2));
    }
    if (evaluateAnchor) {
      icon.setAnchor(evaluateAnchor(context2));
    }
    return icon;
  };
}
function buildShape(flatStyle, context) {
  const prefix = "shape-";
  const pointsName = prefix + "points";
  const radiusName = prefix + "radius";
  const points = requireNumber(flatStyle[pointsName], pointsName);
  const radius = requireNumber(flatStyle[radiusName], radiusName);
  const evaluateFill = buildFill(flatStyle, prefix, context);
  const evaluateStroke = buildStroke(flatStyle, prefix, context);
  const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + "scale", context);
  const evaluateDisplacement = coordinateEvaluator(
    flatStyle,
    prefix + "displacement",
    context
  );
  const evaluateRotation = numberEvaluator(
    flatStyle,
    prefix + "rotation",
    context
  );
  const evaluateRotateWithView = booleanEvaluator(
    flatStyle,
    prefix + "rotate-with-view",
    context
  );
  const radius2 = optionalNumber(flatStyle, prefix + "radius2");
  const angle = optionalNumber(flatStyle, prefix + "angle");
  const declutterMode = optionalDeclutterMode(
    flatStyle,
    prefix + "declutter-mode"
  );
  const shape = new RegularShape({
    points,
    radius,
    radius2,
    angle,
    declutterMode
  });
  return function(context2) {
    if (evaluateFill) {
      shape.setFill(evaluateFill(context2));
    }
    if (evaluateStroke) {
      shape.setStroke(evaluateStroke(context2));
    }
    if (evaluateDisplacement) {
      shape.setDisplacement(evaluateDisplacement(context2));
    }
    if (evaluateRotation) {
      shape.setRotation(evaluateRotation(context2));
    }
    if (evaluateRotateWithView) {
      shape.setRotateWithView(evaluateRotateWithView(context2));
    }
    if (evaluateScale) {
      shape.setScale(evaluateScale(context2));
    }
    return shape;
  };
}
function buildCircle(flatStyle, context) {
  const prefix = "circle-";
  const evaluateFill = buildFill(flatStyle, prefix, context);
  const evaluateStroke = buildStroke(flatStyle, prefix, context);
  const evaluateRadius = numberEvaluator(flatStyle, prefix + "radius", context);
  const evaluateScale = sizeLikeEvaluator(flatStyle, prefix + "scale", context);
  const evaluateDisplacement = coordinateEvaluator(
    flatStyle,
    prefix + "displacement",
    context
  );
  const evaluateRotation = numberEvaluator(
    flatStyle,
    prefix + "rotation",
    context
  );
  const evaluateRotateWithView = booleanEvaluator(
    flatStyle,
    prefix + "rotate-with-view",
    context
  );
  const declutterMode = optionalDeclutterMode(
    flatStyle,
    prefix + "declutter-mode"
  );
  const circle2 = new CircleStyle({
    radius: 5,
    // this is arbitrary, but required - the evaluated radius is used below
    declutterMode
  });
  return function(context2) {
    if (evaluateRadius) {
      circle2.setRadius(evaluateRadius(context2));
    }
    if (evaluateFill) {
      circle2.setFill(evaluateFill(context2));
    }
    if (evaluateStroke) {
      circle2.setStroke(evaluateStroke(context2));
    }
    if (evaluateDisplacement) {
      circle2.setDisplacement(evaluateDisplacement(context2));
    }
    if (evaluateRotation) {
      circle2.setRotation(evaluateRotation(context2));
    }
    if (evaluateRotateWithView) {
      circle2.setRotateWithView(evaluateRotateWithView(context2));
    }
    if (evaluateScale) {
      circle2.setScale(evaluateScale(context2));
    }
    return circle2;
  };
}
function numberEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return void 0;
  }
  const evaluator = buildExpression(flatStyle[name], NumberType, context);
  return function(context2) {
    return requireNumber(evaluator(context2), name);
  };
}
function stringEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(flatStyle[name], StringType, context);
  return function(context2) {
    return requireString(evaluator(context2), name);
  };
}
function patternEvaluator(flatStyle, prefix, context) {
  const srcEvaluator = stringEvaluator(
    flatStyle,
    prefix + "pattern-src",
    context
  );
  const offsetEvaluator = sizeEvaluator(
    flatStyle,
    prefix + "pattern-offset",
    context
  );
  const patternSizeEvaluator = sizeEvaluator(
    flatStyle,
    prefix + "pattern-size",
    context
  );
  const colorEvaluator = colorLikeEvaluator(
    flatStyle,
    prefix + "color",
    context
  );
  return function(context2) {
    return {
      src: srcEvaluator(context2),
      offset: offsetEvaluator && offsetEvaluator(context2),
      size: patternSizeEvaluator && patternSizeEvaluator(context2),
      color: colorEvaluator && colorEvaluator(context2)
    };
  };
}
function booleanEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(flatStyle[name], BooleanType, context);
  return function(context2) {
    const value = evaluator(context2);
    if (typeof value !== "boolean") {
      throw new Error(`Expected a boolean for ${name}`);
    }
    return value;
  };
}
function colorLikeEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(flatStyle[name], ColorType, context);
  return function(context2) {
    return requireColorLike(evaluator(context2), name);
  };
}
function numberArrayEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(flatStyle[name], NumberArrayType, context);
  return function(context2) {
    return requireNumberArray(evaluator(context2), name);
  };
}
function coordinateEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(flatStyle[name], NumberArrayType, context);
  return function(context2) {
    const array = requireNumberArray(evaluator(context2), name);
    if (array.length !== 2) {
      throw new Error(`Expected two numbers for ${name}`);
    }
    return array;
  };
}
function sizeEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(flatStyle[name], NumberArrayType, context);
  return function(context2) {
    return requireSize(evaluator(context2), name);
  };
}
function sizeLikeEvaluator(flatStyle, name, context) {
  if (!(name in flatStyle)) {
    return null;
  }
  const evaluator = buildExpression(
    flatStyle[name],
    NumberArrayType | NumberType,
    context
  );
  return function(context2) {
    return requireSizeLike(evaluator(context2), name);
  };
}
function optionalNumber(flatStyle, property) {
  const value = flatStyle[property];
  if (value === void 0) {
    return void 0;
  }
  if (typeof value !== "number") {
    throw new Error(`Expected a number for ${property}`);
  }
  return value;
}
function optionalSize(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  if (typeof encoded === "number") {
    return toSize(encoded);
  }
  if (!Array.isArray(encoded)) {
    throw new Error(`Expected a number or size array for ${property}`);
  }
  if (encoded.length !== 2 || typeof encoded[0] !== "number" || typeof encoded[1] !== "number") {
    throw new Error(`Expected a number or size array for ${property}`);
  }
  return encoded;
}
function optionalString(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  if (typeof encoded !== "string") {
    throw new Error(`Expected a string for ${property}`);
  }
  return encoded;
}
function optionalIconOrigin(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  if (encoded !== "bottom-left" && encoded !== "bottom-right" && encoded !== "top-left" && encoded !== "top-right") {
    throw new Error(
      `Expected bottom-left, bottom-right, top-left, or top-right for ${property}`
    );
  }
  return encoded;
}
function optionalIconAnchorUnits(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  if (encoded !== "pixels" && encoded !== "fraction") {
    throw new Error(`Expected pixels or fraction for ${property}`);
  }
  return encoded;
}
function optionalNumberArray(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  return requireNumberArray(encoded, property);
}
function optionalDeclutterMode(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  if (typeof encoded !== "string") {
    throw new Error(`Expected a string for ${property}`);
  }
  if (encoded !== "declutter" && encoded !== "obstacle" && encoded !== "none") {
    throw new Error(`Expected declutter, obstacle, or none for ${property}`);
  }
  return encoded;
}
function optionalColorLike(flatStyle, property) {
  const encoded = flatStyle[property];
  if (encoded === void 0) {
    return void 0;
  }
  return requireColorLike(encoded, property);
}
function requireNumberArray(value, property) {
  if (!Array.isArray(value)) {
    throw new Error(`Expected an array for ${property}`);
  }
  const length = value.length;
  for (let i = 0; i < length; ++i) {
    if (typeof value[i] !== "number") {
      throw new Error(`Expected an array of numbers for ${property}`);
    }
  }
  return value;
}
function requireString(value, property) {
  if (typeof value !== "string") {
    throw new Error(`Expected a string for ${property}`);
  }
  return value;
}
function requireNumber(value, property) {
  if (typeof value !== "number") {
    throw new Error(`Expected a number for ${property}`);
  }
  return value;
}
function requireColorLike(value, property) {
  if (typeof value === "string") {
    return value;
  }
  const array = requireNumberArray(value, property);
  const length = array.length;
  if (length < 3 || length > 4) {
    throw new Error(`Expected a color with 3 or 4 values for ${property}`);
  }
  return array;
}
function requireSize(value, property) {
  const size = requireNumberArray(value, property);
  if (size.length !== 2) {
    throw new Error(`Expected an array of two numbers for ${property}`);
  }
  return size;
}
function requireSizeLike(value, property) {
  if (typeof value === "number") {
    return value;
  }
  return requireSize(value, property);
}
const Property = {
  RENDER_ORDER: "renderOrder"
};
class BaseVectorLayer extends Layer {
  /**
   * @param {Options<FeatureType, VectorSourceType>} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    const baseOptions = Object.assign({}, options2);
    delete baseOptions.style;
    delete baseOptions.renderBuffer;
    delete baseOptions.updateWhileAnimating;
    delete baseOptions.updateWhileInteracting;
    super(baseOptions);
    this.declutter_ = options2.declutter ? String(options2.declutter) : void 0;
    this.renderBuffer_ = options2.renderBuffer !== void 0 ? options2.renderBuffer : 100;
    this.style_ = null;
    this.styleFunction_ = void 0;
    this.setStyle(options2.style);
    this.updateWhileAnimating_ = options2.updateWhileAnimating !== void 0 ? options2.updateWhileAnimating : false;
    this.updateWhileInteracting_ = options2.updateWhileInteracting !== void 0 ? options2.updateWhileInteracting : false;
  }
  /**
   * @return {string} Declutter group.
   * @override
   */
  getDeclutter() {
    return this.declutter_;
  }
  /**
   * Get the topmost feature that intersects the given pixel on the viewport. Returns a promise
   * that resolves with an array of features. The array will either contain the topmost feature
   * when a hit was detected, or it will be empty.
   *
   * The hit detection algorithm used for this method is optimized for performance, but is less
   * accurate than the one used in [map.getFeaturesAtPixel()]{@link import("../Map.js").default#getFeaturesAtPixel}.
   * Text is not considered, and icons are only represented by their bounding box instead of the exact
   * image.
   *
   * @param {import("../pixel.js").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../Feature").FeatureLike>>} Promise that resolves with an array of features.
   * @api
   * @override
   */
  getFeatures(pixel) {
    return super.getFeatures(pixel);
  }
  /**
   * @return {number|undefined} Render buffer.
   */
  getRenderBuffer() {
    return this.renderBuffer_;
  }
  /**
   * @return {import("../render.js").OrderFunction|null|undefined} Render order.
   */
  getRenderOrder() {
    return (
      /** @type {import("../render.js").OrderFunction|null|undefined} */
      this.get(Property.RENDER_ORDER)
    );
  }
  /**
   * Get the style for features.  This returns whatever was passed to the `style`
   * option at construction or to the `setStyle` method.
   * @return {import("../style/Style.js").StyleLike|import("../style/flat.js").FlatStyleLike|null|undefined} Layer style.
   * @api
   */
  getStyle() {
    return this.style_;
  }
  /**
   * Get the style function.
   * @return {import("../style/Style.js").StyleFunction|undefined} Layer style function.
   * @api
   */
  getStyleFunction() {
    return this.styleFunction_;
  }
  /**
   * @return {boolean} Whether the rendered layer should be updated while
   *     animating.
   */
  getUpdateWhileAnimating() {
    return this.updateWhileAnimating_;
  }
  /**
   * @return {boolean} Whether the rendered layer should be updated while
   *     interacting.
   */
  getUpdateWhileInteracting() {
    return this.updateWhileInteracting_;
  }
  /**
   * Render declutter items for this layer
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @param {import("../layer/Layer.js").State} layerState Layer state.
   * @override
   */
  renderDeclutter(frameState, layerState) {
    const declutterGroup = this.getDeclutter();
    if (declutterGroup in frameState.declutter === false) {
      frameState.declutter[declutterGroup] = new RBush$1(9);
    }
    this.getRenderer().renderDeclutter(frameState, layerState);
  }
  /**
   * @param {import("../render.js").OrderFunction|null|undefined} renderOrder
   *     Render order.
   */
  setRenderOrder(renderOrder) {
    this.set(Property.RENDER_ORDER, renderOrder);
  }
  /**
   * Set the style for features.  This can be a single style object, an array
   * of styles, or a function that takes a feature and resolution and returns
   * an array of styles. If set to `null`, the layer has no style (a `null` style),
   * so only features that have their own styles will be rendered in the layer. Call
   * `setStyle()` without arguments to reset to the default style. See
   * [the ol/style/Style module]{@link module:ol/style/Style~Style} for information on the default style.
   *
   * If your layer has a static style, you can use [flat style]{@link module:ol/style/flat~FlatStyle} object
   * literals instead of using the `Style` and symbolizer constructors (`Fill`, `Stroke`, etc.):
   * ```js
   * vectorLayer.setStyle({
   *   "fill-color": "yellow",
   *   "stroke-color": "black",
   *   "stroke-width": 4
   * })
   * ```
   *
   * @param {import("../style/Style.js").StyleLike|import("../style/flat.js").FlatStyleLike|null} [style] Layer style.
   * @api
   */
  setStyle(style) {
    this.style_ = style === void 0 ? createDefaultStyle : style;
    const styleLike = toStyleLike(style);
    this.styleFunction_ = style === null ? void 0 : toFunction(styleLike);
    this.changed();
  }
  /**
   * @param {boolean|string|number} declutter Declutter images and text.
   * @api
   */
  setDeclutter(declutter) {
    this.declutter_ = declutter ? String(declutter) : void 0;
    this.changed();
  }
}
function toStyleLike(style) {
  if (style === void 0) {
    return createDefaultStyle;
  }
  if (!style) {
    return null;
  }
  if (typeof style === "function") {
    return style;
  }
  if (style instanceof Style) {
    return style;
  }
  if (!Array.isArray(style)) {
    return flatStylesToStyleFunction([style]);
  }
  if (style.length === 0) {
    return [];
  }
  const length = style.length;
  const first = style[0];
  if (first instanceof Style) {
    const styles = new Array(length);
    for (let i = 0; i < length; ++i) {
      const candidate = style[i];
      if (!(candidate instanceof Style)) {
        throw new Error("Expected a list of style instances");
      }
      styles[i] = candidate;
    }
    return styles;
  }
  if ("style" in first) {
    const rules = new Array(length);
    for (let i = 0; i < length; ++i) {
      const candidate = style[i];
      if (!("style" in candidate)) {
        throw new Error("Expected a list of rules with a style property");
      }
      rules[i] = candidate;
    }
    return rulesToStyleFunction(rules);
  }
  const flatStyles = (
    /** @type {Array<import("../style/flat.js").FlatStyle>} */
    style
  );
  return flatStylesToStyleFunction(flatStyles);
}
class RenderEvent extends BaseEvent {
  /**
   * @param {import("./EventType.js").default} type Type.
   * @param {import("../transform.js").Transform} [inversePixelTransform] Transform for
   *     CSS pixels to rendered pixels.
   * @param {import("../Map.js").FrameState} [frameState] Frame state.
   * @param {?(CanvasRenderingContext2D|WebGLRenderingContext)} [context] Context.
   */
  constructor(type, inversePixelTransform, frameState, context) {
    super(type);
    this.inversePixelTransform = inversePixelTransform;
    this.frameState = frameState;
    this.context = context;
  }
}
class MapRenderer extends Disposable {
  /**
   * @param {import("../Map.js").default} map Map.
   */
  constructor(map) {
    super();
    this.map_ = map;
  }
  /**
   * @abstract
   * @param {import("../render/EventType.js").default} type Event type.
   * @param {import("../Map.js").FrameState} frameState Frame state.
   */
  dispatchRenderEvent(type, frameState) {
    abstract();
  }
  /**
   * @param {import("../Map.js").FrameState} frameState FrameState.
   * @protected
   */
  calculateMatrices2D(frameState) {
    const viewState = frameState.viewState;
    const coordinateToPixelTransform = frameState.coordinateToPixelTransform;
    const pixelToCoordinateTransform = frameState.pixelToCoordinateTransform;
    compose(
      coordinateToPixelTransform,
      frameState.size[0] / 2,
      frameState.size[1] / 2,
      1 / viewState.resolution,
      -1 / viewState.resolution,
      -viewState.rotation,
      -viewState.center[0],
      -viewState.center[1]
    );
    makeInverse(pixelToCoordinateTransform, coordinateToPixelTransform);
  }
  /**
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("../Map.js").FrameState} frameState FrameState.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {boolean} checkWrapped Check for wrapped geometries.
   * @param {import("./vector.js").FeatureCallback<T>} callback Feature callback.
   * @param {S} thisArg Value to use as `this` when executing `callback`.
   * @param {function(this: U, import("../layer/Layer.js").default): boolean} layerFilter Layer filter
   *     function, only layers which are visible and for which this function
   *     returns `true` will be tested for features.  By default, all visible
   *     layers will be tested.
   * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.
   * @return {T|undefined} Callback result.
   * @template S,T,U
   */
  forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, checkWrapped, callback, thisArg, layerFilter, thisArg2) {
    let result;
    const viewState = frameState.viewState;
    function forEachFeatureAtCoordinate(managed, feature, layer, geometry) {
      return callback.call(thisArg, feature, managed ? layer : null, geometry);
    }
    const projection = viewState.projection;
    const translatedCoordinate = wrapX$1(coordinate.slice(), projection);
    const offsets = [[0, 0]];
    if (projection.canWrapX() && checkWrapped) {
      const projectionExtent = projection.getExtent();
      const worldWidth = getWidth(projectionExtent);
      offsets.push([-worldWidth, 0], [worldWidth, 0]);
    }
    const layerStates = frameState.layerStatesArray;
    const numLayers = layerStates.length;
    const matches = (
      /** @type {Array<HitMatch<T>>} */
      []
    );
    const tmpCoord = [];
    for (let i = 0; i < offsets.length; i++) {
      for (let j = numLayers - 1; j >= 0; --j) {
        const layerState = layerStates[j];
        const layer = layerState.layer;
        if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter.call(thisArg2, layer)) {
          const layerRenderer = layer.getRenderer();
          const source = layer.getSource();
          if (layerRenderer && source) {
            const coordinates2 = source.getWrapX() ? translatedCoordinate : coordinate;
            const callback2 = forEachFeatureAtCoordinate.bind(
              null,
              layerState.managed
            );
            tmpCoord[0] = coordinates2[0] + offsets[i][0];
            tmpCoord[1] = coordinates2[1] + offsets[i][1];
            result = layerRenderer.forEachFeatureAtCoordinate(
              tmpCoord,
              frameState,
              hitTolerance,
              callback2,
              matches
            );
          }
          if (result) {
            return result;
          }
        }
      }
    }
    if (matches.length === 0) {
      return void 0;
    }
    const order = 1 / matches.length;
    matches.forEach((m, i) => m.distanceSq += i * order);
    matches.sort((a, b) => a.distanceSq - b.distanceSq);
    matches.some((m) => {
      return result = m.callback(m.feature, m.layer, m.geometry);
    });
    return result;
  }
  /**
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("../Map.js").FrameState} frameState FrameState.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {boolean} checkWrapped Check for wrapped geometries.
   * @param {function(this: U, import("../layer/Layer.js").default): boolean} layerFilter Layer filter
   *     function, only layers which are visible and for which this function
   *     returns `true` will be tested for features.  By default, all visible
   *     layers will be tested.
   * @param {U} thisArg Value to use as `this` when executing `layerFilter`.
   * @return {boolean} Is there a feature at the given coordinate?
   * @template U
   */
  hasFeatureAtCoordinate(coordinate, frameState, hitTolerance, checkWrapped, layerFilter, thisArg) {
    const hasFeature = this.forEachFeatureAtCoordinate(
      coordinate,
      frameState,
      hitTolerance,
      checkWrapped,
      TRUE,
      this,
      layerFilter,
      thisArg
    );
    return hasFeature !== void 0;
  }
  /**
   * @return {import("../Map.js").default} Map.
   */
  getMap() {
    return this.map_;
  }
  /**
   * Render.
   * @abstract
   * @param {?import("../Map.js").FrameState} frameState Frame state.
   */
  renderFrame(frameState) {
    abstract();
  }
  /**
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @protected
   */
  scheduleExpireIconCache(frameState) {
    if (shared.canExpireCache()) {
      frameState.postRenderFunctions.push(expireIconCache);
    }
  }
}
function expireIconCache(map, frameState) {
  shared.expire();
}
class CompositeMapRenderer extends MapRenderer {
  /**
   * @param {import("../Map.js").default} map Map.
   */
  constructor(map) {
    super(map);
    this.fontChangeListenerKey_ = listen(
      checkedFonts,
      ObjectEventType.PROPERTYCHANGE,
      map.redrawText,
      map
    );
    this.element_ = document.createElement("div");
    const style = this.element_.style;
    style.position = "absolute";
    style.width = "100%";
    style.height = "100%";
    style.zIndex = "0";
    this.element_.className = CLASS_UNSELECTABLE + " ol-layers";
    const container = map.getViewport();
    container.insertBefore(this.element_, container.firstChild || null);
    this.children_ = [];
    this.renderedVisible_ = true;
  }
  /**
   * @param {import("../render/EventType.js").default} type Event type.
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @override
   */
  dispatchRenderEvent(type, frameState) {
    const map = this.getMap();
    if (map.hasListener(type)) {
      const event = new RenderEvent(type, void 0, frameState);
      map.dispatchEvent(event);
    }
  }
  /**
   * @override
   */
  disposeInternal() {
    unlistenByKey(this.fontChangeListenerKey_);
    this.element_.remove();
    super.disposeInternal();
  }
  /**
   * Render.
   * @param {?import("../Map.js").FrameState} frameState Frame state.
   * @override
   */
  renderFrame(frameState) {
    if (!frameState) {
      if (this.renderedVisible_) {
        this.element_.style.display = "none";
        this.renderedVisible_ = false;
      }
      return;
    }
    this.calculateMatrices2D(frameState);
    this.dispatchRenderEvent(RenderEventType.PRECOMPOSE, frameState);
    const layerStatesArray = frameState.layerStatesArray.sort(
      (a, b) => a.zIndex - b.zIndex
    );
    const declutter = layerStatesArray.some(
      (layerState) => layerState.layer instanceof BaseVectorLayer && layerState.layer.getDeclutter()
    );
    if (declutter) {
      frameState.declutter = {};
    }
    const viewState = frameState.viewState;
    this.children_.length = 0;
    const renderedLayerStates = [];
    let previousElement = null;
    for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
      const layerState = layerStatesArray[i];
      frameState.layerIndex = i;
      const layer = layerState.layer;
      const sourceState = layer.getSourceState();
      if (!inView(layerState, viewState) || sourceState != "ready" && sourceState != "undefined") {
        layer.unrender();
        continue;
      }
      const element = layer.render(frameState, previousElement);
      if (!element) {
        continue;
      }
      if (element !== previousElement) {
        this.children_.push(element);
        previousElement = element;
      }
      renderedLayerStates.push(layerState);
    }
    this.declutter(frameState, renderedLayerStates);
    replaceChildren(this.element_, this.children_);
    this.dispatchRenderEvent(RenderEventType.POSTCOMPOSE, frameState);
    if (!this.renderedVisible_) {
      this.element_.style.display = "";
      this.renderedVisible_ = true;
    }
    this.scheduleExpireIconCache(frameState);
  }
  /**
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @param {Array<import('../layer/Layer.js').State>} layerStates Layers.
   */
  declutter(frameState, layerStates) {
    if (!frameState.declutter) {
      return;
    }
    for (let i = layerStates.length - 1; i >= 0; --i) {
      const layerState = layerStates[i];
      const layer = layerState.layer;
      if (layer.getDeclutter()) {
        layer.renderDeclutter(frameState, layerState);
      }
    }
    layerStates.forEach(
      (layerState) => layerState.layer.renderDeferred(frameState)
    );
  }
}
function removeLayerMapProperty(layer) {
  if (layer instanceof Layer) {
    layer.setMapInternal(null);
    return;
  }
  if (layer instanceof LayerGroup) {
    layer.getLayers().forEach(removeLayerMapProperty);
  }
}
function setLayerMapProperty(layer, map) {
  if (layer instanceof Layer) {
    layer.setMapInternal(map);
    return;
  }
  if (layer instanceof LayerGroup) {
    const layers = layer.getLayers().getArray();
    for (let i = 0, ii = layers.length; i < ii; ++i) {
      setLayerMapProperty(layers[i], map);
    }
  }
}
let Map$2 = class Map2 extends BaseObject {
  /**
   * @param {MapOptions} [options] Map options.
   */
  constructor(options2) {
    super();
    options2 = options2 || {};
    this.on;
    this.once;
    this.un;
    const optionsInternal = createOptionsInternal(options2);
    this.renderComplete_ = false;
    this.loaded_ = true;
    this.boundHandleBrowserEvent_ = this.handleBrowserEvent.bind(this);
    this.maxTilesLoading_ = options2.maxTilesLoading !== void 0 ? options2.maxTilesLoading : 16;
    this.pixelRatio_ = options2.pixelRatio !== void 0 ? options2.pixelRatio : DEVICE_PIXEL_RATIO;
    this.postRenderTimeoutHandle_;
    this.animationDelayKey_;
    this.animationDelay_ = this.animationDelay_.bind(this);
    this.coordinateToPixelTransform_ = create();
    this.pixelToCoordinateTransform_ = create();
    this.frameIndex_ = 0;
    this.frameState_ = null;
    this.previousExtent_ = null;
    this.viewPropertyListenerKey_ = null;
    this.viewChangeListenerKey_ = null;
    this.layerGroupPropertyListenerKeys_ = null;
    this.viewport_ = document.createElement("div");
    this.viewport_.className = "ol-viewport" + ("ontouchstart" in window ? " ol-touch" : "");
    this.viewport_.style.position = "relative";
    this.viewport_.style.overflow = "hidden";
    this.viewport_.style.width = "100%";
    this.viewport_.style.height = "100%";
    this.overlayContainer_ = document.createElement("div");
    this.overlayContainer_.style.position = "absolute";
    this.overlayContainer_.style.zIndex = "0";
    this.overlayContainer_.style.width = "100%";
    this.overlayContainer_.style.height = "100%";
    this.overlayContainer_.style.pointerEvents = "none";
    this.overlayContainer_.className = "ol-overlaycontainer";
    this.viewport_.appendChild(this.overlayContainer_);
    this.overlayContainerStopEvent_ = document.createElement("div");
    this.overlayContainerStopEvent_.style.position = "absolute";
    this.overlayContainerStopEvent_.style.zIndex = "0";
    this.overlayContainerStopEvent_.style.width = "100%";
    this.overlayContainerStopEvent_.style.height = "100%";
    this.overlayContainerStopEvent_.style.pointerEvents = "none";
    this.overlayContainerStopEvent_.className = "ol-overlaycontainer-stopevent";
    this.viewport_.appendChild(this.overlayContainerStopEvent_);
    this.mapBrowserEventHandler_ = null;
    this.moveTolerance_ = options2.moveTolerance;
    this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget;
    this.targetChangeHandlerKeys_ = null;
    this.targetElement_ = null;
    this.resizeObserver_ = new ResizeObserver(() => this.updateSize());
    this.controls = optionsInternal.controls || defaults$1();
    this.interactions = optionsInternal.interactions || defaults({
      onFocusOnly: true
    });
    this.overlays_ = optionsInternal.overlays;
    this.overlayIdIndex_ = {};
    this.renderer_ = null;
    this.postRenderFunctions_ = [];
    this.tileQueue_ = new TileQueue(
      this.getTilePriority.bind(this),
      this.handleTileChange_.bind(this)
    );
    this.addChangeListener(
      MapProperty.LAYERGROUP,
      this.handleLayerGroupChanged_
    );
    this.addChangeListener(MapProperty.VIEW, this.handleViewChanged_);
    this.addChangeListener(MapProperty.SIZE, this.handleSizeChanged_);
    this.addChangeListener(MapProperty.TARGET, this.handleTargetChanged_);
    this.setProperties(optionsInternal.values);
    const map = this;
    if (options2.view && !(options2.view instanceof View)) {
      options2.view.then(function(viewOptions) {
        map.setView(new View(viewOptions));
      });
    }
    this.controls.addEventListener(
      CollectionEventType.ADD,
      /**
       * @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent
       */
      (event) => {
        event.element.setMap(this);
      }
    );
    this.controls.addEventListener(
      CollectionEventType.REMOVE,
      /**
       * @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent.
       */
      (event) => {
        event.element.setMap(null);
      }
    );
    this.interactions.addEventListener(
      CollectionEventType.ADD,
      /**
       * @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent.
       */
      (event) => {
        event.element.setMap(this);
      }
    );
    this.interactions.addEventListener(
      CollectionEventType.REMOVE,
      /**
       * @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent.
       */
      (event) => {
        event.element.setMap(null);
      }
    );
    this.overlays_.addEventListener(
      CollectionEventType.ADD,
      /**
       * @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent.
       */
      (event) => {
        this.addOverlayInternal_(event.element);
      }
    );
    this.overlays_.addEventListener(
      CollectionEventType.REMOVE,
      /**
       * @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent.
       */
      (event) => {
        const id = event.element.getId();
        if (id !== void 0) {
          delete this.overlayIdIndex_[id.toString()];
        }
        event.element.setMap(null);
      }
    );
    this.controls.forEach(
      /**
       * @param {import("./control/Control.js").default} control Control.
       */
      (control) => {
        control.setMap(this);
      }
    );
    this.interactions.forEach(
      /**
       * @param {import("./interaction/Interaction.js").default} interaction Interaction.
       */
      (interaction) => {
        interaction.setMap(this);
      }
    );
    this.overlays_.forEach(this.addOverlayInternal_.bind(this));
  }
  /**
   * Add the given control to the map.
   * @param {import("./control/Control.js").default} control Control.
   * @api
   */
  addControl(control) {
    this.getControls().push(control);
  }
  /**
   * Add the given interaction to the map. If you want to add an interaction
   * at another point of the collection use `getInteractions()` and the methods
   * available on {@link module:ol/Collection~Collection}. This can be used to
   * stop the event propagation from the handleEvent function. The interactions
   * get to handle the events in the reverse order of this collection.
   * @param {import("./interaction/Interaction.js").default} interaction Interaction to add.
   * @api
   */
  addInteraction(interaction) {
    this.getInteractions().push(interaction);
  }
  /**
   * Adds the given layer to the top of this map. If you want to add a layer
   * elsewhere in the stack, use `getLayers()` and the methods available on
   * {@link module:ol/Collection~Collection}.
   * @param {import("./layer/Base.js").default} layer Layer.
   * @api
   */
  addLayer(layer) {
    const layers = this.getLayerGroup().getLayers();
    layers.push(layer);
  }
  /**
   * @param {import("./layer/Group.js").GroupEvent} event The layer add event.
   * @private
   */
  handleLayerAdd_(event) {
    setLayerMapProperty(event.layer, this);
  }
  /**
   * Add the given overlay to the map.
   * @param {import("./Overlay.js").default} overlay Overlay.
   * @api
   */
  addOverlay(overlay) {
    this.getOverlays().push(overlay);
  }
  /**
   * This deals with map's overlay collection changes.
   * @param {import("./Overlay.js").default} overlay Overlay.
   * @private
   */
  addOverlayInternal_(overlay) {
    const id = overlay.getId();
    if (id !== void 0) {
      this.overlayIdIndex_[id.toString()] = overlay;
    }
    overlay.setMap(this);
  }
  /**
   *
   * Clean up.
   * @override
   */
  disposeInternal() {
    this.controls.clear();
    this.interactions.clear();
    this.overlays_.clear();
    this.resizeObserver_.disconnect();
    this.setTarget(null);
    super.disposeInternal();
  }
  /**
   * Detect features that intersect a pixel on the viewport, and execute a
   * callback with each intersecting feature. Layers included in the detection can
   * be configured through the `layerFilter` option in `options`.
   * For polygons without a fill, only the stroke will be used for hit detection.
   * Polygons must have a fill style applied to ensure that pixels inside a polygon are detected.
   * The fill can be transparent.
   * @param {import("./pixel.js").Pixel} pixel Pixel.
   * @param {function(import("./Feature.js").FeatureLike, import("./layer/Layer.js").default<import("./source/Source").default>, import("./geom/SimpleGeometry.js").default): T} callback Feature callback. The callback will be
   *     called with two arguments. The first argument is one
   *     {@link module:ol/Feature~Feature feature} or
   *     {@link module:ol/render/Feature~RenderFeature render feature} at the pixel, the second is
   *     the {@link module:ol/layer/Layer~Layer layer} of the feature and will be null for
   *     unmanaged layers. To stop detection, callback functions can return a
   *     truthy value.
   * @param {AtPixelOptions} [options] Optional options.
   * @return {T|undefined} Callback result, i.e. the return value of last
   * callback execution, or the first truthy callback return value.
   * @template T
   * @api
   */
  forEachFeatureAtPixel(pixel, callback, options2) {
    if (!this.frameState_ || !this.renderer_) {
      return;
    }
    const coordinate = this.getCoordinateFromPixelInternal(pixel);
    options2 = options2 !== void 0 ? options2 : {};
    const hitTolerance = options2.hitTolerance !== void 0 ? options2.hitTolerance : 0;
    const layerFilter = options2.layerFilter !== void 0 ? options2.layerFilter : TRUE;
    const checkWrapped = options2.checkWrapped !== false;
    return this.renderer_.forEachFeatureAtCoordinate(
      coordinate,
      this.frameState_,
      hitTolerance,
      checkWrapped,
      callback,
      null,
      layerFilter,
      null
    );
  }
  /**
   * Get all features that intersect a pixel on the viewport.
   * For polygons without a fill, only the stroke will be used for hit detection.
   * Polygons must have a fill style applied to ensure that pixels inside a polygon are detected.
   * The fill can be transparent.
   * @param {import("./pixel.js").Pixel} pixel Pixel.
   * @param {AtPixelOptions} [options] Optional options.
   * @return {Array<import("./Feature.js").FeatureLike>} The detected features or
   * an empty array if none were found.
   * @api
   */
  getFeaturesAtPixel(pixel, options2) {
    const features = [];
    this.forEachFeatureAtPixel(
      pixel,
      function(feature) {
        features.push(feature);
      },
      options2
    );
    return features;
  }
  /**
   * Get all layers from all layer groups.
   * @return {Array<import("./layer/Layer.js").default>} Layers.
   * @api
   */
  getAllLayers() {
    const layers = [];
    function addLayersFrom(layerGroup) {
      layerGroup.forEach(function(layer) {
        if (layer instanceof LayerGroup) {
          addLayersFrom(layer.getLayers());
        } else {
          layers.push(layer);
        }
      });
    }
    addLayersFrom(this.getLayers());
    return layers;
  }
  /**
   * Detect if features intersect a pixel on the viewport. Layers included in the
   * detection can be configured through the `layerFilter` option.
   * For polygons without a fill, only the stroke will be used for hit detection.
   * Polygons must have a fill style applied to ensure that pixels inside a polygon are detected.
   * The fill can be transparent.
   * @param {import("./pixel.js").Pixel} pixel Pixel.
   * @param {AtPixelOptions} [options] Optional options.
   * @return {boolean} Is there a feature at the given pixel?
   * @api
   */
  hasFeatureAtPixel(pixel, options2) {
    if (!this.frameState_ || !this.renderer_) {
      return false;
    }
    const coordinate = this.getCoordinateFromPixelInternal(pixel);
    options2 = options2 !== void 0 ? options2 : {};
    const layerFilter = options2.layerFilter !== void 0 ? options2.layerFilter : TRUE;
    const hitTolerance = options2.hitTolerance !== void 0 ? options2.hitTolerance : 0;
    const checkWrapped = options2.checkWrapped !== false;
    return this.renderer_.hasFeatureAtCoordinate(
      coordinate,
      this.frameState_,
      hitTolerance,
      checkWrapped,
      layerFilter,
      null
    );
  }
  /**
   * Returns the coordinate in user projection for a browser event.
   * @param {MouseEvent} event Event.
   * @return {import("./coordinate.js").Coordinate} Coordinate.
   * @api
   */
  getEventCoordinate(event) {
    return this.getCoordinateFromPixel(this.getEventPixel(event));
  }
  /**
   * Returns the coordinate in view projection for a browser event.
   * @param {MouseEvent} event Event.
   * @return {import("./coordinate.js").Coordinate} Coordinate.
   */
  getEventCoordinateInternal(event) {
    return this.getCoordinateFromPixelInternal(this.getEventPixel(event));
  }
  /**
   * Returns the map pixel position for a browser event relative to the viewport.
   * @param {UIEvent|{clientX: number, clientY: number}} event Event.
   * @return {import("./pixel.js").Pixel} Pixel.
   * @api
   */
  getEventPixel(event) {
    const viewport = this.viewport_;
    const viewportPosition = viewport.getBoundingClientRect();
    const viewportSize = this.getSize();
    const scaleX = viewportPosition.width / viewportSize[0];
    const scaleY = viewportPosition.height / viewportSize[1];
    const eventPosition = (
      //FIXME Are we really calling this with a TouchEvent anywhere?
      "changedTouches" in event ? (
        /** @type {TouchEvent} */
        event.changedTouches[0]
      ) : (
        /** @type {MouseEvent} */
        event
      )
    );
    return [
      (eventPosition.clientX - viewportPosition.left) / scaleX,
      (eventPosition.clientY - viewportPosition.top) / scaleY
    ];
  }
  /**
   * Get the target in which this map is rendered.
   * Note that this returns what is entered as an option or in setTarget:
   * if that was an element, it returns an element; if a string, it returns that.
   * @return {HTMLElement|string|undefined} The Element or id of the Element that the
   *     map is rendered in.
   * @observable
   * @api
   */
  getTarget() {
    return (
      /** @type {HTMLElement|string|undefined} */
      this.get(MapProperty.TARGET)
    );
  }
  /**
   * Get the DOM element into which this map is rendered. In contrast to
   * `getTarget` this method always return an `Element`, or `null` if the
   * map has no target.
   * @return {HTMLElement} The element that the map is rendered in.
   * @api
   */
  getTargetElement() {
    return this.targetElement_;
  }
  /**
   * Get the coordinate for a given pixel.  This returns a coordinate in the
   * user projection.
   * @param {import("./pixel.js").Pixel} pixel Pixel position in the map viewport.
   * @return {import("./coordinate.js").Coordinate} The coordinate for the pixel position.
   * @api
   */
  getCoordinateFromPixel(pixel) {
    return toUserCoordinate(
      this.getCoordinateFromPixelInternal(pixel),
      this.getView().getProjection()
    );
  }
  /**
   * Get the coordinate for a given pixel.  This returns a coordinate in the
   * map view projection.
   * @param {import("./pixel.js").Pixel} pixel Pixel position in the map viewport.
   * @return {import("./coordinate.js").Coordinate} The coordinate for the pixel position.
   */
  getCoordinateFromPixelInternal(pixel) {
    const frameState = this.frameState_;
    if (!frameState) {
      return null;
    }
    return apply(frameState.pixelToCoordinateTransform, pixel.slice());
  }
  /**
   * Get the map controls. Modifying this collection changes the controls
   * associated with the map.
   * @return {Collection<import("./control/Control.js").default>} Controls.
   * @api
   */
  getControls() {
    return this.controls;
  }
  /**
   * Get the map overlays. Modifying this collection changes the overlays
   * associated with the map.
   * @return {Collection<import("./Overlay.js").default>} Overlays.
   * @api
   */
  getOverlays() {
    return this.overlays_;
  }
  /**
   * Get an overlay by its identifier (the value returned by overlay.getId()).
   * Note that the index treats string and numeric identifiers as the same. So
   * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`.
   * @param {string|number} id Overlay identifier.
   * @return {import("./Overlay.js").default|null} Overlay.
   * @api
   */
  getOverlayById(id) {
    const overlay = this.overlayIdIndex_[id.toString()];
    return overlay !== void 0 ? overlay : null;
  }
  /**
   * Get the map interactions. Modifying this collection changes the interactions
   * associated with the map.
   *
   * Interactions are used for e.g. pan, zoom and rotate.
   * @return {Collection<import("./interaction/Interaction.js").default>} Interactions.
   * @api
   */
  getInteractions() {
    return this.interactions;
  }
  /**
   * Get the layergroup associated with this map.
   * @return {LayerGroup} A layer group containing the layers in this map.
   * @observable
   * @api
   */
  getLayerGroup() {
    return (
      /** @type {LayerGroup} */
      this.get(MapProperty.LAYERGROUP)
    );
  }
  /**
   * Clear any existing layers and add layers to the map.
   * @param {Array<import("./layer/Base.js").default>|Collection<import("./layer/Base.js").default>} layers The layers to be added to the map.
   * @api
   */
  setLayers(layers) {
    const group2 = this.getLayerGroup();
    if (layers instanceof Collection) {
      group2.setLayers(layers);
      return;
    }
    const collection = group2.getLayers();
    collection.clear();
    collection.extend(layers);
  }
  /**
   * Get the collection of layers associated with this map.
   * @return {!Collection<import("./layer/Base.js").default>} Layers.
   * @api
   */
  getLayers() {
    const layers = this.getLayerGroup().getLayers();
    return layers;
  }
  /**
   * @return {boolean} Layers have sources that are still loading.
   */
  getLoadingOrNotReady() {
    const layerStatesArray = this.getLayerGroup().getLayerStatesArray();
    for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
      const state = layerStatesArray[i];
      if (!state.visible) {
        continue;
      }
      const renderer = state.layer.getRenderer();
      if (renderer && !renderer.ready) {
        return true;
      }
      const source = state.layer.getSource();
      if (source && source.loading) {
        return true;
      }
    }
    return false;
  }
  /**
   * Get the pixel for a coordinate.  This takes a coordinate in the user
   * projection and returns the corresponding pixel.
   * @param {import("./coordinate.js").Coordinate} coordinate A map coordinate.
   * @return {import("./pixel.js").Pixel} A pixel position in the map viewport.
   * @api
   */
  getPixelFromCoordinate(coordinate) {
    const viewCoordinate = fromUserCoordinate(
      coordinate,
      this.getView().getProjection()
    );
    return this.getPixelFromCoordinateInternal(viewCoordinate);
  }
  /**
   * Get the pixel for a coordinate.  This takes a coordinate in the map view
   * projection and returns the corresponding pixel.
   * @param {import("./coordinate.js").Coordinate} coordinate A map coordinate.
   * @return {import("./pixel.js").Pixel} A pixel position in the map viewport.
   */
  getPixelFromCoordinateInternal(coordinate) {
    const frameState = this.frameState_;
    if (!frameState) {
      return null;
    }
    return apply(
      frameState.coordinateToPixelTransform,
      coordinate.slice(0, 2)
    );
  }
  /**
   * Get the map renderer.
   * @return {import("./renderer/Map.js").default|null} Renderer
   */
  getRenderer() {
    return this.renderer_;
  }
  /**
   * Get the size of this map.
   * @return {import("./size.js").Size|undefined} The size in pixels of the map in the DOM.
   * @observable
   * @api
   */
  getSize() {
    return (
      /** @type {import("./size.js").Size|undefined} */
      this.get(MapProperty.SIZE)
    );
  }
  /**
   * Get the view associated with this map. A view manages properties such as
   * center and resolution.
   * @return {View} The view that controls this map.
   * @observable
   * @api
   */
  getView() {
    return (
      /** @type {View} */
      this.get(MapProperty.VIEW)
    );
  }
  /**
   * Get the element that serves as the map viewport.
   * @return {HTMLElement} Viewport.
   * @api
   */
  getViewport() {
    return this.viewport_;
  }
  /**
   * Get the element that serves as the container for overlays.  Elements added to
   * this container will let mousedown and touchstart events through to the map,
   * so clicks and gestures on an overlay will trigger {@link module:ol/MapBrowserEvent~MapBrowserEvent}
   * events.
   * @return {!HTMLElement} The map's overlay container.
   */
  getOverlayContainer() {
    return this.overlayContainer_;
  }
  /**
   * Get the element that serves as a container for overlays that don't allow
   * event propagation. Elements added to this container won't let mousedown and
   * touchstart events through to the map, so clicks and gestures on an overlay
   * don't trigger any {@link module:ol/MapBrowserEvent~MapBrowserEvent}.
   * @return {!HTMLElement} The map's overlay container that stops events.
   */
  getOverlayContainerStopEvent() {
    return this.overlayContainerStopEvent_;
  }
  /**
   * @return {!Document} The document where the map is displayed.
   */
  getOwnerDocument() {
    const targetElement = this.getTargetElement();
    return targetElement ? targetElement.ownerDocument : document;
  }
  /**
   * @param {import("./Tile.js").default} tile Tile.
   * @param {string} tileSourceKey Tile source key.
   * @param {import("./coordinate.js").Coordinate} tileCenter Tile center.
   * @param {number} tileResolution Tile resolution.
   * @return {number} Tile priority.
   */
  getTilePriority(tile, tileSourceKey, tileCenter, tileResolution) {
    return getTilePriority(
      this.frameState_,
      tile,
      tileSourceKey,
      tileCenter,
      tileResolution
    );
  }
  /**
   * @param {PointerEvent|KeyboardEvent|WheelEvent} browserEvent Browser event.
   * @param {string} [type] Type.
   */
  handleBrowserEvent(browserEvent, type) {
    type = type || browserEvent.type;
    const mapBrowserEvent = new MapBrowserEvent(type, this, browserEvent);
    this.handleMapBrowserEvent(mapBrowserEvent);
  }
  /**
   * @param {MapBrowserEvent} mapBrowserEvent The event to handle.
   */
  handleMapBrowserEvent(mapBrowserEvent) {
    if (!this.frameState_) {
      return;
    }
    const originalEvent = mapBrowserEvent.originalEvent;
    const eventType = originalEvent.type;
    if (eventType === PointerEventType.POINTERDOWN || eventType === EventType.WHEEL || eventType === EventType.KEYDOWN) {
      const doc2 = this.getOwnerDocument();
      const rootNode = this.viewport_.getRootNode ? this.viewport_.getRootNode() : doc2;
      const target = (
        /** @type {Node} */
        originalEvent.target
      );
      const currentDoc = rootNode instanceof ShadowRoot ? rootNode.host === target ? rootNode.host.ownerDocument : rootNode : rootNode === doc2 ? doc2.documentElement : rootNode;
      if (
        // Abort if the target is a child of the container for elements whose events are not meant
        // to be handled by map interactions.
        this.overlayContainerStopEvent_.contains(target) || // Abort if the event target is a child of the container that is no longer in the page.
        // It's possible for the target to no longer be in the page if it has been removed in an
        // event listener, this might happen in a Control that recreates it's content based on
        // user interaction either manually or via a render in something like https://reactjs.org/
        !currentDoc.contains(target)
      ) {
        return;
      }
    }
    mapBrowserEvent.frameState = this.frameState_;
    if (this.dispatchEvent(mapBrowserEvent) !== false) {
      const interactionsArray = this.getInteractions().getArray().slice();
      for (let i = interactionsArray.length - 1; i >= 0; i--) {
        const interaction = interactionsArray[i];
        if (interaction.getMap() !== this || !interaction.getActive() || !this.getTargetElement()) {
          continue;
        }
        const cont = interaction.handleEvent(mapBrowserEvent);
        if (!cont || mapBrowserEvent.propagationStopped) {
          break;
        }
      }
    }
  }
  /**
   * @protected
   */
  handlePostRender() {
    const frameState = this.frameState_;
    const tileQueue = this.tileQueue_;
    if (!tileQueue.isEmpty()) {
      let maxTotalLoading = this.maxTilesLoading_;
      let maxNewLoads = maxTotalLoading;
      if (frameState) {
        const hints = frameState.viewHints;
        if (hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING]) {
          const lowOnFrameBudget = Date.now() - frameState.time > 8;
          maxTotalLoading = lowOnFrameBudget ? 0 : 8;
          maxNewLoads = lowOnFrameBudget ? 0 : 2;
        }
      }
      if (tileQueue.getTilesLoading() < maxTotalLoading) {
        tileQueue.reprioritize();
        tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);
      }
    }
    if (frameState && this.renderer_ && !frameState.animate) {
      if (this.renderComplete_) {
        if (this.hasListener(RenderEventType.RENDERCOMPLETE)) {
          this.renderer_.dispatchRenderEvent(
            RenderEventType.RENDERCOMPLETE,
            frameState
          );
        }
        if (this.loaded_ === false) {
          this.loaded_ = true;
          this.dispatchEvent(
            new MapEvent(MapEventType.LOADEND, this, frameState)
          );
        }
      } else if (this.loaded_ === true) {
        this.loaded_ = false;
        this.dispatchEvent(
          new MapEvent(MapEventType.LOADSTART, this, frameState)
        );
      }
    }
    const postRenderFunctions = this.postRenderFunctions_;
    if (frameState) {
      for (let i = 0, ii = postRenderFunctions.length; i < ii; ++i) {
        postRenderFunctions[i](this, frameState);
      }
    }
    postRenderFunctions.length = 0;
  }
  /**
   * @private
   */
  handleSizeChanged_() {
    if (this.getView() && !this.getView().getAnimating()) {
      this.getView().resolveConstraints(0);
    }
    this.render();
  }
  /**
   * @private
   */
  handleTargetChanged_() {
    if (this.mapBrowserEventHandler_) {
      for (let i = 0, ii = this.targetChangeHandlerKeys_.length; i < ii; ++i) {
        unlistenByKey(this.targetChangeHandlerKeys_[i]);
      }
      this.targetChangeHandlerKeys_ = null;
      this.viewport_.removeEventListener(
        EventType.CONTEXTMENU,
        this.boundHandleBrowserEvent_
      );
      this.viewport_.removeEventListener(
        EventType.WHEEL,
        this.boundHandleBrowserEvent_
      );
      this.mapBrowserEventHandler_.dispose();
      this.mapBrowserEventHandler_ = null;
      this.viewport_.remove();
    }
    if (this.targetElement_) {
      this.resizeObserver_.unobserve(this.targetElement_);
      const rootNode = this.targetElement_.getRootNode();
      if (rootNode instanceof ShadowRoot) {
        this.resizeObserver_.unobserve(rootNode.host);
      }
      this.setSize(void 0);
    }
    const target = this.getTarget();
    const targetElement = typeof target === "string" ? document.getElementById(target) : target;
    this.targetElement_ = targetElement;
    if (!targetElement) {
      if (this.renderer_) {
        clearTimeout(this.postRenderTimeoutHandle_);
        this.postRenderTimeoutHandle_ = void 0;
        this.postRenderFunctions_.length = 0;
        this.renderer_.dispose();
        this.renderer_ = null;
      }
      if (this.animationDelayKey_) {
        cancelAnimationFrame(this.animationDelayKey_);
        this.animationDelayKey_ = void 0;
      }
    } else {
      targetElement.appendChild(this.viewport_);
      if (!this.renderer_) {
        this.renderer_ = new CompositeMapRenderer(this);
      }
      this.mapBrowserEventHandler_ = new MapBrowserEventHandler(
        this,
        this.moveTolerance_
      );
      for (const key2 in MapBrowserEventType) {
        this.mapBrowserEventHandler_.addEventListener(
          MapBrowserEventType[key2],
          this.handleMapBrowserEvent.bind(this)
        );
      }
      this.viewport_.addEventListener(
        EventType.CONTEXTMENU,
        this.boundHandleBrowserEvent_,
        false
      );
      this.viewport_.addEventListener(
        EventType.WHEEL,
        this.boundHandleBrowserEvent_,
        PASSIVE_EVENT_LISTENERS ? { passive: false } : false
      );
      let keyboardEventTarget;
      if (!this.keyboardEventTarget_) {
        const targetRoot = targetElement.getRootNode();
        const targetCandidate = targetRoot instanceof ShadowRoot ? targetRoot.host : targetElement;
        keyboardEventTarget = targetCandidate;
      } else {
        keyboardEventTarget = this.keyboardEventTarget_;
      }
      this.targetChangeHandlerKeys_ = [
        listen(
          keyboardEventTarget,
          EventType.KEYDOWN,
          this.handleBrowserEvent,
          this
        ),
        listen(
          keyboardEventTarget,
          EventType.KEYPRESS,
          this.handleBrowserEvent,
          this
        )
      ];
      const rootNode = targetElement.getRootNode();
      if (rootNode instanceof ShadowRoot) {
        this.resizeObserver_.observe(rootNode.host);
      }
      this.resizeObserver_.observe(targetElement);
    }
    this.updateSize();
  }
  /**
   * @private
   */
  handleTileChange_() {
    this.render();
  }
  /**
   * @private
   */
  handleViewPropertyChanged_() {
    this.render();
  }
  /**
   * @private
   */
  handleViewChanged_() {
    if (this.viewPropertyListenerKey_) {
      unlistenByKey(this.viewPropertyListenerKey_);
      this.viewPropertyListenerKey_ = null;
    }
    if (this.viewChangeListenerKey_) {
      unlistenByKey(this.viewChangeListenerKey_);
      this.viewChangeListenerKey_ = null;
    }
    const view = this.getView();
    if (view) {
      this.updateViewportSize_(this.getSize());
      this.viewPropertyListenerKey_ = listen(
        view,
        ObjectEventType.PROPERTYCHANGE,
        this.handleViewPropertyChanged_,
        this
      );
      this.viewChangeListenerKey_ = listen(
        view,
        EventType.CHANGE,
        this.handleViewPropertyChanged_,
        this
      );
      view.resolveConstraints(0);
    }
    this.render();
  }
  /**
   * @private
   */
  handleLayerGroupChanged_() {
    if (this.layerGroupPropertyListenerKeys_) {
      this.layerGroupPropertyListenerKeys_.forEach(unlistenByKey);
      this.layerGroupPropertyListenerKeys_ = null;
    }
    const layerGroup = this.getLayerGroup();
    if (layerGroup) {
      this.handleLayerAdd_(new GroupEvent("addlayer", layerGroup));
      this.layerGroupPropertyListenerKeys_ = [
        listen(layerGroup, ObjectEventType.PROPERTYCHANGE, this.render, this),
        listen(layerGroup, EventType.CHANGE, this.render, this),
        listen(layerGroup, "addlayer", this.handleLayerAdd_, this),
        listen(layerGroup, "removelayer", this.handleLayerRemove_, this)
      ];
    }
    this.render();
  }
  /**
   * @return {boolean} Is rendered.
   */
  isRendered() {
    return !!this.frameState_;
  }
  /**
   * @private
   */
  animationDelay_() {
    this.animationDelayKey_ = void 0;
    this.renderFrame_(Date.now());
  }
  /**
   * Requests an immediate render in a synchronous manner.
   * @api
   */
  renderSync() {
    if (this.animationDelayKey_) {
      cancelAnimationFrame(this.animationDelayKey_);
    }
    this.animationDelay_();
  }
  /**
   * Redraws all text after new fonts have loaded
   */
  redrawText() {
    if (!this.frameState_) {
      return;
    }
    const layerStates = this.frameState_.layerStatesArray;
    for (let i = 0, ii = layerStates.length; i < ii; ++i) {
      const layer = layerStates[i].layer;
      if (layer.hasRenderer()) {
        layer.getRenderer().handleFontsChanged();
      }
    }
  }
  /**
   * Request a map rendering (at the next animation frame).
   * @api
   */
  render() {
    if (this.renderer_ && this.animationDelayKey_ === void 0) {
      this.animationDelayKey_ = requestAnimationFrame(this.animationDelay_);
    }
  }
  /**
   * Remove the given control from the map.
   * @param {import("./control/Control.js").default} control Control.
   * @return {import("./control/Control.js").default|undefined} The removed control (or undefined
   *     if the control was not found).
   * @api
   */
  removeControl(control) {
    return this.getControls().remove(control);
  }
  /**
   * Remove the given interaction from the map.
   * @param {import("./interaction/Interaction.js").default} interaction Interaction to remove.
   * @return {import("./interaction/Interaction.js").default|undefined} The removed interaction (or
   *     undefined if the interaction was not found).
   * @api
   */
  removeInteraction(interaction) {
    return this.getInteractions().remove(interaction);
  }
  /**
   * Removes the given layer from the map.
   * @param {import("./layer/Base.js").default} layer Layer.
   * @return {import("./layer/Base.js").default|undefined} The removed layer (or undefined if the
   *     layer was not found).
   * @api
   */
  removeLayer(layer) {
    const layers = this.getLayerGroup().getLayers();
    return layers.remove(layer);
  }
  /**
   * @param {import("./layer/Group.js").GroupEvent} event The layer remove event.
   * @private
   */
  handleLayerRemove_(event) {
    removeLayerMapProperty(event.layer);
  }
  /**
   * Remove the given overlay from the map.
   * @param {import("./Overlay.js").default} overlay Overlay.
   * @return {import("./Overlay.js").default|undefined} The removed overlay (or undefined
   *     if the overlay was not found).
   * @api
   */
  removeOverlay(overlay) {
    return this.getOverlays().remove(overlay);
  }
  /**
   * @param {number} time Time.
   * @private
   */
  renderFrame_(time) {
    const size = this.getSize();
    const view = this.getView();
    const previousFrameState = this.frameState_;
    let frameState = null;
    if (size !== void 0 && hasArea(size) && view && view.isDef()) {
      const viewHints = view.getHints(
        this.frameState_ ? this.frameState_.viewHints : void 0
      );
      const viewState = view.getState();
      frameState = {
        animate: false,
        coordinateToPixelTransform: this.coordinateToPixelTransform_,
        declutter: null,
        extent: getForViewAndSize(
          viewState.center,
          viewState.resolution,
          viewState.rotation,
          size
        ),
        index: this.frameIndex_++,
        layerIndex: 0,
        layerStatesArray: this.getLayerGroup().getLayerStatesArray(),
        pixelRatio: this.pixelRatio_,
        pixelToCoordinateTransform: this.pixelToCoordinateTransform_,
        postRenderFunctions: [],
        size,
        tileQueue: this.tileQueue_,
        time,
        usedTiles: {},
        viewState,
        viewHints,
        wantedTiles: {},
        mapId: getUid(this),
        renderTargets: {}
      };
      if (viewState.nextCenter && viewState.nextResolution) {
        const rotation = isNaN(viewState.nextRotation) ? viewState.rotation : viewState.nextRotation;
        frameState.nextExtent = getForViewAndSize(
          viewState.nextCenter,
          viewState.nextResolution,
          rotation,
          size
        );
      }
    }
    this.frameState_ = frameState;
    this.renderer_.renderFrame(frameState);
    if (frameState) {
      if (frameState.animate) {
        this.render();
      }
      Array.prototype.push.apply(
        this.postRenderFunctions_,
        frameState.postRenderFunctions
      );
      if (previousFrameState) {
        const moveStart = !this.previousExtent_ || !isEmpty(this.previousExtent_) && !equals$1(frameState.extent, this.previousExtent_);
        if (moveStart) {
          this.dispatchEvent(
            new MapEvent(MapEventType.MOVESTART, this, previousFrameState)
          );
          this.previousExtent_ = createOrUpdateEmpty(this.previousExtent_);
        }
      }
      const idle = this.previousExtent_ && !frameState.viewHints[ViewHint.ANIMATING] && !frameState.viewHints[ViewHint.INTERACTING] && !equals$1(frameState.extent, this.previousExtent_);
      if (idle) {
        this.dispatchEvent(
          new MapEvent(MapEventType.MOVEEND, this, frameState)
        );
        clone(frameState.extent, this.previousExtent_);
      }
    }
    this.dispatchEvent(new MapEvent(MapEventType.POSTRENDER, this, frameState));
    this.renderComplete_ = (this.hasListener(MapEventType.LOADSTART) || this.hasListener(MapEventType.LOADEND) || this.hasListener(RenderEventType.RENDERCOMPLETE)) && !this.tileQueue_.getTilesLoading() && !this.tileQueue_.getCount() && !this.getLoadingOrNotReady();
    if (!this.postRenderTimeoutHandle_) {
      this.postRenderTimeoutHandle_ = setTimeout(() => {
        this.postRenderTimeoutHandle_ = void 0;
        this.handlePostRender();
      }, 0);
    }
  }
  /**
   * Sets the layergroup of this map.
   * @param {LayerGroup} layerGroup A layer group containing the layers in this map.
   * @observable
   * @api
   */
  setLayerGroup(layerGroup) {
    const oldLayerGroup = this.getLayerGroup();
    if (oldLayerGroup) {
      this.handleLayerRemove_(new GroupEvent("removelayer", oldLayerGroup));
    }
    this.set(MapProperty.LAYERGROUP, layerGroup);
  }
  /**
   * Set the size of this map.
   * @param {import("./size.js").Size|undefined} size The size in pixels of the map in the DOM.
   * @observable
   * @api
   */
  setSize(size) {
    this.set(MapProperty.SIZE, size);
  }
  /**
   * Set the target element to render this map into.
   * For accessibility (focus and keyboard events for map navigation), the `target` element must have a
   *  properly configured `tabindex` attribute. If the `target` element is inside a Shadow DOM, the
   *  `tabindex` atribute must be set on the custom element's host element.
   * @param {HTMLElement|string} [target] The Element or id of the Element
   *     that the map is rendered in.
   * @observable
   * @api
   */
  setTarget(target) {
    this.set(MapProperty.TARGET, target);
  }
  /**
   * Set the view for this map.
   * @param {View|Promise<import("./View.js").ViewOptions>|null} view The view that controls this map.
   * It is also possible to pass a promise that resolves to options for constructing a view.  This
   * alternative allows view properties to be resolved by sources or other components that load
   * view-related metadata.
   * @observable
   * @api
   */
  setView(view) {
    if (!view || view instanceof View) {
      this.set(MapProperty.VIEW, view);
      return;
    }
    this.set(MapProperty.VIEW, new View());
    const map = this;
    view.then(function(viewOptions) {
      map.setView(new View(viewOptions));
    });
  }
  /**
   * Force a recalculation of the map viewport size.  This should be called when
   * third-party code changes the size of the map viewport.
   * @api
   */
  updateSize() {
    const targetElement = this.getTargetElement();
    let size = void 0;
    if (targetElement) {
      const computedStyle = getComputedStyle(targetElement);
      const width = targetElement.offsetWidth - parseFloat(computedStyle["borderLeftWidth"]) - parseFloat(computedStyle["paddingLeft"]) - parseFloat(computedStyle["paddingRight"]) - parseFloat(computedStyle["borderRightWidth"]);
      const height = targetElement.offsetHeight - parseFloat(computedStyle["borderTopWidth"]) - parseFloat(computedStyle["paddingTop"]) - parseFloat(computedStyle["paddingBottom"]) - parseFloat(computedStyle["borderBottomWidth"]);
      if (!isNaN(width) && !isNaN(height)) {
        size = [Math.max(0, width), Math.max(0, height)];
        if (!hasArea(size) && !!(targetElement.offsetWidth || targetElement.offsetHeight || targetElement.getClientRects().length)) {
          warn(
            "No map visible because the map container's width or height are 0."
          );
        }
      }
    }
    const oldSize = this.getSize();
    if (size && (!oldSize || !equals$2(size, oldSize))) {
      this.setSize(size);
      this.updateViewportSize_(size);
    }
  }
  /**
   * Recomputes the viewport size and save it on the view object (if any)
   * @param {import("./size.js").Size|undefined} size The size.
   * @private
   */
  updateViewportSize_(size) {
    const view = this.getView();
    if (view) {
      view.setViewportSize(size);
    }
  }
};
function createOptionsInternal(options2) {
  let keyboardEventTarget = null;
  if (options2.keyboardEventTarget !== void 0) {
    keyboardEventTarget = typeof options2.keyboardEventTarget === "string" ? document.getElementById(options2.keyboardEventTarget) : options2.keyboardEventTarget;
  }
  const values = {};
  const layerGroup = options2.layers && typeof /** @type {?} */
  options2.layers.getLayers === "function" ? (
    /** @type {LayerGroup} */
    options2.layers
  ) : new LayerGroup({
    layers: (
      /** @type {Collection<import("./layer/Base.js").default>|Array<import("./layer/Base.js").default>} */
      options2.layers
    )
  });
  values[MapProperty.LAYERGROUP] = layerGroup;
  values[MapProperty.TARGET] = options2.target;
  values[MapProperty.VIEW] = options2.view instanceof View ? options2.view : new View();
  let controls;
  if (options2.controls !== void 0) {
    if (Array.isArray(options2.controls)) {
      controls = new Collection(options2.controls.slice());
    } else {
      assert(
        typeof /** @type {?} */
        options2.controls.getArray === "function",
        "Expected `controls` to be an array or an `ol/Collection.js`"
      );
      controls = options2.controls;
    }
  }
  let interactions;
  if (options2.interactions !== void 0) {
    if (Array.isArray(options2.interactions)) {
      interactions = new Collection(options2.interactions.slice());
    } else {
      assert(
        typeof /** @type {?} */
        options2.interactions.getArray === "function",
        "Expected `interactions` to be an array or an `ol/Collection.js`"
      );
      interactions = options2.interactions;
    }
  }
  let overlays;
  if (options2.overlays !== void 0) {
    if (Array.isArray(options2.overlays)) {
      overlays = new Collection(options2.overlays.slice());
    } else {
      assert(
        typeof /** @type {?} */
        options2.overlays.getArray === "function",
        "Expected `overlays` to be an array or an `ol/Collection.js`"
      );
      overlays = options2.overlays;
    }
  } else {
    overlays = new Collection();
  }
  return {
    controls,
    interactions,
    keyboardEventTarget,
    overlays,
    values
  };
}
const UNITS_PROP = "units";
const LEADING_DIGITS = [1, 2, 5];
const DEFAULT_DPI = 25.4 / 0.28;
class ScaleLine extends Control {
  /**
   * @param {Options} [options] Scale line options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    const element = document.createElement("div");
    element.style.pointerEvents = "none";
    super({
      element,
      render: options2.render,
      target: options2.target
    });
    this.on;
    this.once;
    this.un;
    const className = options2.className !== void 0 ? options2.className : options2.bar ? "ol-scale-bar" : "ol-scale-line";
    this.innerElement_ = document.createElement("div");
    this.innerElement_.className = className + "-inner";
    this.element.className = className + " " + CLASS_UNSELECTABLE;
    this.element.appendChild(this.innerElement_);
    this.viewState_ = null;
    this.minWidth_ = options2.minWidth !== void 0 ? options2.minWidth : 64;
    this.maxWidth_ = options2.maxWidth;
    this.renderedVisible_ = false;
    this.renderedWidth_ = void 0;
    this.renderedHTML_ = "";
    this.addChangeListener(UNITS_PROP, this.handleUnitsChanged_);
    this.setUnits(options2.units || "metric");
    this.scaleBar_ = options2.bar || false;
    this.scaleBarSteps_ = options2.steps || 4;
    this.scaleBarText_ = options2.text || false;
    this.dpi_ = options2.dpi || void 0;
  }
  /**
   * Return the units to use in the scale line.
   * @return {Units} The units
   * to use in the scale line.
   * @observable
   * @api
   */
  getUnits() {
    return this.get(UNITS_PROP);
  }
  /**
   * @private
   */
  handleUnitsChanged_() {
    this.updateElement_();
  }
  /**
   * Set the units to use in the scale line.
   * @param {Units} units The units to use in the scale line.
   * @observable
   * @api
   */
  setUnits(units2) {
    this.set(UNITS_PROP, units2);
  }
  /**
   * Specify the dpi of output device such as printer.
   * @param {number|undefined} dpi The dpi of output device.
   * @api
   */
  setDpi(dpi) {
    this.dpi_ = dpi;
  }
  /**
   * @private
   */
  updateElement_() {
    const viewState = this.viewState_;
    if (!viewState) {
      if (this.renderedVisible_) {
        this.element.style.display = "none";
        this.renderedVisible_ = false;
      }
      return;
    }
    const center = viewState.center;
    const projection = viewState.projection;
    const units2 = this.getUnits();
    const pointResolutionUnits = units2 == "degrees" ? "degrees" : "m";
    let pointResolution = getPointResolution(
      projection,
      viewState.resolution,
      center,
      pointResolutionUnits
    );
    const minWidth = this.minWidth_ * (this.dpi_ || DEFAULT_DPI) / DEFAULT_DPI;
    const maxWidth = this.maxWidth_ !== void 0 ? this.maxWidth_ * (this.dpi_ || DEFAULT_DPI) / DEFAULT_DPI : void 0;
    let nominalCount = minWidth * pointResolution;
    let suffix = "";
    if (units2 == "degrees") {
      const metersPerDegree = METERS_PER_UNIT$1.degrees;
      nominalCount *= metersPerDegree;
      if (nominalCount < metersPerDegree / 60) {
        suffix = "″";
        pointResolution *= 3600;
      } else if (nominalCount < metersPerDegree) {
        suffix = "′";
        pointResolution *= 60;
      } else {
        suffix = "°";
      }
    } else if (units2 == "imperial") {
      if (nominalCount < 0.9144) {
        suffix = "in";
        pointResolution /= 0.0254;
      } else if (nominalCount < 1609.344) {
        suffix = "ft";
        pointResolution /= 0.3048;
      } else {
        suffix = "mi";
        pointResolution /= 1609.344;
      }
    } else if (units2 == "nautical") {
      pointResolution /= 1852;
      suffix = "NM";
    } else if (units2 == "metric") {
      if (nominalCount < 1e-6) {
        suffix = "nm";
        pointResolution *= 1e9;
      } else if (nominalCount < 1e-3) {
        suffix = "μm";
        pointResolution *= 1e6;
      } else if (nominalCount < 1) {
        suffix = "mm";
        pointResolution *= 1e3;
      } else if (nominalCount < 1e3) {
        suffix = "m";
      } else {
        suffix = "km";
        pointResolution /= 1e3;
      }
    } else if (units2 == "us") {
      if (nominalCount < 0.9144) {
        suffix = "in";
        pointResolution *= 39.37;
      } else if (nominalCount < 1609.344) {
        suffix = "ft";
        pointResolution /= 0.30480061;
      } else {
        suffix = "mi";
        pointResolution /= 1609.3472;
      }
    } else {
      throw new Error("Invalid units");
    }
    let i = 3 * Math.floor(Math.log(minWidth * pointResolution) / Math.log(10));
    let count, width, decimalCount;
    let previousCount = 0;
    let previousWidth, previousDecimalCount;
    while (true) {
      decimalCount = Math.floor(i / 3);
      const decimal = Math.pow(10, decimalCount);
      count = LEADING_DIGITS[(i % 3 + 3) % 3] * decimal;
      width = Math.round(count / pointResolution);
      if (isNaN(width)) {
        this.element.style.display = "none";
        this.renderedVisible_ = false;
        return;
      }
      if (maxWidth !== void 0 && width >= maxWidth) {
        count = previousCount;
        width = previousWidth;
        decimalCount = previousDecimalCount;
        break;
      } else if (width >= minWidth) {
        break;
      }
      previousCount = count;
      previousWidth = width;
      previousDecimalCount = decimalCount;
      ++i;
    }
    const html2 = this.scaleBar_ ? this.createScaleBar(width, count, suffix) : count.toFixed(decimalCount < 0 ? -decimalCount : 0) + " " + suffix;
    if (this.renderedHTML_ != html2) {
      this.innerElement_.innerHTML = html2;
      this.renderedHTML_ = html2;
    }
    if (this.renderedWidth_ != width) {
      this.innerElement_.style.width = width + "px";
      this.renderedWidth_ = width;
    }
    if (!this.renderedVisible_) {
      this.element.style.display = "";
      this.renderedVisible_ = true;
    }
  }
  /**
   * @private
   * @param {number} width The current width of the scalebar.
   * @param {number} scale The current scale.
   * @param {string} suffix The suffix to append to the scale text.
   * @return {string} The stringified HTML of the scalebar.
   */
  createScaleBar(width, scale2, suffix) {
    const resolutionScale = this.getScaleForResolution();
    const mapScale = resolutionScale < 1 ? Math.round(1 / resolutionScale).toLocaleString() + " : 1" : "1 : " + Math.round(resolutionScale).toLocaleString();
    const steps = this.scaleBarSteps_;
    const stepWidth = width / steps;
    const scaleSteps = [this.createMarker("absolute")];
    for (let i = 0; i < steps; ++i) {
      const cls = i % 2 === 0 ? "ol-scale-singlebar-odd" : "ol-scale-singlebar-even";
      scaleSteps.push(
        `<div><div class="ol-scale-singlebar ${cls}" style="width: ${stepWidth}px;"></div>` + this.createMarker("relative") + // render text every second step, except when only 2 steps
        (i % 2 === 0 || steps === 2 ? this.createStepText(i, width, false, scale2, suffix) : "") + "</div>"
      );
    }
    scaleSteps.push(this.createStepText(steps, width, true, scale2, suffix));
    const scaleBarText = this.scaleBarText_ ? `<div class="ol-scale-text" style="width: ${width}px;">` + mapScale + "</div>" : "";
    return scaleBarText + scaleSteps.join("");
  }
  /**
   * Creates a marker at given position
   * @param {'absolute'|'relative'} position The position, absolute or relative
   * @return {string} The stringified div containing the marker
   */
  createMarker(position) {
    const top = position === "absolute" ? 3 : -10;
    return `<div class="ol-scale-step-marker" style="position: ${position}; top: ${top}px;"></div>`;
  }
  /**
   * Creates the label for a marker marker at given position
   * @param {number} i The iterator
   * @param {number} width The width the scalebar will currently use
   * @param {boolean} isLast Flag indicating if we add the last step text
   * @param {number} scale The current scale for the whole scalebar
   * @param {string} suffix The suffix for the scale
   * @return {string} The stringified div containing the step text
   */
  createStepText(i, width, isLast, scale2, suffix) {
    const length = i === 0 ? 0 : Math.round(scale2 / this.scaleBarSteps_ * i * 100) / 100;
    const lengthString = length + (i === 0 ? "" : " " + suffix);
    const margin = i === 0 ? -3 : width / this.scaleBarSteps_ * -1;
    const minWidth = i === 0 ? 0 : width / this.scaleBarSteps_ * 2;
    return `<div class="ol-scale-step-text" style="margin-left: ${margin}px;text-align: ${i === 0 ? "left" : "center"};min-width: ${minWidth}px;left: ${isLast ? width + "px" : "unset"};">` + lengthString + "</div>";
  }
  /**
   * Returns the appropriate scale for the given resolution and units.
   * @return {number} The appropriate scale.
   */
  getScaleForResolution() {
    const resolution = getPointResolution(
      this.viewState_.projection,
      this.viewState_.resolution,
      this.viewState_.center,
      "m"
    );
    const dpi = this.dpi_ || DEFAULT_DPI;
    const inchesPerMeter = 1e3 / 25.4;
    return resolution * inchesPerMeter * dpi;
  }
  /**
   * Update the scale line element.
   * @param {import("../MapEvent.js").default} mapEvent Map event.
   * @override
   */
  render(mapEvent) {
    const frameState = mapEvent.frameState;
    if (!frameState) {
      this.viewState_ = null;
    } else {
      this.viewState_ = frameState.viewState;
    }
    this.updateElement_();
  }
}
class Feature extends BaseObject {
  /**
   * @param {Geometry|ObjectWithGeometry<Geometry>} [geometryOrProperties]
   *     You may pass a Geometry object directly, or an object literal containing
   *     properties. If you pass an object literal, you may include a Geometry
   *     associated with a `geometry` key.
   */
  constructor(geometryOrProperties) {
    super();
    this.on;
    this.once;
    this.un;
    this.id_ = void 0;
    this.geometryName_ = "geometry";
    this.style_ = null;
    this.styleFunction_ = void 0;
    this.geometryChangeKey_ = null;
    this.addChangeListener(this.geometryName_, this.handleGeometryChanged_);
    if (geometryOrProperties) {
      if (typeof /** @type {?} */
      geometryOrProperties.getSimplifiedGeometry === "function") {
        const geometry = (
          /** @type {Geometry} */
          geometryOrProperties
        );
        this.setGeometry(geometry);
      } else {
        const properties = geometryOrProperties;
        this.setProperties(properties);
      }
    }
  }
  /**
   * Clone this feature. If the original feature has a geometry it
   * is also cloned. The feature id is not set in the clone.
   * @return {Feature<Geometry>} The clone.
   * @api
   */
  clone() {
    const clone2 = (
      /** @type {Feature<Geometry>} */
      new Feature(this.hasProperties() ? this.getProperties() : null)
    );
    clone2.setGeometryName(this.getGeometryName());
    const geometry = this.getGeometry();
    if (geometry) {
      clone2.setGeometry(
        /** @type {Geometry} */
        geometry.clone()
      );
    }
    const style = this.getStyle();
    if (style) {
      clone2.setStyle(style);
    }
    return clone2;
  }
  /**
   * Get the feature's default geometry.  A feature may have any number of named
   * geometries.  The "default" geometry (the one that is rendered by default) is
   * set when calling {@link module:ol/Feature~Feature#setGeometry}.
   * @return {Geometry|undefined} The default geometry for the feature.
   * @api
   * @observable
   */
  getGeometry() {
    return (
      /** @type {Geometry|undefined} */
      this.get(this.geometryName_)
    );
  }
  /**
   * Get the feature identifier.  This is a stable identifier for the feature and
   * is either set when reading data from a remote source or set explicitly by
   * calling {@link module:ol/Feature~Feature#setId}.
   * @return {number|string|undefined} Id.
   * @api
   */
  getId() {
    return this.id_;
  }
  /**
   * Get the name of the feature's default geometry.  By default, the default
   * geometry is named `geometry`.
   * @return {string} Get the property name associated with the default geometry
   *     for this feature.
   * @api
   */
  getGeometryName() {
    return this.geometryName_;
  }
  /**
   * Get the feature's style. Will return what was provided to the
   * {@link module:ol/Feature~Feature#setStyle} method.
   * @return {import("./style/Style.js").StyleLike|undefined} The feature style.
   * @api
   */
  getStyle() {
    return this.style_;
  }
  /**
   * Get the feature's style function.
   * @return {import("./style/Style.js").StyleFunction|undefined} Return a function
   * representing the current style of this feature.
   * @api
   */
  getStyleFunction() {
    return this.styleFunction_;
  }
  /**
   * @private
   */
  handleGeometryChange_() {
    this.changed();
  }
  /**
   * @private
   */
  handleGeometryChanged_() {
    if (this.geometryChangeKey_) {
      unlistenByKey(this.geometryChangeKey_);
      this.geometryChangeKey_ = null;
    }
    const geometry = this.getGeometry();
    if (geometry) {
      this.geometryChangeKey_ = listen(
        geometry,
        EventType.CHANGE,
        this.handleGeometryChange_,
        this
      );
    }
    this.changed();
  }
  /**
   * Set the default geometry for the feature.  This will update the property
   * with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.
   * @param {Geometry|undefined} geometry The new geometry.
   * @api
   * @observable
   */
  setGeometry(geometry) {
    this.set(this.geometryName_, geometry);
  }
  /**
   * Set the style for the feature to override the layer style.  This can be a
   * single style object, an array of styles, or a function that takes a
   * resolution and returns an array of styles. To unset the feature style, call
   * `setStyle()` without arguments or a falsey value.
   * @param {import("./style/Style.js").StyleLike} [style] Style for this feature.
   * @api
   * @fires module:ol/events/Event~BaseEvent#event:change
   */
  setStyle(style) {
    this.style_ = style;
    this.styleFunction_ = !style ? void 0 : createStyleFunction(style);
    this.changed();
  }
  /**
   * Set the feature id.  The feature id is considered stable and may be used when
   * requesting features or comparing identifiers returned from a remote source.
   * The feature id can be used with the
   * {@link module:ol/source/Vector~VectorSource#getFeatureById} method.
   * @param {number|string|undefined} id The feature id.
   * @api
   * @fires module:ol/events/Event~BaseEvent#event:change
   */
  setId(id) {
    this.id_ = id;
    this.changed();
  }
  /**
   * Set the property name to be used when getting the feature's default geometry.
   * When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with
   * this name will be returned.
   * @param {string} name The property name of the default geometry.
   * @api
   */
  setGeometryName(name) {
    this.removeChangeListener(this.geometryName_, this.handleGeometryChanged_);
    this.geometryName_ = name;
    this.addChangeListener(this.geometryName_, this.handleGeometryChanged_);
    this.handleGeometryChanged_();
  }
}
function createStyleFunction(obj) {
  if (typeof obj === "function") {
    return obj;
  }
  let styles;
  if (Array.isArray(obj)) {
    styles = obj;
  } else {
    assert(
      typeof /** @type {?} */
      obj.getZIndex === "function",
      "Expected an `ol/style/Style` or an array of `ol/style/Style.js`"
    );
    const style = (
      /** @type {import("./style/Style.js").default} */
      obj
    );
    styles = [style];
  }
  return function() {
    return styles;
  };
}
function interpolatePoint(flatCoordinates, offset2, end, stride, fraction, dest, dimension) {
  let o, t;
  const n = (end - offset2) / stride;
  if (n === 1) {
    o = offset2;
  } else if (n === 2) {
    o = offset2;
    t = fraction;
  } else if (n !== 0) {
    let x1 = flatCoordinates[offset2];
    let y1 = flatCoordinates[offset2 + 1];
    let length = 0;
    const cumulativeLengths = [0];
    for (let i = offset2 + stride; i < end; i += stride) {
      const x2 = flatCoordinates[i];
      const y2 = flatCoordinates[i + 1];
      length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
      cumulativeLengths.push(length);
      x1 = x2;
      y1 = y2;
    }
    const target = fraction * length;
    const index = binarySearch(cumulativeLengths, target);
    if (index < 0) {
      t = (target - cumulativeLengths[-index - 2]) / (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);
      o = offset2 + (-index - 2) * stride;
    } else {
      o = offset2 + index * stride;
    }
  }
  dimension = dimension > 1 ? dimension : 2;
  dest = dest ? dest : new Array(dimension);
  for (let i = 0; i < dimension; ++i) {
    dest[i] = o === void 0 ? NaN : t === void 0 ? flatCoordinates[o + i] : lerp(flatCoordinates[o + i], flatCoordinates[o + stride + i], t);
  }
  return dest;
}
function lineStringCoordinateAtM(flatCoordinates, offset2, end, stride, m, extrapolate) {
  if (end == offset2) {
    return null;
  }
  let coordinate;
  if (m < flatCoordinates[offset2 + stride - 1]) {
    if (extrapolate) {
      coordinate = flatCoordinates.slice(offset2, offset2 + stride);
      coordinate[stride - 1] = m;
      return coordinate;
    }
    return null;
  }
  if (flatCoordinates[end - 1] < m) {
    if (extrapolate) {
      coordinate = flatCoordinates.slice(end - stride, end);
      coordinate[stride - 1] = m;
      return coordinate;
    }
    return null;
  }
  if (m == flatCoordinates[offset2 + stride - 1]) {
    return flatCoordinates.slice(offset2, offset2 + stride);
  }
  let lo = offset2 / stride;
  let hi = end / stride;
  while (lo < hi) {
    const mid = lo + hi >> 1;
    if (m < flatCoordinates[(mid + 1) * stride - 1]) {
      hi = mid;
    } else {
      lo = mid + 1;
    }
  }
  const m0 = flatCoordinates[lo * stride - 1];
  if (m == m0) {
    return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);
  }
  const m1 = flatCoordinates[(lo + 1) * stride - 1];
  const t = (m - m0) / (m1 - m0);
  coordinate = [];
  for (let i = 0; i < stride - 1; ++i) {
    coordinate.push(
      lerp(
        flatCoordinates[(lo - 1) * stride + i],
        flatCoordinates[lo * stride + i],
        t
      )
    );
  }
  coordinate.push(m);
  return coordinate;
}
function lineStringLength(flatCoordinates, offset2, end, stride) {
  let x1 = flatCoordinates[offset2];
  let y1 = flatCoordinates[offset2 + 1];
  let length = 0;
  for (let i = offset2 + stride; i < end; i += stride) {
    const x2 = flatCoordinates[i];
    const y2 = flatCoordinates[i + 1];
    length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    x1 = x2;
    y1 = y2;
  }
  return length;
}
class LineString extends SimpleGeometry {
  /**
   * @param {Array<import("../coordinate.js").Coordinate>|Array<number>} coordinates Coordinates.
   *     For internal use, flat coordinates in combination with `layout` are also accepted.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   */
  constructor(coordinates2, layout) {
    super();
    this.flatMidpoint_ = null;
    this.flatMidpointRevision_ = -1;
    this.maxDelta_ = -1;
    this.maxDeltaRevision_ = -1;
    if (layout !== void 0 && !Array.isArray(coordinates2[0])) {
      this.setFlatCoordinates(
        layout,
        /** @type {Array<number>} */
        coordinates2
      );
    } else {
      this.setCoordinates(
        /** @type {Array<import("../coordinate.js").Coordinate>} */
        coordinates2,
        layout
      );
    }
  }
  /**
   * Append the passed coordinate to the coordinates of the linestring.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @api
   */
  appendCoordinate(coordinate) {
    extend$3(this.flatCoordinates, coordinate);
    this.changed();
  }
  /**
   * Make a complete copy of the geometry.
   * @return {!LineString} Clone.
   * @api
   * @override
   */
  clone() {
    const lineString = new LineString(
      this.flatCoordinates.slice(),
      this.layout
    );
    lineString.applyProperties(this);
    return lineString;
  }
  /**
   * @param {number} x X.
   * @param {number} y Y.
   * @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
   * @param {number} minSquaredDistance Minimum squared distance.
   * @return {number} Minimum squared distance.
   * @override
   */
  closestPointXY(x, y, closestPoint, minSquaredDistance) {
    if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
      return minSquaredDistance;
    }
    if (this.maxDeltaRevision_ != this.getRevision()) {
      this.maxDelta_ = Math.sqrt(
        maxSquaredDelta(
          this.flatCoordinates,
          0,
          this.flatCoordinates.length,
          this.stride,
          0
        )
      );
      this.maxDeltaRevision_ = this.getRevision();
    }
    return assignClosestPoint(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      this.maxDelta_,
      false,
      x,
      y,
      closestPoint,
      minSquaredDistance
    );
  }
  /**
   * Iterate over each segment, calling the provided callback.
   * If the callback returns a truthy value the function returns that
   * value immediately. Otherwise the function returns `false`.
   *
   * @param {function(this: S, import("../coordinate.js").Coordinate, import("../coordinate.js").Coordinate): T} callback Function
   *     called for each segment. The function will receive two arguments, the start and end coordinates of the segment.
   * @return {T|boolean} Value.
   * @template T,S
   * @api
   */
  forEachSegment(callback) {
    return forEach(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      callback
    );
  }
  /**
   * Returns the coordinate at `m` using linear interpolation, or `null` if no
   * such coordinate exists.
   *
   * `extrapolate` controls extrapolation beyond the range of Ms in the
   * MultiLineString. If `extrapolate` is `true` then Ms less than the first
   * M will return the first coordinate and Ms greater than the last M will
   * return the last coordinate.
   *
   * @param {number} m M.
   * @param {boolean} [extrapolate] Extrapolate. Default is `false`.
   * @return {import("../coordinate.js").Coordinate|null} Coordinate.
   * @api
   */
  getCoordinateAtM(m, extrapolate) {
    if (this.layout != "XYM" && this.layout != "XYZM") {
      return null;
    }
    extrapolate = extrapolate !== void 0 ? extrapolate : false;
    return lineStringCoordinateAtM(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      m,
      extrapolate
    );
  }
  /**
   * Return the coordinates of the linestring.
   * @return {Array<import("../coordinate.js").Coordinate>} Coordinates.
   * @api
   * @override
   */
  getCoordinates() {
    return inflateCoordinates(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride
    );
  }
  /**
   * Return the coordinate at the provided fraction along the linestring.
   * The `fraction` is a number between 0 and 1, where 0 is the start of the
   * linestring and 1 is the end.
   * @param {number} fraction Fraction.
   * @param {import("../coordinate.js").Coordinate} [dest] Optional coordinate whose values will
   *     be modified. If not provided, a new coordinate will be returned.
   * @return {import("../coordinate.js").Coordinate} Coordinate of the interpolated point.
   * @api
   */
  getCoordinateAt(fraction, dest) {
    return interpolatePoint(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      fraction,
      dest,
      this.stride
    );
  }
  /**
   * Return the length of the linestring on projected plane.
   * @return {number} Length (on projected plane).
   * @api
   */
  getLength() {
    return lineStringLength(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride
    );
  }
  /**
   * @return {Array<number>} Flat midpoint.
   */
  getFlatMidpoint() {
    if (this.flatMidpointRevision_ != this.getRevision()) {
      this.flatMidpoint_ = this.getCoordinateAt(
        0.5,
        this.flatMidpoint_ ?? void 0
      );
      this.flatMidpointRevision_ = this.getRevision();
    }
    return (
      /** @type {Array<number>} */
      this.flatMidpoint_
    );
  }
  /**
   * @param {number} squaredTolerance Squared tolerance.
   * @return {LineString} Simplified LineString.
   * @protected
   * @override
   */
  getSimplifiedGeometryInternal(squaredTolerance) {
    const simplifiedFlatCoordinates = [];
    simplifiedFlatCoordinates.length = douglasPeucker(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      squaredTolerance,
      simplifiedFlatCoordinates,
      0
    );
    return new LineString(simplifiedFlatCoordinates, "XY");
  }
  /**
   * Get the type of this geometry.
   * @return {import("./Geometry.js").Type} Geometry type.
   * @api
   * @override
   */
  getType() {
    return "LineString";
  }
  /**
   * Test if the geometry and the passed extent intersect.
   * @param {import("../extent.js").Extent} extent Extent.
   * @return {boolean} `true` if the geometry and the extent intersect.
   * @api
   * @override
   */
  intersectsExtent(extent) {
    return intersectsLineString(
      this.flatCoordinates,
      0,
      this.flatCoordinates.length,
      this.stride,
      extent,
      this.getExtent()
    );
  }
  /**
   * Set the coordinates of the linestring.
   * @param {!Array<import("../coordinate.js").Coordinate>} coordinates Coordinates.
   * @param {import("./Geometry.js").GeometryLayout} [layout] Layout.
   * @api
   * @override
   */
  setCoordinates(coordinates2, layout) {
    this.setLayout(layout, coordinates2, 1);
    if (!this.flatCoordinates) {
      this.flatCoordinates = [];
    }
    this.flatCoordinates.length = deflateCoordinates(
      this.flatCoordinates,
      0,
      coordinates2,
      this.stride
    );
    this.changed();
  }
}
function linearRingss(flatCoordinates, offset2, endss, stride) {
  const flatCenters = [];
  let extent = createEmpty();
  for (let i = 0, ii = endss.length; i < ii; ++i) {
    const ends = endss[i];
    extent = createOrUpdateFromFlatCoordinates(
      flatCoordinates,
      offset2,
      ends[0],
      stride
    );
    flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2);
    offset2 = ends[ends.length - 1];
  }
  return flatCenters;
}
class VectorContext {
  /**
   * Render a geometry with a custom renderer.
   *
   * @param {import("../geom/SimpleGeometry.js").default} geometry Geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {Function} renderer Renderer.
   * @param {Function} hitDetectionRenderer Renderer.
   * @param {number} [index] Render order index.
   */
  drawCustom(geometry, feature, renderer, hitDetectionRenderer, index) {
  }
  /**
   * Render a geometry.
   *
   * @param {import("../geom/Geometry.js").default} geometry The geometry to render.
   */
  drawGeometry(geometry) {
  }
  /**
   * Set the rendering style.
   *
   * @param {import("../style/Style.js").default} style The rendering style.
   */
  setStyle(style) {
  }
  /**
   * @param {import("../geom/Circle.js").default} circleGeometry Circle geometry.
   * @param {import("../Feature.js").default} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawCircle(circleGeometry, feature, index) {
  }
  /**
   * @param {import("../Feature.js").default} feature Feature.
   * @param {import("../style/Style.js").default} style Style.
   * @param {number} [index] Render order index.
   */
  drawFeature(feature, style, index) {
  }
  /**
   * @param {import("../geom/GeometryCollection.js").default} geometryCollectionGeometry Geometry collection.
   * @param {import("../Feature.js").default} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawGeometryCollection(geometryCollectionGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/LineString.js").default|import("./Feature.js").default} lineStringGeometry Line string geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawLineString(lineStringGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/MultiLineString.js").default|import("./Feature.js").default} multiLineStringGeometry MultiLineString geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawMultiLineString(multiLineStringGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/MultiPoint.js").default|import("./Feature.js").default} multiPointGeometry MultiPoint geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawMultiPoint(multiPointGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/MultiPolygon.js").default} multiPolygonGeometry MultiPolygon geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawMultiPolygon(multiPolygonGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/Point.js").default|import("./Feature.js").default} pointGeometry Point geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawPoint(pointGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/Polygon.js").default|import("./Feature.js").default} polygonGeometry Polygon geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawPolygon(polygonGeometry, feature, index) {
  }
  /**
   * @param {import("../geom/SimpleGeometry.js").default|import("./Feature.js").default} geometry Geometry.
   * @param {import("../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   */
  drawText(geometry, feature, index) {
  }
  /**
   * @param {import("../style/Fill.js").default} fillStyle Fill style.
   * @param {import("../style/Stroke.js").default} strokeStyle Stroke style.
   */
  setFillStrokeStyle(fillStyle, strokeStyle) {
  }
  /**
   * @param {import("../style/Image.js").default} imageStyle Image style.
   * @param {import("../render/canvas.js").DeclutterImageWithText} [declutterImageWithText] Shared data for combined decluttering with a text style.
   */
  setImageStyle(imageStyle, declutterImageWithText) {
  }
  /**
   * @param {import("../style/Text.js").default} textStyle Text style.
   * @param {import("../render/canvas.js").DeclutterImageWithText} [declutterImageWithText] Shared data for combined decluttering with an image style.
   */
  setTextStyle(textStyle, declutterImageWithText) {
  }
}
const Instruction = {
  BEGIN_GEOMETRY: 0,
  BEGIN_PATH: 1,
  CIRCLE: 2,
  CLOSE_PATH: 3,
  CUSTOM: 4,
  DRAW_CHARS: 5,
  DRAW_IMAGE: 6,
  END_GEOMETRY: 7,
  FILL: 8,
  MOVE_TO_LINE_TO: 9,
  SET_FILL_STYLE: 10,
  SET_STROKE_STYLE: 11,
  STROKE: 12
};
const fillInstruction = [Instruction.FILL];
const strokeInstruction = [Instruction.STROKE];
const beginPathInstruction = [Instruction.BEGIN_PATH];
const closePathInstruction = [Instruction.CLOSE_PATH];
class CanvasBuilder extends VectorContext {
  /**
   * @param {number} tolerance Tolerance.
   * @param {import("../../extent.js").Extent} maxExtent Maximum extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   */
  constructor(tolerance, maxExtent, resolution, pixelRatio) {
    super();
    this.tolerance = tolerance;
    this.maxExtent = maxExtent;
    this.pixelRatio = pixelRatio;
    this.maxLineWidth = 0;
    this.resolution = resolution;
    this.beginGeometryInstruction1_ = null;
    this.beginGeometryInstruction2_ = null;
    this.bufferedMaxExtent_ = null;
    this.instructions = [];
    this.coordinates = [];
    this.tmpCoordinate_ = [];
    this.hitDetectionInstructions = [];
    this.state = /** @type {import("../canvas.js").FillStrokeState} */
    {};
  }
  /**
   * @protected
   * @param {Array<number>} dashArray Dash array.
   * @return {Array<number>} Dash array with pixel ratio applied
   */
  applyPixelRatio(dashArray) {
    const pixelRatio = this.pixelRatio;
    return pixelRatio == 1 ? dashArray : dashArray.map(function(dash) {
      return dash * pixelRatio;
    });
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} stride Stride.
   * @protected
   * @return {number} My end
   */
  appendFlatPointCoordinates(flatCoordinates, stride) {
    const extent = this.getBufferedMaxExtent();
    const tmpCoord = this.tmpCoordinate_;
    const coordinates2 = this.coordinates;
    let myEnd = coordinates2.length;
    for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
      tmpCoord[0] = flatCoordinates[i];
      tmpCoord[1] = flatCoordinates[i + 1];
      if (containsCoordinate(extent, tmpCoord)) {
        coordinates2[myEnd++] = tmpCoord[0];
        coordinates2[myEnd++] = tmpCoord[1];
      }
    }
    return myEnd;
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @param {boolean} closed Last input coordinate equals first.
   * @param {boolean} skipFirst Skip first coordinate.
   * @protected
   * @return {number} My end.
   */
  appendFlatLineCoordinates(flatCoordinates, offset2, end, stride, closed, skipFirst) {
    const coordinates2 = this.coordinates;
    let myEnd = coordinates2.length;
    const extent = this.getBufferedMaxExtent();
    if (skipFirst) {
      offset2 += stride;
    }
    let lastXCoord = flatCoordinates[offset2];
    let lastYCoord = flatCoordinates[offset2 + 1];
    const nextCoord = this.tmpCoordinate_;
    let skipped = true;
    let i, lastRel, nextRel;
    for (i = offset2 + stride; i < end; i += stride) {
      nextCoord[0] = flatCoordinates[i];
      nextCoord[1] = flatCoordinates[i + 1];
      nextRel = coordinateRelationship(extent, nextCoord);
      if (nextRel !== lastRel) {
        if (skipped) {
          coordinates2[myEnd++] = lastXCoord;
          coordinates2[myEnd++] = lastYCoord;
          skipped = false;
        }
        coordinates2[myEnd++] = nextCoord[0];
        coordinates2[myEnd++] = nextCoord[1];
      } else if (nextRel === Relationship.INTERSECTING) {
        coordinates2[myEnd++] = nextCoord[0];
        coordinates2[myEnd++] = nextCoord[1];
        skipped = false;
      } else {
        skipped = true;
      }
      lastXCoord = nextCoord[0];
      lastYCoord = nextCoord[1];
      lastRel = nextRel;
    }
    if (closed && skipped || i === offset2 + stride) {
      coordinates2[myEnd++] = lastXCoord;
      coordinates2[myEnd++] = lastYCoord;
    }
    return myEnd;
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array<number>} ends Ends.
   * @param {number} stride Stride.
   * @param {Array<number>} builderEnds Builder ends.
   * @return {number} Offset.
   */
  drawCustomCoordinates_(flatCoordinates, offset2, ends, stride, builderEnds) {
    for (let i = 0, ii = ends.length; i < ii; ++i) {
      const end = ends[i];
      const builderEnd = this.appendFlatLineCoordinates(
        flatCoordinates,
        offset2,
        end,
        stride,
        false,
        false
      );
      builderEnds.push(builderEnd);
      offset2 = end;
    }
    return offset2;
  }
  /**
   * @param {import("../../geom/SimpleGeometry.js").default} geometry Geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {Function} renderer Renderer.
   * @param {Function} hitDetectionRenderer Renderer.
   * @param {number} [index] Render order index.
   * @override
   */
  drawCustom(geometry, feature, renderer, hitDetectionRenderer, index) {
    this.beginGeometry(geometry, feature, index);
    const type = geometry.getType();
    const stride = geometry.getStride();
    const builderBegin = this.coordinates.length;
    let flatCoordinates, builderEnd, builderEnds, builderEndss;
    let offset2;
    switch (type) {
      case "MultiPolygon":
        flatCoordinates = /** @type {import("../../geom/MultiPolygon.js").default} */
        geometry.getOrientedFlatCoordinates();
        builderEndss = [];
        const endss = (
          /** @type {import("../../geom/MultiPolygon.js").default} */
          geometry.getEndss()
        );
        offset2 = 0;
        for (let i = 0, ii = endss.length; i < ii; ++i) {
          const myEnds = [];
          offset2 = this.drawCustomCoordinates_(
            flatCoordinates,
            offset2,
            endss[i],
            stride,
            myEnds
          );
          builderEndss.push(myEnds);
        }
        this.instructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEndss,
          geometry,
          renderer,
          inflateMultiCoordinatesArray,
          index
        ]);
        this.hitDetectionInstructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEndss,
          geometry,
          hitDetectionRenderer || renderer,
          inflateMultiCoordinatesArray,
          index
        ]);
        break;
      case "Polygon":
      case "MultiLineString":
        builderEnds = [];
        flatCoordinates = type == "Polygon" ? (
          /** @type {import("../../geom/Polygon.js").default} */
          geometry.getOrientedFlatCoordinates()
        ) : geometry.getFlatCoordinates();
        offset2 = this.drawCustomCoordinates_(
          flatCoordinates,
          0,
          /** @type {import("../../geom/Polygon.js").default|import("../../geom/MultiLineString.js").default} */
          geometry.getEnds(),
          stride,
          builderEnds
        );
        this.instructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEnds,
          geometry,
          renderer,
          inflateCoordinatesArray,
          index
        ]);
        this.hitDetectionInstructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEnds,
          geometry,
          hitDetectionRenderer || renderer,
          inflateCoordinatesArray,
          index
        ]);
        break;
      case "LineString":
      case "Circle":
        flatCoordinates = geometry.getFlatCoordinates();
        builderEnd = this.appendFlatLineCoordinates(
          flatCoordinates,
          0,
          flatCoordinates.length,
          stride,
          false,
          false
        );
        this.instructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEnd,
          geometry,
          renderer,
          inflateCoordinates,
          index
        ]);
        this.hitDetectionInstructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEnd,
          geometry,
          hitDetectionRenderer || renderer,
          inflateCoordinates,
          index
        ]);
        break;
      case "MultiPoint":
        flatCoordinates = geometry.getFlatCoordinates();
        builderEnd = this.appendFlatPointCoordinates(flatCoordinates, stride);
        if (builderEnd > builderBegin) {
          this.instructions.push([
            Instruction.CUSTOM,
            builderBegin,
            builderEnd,
            geometry,
            renderer,
            inflateCoordinates,
            index
          ]);
          this.hitDetectionInstructions.push([
            Instruction.CUSTOM,
            builderBegin,
            builderEnd,
            geometry,
            hitDetectionRenderer || renderer,
            inflateCoordinates,
            index
          ]);
        }
        break;
      case "Point":
        flatCoordinates = geometry.getFlatCoordinates();
        this.coordinates.push(flatCoordinates[0], flatCoordinates[1]);
        builderEnd = this.coordinates.length;
        this.instructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEnd,
          geometry,
          renderer,
          void 0,
          index
        ]);
        this.hitDetectionInstructions.push([
          Instruction.CUSTOM,
          builderBegin,
          builderEnd,
          geometry,
          hitDetectionRenderer || renderer,
          void 0,
          index
        ]);
        break;
    }
    this.endGeometry(feature);
  }
  /**
   * @protected
   * @param {import("../../geom/Geometry").default|import("../Feature.js").default} geometry The geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} index Render order index
   */
  beginGeometry(geometry, feature, index) {
    this.beginGeometryInstruction1_ = [
      Instruction.BEGIN_GEOMETRY,
      feature,
      0,
      geometry,
      index
    ];
    this.instructions.push(this.beginGeometryInstruction1_);
    this.beginGeometryInstruction2_ = [
      Instruction.BEGIN_GEOMETRY,
      feature,
      0,
      geometry,
      index
    ];
    this.hitDetectionInstructions.push(this.beginGeometryInstruction2_);
  }
  /**
   * @return {import("../canvas.js").SerializableInstructions} the serializable instructions.
   */
  finish() {
    return {
      instructions: this.instructions,
      hitDetectionInstructions: this.hitDetectionInstructions,
      coordinates: this.coordinates
    };
  }
  /**
   * Reverse the hit detection instructions.
   */
  reverseHitDetectionInstructions() {
    const hitDetectionInstructions = this.hitDetectionInstructions;
    hitDetectionInstructions.reverse();
    let i;
    const n = hitDetectionInstructions.length;
    let instruction;
    let type;
    let begin = -1;
    for (i = 0; i < n; ++i) {
      instruction = hitDetectionInstructions[i];
      type = /** @type {import("./Instruction.js").default} */
      instruction[0];
      if (type == Instruction.END_GEOMETRY) {
        begin = i;
      } else if (type == Instruction.BEGIN_GEOMETRY) {
        instruction[2] = i;
        reverseSubArray(this.hitDetectionInstructions, begin, i);
        begin = -1;
      }
    }
  }
  /**
   * @param {import("../../style/Fill.js").default} fillStyle Fill style.
   * @param {import('../canvas.js').FillStrokeState} [state] State.
   * @return {import('../canvas.js').FillStrokeState} State.
   */
  fillStyleToState(fillStyle, state = (
    /** @type {import('../canvas.js').FillStrokeState} */
    {}
  )) {
    if (fillStyle) {
      const fillStyleColor = fillStyle.getColor();
      state.fillPatternScale = fillStyleColor && typeof fillStyleColor === "object" && "src" in fillStyleColor ? this.pixelRatio : 1;
      state.fillStyle = asColorLike(
        fillStyleColor ? fillStyleColor : defaultFillStyle
      );
    } else {
      state.fillStyle = void 0;
    }
    return state;
  }
  /**
   * @param {import("../../style/Stroke.js").default} strokeStyle Stroke style.
   * @param {import("../canvas.js").FillStrokeState} state State.
   * @return {import("../canvas.js").FillStrokeState} State.
   */
  strokeStyleToState(strokeStyle, state = (
    /** @type {import('../canvas.js').FillStrokeState} */
    {}
  )) {
    if (strokeStyle) {
      const strokeStyleColor = strokeStyle.getColor();
      state.strokeStyle = asColorLike(
        strokeStyleColor ? strokeStyleColor : defaultStrokeStyle
      );
      const strokeStyleLineCap = strokeStyle.getLineCap();
      state.lineCap = strokeStyleLineCap !== void 0 ? strokeStyleLineCap : defaultLineCap;
      const strokeStyleLineDash = strokeStyle.getLineDash();
      state.lineDash = strokeStyleLineDash ? strokeStyleLineDash.slice() : defaultLineDash;
      const strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
      state.lineDashOffset = strokeStyleLineDashOffset ? strokeStyleLineDashOffset : defaultLineDashOffset;
      const strokeStyleLineJoin = strokeStyle.getLineJoin();
      state.lineJoin = strokeStyleLineJoin !== void 0 ? strokeStyleLineJoin : defaultLineJoin;
      const strokeStyleWidth = strokeStyle.getWidth();
      state.lineWidth = strokeStyleWidth !== void 0 ? strokeStyleWidth : defaultLineWidth;
      const strokeStyleMiterLimit = strokeStyle.getMiterLimit();
      state.miterLimit = strokeStyleMiterLimit !== void 0 ? strokeStyleMiterLimit : defaultMiterLimit;
      if (state.lineWidth > this.maxLineWidth) {
        this.maxLineWidth = state.lineWidth;
        this.bufferedMaxExtent_ = null;
      }
    } else {
      state.strokeStyle = void 0;
      state.lineCap = void 0;
      state.lineDash = null;
      state.lineDashOffset = void 0;
      state.lineJoin = void 0;
      state.lineWidth = void 0;
      state.miterLimit = void 0;
    }
    return state;
  }
  /**
   * @param {import("../../style/Fill.js").default} fillStyle Fill style.
   * @param {import("../../style/Stroke.js").default} strokeStyle Stroke style.
   * @override
   */
  setFillStrokeStyle(fillStyle, strokeStyle) {
    const state = this.state;
    this.fillStyleToState(fillStyle, state);
    this.strokeStyleToState(strokeStyle, state);
  }
  /**
   * @param {import("../canvas.js").FillStrokeState} state State.
   * @return {Array<*>} Fill instruction.
   */
  createFill(state) {
    const fillStyle = state.fillStyle;
    const fillInstruction2 = [Instruction.SET_FILL_STYLE, fillStyle];
    if (typeof fillStyle !== "string") {
      fillInstruction2.push(state.fillPatternScale);
    }
    return fillInstruction2;
  }
  /**
   * @param {import("../canvas.js").FillStrokeState} state State.
   */
  applyStroke(state) {
    this.instructions.push(this.createStroke(state));
  }
  /**
   * @param {import("../canvas.js").FillStrokeState} state State.
   * @return {Array<*>} Stroke instruction.
   */
  createStroke(state) {
    return [
      Instruction.SET_STROKE_STYLE,
      state.strokeStyle,
      state.lineWidth * this.pixelRatio,
      state.lineCap,
      state.lineJoin,
      state.miterLimit,
      state.lineDash ? this.applyPixelRatio(state.lineDash) : null,
      state.lineDashOffset * this.pixelRatio
    ];
  }
  /**
   * @param {import("../canvas.js").FillStrokeState} state State.
   * @param {function(this:CanvasBuilder, import("../canvas.js").FillStrokeState):Array<*>} createFill Create fill.
   */
  updateFillStyle(state, createFill) {
    const fillStyle = state.fillStyle;
    if (typeof fillStyle !== "string" || state.currentFillStyle != fillStyle) {
      this.instructions.push(createFill.call(this, state));
      state.currentFillStyle = fillStyle;
    }
  }
  /**
   * @param {import("../canvas.js").FillStrokeState} state State.
   * @param {function(this:CanvasBuilder, import("../canvas.js").FillStrokeState): void} applyStroke Apply stroke.
   */
  updateStrokeStyle(state, applyStroke) {
    const strokeStyle = state.strokeStyle;
    const lineCap = state.lineCap;
    const lineDash = state.lineDash;
    const lineDashOffset = state.lineDashOffset;
    const lineJoin = state.lineJoin;
    const lineWidth = state.lineWidth;
    const miterLimit = state.miterLimit;
    if (state.currentStrokeStyle != strokeStyle || state.currentLineCap != lineCap || lineDash != state.currentLineDash && !equals$2(state.currentLineDash, lineDash) || state.currentLineDashOffset != lineDashOffset || state.currentLineJoin != lineJoin || state.currentLineWidth != lineWidth || state.currentMiterLimit != miterLimit) {
      applyStroke.call(this, state);
      state.currentStrokeStyle = strokeStyle;
      state.currentLineCap = lineCap;
      state.currentLineDash = lineDash;
      state.currentLineDashOffset = lineDashOffset;
      state.currentLineJoin = lineJoin;
      state.currentLineWidth = lineWidth;
      state.currentMiterLimit = miterLimit;
    }
  }
  /**
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   */
  endGeometry(feature) {
    this.beginGeometryInstruction1_[2] = this.instructions.length;
    this.beginGeometryInstruction1_ = null;
    this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length;
    this.beginGeometryInstruction2_ = null;
    const endGeometryInstruction = [Instruction.END_GEOMETRY, feature];
    this.instructions.push(endGeometryInstruction);
    this.hitDetectionInstructions.push(endGeometryInstruction);
  }
  /**
   * Get the buffered rendering extent.  Rendering will be clipped to the extent
   * provided to the constructor.  To account for symbolizers that may intersect
   * this extent, we calculate a buffered extent (e.g. based on stroke width).
   * @return {import("../../extent.js").Extent} The buffered rendering extent.
   * @protected
   */
  getBufferedMaxExtent() {
    if (!this.bufferedMaxExtent_) {
      this.bufferedMaxExtent_ = clone(this.maxExtent);
      if (this.maxLineWidth > 0) {
        const width = this.resolution * (this.maxLineWidth + 1) / 2;
        buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
      }
    }
    return this.bufferedMaxExtent_;
  }
}
class CanvasImageBuilder extends CanvasBuilder {
  /**
   * @param {number} tolerance Tolerance.
   * @param {import("../../extent.js").Extent} maxExtent Maximum extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   */
  constructor(tolerance, maxExtent, resolution, pixelRatio) {
    super(tolerance, maxExtent, resolution, pixelRatio);
    this.hitDetectionImage_ = null;
    this.image_ = null;
    this.imagePixelRatio_ = void 0;
    this.anchorX_ = void 0;
    this.anchorY_ = void 0;
    this.height_ = void 0;
    this.opacity_ = void 0;
    this.originX_ = void 0;
    this.originY_ = void 0;
    this.rotateWithView_ = void 0;
    this.rotation_ = void 0;
    this.scale_ = void 0;
    this.width_ = void 0;
    this.declutterMode_ = void 0;
    this.declutterImageWithText_ = void 0;
  }
  /**
   * @param {import("../../geom/Point.js").default|import("../Feature.js").default} pointGeometry Point geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawPoint(pointGeometry, feature, index) {
    if (!this.image_ || this.maxExtent && !containsCoordinate(this.maxExtent, pointGeometry.getFlatCoordinates())) {
      return;
    }
    this.beginGeometry(pointGeometry, feature, index);
    const flatCoordinates = pointGeometry.getFlatCoordinates();
    const stride = pointGeometry.getStride();
    const myBegin = this.coordinates.length;
    const myEnd = this.appendFlatPointCoordinates(flatCoordinates, stride);
    this.instructions.push([
      Instruction.DRAW_IMAGE,
      myBegin,
      myEnd,
      this.image_,
      // Remaining arguments to DRAW_IMAGE are in alphabetical order
      this.anchorX_ * this.imagePixelRatio_,
      this.anchorY_ * this.imagePixelRatio_,
      Math.ceil(this.height_ * this.imagePixelRatio_),
      this.opacity_,
      this.originX_ * this.imagePixelRatio_,
      this.originY_ * this.imagePixelRatio_,
      this.rotateWithView_,
      this.rotation_,
      [
        this.scale_[0] * this.pixelRatio / this.imagePixelRatio_,
        this.scale_[1] * this.pixelRatio / this.imagePixelRatio_
      ],
      Math.ceil(this.width_ * this.imagePixelRatio_),
      this.declutterMode_,
      this.declutterImageWithText_
    ]);
    this.hitDetectionInstructions.push([
      Instruction.DRAW_IMAGE,
      myBegin,
      myEnd,
      this.hitDetectionImage_,
      // Remaining arguments to DRAW_IMAGE are in alphabetical order
      this.anchorX_,
      this.anchorY_,
      this.height_,
      1,
      this.originX_,
      this.originY_,
      this.rotateWithView_,
      this.rotation_,
      this.scale_,
      this.width_,
      this.declutterMode_,
      this.declutterImageWithText_
    ]);
    this.endGeometry(feature);
  }
  /**
   * @param {import("../../geom/MultiPoint.js").default|import("../Feature.js").default} multiPointGeometry MultiPoint geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawMultiPoint(multiPointGeometry, feature, index) {
    if (!this.image_) {
      return;
    }
    this.beginGeometry(multiPointGeometry, feature, index);
    const flatCoordinates = multiPointGeometry.getFlatCoordinates();
    const filteredFlatCoordinates = [];
    for (let i = 0, ii = flatCoordinates.length; i < ii; i += multiPointGeometry.getStride()) {
      if (!this.maxExtent || containsCoordinate(this.maxExtent, flatCoordinates.slice(i, i + 2))) {
        filteredFlatCoordinates.push(
          flatCoordinates[i],
          flatCoordinates[i + 1]
        );
      }
    }
    const myBegin = this.coordinates.length;
    const myEnd = this.appendFlatPointCoordinates(filteredFlatCoordinates, 2);
    this.instructions.push([
      Instruction.DRAW_IMAGE,
      myBegin,
      myEnd,
      this.image_,
      // Remaining arguments to DRAW_IMAGE are in alphabetical order
      this.anchorX_ * this.imagePixelRatio_,
      this.anchorY_ * this.imagePixelRatio_,
      Math.ceil(this.height_ * this.imagePixelRatio_),
      this.opacity_,
      this.originX_ * this.imagePixelRatio_,
      this.originY_ * this.imagePixelRatio_,
      this.rotateWithView_,
      this.rotation_,
      [
        this.scale_[0] * this.pixelRatio / this.imagePixelRatio_,
        this.scale_[1] * this.pixelRatio / this.imagePixelRatio_
      ],
      Math.ceil(this.width_ * this.imagePixelRatio_),
      this.declutterMode_,
      this.declutterImageWithText_
    ]);
    this.hitDetectionInstructions.push([
      Instruction.DRAW_IMAGE,
      myBegin,
      myEnd,
      this.hitDetectionImage_,
      // Remaining arguments to DRAW_IMAGE are in alphabetical order
      this.anchorX_,
      this.anchorY_,
      this.height_,
      1,
      this.originX_,
      this.originY_,
      this.rotateWithView_,
      this.rotation_,
      this.scale_,
      this.width_,
      this.declutterMode_,
      this.declutterImageWithText_
    ]);
    this.endGeometry(feature);
  }
  /**
   * @return {import("../canvas.js").SerializableInstructions} the serializable instructions.
   * @override
   */
  finish() {
    this.reverseHitDetectionInstructions();
    this.anchorX_ = void 0;
    this.anchorY_ = void 0;
    this.hitDetectionImage_ = null;
    this.image_ = null;
    this.imagePixelRatio_ = void 0;
    this.height_ = void 0;
    this.scale_ = void 0;
    this.opacity_ = void 0;
    this.originX_ = void 0;
    this.originY_ = void 0;
    this.rotateWithView_ = void 0;
    this.rotation_ = void 0;
    this.width_ = void 0;
    return super.finish();
  }
  /**
   * @param {import("../../style/Image.js").default} imageStyle Image style.
   * @param {Object} [sharedData] Shared data.
   * @override
   */
  setImageStyle(imageStyle, sharedData) {
    const anchor = imageStyle.getAnchor();
    const size = imageStyle.getSize();
    const origin = imageStyle.getOrigin();
    this.imagePixelRatio_ = imageStyle.getPixelRatio(this.pixelRatio);
    this.anchorX_ = anchor[0];
    this.anchorY_ = anchor[1];
    this.hitDetectionImage_ = imageStyle.getHitDetectionImage();
    this.image_ = imageStyle.getImage(this.pixelRatio);
    this.height_ = size[1];
    this.opacity_ = imageStyle.getOpacity();
    this.originX_ = origin[0];
    this.originY_ = origin[1];
    this.rotateWithView_ = imageStyle.getRotateWithView();
    this.rotation_ = imageStyle.getRotation();
    this.scale_ = imageStyle.getScaleArray();
    this.width_ = size[0];
    this.declutterMode_ = imageStyle.getDeclutterMode();
    this.declutterImageWithText_ = sharedData;
  }
}
class CanvasLineStringBuilder extends CanvasBuilder {
  /**
   * @param {number} tolerance Tolerance.
   * @param {import("../../extent.js").Extent} maxExtent Maximum extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   */
  constructor(tolerance, maxExtent, resolution, pixelRatio) {
    super(tolerance, maxExtent, resolution, pixelRatio);
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @private
   * @return {number} end.
   */
  drawFlatCoordinates_(flatCoordinates, offset2, end, stride) {
    const myBegin = this.coordinates.length;
    const myEnd = this.appendFlatLineCoordinates(
      flatCoordinates,
      offset2,
      end,
      stride,
      false,
      false
    );
    const moveToLineToInstruction = [
      Instruction.MOVE_TO_LINE_TO,
      myBegin,
      myEnd
    ];
    this.instructions.push(moveToLineToInstruction);
    this.hitDetectionInstructions.push(moveToLineToInstruction);
    return end;
  }
  /**
   * @param {import("../../geom/LineString.js").default|import("../Feature.js").default} lineStringGeometry Line string geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawLineString(lineStringGeometry, feature, index) {
    const state = this.state;
    const strokeStyle = state.strokeStyle;
    const lineWidth = state.lineWidth;
    if (strokeStyle === void 0 || lineWidth === void 0) {
      return;
    }
    this.updateStrokeStyle(state, this.applyStroke);
    this.beginGeometry(lineStringGeometry, feature, index);
    this.hitDetectionInstructions.push(
      [
        Instruction.SET_STROKE_STYLE,
        state.strokeStyle,
        state.lineWidth,
        state.lineCap,
        state.lineJoin,
        state.miterLimit,
        defaultLineDash,
        defaultLineDashOffset
      ],
      beginPathInstruction
    );
    const flatCoordinates = lineStringGeometry.getFlatCoordinates();
    const stride = lineStringGeometry.getStride();
    this.drawFlatCoordinates_(
      flatCoordinates,
      0,
      flatCoordinates.length,
      stride
    );
    this.hitDetectionInstructions.push(strokeInstruction);
    this.endGeometry(feature);
  }
  /**
   * @param {import("../../geom/MultiLineString.js").default|import("../Feature.js").default} multiLineStringGeometry MultiLineString geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawMultiLineString(multiLineStringGeometry, feature, index) {
    const state = this.state;
    const strokeStyle = state.strokeStyle;
    const lineWidth = state.lineWidth;
    if (strokeStyle === void 0 || lineWidth === void 0) {
      return;
    }
    this.updateStrokeStyle(state, this.applyStroke);
    this.beginGeometry(multiLineStringGeometry, feature, index);
    this.hitDetectionInstructions.push(
      [
        Instruction.SET_STROKE_STYLE,
        state.strokeStyle,
        state.lineWidth,
        state.lineCap,
        state.lineJoin,
        state.miterLimit,
        defaultLineDash,
        defaultLineDashOffset
      ],
      beginPathInstruction
    );
    const ends = multiLineStringGeometry.getEnds();
    const flatCoordinates = multiLineStringGeometry.getFlatCoordinates();
    const stride = multiLineStringGeometry.getStride();
    let offset2 = 0;
    for (let i = 0, ii = ends.length; i < ii; ++i) {
      offset2 = this.drawFlatCoordinates_(
        flatCoordinates,
        offset2,
        /** @type {number} */
        ends[i],
        stride
      );
    }
    this.hitDetectionInstructions.push(strokeInstruction);
    this.endGeometry(feature);
  }
  /**
   * @return {import("../canvas.js").SerializableInstructions} the serializable instructions.
   * @override
   */
  finish() {
    const state = this.state;
    if (state.lastStroke != void 0 && state.lastStroke != this.coordinates.length) {
      this.instructions.push(strokeInstruction);
    }
    this.reverseHitDetectionInstructions();
    this.state = null;
    return super.finish();
  }
  /**
   * @param {import("../canvas.js").FillStrokeState} state State.
   * @override
   */
  applyStroke(state) {
    if (state.lastStroke != void 0 && state.lastStroke != this.coordinates.length) {
      this.instructions.push(strokeInstruction);
      state.lastStroke = this.coordinates.length;
    }
    state.lastStroke = 0;
    super.applyStroke(state);
    this.instructions.push(beginPathInstruction);
  }
}
class CanvasPolygonBuilder extends CanvasBuilder {
  /**
   * @param {number} tolerance Tolerance.
   * @param {import("../../extent.js").Extent} maxExtent Maximum extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   */
  constructor(tolerance, maxExtent, resolution, pixelRatio) {
    super(tolerance, maxExtent, resolution, pixelRatio);
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array<number>} ends Ends.
   * @param {number} stride Stride.
   * @private
   * @return {number} End.
   */
  drawFlatCoordinatess_(flatCoordinates, offset2, ends, stride) {
    const state = this.state;
    const fill = state.fillStyle !== void 0;
    const stroke = state.strokeStyle !== void 0;
    const numEnds = ends.length;
    this.instructions.push(beginPathInstruction);
    this.hitDetectionInstructions.push(beginPathInstruction);
    for (let i = 0; i < numEnds; ++i) {
      const end = ends[i];
      const myBegin = this.coordinates.length;
      const myEnd = this.appendFlatLineCoordinates(
        flatCoordinates,
        offset2,
        end,
        stride,
        true,
        !stroke
      );
      const moveToLineToInstruction = [
        Instruction.MOVE_TO_LINE_TO,
        myBegin,
        myEnd
      ];
      this.instructions.push(moveToLineToInstruction);
      this.hitDetectionInstructions.push(moveToLineToInstruction);
      if (stroke) {
        this.instructions.push(closePathInstruction);
        this.hitDetectionInstructions.push(closePathInstruction);
      }
      offset2 = end;
    }
    if (fill) {
      this.instructions.push(fillInstruction);
      this.hitDetectionInstructions.push(fillInstruction);
    }
    if (stroke) {
      this.instructions.push(strokeInstruction);
      this.hitDetectionInstructions.push(strokeInstruction);
    }
    return offset2;
  }
  /**
   * @param {import("../../geom/Circle.js").default} circleGeometry Circle geometry.
   * @param {import("../../Feature.js").default} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawCircle(circleGeometry, feature, index) {
    const state = this.state;
    const fillStyle = state.fillStyle;
    const strokeStyle = state.strokeStyle;
    if (fillStyle === void 0 && strokeStyle === void 0) {
      return;
    }
    this.setFillStrokeStyles_();
    this.beginGeometry(circleGeometry, feature, index);
    if (state.fillStyle !== void 0) {
      this.hitDetectionInstructions.push([
        Instruction.SET_FILL_STYLE,
        defaultFillStyle
      ]);
    }
    if (state.strokeStyle !== void 0) {
      this.hitDetectionInstructions.push([
        Instruction.SET_STROKE_STYLE,
        state.strokeStyle,
        state.lineWidth,
        state.lineCap,
        state.lineJoin,
        state.miterLimit,
        defaultLineDash,
        defaultLineDashOffset
      ]);
    }
    const flatCoordinates = circleGeometry.getFlatCoordinates();
    const stride = circleGeometry.getStride();
    const myBegin = this.coordinates.length;
    this.appendFlatLineCoordinates(
      flatCoordinates,
      0,
      flatCoordinates.length,
      stride,
      false,
      false
    );
    const circleInstruction = [Instruction.CIRCLE, myBegin];
    this.instructions.push(beginPathInstruction, circleInstruction);
    this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction);
    if (state.fillStyle !== void 0) {
      this.instructions.push(fillInstruction);
      this.hitDetectionInstructions.push(fillInstruction);
    }
    if (state.strokeStyle !== void 0) {
      this.instructions.push(strokeInstruction);
      this.hitDetectionInstructions.push(strokeInstruction);
    }
    this.endGeometry(feature);
  }
  /**
   * @param {import("../../geom/Polygon.js").default|import("../Feature.js").default} polygonGeometry Polygon geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawPolygon(polygonGeometry, feature, index) {
    const state = this.state;
    const fillStyle = state.fillStyle;
    const strokeStyle = state.strokeStyle;
    if (fillStyle === void 0 && strokeStyle === void 0) {
      return;
    }
    this.setFillStrokeStyles_();
    this.beginGeometry(polygonGeometry, feature, index);
    if (state.fillStyle !== void 0) {
      this.hitDetectionInstructions.push([
        Instruction.SET_FILL_STYLE,
        defaultFillStyle
      ]);
    }
    if (state.strokeStyle !== void 0) {
      this.hitDetectionInstructions.push([
        Instruction.SET_STROKE_STYLE,
        state.strokeStyle,
        state.lineWidth,
        state.lineCap,
        state.lineJoin,
        state.miterLimit,
        defaultLineDash,
        defaultLineDashOffset
      ]);
    }
    const ends = polygonGeometry.getEnds();
    const flatCoordinates = polygonGeometry.getOrientedFlatCoordinates();
    const stride = polygonGeometry.getStride();
    this.drawFlatCoordinatess_(
      flatCoordinates,
      0,
      /** @type {Array<number>} */
      ends,
      stride
    );
    this.endGeometry(feature);
  }
  /**
   * @param {import("../../geom/MultiPolygon.js").default} multiPolygonGeometry MultiPolygon geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawMultiPolygon(multiPolygonGeometry, feature, index) {
    const state = this.state;
    const fillStyle = state.fillStyle;
    const strokeStyle = state.strokeStyle;
    if (fillStyle === void 0 && strokeStyle === void 0) {
      return;
    }
    this.setFillStrokeStyles_();
    this.beginGeometry(multiPolygonGeometry, feature, index);
    if (state.fillStyle !== void 0) {
      this.hitDetectionInstructions.push([
        Instruction.SET_FILL_STYLE,
        defaultFillStyle
      ]);
    }
    if (state.strokeStyle !== void 0) {
      this.hitDetectionInstructions.push([
        Instruction.SET_STROKE_STYLE,
        state.strokeStyle,
        state.lineWidth,
        state.lineCap,
        state.lineJoin,
        state.miterLimit,
        defaultLineDash,
        defaultLineDashOffset
      ]);
    }
    const endss = multiPolygonGeometry.getEndss();
    const flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates();
    const stride = multiPolygonGeometry.getStride();
    let offset2 = 0;
    for (let i = 0, ii = endss.length; i < ii; ++i) {
      offset2 = this.drawFlatCoordinatess_(
        flatCoordinates,
        offset2,
        endss[i],
        stride
      );
    }
    this.endGeometry(feature);
  }
  /**
   * @return {import("../canvas.js").SerializableInstructions} the serializable instructions.
   * @override
   */
  finish() {
    this.reverseHitDetectionInstructions();
    this.state = null;
    const tolerance = this.tolerance;
    if (tolerance !== 0) {
      const coordinates2 = this.coordinates;
      for (let i = 0, ii = coordinates2.length; i < ii; ++i) {
        coordinates2[i] = snap(coordinates2[i], tolerance);
      }
    }
    return super.finish();
  }
  /**
   * @private
   */
  setFillStrokeStyles_() {
    const state = this.state;
    this.updateFillStyle(state, this.createFill);
    this.updateStrokeStyle(state, this.applyStroke);
  }
}
function lineChunk(chunkLength, flatCoordinates, offset2, end, stride) {
  const chunks = [];
  let cursor = offset2;
  let chunkM = 0;
  let currentChunk = flatCoordinates.slice(offset2, 2);
  while (chunkM < chunkLength && cursor + stride < end) {
    const [x1, y1] = currentChunk.slice(-2);
    const x2 = flatCoordinates[cursor + stride];
    const y2 = flatCoordinates[cursor + stride + 1];
    const segmentLength = Math.sqrt(
      (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
    );
    chunkM += segmentLength;
    if (chunkM >= chunkLength) {
      const m = (chunkLength - chunkM + segmentLength) / segmentLength;
      const x = lerp(x1, x2, m);
      const y = lerp(y1, y2, m);
      currentChunk.push(x, y);
      chunks.push(currentChunk);
      currentChunk = [x, y];
      if (chunkM == chunkLength) {
        cursor += stride;
      }
      chunkM = 0;
    } else if (chunkM < chunkLength) {
      currentChunk.push(
        flatCoordinates[cursor + stride],
        flatCoordinates[cursor + stride + 1]
      );
      cursor += stride;
    } else {
      const missing = segmentLength - chunkM;
      const x = lerp(x1, x2, missing / segmentLength);
      const y = lerp(y1, y2, missing / segmentLength);
      currentChunk.push(x, y);
      chunks.push(currentChunk);
      currentChunk = [x, y];
      chunkM = 0;
      cursor += stride;
    }
  }
  if (chunkM > 0) {
    chunks.push(currentChunk);
  }
  return chunks;
}
function matchingChunk(maxAngle, flatCoordinates, offset2, end, stride) {
  let chunkStart = offset2;
  let chunkEnd = offset2;
  let chunkM = 0;
  let m = 0;
  let start2 = offset2;
  let acos, i, m12, m23, x1, y1, x12, y12, x23, y23;
  for (i = offset2; i < end; i += stride) {
    const x2 = flatCoordinates[i];
    const y2 = flatCoordinates[i + 1];
    if (x1 !== void 0) {
      x23 = x2 - x1;
      y23 = y2 - y1;
      m23 = Math.sqrt(x23 * x23 + y23 * y23);
      if (x12 !== void 0) {
        m += m12;
        acos = Math.acos((x12 * x23 + y12 * y23) / (m12 * m23));
        if (acos > maxAngle) {
          if (m > chunkM) {
            chunkM = m;
            chunkStart = start2;
            chunkEnd = i;
          }
          m = 0;
          start2 = i - stride;
        }
      }
      m12 = m23;
      x12 = x23;
      y12 = y23;
    }
    x1 = x2;
    y1 = y2;
  }
  m += m23;
  return m > chunkM ? [start2, i] : [chunkStart, chunkEnd];
}
const TEXT_ALIGN = {
  "left": 0,
  "center": 0.5,
  "right": 1,
  "top": 0,
  "middle": 0.5,
  "hanging": 0.2,
  "alphabetic": 0.8,
  "ideographic": 0.8,
  "bottom": 1
};
class CanvasTextBuilder extends CanvasBuilder {
  /**
   * @param {number} tolerance Tolerance.
   * @param {import("../../extent.js").Extent} maxExtent Maximum extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   */
  constructor(tolerance, maxExtent, resolution, pixelRatio) {
    super(tolerance, maxExtent, resolution, pixelRatio);
    this.labels_ = null;
    this.text_ = "";
    this.textOffsetX_ = 0;
    this.textOffsetY_ = 0;
    this.textRotateWithView_ = void 0;
    this.textKeepUpright_ = void 0;
    this.textRotation_ = 0;
    this.textFillState_ = null;
    this.fillStates = {};
    this.fillStates[defaultFillStyle] = { fillStyle: defaultFillStyle };
    this.textStrokeState_ = null;
    this.strokeStates = {};
    this.textState_ = /** @type {import("../canvas.js").TextState} */
    {};
    this.textStates = {};
    this.textKey_ = "";
    this.fillKey_ = "";
    this.strokeKey_ = "";
    this.declutterMode_ = void 0;
    this.declutterImageWithText_ = void 0;
  }
  /**
   * @return {import("../canvas.js").SerializableInstructions} the serializable instructions.
   * @override
   */
  finish() {
    const instructions = super.finish();
    instructions.textStates = this.textStates;
    instructions.fillStates = this.fillStates;
    instructions.strokeStates = this.strokeStates;
    return instructions;
  }
  /**
   * @param {import("../../geom/SimpleGeometry.js").default|import("../Feature.js").default} geometry Geometry.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @param {number} [index] Render order index.
   * @override
   */
  drawText(geometry, feature, index) {
    const fillState = this.textFillState_;
    const strokeState = this.textStrokeState_;
    const textState = this.textState_;
    if (this.text_ === "" || !textState || !fillState && !strokeState) {
      return;
    }
    const coordinates2 = this.coordinates;
    let begin = coordinates2.length;
    const geometryType = geometry.getType();
    let flatCoordinates = null;
    let stride = geometry.getStride();
    if (textState.placement === "line" && (geometryType == "LineString" || geometryType == "MultiLineString" || geometryType == "Polygon" || geometryType == "MultiPolygon")) {
      if (!intersects$1(this.maxExtent, geometry.getExtent())) {
        return;
      }
      let ends;
      flatCoordinates = geometry.getFlatCoordinates();
      if (geometryType == "LineString") {
        ends = [flatCoordinates.length];
      } else if (geometryType == "MultiLineString") {
        ends = /** @type {import("../../geom/MultiLineString.js").default} */
        geometry.getEnds();
      } else if (geometryType == "Polygon") {
        ends = /** @type {import("../../geom/Polygon.js").default} */
        geometry.getEnds().slice(0, 1);
      } else if (geometryType == "MultiPolygon") {
        const endss = (
          /** @type {import("../../geom/MultiPolygon.js").default} */
          geometry.getEndss()
        );
        ends = [];
        for (let i = 0, ii = endss.length; i < ii; ++i) {
          ends.push(endss[i][0]);
        }
      }
      this.beginGeometry(geometry, feature, index);
      const repeat = textState.repeat;
      const textAlign = repeat ? void 0 : textState.textAlign;
      let flatOffset = 0;
      for (let o = 0, oo = ends.length; o < oo; ++o) {
        let chunks;
        if (repeat) {
          chunks = lineChunk(
            repeat * this.resolution,
            flatCoordinates,
            flatOffset,
            ends[o],
            stride
          );
        } else {
          chunks = [flatCoordinates.slice(flatOffset, ends[o])];
        }
        for (let c = 0, cc = chunks.length; c < cc; ++c) {
          const chunk = chunks[c];
          let chunkBegin = 0;
          let chunkEnd = chunk.length;
          if (textAlign == void 0) {
            const range2 = matchingChunk(
              textState.maxAngle,
              chunk,
              0,
              chunk.length,
              2
            );
            chunkBegin = range2[0];
            chunkEnd = range2[1];
          }
          for (let i = chunkBegin; i < chunkEnd; i += stride) {
            coordinates2.push(chunk[i], chunk[i + 1]);
          }
          const end = coordinates2.length;
          flatOffset = ends[o];
          this.drawChars_(begin, end);
          begin = end;
        }
      }
      this.endGeometry(feature);
    } else {
      let geometryWidths = textState.overflow ? null : [];
      switch (geometryType) {
        case "Point":
        case "MultiPoint":
          flatCoordinates = /** @type {import("../../geom/MultiPoint.js").default} */
          geometry.getFlatCoordinates();
          break;
        case "LineString":
          flatCoordinates = /** @type {import("../../geom/LineString.js").default} */
          geometry.getFlatMidpoint();
          break;
        case "Circle":
          flatCoordinates = /** @type {import("../../geom/Circle.js").default} */
          geometry.getCenter();
          break;
        case "MultiLineString":
          flatCoordinates = /** @type {import("../../geom/MultiLineString.js").default} */
          geometry.getFlatMidpoints();
          stride = 2;
          break;
        case "Polygon":
          flatCoordinates = /** @type {import("../../geom/Polygon.js").default} */
          geometry.getFlatInteriorPoint();
          if (!textState.overflow) {
            geometryWidths.push(flatCoordinates[2] / this.resolution);
          }
          stride = 3;
          break;
        case "MultiPolygon":
          const interiorPoints = (
            /** @type {import("../../geom/MultiPolygon.js").default} */
            geometry.getFlatInteriorPoints()
          );
          flatCoordinates = [];
          for (let i = 0, ii = interiorPoints.length; i < ii; i += 3) {
            if (!textState.overflow) {
              geometryWidths.push(interiorPoints[i + 2] / this.resolution);
            }
            flatCoordinates.push(interiorPoints[i], interiorPoints[i + 1]);
          }
          if (flatCoordinates.length === 0) {
            return;
          }
          stride = 2;
          break;
      }
      const end = this.appendFlatPointCoordinates(flatCoordinates, stride);
      if (end === begin) {
        return;
      }
      if (geometryWidths && (end - begin) / 2 !== flatCoordinates.length / stride) {
        let beg = begin / 2;
        geometryWidths = geometryWidths.filter((w, i) => {
          const keep = coordinates2[(beg + i) * 2] === flatCoordinates[i * stride] && coordinates2[(beg + i) * 2 + 1] === flatCoordinates[i * stride + 1];
          if (!keep) {
            --beg;
          }
          return keep;
        });
      }
      this.saveTextStates_();
      const backgroundFill = textState.backgroundFill ? this.createFill(this.fillStyleToState(textState.backgroundFill)) : null;
      const backgroundStroke = textState.backgroundStroke ? this.createStroke(this.strokeStyleToState(textState.backgroundStroke)) : null;
      this.beginGeometry(geometry, feature, index);
      let padding = textState.padding;
      if (padding != defaultPadding && (textState.scale[0] < 0 || textState.scale[1] < 0)) {
        let p0 = textState.padding[0];
        let p12 = textState.padding[1];
        let p22 = textState.padding[2];
        let p32 = textState.padding[3];
        if (textState.scale[0] < 0) {
          p12 = -p12;
          p32 = -p32;
        }
        if (textState.scale[1] < 0) {
          p0 = -p0;
          p22 = -p22;
        }
        padding = [p0, p12, p22, p32];
      }
      const pixelRatio = this.pixelRatio;
      this.instructions.push([
        Instruction.DRAW_IMAGE,
        begin,
        end,
        null,
        NaN,
        NaN,
        NaN,
        1,
        0,
        0,
        this.textRotateWithView_,
        this.textRotation_,
        [1, 1],
        NaN,
        this.declutterMode_,
        this.declutterImageWithText_,
        padding == defaultPadding ? defaultPadding : padding.map(function(p) {
          return p * pixelRatio;
        }),
        backgroundFill,
        backgroundStroke,
        this.text_,
        this.textKey_,
        this.strokeKey_,
        this.fillKey_,
        this.textOffsetX_,
        this.textOffsetY_,
        geometryWidths
      ]);
      const scale2 = 1 / pixelRatio;
      const hitDetectionBackgroundFill = backgroundFill ? backgroundFill.slice(0) : null;
      if (hitDetectionBackgroundFill) {
        hitDetectionBackgroundFill[1] = defaultFillStyle;
      }
      this.hitDetectionInstructions.push([
        Instruction.DRAW_IMAGE,
        begin,
        end,
        null,
        NaN,
        NaN,
        NaN,
        1,
        0,
        0,
        this.textRotateWithView_,
        this.textRotation_,
        [scale2, scale2],
        NaN,
        this.declutterMode_,
        this.declutterImageWithText_,
        padding,
        hitDetectionBackgroundFill,
        backgroundStroke,
        this.text_,
        this.textKey_,
        this.strokeKey_,
        this.fillKey_ ? defaultFillStyle : this.fillKey_,
        this.textOffsetX_,
        this.textOffsetY_,
        geometryWidths
      ]);
      this.endGeometry(feature);
    }
  }
  /**
   * @private
   */
  saveTextStates_() {
    const strokeState = this.textStrokeState_;
    const textState = this.textState_;
    const fillState = this.textFillState_;
    const strokeKey = this.strokeKey_;
    if (strokeState) {
      if (!(strokeKey in this.strokeStates)) {
        this.strokeStates[strokeKey] = {
          strokeStyle: strokeState.strokeStyle,
          lineCap: strokeState.lineCap,
          lineDashOffset: strokeState.lineDashOffset,
          lineWidth: strokeState.lineWidth,
          lineJoin: strokeState.lineJoin,
          miterLimit: strokeState.miterLimit,
          lineDash: strokeState.lineDash
        };
      }
    }
    const textKey = this.textKey_;
    if (!(textKey in this.textStates)) {
      this.textStates[textKey] = {
        font: textState.font,
        textAlign: textState.textAlign || defaultTextAlign,
        justify: textState.justify,
        textBaseline: textState.textBaseline || defaultTextBaseline,
        scale: textState.scale
      };
    }
    const fillKey = this.fillKey_;
    if (fillState) {
      if (!(fillKey in this.fillStates)) {
        this.fillStates[fillKey] = {
          fillStyle: fillState.fillStyle
        };
      }
    }
  }
  /**
   * @private
   * @param {number} begin Begin.
   * @param {number} end End.
   */
  drawChars_(begin, end) {
    const strokeState = this.textStrokeState_;
    const textState = this.textState_;
    const strokeKey = this.strokeKey_;
    const textKey = this.textKey_;
    const fillKey = this.fillKey_;
    this.saveTextStates_();
    const pixelRatio = this.pixelRatio;
    const baseline = TEXT_ALIGN[textState.textBaseline];
    const offsetY = this.textOffsetY_ * pixelRatio;
    const text = this.text_;
    const strokeWidth = strokeState ? strokeState.lineWidth * Math.abs(textState.scale[0]) / 2 : 0;
    this.instructions.push([
      Instruction.DRAW_CHARS,
      begin,
      end,
      baseline,
      textState.overflow,
      fillKey,
      textState.maxAngle,
      pixelRatio,
      offsetY,
      strokeKey,
      strokeWidth * pixelRatio,
      text,
      textKey,
      1,
      this.declutterMode_,
      this.textKeepUpright_
    ]);
    this.hitDetectionInstructions.push([
      Instruction.DRAW_CHARS,
      begin,
      end,
      baseline,
      textState.overflow,
      fillKey ? defaultFillStyle : fillKey,
      textState.maxAngle,
      pixelRatio,
      offsetY,
      strokeKey,
      strokeWidth * pixelRatio,
      text,
      textKey,
      1 / pixelRatio,
      this.declutterMode_,
      this.textKeepUpright_
    ]);
  }
  /**
   * @param {import("../../style/Text.js").default} textStyle Text style.
   * @param {Object} [sharedData] Shared data.
   * @override
   */
  setTextStyle(textStyle, sharedData) {
    let textState, fillState, strokeState;
    if (!textStyle) {
      this.text_ = "";
    } else {
      const textFillStyle = textStyle.getFill();
      if (!textFillStyle) {
        fillState = null;
        this.textFillState_ = fillState;
      } else {
        fillState = this.textFillState_;
        if (!fillState) {
          fillState = /** @type {import("../canvas.js").FillState} */
          {};
          this.textFillState_ = fillState;
        }
        fillState.fillStyle = asColorLike(
          textFillStyle.getColor() || defaultFillStyle
        );
      }
      const textStrokeStyle = textStyle.getStroke();
      if (!textStrokeStyle) {
        strokeState = null;
        this.textStrokeState_ = strokeState;
      } else {
        strokeState = this.textStrokeState_;
        if (!strokeState) {
          strokeState = /** @type {import("../canvas.js").StrokeState} */
          {};
          this.textStrokeState_ = strokeState;
        }
        const lineDash = textStrokeStyle.getLineDash();
        const lineDashOffset = textStrokeStyle.getLineDashOffset();
        const lineWidth = textStrokeStyle.getWidth();
        const miterLimit = textStrokeStyle.getMiterLimit();
        strokeState.lineCap = textStrokeStyle.getLineCap() || defaultLineCap;
        strokeState.lineDash = lineDash ? lineDash.slice() : defaultLineDash;
        strokeState.lineDashOffset = lineDashOffset === void 0 ? defaultLineDashOffset : lineDashOffset;
        strokeState.lineJoin = textStrokeStyle.getLineJoin() || defaultLineJoin;
        strokeState.lineWidth = lineWidth === void 0 ? defaultLineWidth : lineWidth;
        strokeState.miterLimit = miterLimit === void 0 ? defaultMiterLimit : miterLimit;
        strokeState.strokeStyle = asColorLike(
          textStrokeStyle.getColor() || defaultStrokeStyle
        );
      }
      textState = this.textState_;
      const font = textStyle.getFont() || defaultFont;
      registerFont(font);
      const textScale = textStyle.getScaleArray();
      textState.overflow = textStyle.getOverflow();
      textState.font = font;
      textState.maxAngle = textStyle.getMaxAngle();
      textState.placement = textStyle.getPlacement();
      textState.textAlign = textStyle.getTextAlign();
      textState.repeat = textStyle.getRepeat();
      textState.justify = textStyle.getJustify();
      textState.textBaseline = textStyle.getTextBaseline() || defaultTextBaseline;
      textState.backgroundFill = textStyle.getBackgroundFill();
      textState.backgroundStroke = textStyle.getBackgroundStroke();
      textState.padding = textStyle.getPadding() || defaultPadding;
      textState.scale = textScale === void 0 ? [1, 1] : textScale;
      const textOffsetX = textStyle.getOffsetX();
      const textOffsetY = textStyle.getOffsetY();
      const textRotateWithView = textStyle.getRotateWithView();
      const textKeepUpright = textStyle.getKeepUpright();
      const textRotation = textStyle.getRotation();
      this.text_ = textStyle.getText() || "";
      this.textOffsetX_ = textOffsetX === void 0 ? 0 : textOffsetX;
      this.textOffsetY_ = textOffsetY === void 0 ? 0 : textOffsetY;
      this.textRotateWithView_ = textRotateWithView === void 0 ? false : textRotateWithView;
      this.textKeepUpright_ = textKeepUpright === void 0 ? true : textKeepUpright;
      this.textRotation_ = textRotation === void 0 ? 0 : textRotation;
      this.strokeKey_ = strokeState ? (typeof strokeState.strokeStyle == "string" ? strokeState.strokeStyle : getUid(strokeState.strokeStyle)) + strokeState.lineCap + strokeState.lineDashOffset + "|" + strokeState.lineWidth + strokeState.lineJoin + strokeState.miterLimit + "[" + strokeState.lineDash.join() + "]" : "";
      this.textKey_ = textState.font + textState.scale + (textState.textAlign || "?") + (textState.repeat || "?") + (textState.justify || "?") + (textState.textBaseline || "?");
      this.fillKey_ = fillState && fillState.fillStyle ? typeof fillState.fillStyle == "string" ? fillState.fillStyle : "|" + getUid(fillState.fillStyle) : "";
    }
    this.declutterMode_ = textStyle.getDeclutterMode();
    this.declutterImageWithText_ = sharedData;
  }
}
const BATCH_CONSTRUCTORS = {
  "Circle": CanvasPolygonBuilder,
  "Default": CanvasBuilder,
  "Image": CanvasImageBuilder,
  "LineString": CanvasLineStringBuilder,
  "Polygon": CanvasPolygonBuilder,
  "Text": CanvasTextBuilder
};
class BuilderGroup {
  /**
   * @param {number} tolerance Tolerance.
   * @param {import("../../extent.js").Extent} maxExtent Max extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   */
  constructor(tolerance, maxExtent, resolution, pixelRatio) {
    this.tolerance_ = tolerance;
    this.maxExtent_ = maxExtent;
    this.pixelRatio_ = pixelRatio;
    this.resolution_ = resolution;
    this.buildersByZIndex_ = {};
  }
  /**
   * @return {!Object<string, !Object<import("../canvas.js").BuilderType, import("./Builder.js").SerializableInstructions>>} The serializable instructions
   */
  finish() {
    const builderInstructions = {};
    for (const zKey in this.buildersByZIndex_) {
      builderInstructions[zKey] = builderInstructions[zKey] || {};
      const builders = this.buildersByZIndex_[zKey];
      for (const builderKey in builders) {
        const builderInstruction = builders[builderKey].finish();
        builderInstructions[zKey][builderKey] = builderInstruction;
      }
    }
    return builderInstructions;
  }
  /**
   * @param {number|undefined} zIndex Z index.
   * @param {import("../canvas.js").BuilderType} builderType Replay type.
   * @return {import("../VectorContext.js").default} Replay.
   */
  getBuilder(zIndex, builderType) {
    const zIndexKey = zIndex !== void 0 ? zIndex.toString() : "0";
    let replays = this.buildersByZIndex_[zIndexKey];
    if (replays === void 0) {
      replays = {};
      this.buildersByZIndex_[zIndexKey] = replays;
    }
    let replay = replays[builderType];
    if (replay === void 0) {
      const Constructor = BATCH_CONSTRUCTORS[builderType];
      replay = new Constructor(
        this.tolerance_,
        this.maxExtent_,
        this.resolution_,
        this.pixelRatio_
      );
      replays[builderType] = replay;
    }
    return replay;
  }
}
function drawTextOnPath(flatCoordinates, offset2, end, stride, text, startM, maxAngle, scale2, measureAndCacheTextWidth2, font, cache2, rotation, keepUpright = true) {
  let x2 = flatCoordinates[offset2];
  let y2 = flatCoordinates[offset2 + 1];
  let x1 = 0;
  let y1 = 0;
  let segmentLength = 0;
  let segmentM = 0;
  function advance() {
    x1 = x2;
    y1 = y2;
    offset2 += stride;
    x2 = flatCoordinates[offset2];
    y2 = flatCoordinates[offset2 + 1];
    segmentM += segmentLength;
    segmentLength = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  }
  do {
    advance();
  } while (offset2 < end - stride && segmentM + segmentLength < startM);
  let interpolate = segmentLength === 0 ? 0 : (startM - segmentM) / segmentLength;
  const beginX = lerp(x1, x2, interpolate);
  const beginY = lerp(y1, y2, interpolate);
  const startOffset = offset2 - stride;
  const startLength = segmentM;
  const endM = startM + scale2 * measureAndCacheTextWidth2(font, text, cache2);
  while (offset2 < end - stride && segmentM + segmentLength < endM) {
    advance();
  }
  interpolate = segmentLength === 0 ? 0 : (endM - segmentM) / segmentLength;
  const endX = lerp(x1, x2, interpolate);
  const endY = lerp(y1, y2, interpolate);
  let reverse = false;
  if (keepUpright) {
    if (rotation) {
      const flat = [beginX, beginY, endX, endY];
      rotate(flat, 0, 4, 2, rotation, flat, flat);
      reverse = flat[0] > flat[2];
    } else {
      reverse = beginX > endX;
    }
  }
  const PI2 = Math.PI;
  const result = [];
  const singleSegment = startOffset + stride === offset2;
  offset2 = startOffset;
  segmentLength = 0;
  segmentM = startLength;
  x2 = flatCoordinates[offset2];
  y2 = flatCoordinates[offset2 + 1];
  let previousAngle;
  if (singleSegment) {
    advance();
    previousAngle = Math.atan2(y2 - y1, x2 - x1);
    if (reverse) {
      previousAngle += previousAngle > 0 ? -PI2 : PI2;
    }
    const x = (endX + beginX) / 2;
    const y = (endY + beginY) / 2;
    result[0] = [x, y, (endM - startM) / 2, previousAngle, text];
    return result;
  }
  text = text.replace(/\n/g, " ");
  for (let i = 0, ii = text.length; i < ii; ) {
    advance();
    let angle = Math.atan2(y2 - y1, x2 - x1);
    if (reverse) {
      angle += angle > 0 ? -PI2 : PI2;
    }
    if (previousAngle !== void 0) {
      let delta = angle - previousAngle;
      delta += delta > PI2 ? -2 * PI2 : delta < -PI2 ? 2 * PI2 : 0;
      if (Math.abs(delta) > maxAngle) {
        return null;
      }
    }
    previousAngle = angle;
    const iStart = i;
    let charLength = 0;
    for (; i < ii; ++i) {
      const index = reverse ? ii - i - 1 : i;
      const len = scale2 * measureAndCacheTextWidth2(font, text[index], cache2);
      if (offset2 + stride < end && segmentM + segmentLength < startM + charLength + len / 2) {
        break;
      }
      charLength += len;
    }
    if (i === iStart) {
      continue;
    }
    const chars = reverse ? text.substring(ii - iStart, ii - i) : text.substring(iStart, i);
    interpolate = segmentLength === 0 ? 0 : (startM + charLength / 2 - segmentM) / segmentLength;
    const x = lerp(x1, x2, interpolate);
    const y = lerp(y1, y2, interpolate);
    result.push([x, y, charLength / 2, angle, chars]);
    startM += charLength;
  }
  return result;
}
class ZIndexContext {
  constructor() {
    this.instructions_ = [];
    this.zIndex = 0;
    this.offset_ = 0;
    this.context_ = /** @type {ZIndexContextProxy} */
    new Proxy(getSharedCanvasContext2D(), {
      get: (target, property) => {
        if (typeof /** @type {*} */
        getSharedCanvasContext2D()[property] !== "function") {
          return void 0;
        }
        this.push_(property);
        return this.pushMethodArgs_;
      },
      set: (target, property, value) => {
        this.push_(property, value);
        return true;
      }
    });
  }
  /**
   * @param {...*} args Arguments to push to the instructions array.
   * @private
   */
  push_(...args) {
    const instructions = this.instructions_;
    const index = this.zIndex + this.offset_;
    if (!instructions[index]) {
      instructions[index] = [];
    }
    instructions[index].push(...args);
  }
  /**
   * @private
   * @param {...*} args Args.
   * @return {ZIndexContext} This.
   */
  pushMethodArgs_ = (...args) => {
    this.push_(args);
    return this;
  };
  /**
   * Push a function that renders to the context directly.
   * @param {function(CanvasRenderingContext2D): void} render Function.
   */
  pushFunction(render2) {
    this.push_(render2);
  }
  /**
   * Get a proxy for CanvasRenderingContext2D which does not support getting state
   * (e.g. `context.globalAlpha`, which will return `undefined`). To set state, if it relies on a
   * previous state (e.g. `context.globalAlpha = context.globalAlpha / 2`), set a function,
   * e.g. `context.globalAlpha = (context) => context.globalAlpha / 2`.
   * @return {ZIndexContextProxy} Context.
   */
  getContext() {
    return this.context_;
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   */
  draw(context) {
    this.instructions_.forEach((instructionsAtIndex) => {
      for (let i = 0, ii = instructionsAtIndex.length; i < ii; ++i) {
        const property = instructionsAtIndex[i];
        if (typeof property === "function") {
          property(context);
          continue;
        }
        const instructionAtIndex = instructionsAtIndex[++i];
        if (typeof /** @type {*} */
        context[property] === "function") {
          context[property](...instructionAtIndex);
        } else {
          if (typeof instructionAtIndex === "function") {
            context[property] = instructionAtIndex(context);
            continue;
          }
          context[property] = instructionAtIndex;
        }
      }
    });
  }
  clear() {
    this.instructions_.length = 0;
    this.zIndex = 0;
    this.offset_ = 0;
  }
  /**
   * Offsets the zIndex by the highest current zIndex. Useful for rendering multiple worlds or tiles, to
   * avoid conflicting context.clip() or context.save()/restore() calls.
   */
  offset() {
    this.offset_ = this.instructions_.length;
    this.zIndex = 0;
  }
}
const tmpExtent = createEmpty();
const p1 = [];
const p2 = [];
const p3 = [];
const p4 = [];
function getDeclutterBox(replayImageOrLabelArgs) {
  return replayImageOrLabelArgs[3].declutterBox;
}
const rtlRegEx = new RegExp(
  /* eslint-disable prettier/prettier */
  "[" + String.fromCharCode(1425) + "-" + String.fromCharCode(2303) + String.fromCharCode(64285) + "-" + String.fromCharCode(65023) + String.fromCharCode(65136) + "-" + String.fromCharCode(65276) + String.fromCharCode(67584) + "-" + String.fromCharCode(69631) + String.fromCharCode(124928) + "-" + String.fromCharCode(126975) + "]"
  /* eslint-enable prettier/prettier */
);
function horizontalTextAlign(text, align) {
  if (align === "start") {
    align = rtlRegEx.test(text) ? "right" : "left";
  } else if (align === "end") {
    align = rtlRegEx.test(text) ? "left" : "right";
  }
  return TEXT_ALIGN[align];
}
function createTextChunks(acc, line2, i) {
  if (i > 0) {
    acc.push("\n", "");
  }
  acc.push(line2, "");
  return acc;
}
function richTextToPlainText(result, part, index) {
  if (index % 2 === 0) {
    result += part;
  }
  return result;
}
class Executor {
  /**
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   * @param {boolean} overlaps The replay can have overlapping geometries.
   * @param {import("../canvas.js").SerializableInstructions} instructions The serializable instructions.
   * @param {boolean} [deferredRendering] Enable deferred rendering.
   */
  constructor(resolution, pixelRatio, overlaps, instructions, deferredRendering) {
    this.overlaps = overlaps;
    this.pixelRatio = pixelRatio;
    this.resolution = resolution;
    this.alignAndScaleFill_;
    this.instructions = instructions.instructions;
    this.coordinates = instructions.coordinates;
    this.coordinateCache_ = {};
    this.renderedTransform_ = create();
    this.hitDetectionInstructions = instructions.hitDetectionInstructions;
    this.pixelCoordinates_ = null;
    this.viewRotation_ = 0;
    this.fillStates = instructions.fillStates || {};
    this.strokeStates = instructions.strokeStates || {};
    this.textStates = instructions.textStates || {};
    this.widths_ = {};
    this.labels_ = {};
    this.zIndexContext_ = deferredRendering ? new ZIndexContext() : null;
  }
  /**
   * @return {ZIndexContext} ZIndex context.
   */
  getZIndexContext() {
    return this.zIndexContext_;
  }
  /**
   * @param {string|Array<string>} text Text.
   * @param {string} textKey Text style key.
   * @param {string} fillKey Fill style key.
   * @param {string} strokeKey Stroke style key.
   * @return {import("../canvas.js").Label} Label.
   */
  createLabel(text, textKey, fillKey, strokeKey) {
    const key2 = text + textKey + fillKey + strokeKey;
    if (this.labels_[key2]) {
      return this.labels_[key2];
    }
    const strokeState = strokeKey ? this.strokeStates[strokeKey] : null;
    const fillState = fillKey ? this.fillStates[fillKey] : null;
    const textState = this.textStates[textKey];
    const pixelRatio = this.pixelRatio;
    const scale2 = [
      textState.scale[0] * pixelRatio,
      textState.scale[1] * pixelRatio
    ];
    const align = textState.justify ? TEXT_ALIGN[textState.justify] : horizontalTextAlign(
      Array.isArray(text) ? text[0] : text,
      textState.textAlign || defaultTextAlign
    );
    const strokeWidth = strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
    const chunks = Array.isArray(text) ? text : String(text).split("\n").reduce(createTextChunks, []);
    const { width, height, widths, heights, lineWidths } = getTextDimensions(
      textState,
      chunks
    );
    const renderWidth = width + strokeWidth;
    const contextInstructions = [];
    const w = (renderWidth + 2) * scale2[0];
    const h = (height + strokeWidth) * scale2[1];
    const label = {
      width: w < 0 ? Math.floor(w) : Math.ceil(w),
      height: h < 0 ? Math.floor(h) : Math.ceil(h),
      contextInstructions
    };
    if (scale2[0] != 1 || scale2[1] != 1) {
      contextInstructions.push("scale", scale2);
    }
    if (strokeKey) {
      contextInstructions.push("strokeStyle", strokeState.strokeStyle);
      contextInstructions.push("lineWidth", strokeWidth);
      contextInstructions.push("lineCap", strokeState.lineCap);
      contextInstructions.push("lineJoin", strokeState.lineJoin);
      contextInstructions.push("miterLimit", strokeState.miterLimit);
      contextInstructions.push("setLineDash", [strokeState.lineDash]);
      contextInstructions.push("lineDashOffset", strokeState.lineDashOffset);
    }
    if (fillKey) {
      contextInstructions.push("fillStyle", fillState.fillStyle);
    }
    contextInstructions.push("textBaseline", "middle");
    contextInstructions.push("textAlign", "center");
    const leftRight = 0.5 - align;
    let x = align * renderWidth + leftRight * strokeWidth;
    const strokeInstructions = [];
    const fillInstructions = [];
    let lineHeight = 0;
    let lineOffset = 0;
    let widthHeightIndex = 0;
    let lineWidthIndex = 0;
    let previousFont;
    for (let i = 0, ii = chunks.length; i < ii; i += 2) {
      const text2 = chunks[i];
      if (text2 === "\n") {
        lineOffset += lineHeight;
        lineHeight = 0;
        x = align * renderWidth + leftRight * strokeWidth;
        ++lineWidthIndex;
        continue;
      }
      const font = chunks[i + 1] || textState.font;
      if (font !== previousFont) {
        if (strokeKey) {
          strokeInstructions.push("font", font);
        }
        if (fillKey) {
          fillInstructions.push("font", font);
        }
        previousFont = font;
      }
      lineHeight = Math.max(lineHeight, heights[widthHeightIndex]);
      const fillStrokeArgs = [
        text2,
        x + leftRight * widths[widthHeightIndex] + align * (widths[widthHeightIndex] - lineWidths[lineWidthIndex]),
        0.5 * (strokeWidth + lineHeight) + lineOffset
      ];
      x += widths[widthHeightIndex];
      if (strokeKey) {
        strokeInstructions.push("strokeText", fillStrokeArgs);
      }
      if (fillKey) {
        fillInstructions.push("fillText", fillStrokeArgs);
      }
      ++widthHeightIndex;
    }
    Array.prototype.push.apply(contextInstructions, strokeInstructions);
    Array.prototype.push.apply(contextInstructions, fillInstructions);
    this.labels_[key2] = label;
    return label;
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../coordinate.js").Coordinate} p1 1st point of the background box.
   * @param {import("../../coordinate.js").Coordinate} p2 2nd point of the background box.
   * @param {import("../../coordinate.js").Coordinate} p3 3rd point of the background box.
   * @param {import("../../coordinate.js").Coordinate} p4 4th point of the background box.
   * @param {Array<*>} fillInstruction Fill instruction.
   * @param {Array<*>} strokeInstruction Stroke instruction.
   */
  replayTextBackground_(context, p12, p22, p32, p42, fillInstruction2, strokeInstruction2) {
    context.beginPath();
    context.moveTo.apply(context, p12);
    context.lineTo.apply(context, p22);
    context.lineTo.apply(context, p32);
    context.lineTo.apply(context, p42);
    context.lineTo.apply(context, p12);
    if (fillInstruction2) {
      this.alignAndScaleFill_ = /** @type {number} */
      fillInstruction2[2];
      context.fillStyle = /** @type {string} */
      fillInstruction2[1];
      this.fill_(context);
    }
    if (strokeInstruction2) {
      this.setStrokeStyle_(
        context,
        /** @type {Array<*>} */
        strokeInstruction2
      );
      context.stroke();
    }
  }
  /**
   * @private
   * @param {number} sheetWidth Width of the sprite sheet.
   * @param {number} sheetHeight Height of the sprite sheet.
   * @param {number} centerX X.
   * @param {number} centerY Y.
   * @param {number} width Width.
   * @param {number} height Height.
   * @param {number} anchorX Anchor X.
   * @param {number} anchorY Anchor Y.
   * @param {number} originX Origin X.
   * @param {number} originY Origin Y.
   * @param {number} rotation Rotation.
   * @param {import("../../size.js").Size} scale Scale.
   * @param {boolean} snapToPixel Snap to pixel.
   * @param {Array<number>} padding Padding.
   * @param {boolean} fillStroke Background fill or stroke.
   * @param {import("../../Feature.js").FeatureLike} feature Feature.
   * @return {ImageOrLabelDimensions} Dimensions for positioning and decluttering the image or label.
   */
  calculateImageOrLabelDimensions_(sheetWidth, sheetHeight, centerX, centerY, width, height, anchorX, anchorY, originX, originY, rotation, scale2, snapToPixel, padding, fillStroke, feature) {
    anchorX *= scale2[0];
    anchorY *= scale2[1];
    let x = centerX - anchorX;
    let y = centerY - anchorY;
    const w = width + originX > sheetWidth ? sheetWidth - originX : width;
    const h = height + originY > sheetHeight ? sheetHeight - originY : height;
    const boxW = padding[3] + w * scale2[0] + padding[1];
    const boxH = padding[0] + h * scale2[1] + padding[2];
    const boxX = x - padding[3];
    const boxY = y - padding[0];
    if (fillStroke || rotation !== 0) {
      p1[0] = boxX;
      p4[0] = boxX;
      p1[1] = boxY;
      p2[1] = boxY;
      p2[0] = boxX + boxW;
      p3[0] = p2[0];
      p3[1] = boxY + boxH;
      p4[1] = p3[1];
    }
    let transform2;
    if (rotation !== 0) {
      transform2 = compose(
        create(),
        centerX,
        centerY,
        1,
        1,
        rotation,
        -centerX,
        -centerY
      );
      apply(transform2, p1);
      apply(transform2, p2);
      apply(transform2, p3);
      apply(transform2, p4);
      createOrUpdate$2(
        Math.min(p1[0], p2[0], p3[0], p4[0]),
        Math.min(p1[1], p2[1], p3[1], p4[1]),
        Math.max(p1[0], p2[0], p3[0], p4[0]),
        Math.max(p1[1], p2[1], p3[1], p4[1]),
        tmpExtent
      );
    } else {
      createOrUpdate$2(
        Math.min(boxX, boxX + boxW),
        Math.min(boxY, boxY + boxH),
        Math.max(boxX, boxX + boxW),
        Math.max(boxY, boxY + boxH),
        tmpExtent
      );
    }
    if (snapToPixel) {
      x = Math.round(x);
      y = Math.round(y);
    }
    return {
      drawImageX: x,
      drawImageY: y,
      drawImageW: w,
      drawImageH: h,
      originX,
      originY,
      declutterBox: {
        minX: tmpExtent[0],
        minY: tmpExtent[1],
        maxX: tmpExtent[2],
        maxY: tmpExtent[3],
        value: feature
      },
      canvasTransform: transform2,
      scale: scale2
    };
  }
  /**
   * @private
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import('../../size.js').Size} scaledCanvasSize Scaled canvas size.
   * @param {import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imageOrLabel Image.
   * @param {ImageOrLabelDimensions} dimensions Dimensions.
   * @param {number} opacity Opacity.
   * @param {Array<*>} fillInstruction Fill instruction.
   * @param {Array<*>} strokeInstruction Stroke instruction.
   * @return {boolean} The image or label was rendered.
   */
  replayImageOrLabel_(context, scaledCanvasSize, imageOrLabel, dimensions, opacity, fillInstruction2, strokeInstruction2) {
    const fillStroke = !!(fillInstruction2 || strokeInstruction2);
    const box = dimensions.declutterBox;
    const strokePadding = strokeInstruction2 ? strokeInstruction2[2] * dimensions.scale[0] / 2 : 0;
    const intersects2 = box.minX - strokePadding <= scaledCanvasSize[0] && box.maxX + strokePadding >= 0 && box.minY - strokePadding <= scaledCanvasSize[1] && box.maxY + strokePadding >= 0;
    if (intersects2) {
      if (fillStroke) {
        this.replayTextBackground_(
          context,
          p1,
          p2,
          p3,
          p4,
          /** @type {Array<*>} */
          fillInstruction2,
          /** @type {Array<*>} */
          strokeInstruction2
        );
      }
      drawImageOrLabel(
        context,
        dimensions.canvasTransform,
        opacity,
        imageOrLabel,
        dimensions.originX,
        dimensions.originY,
        dimensions.drawImageW,
        dimensions.drawImageH,
        dimensions.drawImageX,
        dimensions.drawImageY,
        dimensions.scale
      );
    }
    return true;
  }
  /**
   * @private
   * @param {CanvasRenderingContext2D} context Context.
   */
  fill_(context) {
    const alignAndScale = this.alignAndScaleFill_;
    if (alignAndScale) {
      const origin = apply(this.renderedTransform_, [0, 0]);
      const repeatSize = 512 * this.pixelRatio;
      context.save();
      context.translate(origin[0] % repeatSize, origin[1] % repeatSize);
      if (alignAndScale !== 1) {
        context.scale(alignAndScale, alignAndScale);
      }
      context.rotate(this.viewRotation_);
    }
    context.fill();
    if (alignAndScale) {
      context.restore();
    }
  }
  /**
   * @private
   * @param {CanvasRenderingContext2D} context Context.
   * @param {Array<*>} instruction Instruction.
   */
  setStrokeStyle_(context, instruction) {
    context.strokeStyle = /** @type {import("../../colorlike.js").ColorLike} */
    instruction[1];
    if (!instruction[1]) {
      return;
    }
    context.lineWidth = /** @type {number} */
    instruction[2];
    context.lineCap = /** @type {CanvasLineCap} */
    instruction[3];
    context.lineJoin = /** @type {CanvasLineJoin} */
    instruction[4];
    context.miterLimit = /** @type {number} */
    instruction[5];
    context.lineDashOffset = /** @type {number} */
    instruction[7];
    context.setLineDash(
      /** @type {Array<number>} */
      instruction[6]
    );
  }
  /**
   * @private
   * @param {string|Array<string>} text The text to draw.
   * @param {string} textKey The key of the text state.
   * @param {string} strokeKey The key for the stroke state.
   * @param {string} fillKey The key for the fill state.
   * @return {{label: import("../canvas.js").Label, anchorX: number, anchorY: number}} The text image and its anchor.
   */
  drawLabelWithPointPlacement_(text, textKey, strokeKey, fillKey) {
    const textState = this.textStates[textKey];
    const label = this.createLabel(text, textKey, fillKey, strokeKey);
    const strokeState = this.strokeStates[strokeKey];
    const pixelRatio = this.pixelRatio;
    const align = horizontalTextAlign(
      Array.isArray(text) ? text[0] : text,
      textState.textAlign || defaultTextAlign
    );
    const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
    const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
    const width = label.width / pixelRatio - 2 * textState.scale[0];
    const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
    const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
    return {
      label,
      anchorX,
      anchorY
    };
  }
  /**
   * @private
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import('../../size.js').Size} scaledCanvasSize Scaled canvas size
   * @param {import("../../transform.js").Transform} transform Transform.
   * @param {Array<*>} instructions Instructions array.
   * @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
   * @param {FeatureCallback<T>} [featureCallback] Feature callback.
   * @param {import("../../extent.js").Extent} [hitExtent] Only check
   *     features that intersect this extent.
   * @param {import("rbush").default<DeclutterEntry>} [declutterTree] Declutter tree.
   * @return {T|undefined} Callback result.
   * @template T
   */
  execute_(context, scaledCanvasSize, transform2, instructions, snapToPixel, featureCallback, hitExtent, declutterTree) {
    const zIndexContext = this.zIndexContext_;
    let pixelCoordinates;
    if (this.pixelCoordinates_ && equals$2(transform2, this.renderedTransform_)) {
      pixelCoordinates = this.pixelCoordinates_;
    } else {
      if (!this.pixelCoordinates_) {
        this.pixelCoordinates_ = [];
      }
      pixelCoordinates = transform2D(
        this.coordinates,
        0,
        this.coordinates.length,
        2,
        transform2,
        this.pixelCoordinates_
      );
      setFromArray(this.renderedTransform_, transform2);
    }
    let i = 0;
    const ii = instructions.length;
    let d = 0;
    let dd;
    let anchorX, anchorY, declutterMode, prevX, prevY, roundX, roundY, image, text, textKey, strokeKey, fillKey;
    let pendingFill = 0;
    let pendingStroke = 0;
    const coordinateCache = this.coordinateCache_;
    const viewRotation = this.viewRotation_;
    const viewRotationFromTransform = Math.round(Math.atan2(-transform2[1], transform2[0]) * 1e12) / 1e12;
    const state = (
      /** @type {import("../../render.js").State} */
      {
        context,
        pixelRatio: this.pixelRatio,
        resolution: this.resolution,
        rotation: viewRotation
      }
    );
    const batchSize = this.instructions != instructions || this.overlaps ? 0 : 200;
    let feature;
    let x, y, currentGeometry;
    while (i < ii) {
      const instruction = instructions[i];
      const type = (
        /** @type {import("./Instruction.js").default} */
        instruction[0]
      );
      switch (type) {
        case Instruction.BEGIN_GEOMETRY:
          feature = /** @type {import("../../Feature.js").FeatureLike} */
          instruction[1];
          currentGeometry = instruction[3];
          if (!feature.getGeometry()) {
            i = /** @type {number} */
            instruction[2];
          } else if (hitExtent !== void 0 && !intersects$1(hitExtent, currentGeometry.getExtent())) {
            i = /** @type {number} */
            instruction[2] + 1;
          } else {
            ++i;
          }
          if (zIndexContext) {
            zIndexContext.zIndex = instruction[4];
          }
          break;
        case Instruction.BEGIN_PATH:
          if (pendingFill > batchSize) {
            this.fill_(context);
            pendingFill = 0;
          }
          if (pendingStroke > batchSize) {
            context.stroke();
            pendingStroke = 0;
          }
          if (!pendingFill && !pendingStroke) {
            context.beginPath();
            prevX = NaN;
            prevY = NaN;
          }
          ++i;
          break;
        case Instruction.CIRCLE:
          d = /** @type {number} */
          instruction[1];
          const x1 = pixelCoordinates[d];
          const y1 = pixelCoordinates[d + 1];
          const x2 = pixelCoordinates[d + 2];
          const y2 = pixelCoordinates[d + 3];
          const dx = x2 - x1;
          const dy = y2 - y1;
          const r = Math.sqrt(dx * dx + dy * dy);
          context.moveTo(x1 + r, y1);
          context.arc(x1, y1, r, 0, 2 * Math.PI, true);
          ++i;
          break;
        case Instruction.CLOSE_PATH:
          context.closePath();
          ++i;
          break;
        case Instruction.CUSTOM:
          d = /** @type {number} */
          instruction[1];
          dd = instruction[2];
          const geometry = (
            /** @type {import("../../geom/SimpleGeometry.js").default} */
            instruction[3]
          );
          const renderer = instruction[4];
          const fn = instruction[5];
          state.geometry = geometry;
          state.feature = feature;
          if (!(i in coordinateCache)) {
            coordinateCache[i] = [];
          }
          const coords = coordinateCache[i];
          if (fn) {
            fn(pixelCoordinates, d, dd, 2, coords);
          } else {
            coords[0] = pixelCoordinates[d];
            coords[1] = pixelCoordinates[d + 1];
            coords.length = 2;
          }
          if (zIndexContext) {
            zIndexContext.zIndex = instruction[6];
          }
          renderer(coords, state);
          ++i;
          break;
        case Instruction.DRAW_IMAGE:
          d = /** @type {number} */
          instruction[1];
          dd = /** @type {number} */
          instruction[2];
          image = /** @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} */
          instruction[3];
          anchorX = /** @type {number} */
          instruction[4];
          anchorY = /** @type {number} */
          instruction[5];
          let height = (
            /** @type {number} */
            instruction[6]
          );
          const opacity = (
            /** @type {number} */
            instruction[7]
          );
          const originX = (
            /** @type {number} */
            instruction[8]
          );
          const originY = (
            /** @type {number} */
            instruction[9]
          );
          const rotateWithView = (
            /** @type {boolean} */
            instruction[10]
          );
          let rotation = (
            /** @type {number} */
            instruction[11]
          );
          const scale2 = (
            /** @type {import("../../size.js").Size} */
            instruction[12]
          );
          let width = (
            /** @type {number} */
            instruction[13]
          );
          declutterMode = instruction[14] || "declutter";
          const declutterImageWithText = (
            /** @type {{args: import("../canvas.js").DeclutterImageWithText, declutterMode: import('../../style/Style.js').DeclutterMode}} */
            instruction[15]
          );
          if (!image && instruction.length >= 20) {
            text = /** @type {string} */
            instruction[19];
            textKey = /** @type {string} */
            instruction[20];
            strokeKey = /** @type {string} */
            instruction[21];
            fillKey = /** @type {string} */
            instruction[22];
            const labelWithAnchor = this.drawLabelWithPointPlacement_(
              text,
              textKey,
              strokeKey,
              fillKey
            );
            image = labelWithAnchor.label;
            instruction[3] = image;
            const textOffsetX = (
              /** @type {number} */
              instruction[23]
            );
            anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
            instruction[4] = anchorX;
            const textOffsetY = (
              /** @type {number} */
              instruction[24]
            );
            anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
            instruction[5] = anchorY;
            height = image.height;
            instruction[6] = height;
            width = image.width;
            instruction[13] = width;
          }
          let geometryWidths;
          if (instruction.length > 25) {
            geometryWidths = /** @type {number} */
            instruction[25];
          }
          let padding, backgroundFillInstruction, backgroundStrokeInstruction;
          if (instruction.length > 17) {
            padding = /** @type {Array<number>} */
            instruction[16];
            backgroundFillInstruction = /** @type {Array<*>} */
            instruction[17];
            backgroundStrokeInstruction = /** @type {Array<*>} */
            instruction[18];
          } else {
            padding = defaultPadding;
            backgroundFillInstruction = null;
            backgroundStrokeInstruction = null;
          }
          if (rotateWithView && viewRotationFromTransform) {
            rotation += viewRotation;
          } else if (!rotateWithView && !viewRotationFromTransform) {
            rotation -= viewRotation;
          }
          let widthIndex = 0;
          for (; d < dd; d += 2) {
            if (geometryWidths && geometryWidths[widthIndex++] < width / this.pixelRatio) {
              continue;
            }
            const dimensions = this.calculateImageOrLabelDimensions_(
              image.width,
              image.height,
              pixelCoordinates[d],
              pixelCoordinates[d + 1],
              width,
              height,
              anchorX,
              anchorY,
              originX,
              originY,
              rotation,
              scale2,
              snapToPixel,
              padding,
              !!backgroundFillInstruction || !!backgroundStrokeInstruction,
              feature
            );
            const args = [
              context,
              scaledCanvasSize,
              image,
              dimensions,
              opacity,
              backgroundFillInstruction,
              backgroundStrokeInstruction
            ];
            if (declutterTree) {
              let imageArgs, imageDeclutterMode, imageDeclutterBox;
              if (declutterImageWithText) {
                const index = dd - d;
                if (!declutterImageWithText[index]) {
                  declutterImageWithText[index] = { args, declutterMode };
                  continue;
                }
                const imageDeclutter = declutterImageWithText[index];
                imageArgs = imageDeclutter.args;
                imageDeclutterMode = imageDeclutter.declutterMode;
                delete declutterImageWithText[index];
                imageDeclutterBox = getDeclutterBox(imageArgs);
              }
              let renderImage, renderText;
              if (imageArgs && (imageDeclutterMode !== "declutter" || !declutterTree.collides(imageDeclutterBox))) {
                renderImage = true;
              }
              if (declutterMode !== "declutter" || !declutterTree.collides(dimensions.declutterBox)) {
                renderText = true;
              }
              if (imageDeclutterMode === "declutter" && declutterMode === "declutter") {
                const render2 = renderImage && renderText;
                renderImage = render2;
                renderText = render2;
              }
              if (renderImage) {
                if (imageDeclutterMode !== "none") {
                  declutterTree.insert(imageDeclutterBox);
                }
                this.replayImageOrLabel_.apply(this, imageArgs);
              }
              if (renderText) {
                if (declutterMode !== "none") {
                  declutterTree.insert(dimensions.declutterBox);
                }
                this.replayImageOrLabel_.apply(this, args);
              }
            } else {
              this.replayImageOrLabel_.apply(this, args);
            }
          }
          ++i;
          break;
        case Instruction.DRAW_CHARS:
          const begin = (
            /** @type {number} */
            instruction[1]
          );
          const end = (
            /** @type {number} */
            instruction[2]
          );
          const baseline = (
            /** @type {number} */
            instruction[3]
          );
          const overflow = (
            /** @type {number} */
            instruction[4]
          );
          fillKey = /** @type {string} */
          instruction[5];
          const maxAngle = (
            /** @type {number} */
            instruction[6]
          );
          const measurePixelRatio = (
            /** @type {number} */
            instruction[7]
          );
          const offsetY = (
            /** @type {number} */
            instruction[8]
          );
          strokeKey = /** @type {string} */
          instruction[9];
          const strokeWidth = (
            /** @type {number} */
            instruction[10]
          );
          text = /** @type {string|Array<string>} */
          instruction[11];
          if (Array.isArray(text)) {
            text = text.reduce(richTextToPlainText, "");
          }
          textKey = /** @type {string} */
          instruction[12];
          const pixelRatioScale = [
            /** @type {number} */
            instruction[13],
            /** @type {number} */
            instruction[13]
          ];
          declutterMode = instruction[14] || "declutter";
          const textKeepUpright = (
            /** @type {boolean} */
            instruction[15]
          );
          const textState = this.textStates[textKey];
          const font = textState.font;
          const textScale = [
            textState.scale[0] * measurePixelRatio,
            textState.scale[1] * measurePixelRatio
          ];
          let cachedWidths;
          if (font in this.widths_) {
            cachedWidths = this.widths_[font];
          } else {
            cachedWidths = {};
            this.widths_[font] = cachedWidths;
          }
          const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);
          const textLength = Math.abs(textScale[0]) * measureAndCacheTextWidth(font, text, cachedWidths);
          if (overflow || textLength <= pathLength) {
            const textAlign = this.textStates[textKey].textAlign;
            const startM = (pathLength - textLength) * horizontalTextAlign(text, textAlign);
            const parts = drawTextOnPath(
              pixelCoordinates,
              begin,
              end,
              2,
              text,
              startM,
              maxAngle,
              Math.abs(textScale[0]),
              measureAndCacheTextWidth,
              font,
              cachedWidths,
              viewRotationFromTransform ? 0 : this.viewRotation_,
              textKeepUpright
            );
            drawChars: if (parts) {
              const replayImageOrLabelArgs = [];
              let c, cc, chars, label, part;
              if (strokeKey) {
                for (c = 0, cc = parts.length; c < cc; ++c) {
                  part = parts[c];
                  chars = /** @type {string} */
                  part[4];
                  label = this.createLabel(chars, textKey, "", strokeKey);
                  anchorX = /** @type {number} */
                  part[2] + (textScale[0] < 0 ? -strokeWidth : strokeWidth);
                  anchorY = baseline * label.height + (0.5 - baseline) * 2 * strokeWidth * textScale[1] / textScale[0] - offsetY;
                  const dimensions = this.calculateImageOrLabelDimensions_(
                    label.width,
                    label.height,
                    part[0],
                    part[1],
                    label.width,
                    label.height,
                    anchorX,
                    anchorY,
                    0,
                    0,
                    part[3],
                    pixelRatioScale,
                    false,
                    defaultPadding,
                    false,
                    feature
                  );
                  if (declutterTree && declutterMode === "declutter" && declutterTree.collides(dimensions.declutterBox)) {
                    break drawChars;
                  }
                  replayImageOrLabelArgs.push([
                    context,
                    scaledCanvasSize,
                    label,
                    dimensions,
                    1,
                    null,
                    null
                  ]);
                }
              }
              if (fillKey) {
                for (c = 0, cc = parts.length; c < cc; ++c) {
                  part = parts[c];
                  chars = /** @type {string} */
                  part[4];
                  label = this.createLabel(chars, textKey, fillKey, "");
                  anchorX = /** @type {number} */
                  part[2];
                  anchorY = baseline * label.height - offsetY;
                  const dimensions = this.calculateImageOrLabelDimensions_(
                    label.width,
                    label.height,
                    part[0],
                    part[1],
                    label.width,
                    label.height,
                    anchorX,
                    anchorY,
                    0,
                    0,
                    part[3],
                    pixelRatioScale,
                    false,
                    defaultPadding,
                    false,
                    feature
                  );
                  if (declutterTree && declutterMode === "declutter" && declutterTree.collides(dimensions.declutterBox)) {
                    break drawChars;
                  }
                  replayImageOrLabelArgs.push([
                    context,
                    scaledCanvasSize,
                    label,
                    dimensions,
                    1,
                    null,
                    null
                  ]);
                }
              }
              if (declutterTree && declutterMode !== "none") {
                declutterTree.load(replayImageOrLabelArgs.map(getDeclutterBox));
              }
              for (let i2 = 0, ii2 = replayImageOrLabelArgs.length; i2 < ii2; ++i2) {
                this.replayImageOrLabel_.apply(this, replayImageOrLabelArgs[i2]);
              }
            }
          }
          ++i;
          break;
        case Instruction.END_GEOMETRY:
          if (featureCallback !== void 0) {
            feature = /** @type {import("../../Feature.js").FeatureLike} */
            instruction[1];
            const result = featureCallback(
              feature,
              currentGeometry,
              declutterMode
            );
            if (result) {
              return result;
            }
          }
          ++i;
          break;
        case Instruction.FILL:
          if (batchSize) {
            pendingFill++;
          } else {
            this.fill_(context);
          }
          ++i;
          break;
        case Instruction.MOVE_TO_LINE_TO:
          d = /** @type {number} */
          instruction[1];
          dd = /** @type {number} */
          instruction[2];
          x = pixelCoordinates[d];
          y = pixelCoordinates[d + 1];
          context.moveTo(x, y);
          prevX = x + 0.5 | 0;
          prevY = y + 0.5 | 0;
          for (d += 2; d < dd; d += 2) {
            x = pixelCoordinates[d];
            y = pixelCoordinates[d + 1];
            roundX = x + 0.5 | 0;
            roundY = y + 0.5 | 0;
            if (d == dd - 2 || roundX !== prevX || roundY !== prevY) {
              context.lineTo(x, y);
              prevX = roundX;
              prevY = roundY;
            }
          }
          ++i;
          break;
        case Instruction.SET_FILL_STYLE:
          this.alignAndScaleFill_ = instruction[2];
          if (pendingFill) {
            this.fill_(context);
            pendingFill = 0;
            if (pendingStroke) {
              context.stroke();
              pendingStroke = 0;
            }
          }
          context.fillStyle = instruction[1];
          ++i;
          break;
        case Instruction.SET_STROKE_STYLE:
          if (pendingStroke) {
            context.stroke();
            pendingStroke = 0;
          }
          this.setStrokeStyle_(
            context,
            /** @type {Array<*>} */
            instruction
          );
          ++i;
          break;
        case Instruction.STROKE:
          if (batchSize) {
            pendingStroke++;
          } else {
            context.stroke();
          }
          ++i;
          break;
        default:
          ++i;
          break;
      }
    }
    if (pendingFill) {
      this.fill_(context);
    }
    if (pendingStroke) {
      context.stroke();
    }
    return void 0;
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import('../../size.js').Size} scaledCanvasSize Scaled canvas size.
   * @param {import("../../transform.js").Transform} transform Transform.
   * @param {number} viewRotation View rotation.
   * @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
   * @param {import("rbush").default<DeclutterEntry>} [declutterTree] Declutter tree.
   */
  execute(context, scaledCanvasSize, transform2, viewRotation, snapToPixel, declutterTree) {
    this.viewRotation_ = viewRotation;
    this.execute_(
      context,
      scaledCanvasSize,
      transform2,
      this.instructions,
      snapToPixel,
      void 0,
      void 0,
      declutterTree
    );
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../transform.js").Transform} transform Transform.
   * @param {number} viewRotation View rotation.
   * @param {FeatureCallback<T>} [featureCallback] Feature callback.
   * @param {import("../../extent.js").Extent} [hitExtent] Only check
   *     features that intersect this extent.
   * @return {T|undefined} Callback result.
   * @template T
   */
  executeHitDetection(context, transform2, viewRotation, featureCallback, hitExtent) {
    this.viewRotation_ = viewRotation;
    return this.execute_(
      context,
      [context.canvas.width, context.canvas.height],
      transform2,
      this.hitDetectionInstructions,
      true,
      featureCallback,
      hitExtent
    );
  }
}
const ALL = [
  "Polygon",
  "Circle",
  "LineString",
  "Image",
  "Text",
  "Default"
];
const DECLUTTER = ["Image", "Text"];
const NON_DECLUTTER = ALL.filter(
  (builderType) => !DECLUTTER.includes(builderType)
);
class ExecutorGroup {
  /**
   * @param {import("../../extent.js").Extent} maxExtent Max extent for clipping. When a
   * `maxExtent` was set on the Builder for this executor group, the same `maxExtent`
   * should be set here, unless the target context does not exceed that extent (which
   * can be the case when rendering to tiles).
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   * @param {boolean} overlaps The executor group can have overlapping geometries.
   * @param {!Object<string, !Object<import("../canvas.js").BuilderType, import("../canvas.js").SerializableInstructions>>} allInstructions
   * The serializable instructions.
   * @param {number} [renderBuffer] Optional rendering buffer.
   * @param {boolean} [deferredRendering] Enable deferred rendering with renderDeferred().
   */
  constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, renderBuffer, deferredRendering) {
    this.maxExtent_ = maxExtent;
    this.overlaps_ = overlaps;
    this.pixelRatio_ = pixelRatio;
    this.resolution_ = resolution;
    this.renderBuffer_ = renderBuffer;
    this.executorsByZIndex_ = {};
    this.hitDetectionContext_ = null;
    this.hitDetectionTransform_ = create();
    this.renderedContext_ = null;
    this.deferredZIndexContexts_ = {};
    this.createExecutors_(allInstructions, deferredRendering);
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../transform.js").Transform} transform Transform.
   */
  clip(context, transform2) {
    const flatClipCoords = this.getClipCoords(transform2);
    context.beginPath();
    context.moveTo(flatClipCoords[0], flatClipCoords[1]);
    context.lineTo(flatClipCoords[2], flatClipCoords[3]);
    context.lineTo(flatClipCoords[4], flatClipCoords[5]);
    context.lineTo(flatClipCoords[6], flatClipCoords[7]);
    context.clip();
  }
  /**
   * Create executors and populate them using the provided instructions.
   * @private
   * @param {!Object<string, !Object<string, import("../canvas.js").SerializableInstructions>>} allInstructions The serializable instructions
   * @param {boolean} deferredRendering Enable deferred rendering.
   */
  createExecutors_(allInstructions, deferredRendering) {
    for (const zIndex in allInstructions) {
      let executors = this.executorsByZIndex_[zIndex];
      if (executors === void 0) {
        executors = {};
        this.executorsByZIndex_[zIndex] = executors;
      }
      const instructionByZindex = allInstructions[zIndex];
      for (const builderType in instructionByZindex) {
        const instructions = instructionByZindex[builderType];
        executors[builderType] = new Executor(
          this.resolution_,
          this.pixelRatio_,
          this.overlaps_,
          instructions,
          deferredRendering
        );
      }
    }
  }
  /**
   * @param {Array<import("../canvas.js").BuilderType>} executors Executors.
   * @return {boolean} Has executors of the provided types.
   */
  hasExecutors(executors) {
    for (const zIndex in this.executorsByZIndex_) {
      const candidates = this.executorsByZIndex_[zIndex];
      for (let i = 0, ii = executors.length; i < ii; ++i) {
        if (executors[i] in candidates) {
          return true;
        }
      }
    }
    return false;
  }
  /**
   * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {number} resolution Resolution.
   * @param {number} rotation Rotation.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {function(import("../../Feature.js").FeatureLike, import("../../geom/SimpleGeometry.js").default, number): T} callback Feature callback.
   * @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features.
   * @return {T|undefined} Callback result.
   * @template T
   */
  forEachFeatureAtCoordinate(coordinate, resolution, rotation, hitTolerance, callback, declutteredFeatures) {
    hitTolerance = Math.round(hitTolerance);
    const contextSize = hitTolerance * 2 + 1;
    const transform2 = compose(
      this.hitDetectionTransform_,
      hitTolerance + 0.5,
      hitTolerance + 0.5,
      1 / resolution,
      -1 / resolution,
      -rotation,
      -coordinate[0],
      -coordinate[1]
    );
    const newContext = !this.hitDetectionContext_;
    if (newContext) {
      this.hitDetectionContext_ = createCanvasContext2D(
        contextSize,
        contextSize
      );
    }
    const context = this.hitDetectionContext_;
    if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
      context.canvas.width = contextSize;
      context.canvas.height = contextSize;
    } else if (!newContext) {
      context.clearRect(0, 0, contextSize, contextSize);
    }
    let hitExtent;
    if (this.renderBuffer_ !== void 0) {
      hitExtent = createEmpty();
      extendCoordinate(hitExtent, coordinate);
      buffer(
        hitExtent,
        resolution * (this.renderBuffer_ + hitTolerance),
        hitExtent
      );
    }
    const indexes = getPixelIndexArray(hitTolerance);
    let builderType;
    function featureCallback(feature, geometry, declutterMode) {
      const imageData = context.getImageData(
        0,
        0,
        contextSize,
        contextSize
      ).data;
      for (let i2 = 0, ii = indexes.length; i2 < ii; i2++) {
        if (imageData[indexes[i2]] > 0) {
          if (!declutteredFeatures || declutterMode === "none" || builderType !== "Image" && builderType !== "Text" || declutteredFeatures.includes(feature)) {
            const idx = (indexes[i2] - 3) / 4;
            const x = hitTolerance - idx % contextSize;
            const y = hitTolerance - (idx / contextSize | 0);
            const result2 = callback(feature, geometry, x * x + y * y);
            if (result2) {
              return result2;
            }
          }
          context.clearRect(0, 0, contextSize, contextSize);
          break;
        }
      }
      return void 0;
    }
    const zs = Object.keys(this.executorsByZIndex_).map(Number);
    zs.sort(ascending);
    let i, j, executors, executor, result;
    for (i = zs.length - 1; i >= 0; --i) {
      const zIndexKey = zs[i].toString();
      executors = this.executorsByZIndex_[zIndexKey];
      for (j = ALL.length - 1; j >= 0; --j) {
        builderType = ALL[j];
        executor = executors[builderType];
        if (executor !== void 0) {
          result = executor.executeHitDetection(
            context,
            transform2,
            rotation,
            featureCallback,
            hitExtent
          );
          if (result) {
            return result;
          }
        }
      }
    }
    return void 0;
  }
  /**
   * @param {import("../../transform.js").Transform} transform Transform.
   * @return {Array<number>|null} Clip coordinates.
   */
  getClipCoords(transform2) {
    const maxExtent = this.maxExtent_;
    if (!maxExtent) {
      return null;
    }
    const minX = maxExtent[0];
    const minY = maxExtent[1];
    const maxX = maxExtent[2];
    const maxY = maxExtent[3];
    const flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];
    transform2D(flatClipCoords, 0, 8, 2, transform2, flatClipCoords);
    return flatClipCoords;
  }
  /**
   * @return {boolean} Is empty.
   */
  isEmpty() {
    return isEmpty$1(this.executorsByZIndex_);
  }
  /**
   * @param {CanvasRenderingContext2D} targetContext Context.
   * @param {import('../../size.js').Size} scaledCanvasSize Scale of the context.
   * @param {import("../../transform.js").Transform} transform Transform.
   * @param {number} viewRotation View rotation.
   * @param {boolean} snapToPixel Snap point symbols and test to integer pixel.
   * @param {Array<import("../canvas.js").BuilderType>} [builderTypes] Ordered replay types to replay.
   *     Default is {@link module:ol/render/replay~ALL}
   * @param {import("rbush").default<import('./Executor.js').DeclutterEntry>|null} [declutterTree] Declutter tree.
   *     When set to null, no decluttering is done, even when the executor group has a `ZIndexContext`.
   */
  execute(targetContext, scaledCanvasSize, transform2, viewRotation, snapToPixel, builderTypes, declutterTree) {
    const zs = Object.keys(this.executorsByZIndex_).map(Number);
    zs.sort(declutterTree ? descending : ascending);
    builderTypes = builderTypes ? builderTypes : ALL;
    const maxBuilderTypes = ALL.length;
    for (let i = 0, ii = zs.length; i < ii; ++i) {
      const zIndexKey = zs[i].toString();
      const replays = this.executorsByZIndex_[zIndexKey];
      for (let j = 0, jj = builderTypes.length; j < jj; ++j) {
        const builderType = builderTypes[j];
        const replay = replays[builderType];
        if (replay !== void 0) {
          const zIndexContext = declutterTree === null ? void 0 : replay.getZIndexContext();
          const context = zIndexContext ? zIndexContext.getContext() : targetContext;
          const requireClip = this.maxExtent_ && builderType !== "Image" && builderType !== "Text";
          if (requireClip) {
            context.save();
            this.clip(context, transform2);
          }
          if (!zIndexContext || builderType === "Text" || builderType === "Image") {
            replay.execute(
              context,
              scaledCanvasSize,
              transform2,
              viewRotation,
              snapToPixel,
              declutterTree
            );
          } else {
            zIndexContext.pushFunction(
              (context2) => replay.execute(
                context2,
                scaledCanvasSize,
                transform2,
                viewRotation,
                snapToPixel,
                declutterTree
              )
            );
          }
          if (requireClip) {
            context.restore();
          }
          if (zIndexContext) {
            zIndexContext.offset();
            const index = zs[i] * maxBuilderTypes + ALL.indexOf(builderType);
            if (!this.deferredZIndexContexts_[index]) {
              this.deferredZIndexContexts_[index] = [];
            }
            this.deferredZIndexContexts_[index].push(zIndexContext);
          }
        }
      }
    }
    this.renderedContext_ = targetContext;
  }
  getDeferredZIndexContexts() {
    return this.deferredZIndexContexts_;
  }
  getRenderedContext() {
    return this.renderedContext_;
  }
  renderDeferred() {
    const deferredZIndexContexts = this.deferredZIndexContexts_;
    const zs = Object.keys(deferredZIndexContexts).map(Number).sort(ascending);
    for (let i = 0, ii = zs.length; i < ii; ++i) {
      deferredZIndexContexts[zs[i]].forEach((zIndexContext) => {
        zIndexContext.draw(this.renderedContext_);
        zIndexContext.clear();
      });
      deferredZIndexContexts[zs[i]].length = 0;
    }
  }
}
const circlePixelIndexArrayCache = {};
function getPixelIndexArray(radius) {
  if (circlePixelIndexArrayCache[radius] !== void 0) {
    return circlePixelIndexArrayCache[radius];
  }
  const size = radius * 2 + 1;
  const maxDistanceSq = radius * radius;
  const distances = new Array(maxDistanceSq + 1);
  for (let i = 0; i <= radius; ++i) {
    for (let j = 0; j <= radius; ++j) {
      const distanceSq = i * i + j * j;
      if (distanceSq > maxDistanceSq) {
        break;
      }
      let distance = distances[distanceSq];
      if (!distance) {
        distance = [];
        distances[distanceSq] = distance;
      }
      distance.push(((radius + i) * size + (radius + j)) * 4 + 3);
      if (i > 0) {
        distance.push(((radius - i) * size + (radius + j)) * 4 + 3);
      }
      if (j > 0) {
        distance.push(((radius + i) * size + (radius - j)) * 4 + 3);
        if (i > 0) {
          distance.push(((radius - i) * size + (radius - j)) * 4 + 3);
        }
      }
    }
  }
  const pixelIndex = [];
  for (let i = 0, ii = distances.length; i < ii; ++i) {
    if (distances[i]) {
      pixelIndex.push(...distances[i]);
    }
  }
  circlePixelIndexArrayCache[radius] = pixelIndex;
  return pixelIndex;
}
class CanvasImmediateRenderer extends VectorContext {
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../../extent.js").Extent} extent Extent.
   * @param {import("../../transform.js").Transform} transform Transform.
   * @param {number} viewRotation View rotation.
   * @param {number} [squaredTolerance] Optional squared tolerance for simplification.
   * @param {import("../../proj.js").TransformFunction} [userTransform] Transform from user to view projection.
   */
  constructor(context, pixelRatio, extent, transform2, viewRotation, squaredTolerance, userTransform) {
    super();
    this.context_ = context;
    this.pixelRatio_ = pixelRatio;
    this.extent_ = extent;
    this.transform_ = transform2;
    this.transformRotation_ = transform2 ? toFixed(Math.atan2(transform2[1], transform2[0]), 10) : 0;
    this.viewRotation_ = viewRotation;
    this.squaredTolerance_ = squaredTolerance;
    this.userTransform_ = userTransform;
    this.contextFillState_ = null;
    this.contextStrokeState_ = null;
    this.contextTextState_ = null;
    this.fillState_ = null;
    this.strokeState_ = null;
    this.image_ = null;
    this.imageAnchorX_ = 0;
    this.imageAnchorY_ = 0;
    this.imageHeight_ = 0;
    this.imageOpacity_ = 0;
    this.imageOriginX_ = 0;
    this.imageOriginY_ = 0;
    this.imageRotateWithView_ = false;
    this.imageRotation_ = 0;
    this.imageScale_ = [0, 0];
    this.imageWidth_ = 0;
    this.text_ = "";
    this.textOffsetX_ = 0;
    this.textOffsetY_ = 0;
    this.textRotateWithView_ = false;
    this.textRotation_ = 0;
    this.textScale_ = [0, 0];
    this.textFillState_ = null;
    this.textStrokeState_ = null;
    this.textState_ = null;
    this.pixelCoordinates_ = [];
    this.tmpLocalTransform_ = create();
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @private
   */
  drawImages_(flatCoordinates, offset2, end, stride) {
    if (!this.image_) {
      return;
    }
    const pixelCoordinates = transform2D(
      flatCoordinates,
      offset2,
      end,
      stride,
      this.transform_,
      this.pixelCoordinates_
    );
    const context = this.context_;
    const localTransform = this.tmpLocalTransform_;
    const alpha = context.globalAlpha;
    if (this.imageOpacity_ != 1) {
      context.globalAlpha = alpha * this.imageOpacity_;
    }
    let rotation = this.imageRotation_;
    if (this.transformRotation_ === 0) {
      rotation -= this.viewRotation_;
    }
    if (this.imageRotateWithView_) {
      rotation += this.viewRotation_;
    }
    for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {
      const x = pixelCoordinates[i] - this.imageAnchorX_;
      const y = pixelCoordinates[i + 1] - this.imageAnchorY_;
      if (rotation !== 0 || this.imageScale_[0] != 1 || this.imageScale_[1] != 1) {
        const centerX = x + this.imageAnchorX_;
        const centerY = y + this.imageAnchorY_;
        compose(
          localTransform,
          centerX,
          centerY,
          1,
          1,
          rotation,
          -centerX,
          -centerY
        );
        context.save();
        context.transform.apply(context, localTransform);
        context.translate(centerX, centerY);
        context.scale(this.imageScale_[0], this.imageScale_[1]);
        context.drawImage(
          this.image_,
          this.imageOriginX_,
          this.imageOriginY_,
          this.imageWidth_,
          this.imageHeight_,
          -this.imageAnchorX_,
          -this.imageAnchorY_,
          this.imageWidth_,
          this.imageHeight_
        );
        context.restore();
      } else {
        context.drawImage(
          this.image_,
          this.imageOriginX_,
          this.imageOriginY_,
          this.imageWidth_,
          this.imageHeight_,
          x,
          y,
          this.imageWidth_,
          this.imageHeight_
        );
      }
    }
    if (this.imageOpacity_ != 1) {
      context.globalAlpha = alpha;
    }
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @private
   */
  drawText_(flatCoordinates, offset2, end, stride) {
    if (!this.textState_ || this.text_ === "") {
      return;
    }
    if (this.textFillState_) {
      this.setContextFillState_(this.textFillState_);
    }
    if (this.textStrokeState_) {
      this.setContextStrokeState_(this.textStrokeState_);
    }
    this.setContextTextState_(this.textState_);
    const pixelCoordinates = transform2D(
      flatCoordinates,
      offset2,
      end,
      stride,
      this.transform_,
      this.pixelCoordinates_
    );
    const context = this.context_;
    let rotation = this.textRotation_;
    if (this.transformRotation_ === 0) {
      rotation -= this.viewRotation_;
    }
    if (this.textRotateWithView_) {
      rotation += this.viewRotation_;
    }
    for (; offset2 < end; offset2 += stride) {
      const x = pixelCoordinates[offset2] + this.textOffsetX_;
      const y = pixelCoordinates[offset2 + 1] + this.textOffsetY_;
      if (rotation !== 0 || this.textScale_[0] != 1 || this.textScale_[1] != 1) {
        context.save();
        context.translate(x - this.textOffsetX_, y - this.textOffsetY_);
        context.rotate(rotation);
        context.translate(this.textOffsetX_, this.textOffsetY_);
        context.scale(this.textScale_[0], this.textScale_[1]);
        if (this.textStrokeState_) {
          context.strokeText(this.text_, 0, 0);
        }
        if (this.textFillState_) {
          context.fillText(this.text_, 0, 0);
        }
        context.restore();
      } else {
        if (this.textStrokeState_) {
          context.strokeText(this.text_, x, y);
        }
        if (this.textFillState_) {
          context.fillText(this.text_, x, y);
        }
      }
    }
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {number} end End.
   * @param {number} stride Stride.
   * @param {boolean} close Close.
   * @private
   * @return {number} end End.
   */
  moveToLineTo_(flatCoordinates, offset2, end, stride, close2) {
    const context = this.context_;
    const pixelCoordinates = transform2D(
      flatCoordinates,
      offset2,
      end,
      stride,
      this.transform_,
      this.pixelCoordinates_
    );
    context.moveTo(pixelCoordinates[0], pixelCoordinates[1]);
    let length = pixelCoordinates.length;
    if (close2) {
      length -= 2;
    }
    for (let i = 2; i < length; i += 2) {
      context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]);
    }
    if (close2) {
      context.closePath();
    }
    return end;
  }
  /**
   * @param {Array<number>} flatCoordinates Flat coordinates.
   * @param {number} offset Offset.
   * @param {Array<number>} ends Ends.
   * @param {number} stride Stride.
   * @private
   * @return {number} End.
   */
  drawRings_(flatCoordinates, offset2, ends, stride) {
    for (let i = 0, ii = ends.length; i < ii; ++i) {
      offset2 = this.moveToLineTo_(
        flatCoordinates,
        offset2,
        ends[i],
        stride,
        true
      );
    }
    return offset2;
  }
  /**
   * Render a circle geometry into the canvas.  Rendering is immediate and uses
   * the current fill and stroke styles.
   *
   * @param {import("../../geom/Circle.js").default} geometry Circle geometry.
   * @api
   * @override
   */
  drawCircle(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/Circle.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    if (!intersects$1(this.extent_, geometry.getExtent())) {
      return;
    }
    if (this.fillState_ || this.strokeState_) {
      if (this.fillState_) {
        this.setContextFillState_(this.fillState_);
      }
      if (this.strokeState_) {
        this.setContextStrokeState_(this.strokeState_);
      }
      const pixelCoordinates = transformGeom2D(
        geometry,
        this.transform_,
        this.pixelCoordinates_
      );
      const dx = pixelCoordinates[2] - pixelCoordinates[0];
      const dy = pixelCoordinates[3] - pixelCoordinates[1];
      const radius = Math.sqrt(dx * dx + dy * dy);
      const context = this.context_;
      context.beginPath();
      context.arc(
        pixelCoordinates[0],
        pixelCoordinates[1],
        radius,
        0,
        2 * Math.PI
      );
      if (this.fillState_) {
        context.fill();
      }
      if (this.strokeState_) {
        context.stroke();
      }
    }
    if (this.text_ !== "") {
      this.drawText_(geometry.getCenter(), 0, 2, 2);
    }
  }
  /**
   * Set the rendering style.  Note that since this is an immediate rendering API,
   * any `zIndex` on the provided style will be ignored.
   *
   * @param {import("../../style/Style.js").default} style The rendering style.
   * @api
   * @override
   */
  setStyle(style) {
    this.setFillStrokeStyle(style.getFill(), style.getStroke());
    this.setImageStyle(style.getImage());
    this.setTextStyle(style.getText());
  }
  /**
   * @param {import("../../transform.js").Transform} transform Transform.
   */
  setTransform(transform2) {
    this.transform_ = transform2;
  }
  /**
   * Render a geometry into the canvas.  Call
   * {@link module:ol/render/canvas/Immediate~CanvasImmediateRenderer#setStyle renderer.setStyle()} first to set the rendering style.
   *
   * @param {import("../../geom/Geometry.js").default|import("../Feature.js").default} geometry The geometry to render.
   * @api
   * @override
   */
  drawGeometry(geometry) {
    const type = geometry.getType();
    switch (type) {
      case "Point":
        this.drawPoint(
          /** @type {import("../../geom/Point.js").default} */
          geometry
        );
        break;
      case "LineString":
        this.drawLineString(
          /** @type {import("../../geom/LineString.js").default} */
          geometry
        );
        break;
      case "Polygon":
        this.drawPolygon(
          /** @type {import("../../geom/Polygon.js").default} */
          geometry
        );
        break;
      case "MultiPoint":
        this.drawMultiPoint(
          /** @type {import("../../geom/MultiPoint.js").default} */
          geometry
        );
        break;
      case "MultiLineString":
        this.drawMultiLineString(
          /** @type {import("../../geom/MultiLineString.js").default} */
          geometry
        );
        break;
      case "MultiPolygon":
        this.drawMultiPolygon(
          /** @type {import("../../geom/MultiPolygon.js").default} */
          geometry
        );
        break;
      case "GeometryCollection":
        this.drawGeometryCollection(
          /** @type {import("../../geom/GeometryCollection.js").default} */
          geometry
        );
        break;
      case "Circle":
        this.drawCircle(
          /** @type {import("../../geom/Circle.js").default} */
          geometry
        );
        break;
    }
  }
  /**
   * Render a feature into the canvas.  Note that any `zIndex` on the provided
   * style will be ignored - features are rendered immediately in the order that
   * this method is called.  If you need `zIndex` support, you should be using an
   * {@link module:ol/layer/Vector~VectorLayer} instead.
   *
   * @param {import("../../Feature.js").default} feature Feature.
   * @param {import("../../style/Style.js").default} style Style.
   * @api
   * @override
   */
  drawFeature(feature, style) {
    const geometry = style.getGeometryFunction()(feature);
    if (!geometry) {
      return;
    }
    this.setStyle(style);
    this.drawGeometry(geometry);
  }
  /**
   * Render a GeometryCollection to the canvas.  Rendering is immediate and
   * uses the current styles appropriate for each geometry in the collection.
   *
   * @param {import("../../geom/GeometryCollection.js").default} geometry Geometry collection.
   * @override
   */
  drawGeometryCollection(geometry) {
    const geometries = geometry.getGeometriesArray();
    for (let i = 0, ii = geometries.length; i < ii; ++i) {
      this.drawGeometry(geometries[i]);
    }
  }
  /**
   * Render a Point geometry into the canvas.  Rendering is immediate and uses
   * the current style.
   *
   * @param {import("../../geom/Point.js").default|import("../Feature.js").default} geometry Point geometry.
   * @override
   */
  drawPoint(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/Point.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    const flatCoordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    if (this.image_) {
      this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);
    }
    if (this.text_ !== "") {
      this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);
    }
  }
  /**
   * Render a MultiPoint geometry  into the canvas.  Rendering is immediate and
   * uses the current style.
   *
   * @param {import("../../geom/MultiPoint.js").default|import("../Feature.js").default} geometry MultiPoint geometry.
   * @override
   */
  drawMultiPoint(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/MultiPoint.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    const flatCoordinates = geometry.getFlatCoordinates();
    const stride = geometry.getStride();
    if (this.image_) {
      this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);
    }
    if (this.text_ !== "") {
      this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);
    }
  }
  /**
   * Render a LineString into the canvas.  Rendering is immediate and uses
   * the current style.
   *
   * @param {import("../../geom/LineString.js").default|import("../Feature.js").default} geometry LineString geometry.
   * @override
   */
  drawLineString(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/LineString.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    if (!intersects$1(this.extent_, geometry.getExtent())) {
      return;
    }
    if (this.strokeState_) {
      this.setContextStrokeState_(this.strokeState_);
      const context = this.context_;
      const flatCoordinates = geometry.getFlatCoordinates();
      context.beginPath();
      this.moveToLineTo_(
        flatCoordinates,
        0,
        flatCoordinates.length,
        geometry.getStride(),
        false
      );
      context.stroke();
    }
    if (this.text_ !== "") {
      const flatMidpoint = geometry.getFlatMidpoint();
      this.drawText_(flatMidpoint, 0, 2, 2);
    }
  }
  /**
   * Render a MultiLineString geometry into the canvas.  Rendering is immediate
   * and uses the current style.
   *
   * @param {import("../../geom/MultiLineString.js").default|import("../Feature.js").default} geometry MultiLineString geometry.
   * @override
   */
  drawMultiLineString(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/MultiLineString.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    const geometryExtent = geometry.getExtent();
    if (!intersects$1(this.extent_, geometryExtent)) {
      return;
    }
    if (this.strokeState_) {
      this.setContextStrokeState_(this.strokeState_);
      const context = this.context_;
      const flatCoordinates = geometry.getFlatCoordinates();
      let offset2 = 0;
      const ends = (
        /** @type {Array<number>} */
        geometry.getEnds()
      );
      const stride = geometry.getStride();
      context.beginPath();
      for (let i = 0, ii = ends.length; i < ii; ++i) {
        offset2 = this.moveToLineTo_(
          flatCoordinates,
          offset2,
          ends[i],
          stride,
          false
        );
      }
      context.stroke();
    }
    if (this.text_ !== "") {
      const flatMidpoints = geometry.getFlatMidpoints();
      this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2);
    }
  }
  /**
   * Render a Polygon geometry into the canvas.  Rendering is immediate and uses
   * the current style.
   *
   * @param {import("../../geom/Polygon.js").default|import("../Feature.js").default} geometry Polygon geometry.
   * @override
   */
  drawPolygon(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/Polygon.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    if (!intersects$1(this.extent_, geometry.getExtent())) {
      return;
    }
    if (this.strokeState_ || this.fillState_) {
      if (this.fillState_) {
        this.setContextFillState_(this.fillState_);
      }
      if (this.strokeState_) {
        this.setContextStrokeState_(this.strokeState_);
      }
      const context = this.context_;
      context.beginPath();
      this.drawRings_(
        geometry.getOrientedFlatCoordinates(),
        0,
        /** @type {Array<number>} */
        geometry.getEnds(),
        geometry.getStride()
      );
      if (this.fillState_) {
        context.fill();
      }
      if (this.strokeState_) {
        context.stroke();
      }
    }
    if (this.text_ !== "") {
      const flatInteriorPoint = geometry.getFlatInteriorPoint();
      this.drawText_(flatInteriorPoint, 0, 2, 2);
    }
  }
  /**
   * Render MultiPolygon geometry into the canvas.  Rendering is immediate and
   * uses the current style.
   * @param {import("../../geom/MultiPolygon.js").default} geometry MultiPolygon geometry.
   * @override
   */
  drawMultiPolygon(geometry) {
    if (this.squaredTolerance_) {
      geometry = /** @type {import("../../geom/MultiPolygon.js").default} */
      geometry.simplifyTransformed(
        this.squaredTolerance_,
        this.userTransform_
      );
    }
    if (!intersects$1(this.extent_, geometry.getExtent())) {
      return;
    }
    if (this.strokeState_ || this.fillState_) {
      if (this.fillState_) {
        this.setContextFillState_(this.fillState_);
      }
      if (this.strokeState_) {
        this.setContextStrokeState_(this.strokeState_);
      }
      const context = this.context_;
      const flatCoordinates = geometry.getOrientedFlatCoordinates();
      let offset2 = 0;
      const endss = geometry.getEndss();
      const stride = geometry.getStride();
      context.beginPath();
      for (let i = 0, ii = endss.length; i < ii; ++i) {
        const ends = endss[i];
        offset2 = this.drawRings_(flatCoordinates, offset2, ends, stride);
      }
      if (this.fillState_) {
        context.fill();
      }
      if (this.strokeState_) {
        context.stroke();
      }
    }
    if (this.text_ !== "") {
      const flatInteriorPoints = geometry.getFlatInteriorPoints();
      this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2);
    }
  }
  /**
   * @param {import("../canvas.js").FillState} fillState Fill state.
   * @private
   */
  setContextFillState_(fillState) {
    const context = this.context_;
    const contextFillState = this.contextFillState_;
    if (!contextFillState) {
      context.fillStyle = fillState.fillStyle;
      this.contextFillState_ = {
        fillStyle: fillState.fillStyle
      };
    } else {
      if (contextFillState.fillStyle != fillState.fillStyle) {
        contextFillState.fillStyle = fillState.fillStyle;
        context.fillStyle = fillState.fillStyle;
      }
    }
  }
  /**
   * @param {import("../canvas.js").StrokeState} strokeState Stroke state.
   * @private
   */
  setContextStrokeState_(strokeState) {
    const context = this.context_;
    const contextStrokeState = this.contextStrokeState_;
    if (!contextStrokeState) {
      context.lineCap = strokeState.lineCap;
      context.setLineDash(strokeState.lineDash);
      context.lineDashOffset = strokeState.lineDashOffset;
      context.lineJoin = strokeState.lineJoin;
      context.lineWidth = strokeState.lineWidth;
      context.miterLimit = strokeState.miterLimit;
      context.strokeStyle = strokeState.strokeStyle;
      this.contextStrokeState_ = {
        lineCap: strokeState.lineCap,
        lineDash: strokeState.lineDash,
        lineDashOffset: strokeState.lineDashOffset,
        lineJoin: strokeState.lineJoin,
        lineWidth: strokeState.lineWidth,
        miterLimit: strokeState.miterLimit,
        strokeStyle: strokeState.strokeStyle
      };
    } else {
      if (contextStrokeState.lineCap != strokeState.lineCap) {
        contextStrokeState.lineCap = strokeState.lineCap;
        context.lineCap = strokeState.lineCap;
      }
      if (!equals$2(contextStrokeState.lineDash, strokeState.lineDash)) {
        context.setLineDash(
          contextStrokeState.lineDash = strokeState.lineDash
        );
      }
      if (contextStrokeState.lineDashOffset != strokeState.lineDashOffset) {
        contextStrokeState.lineDashOffset = strokeState.lineDashOffset;
        context.lineDashOffset = strokeState.lineDashOffset;
      }
      if (contextStrokeState.lineJoin != strokeState.lineJoin) {
        contextStrokeState.lineJoin = strokeState.lineJoin;
        context.lineJoin = strokeState.lineJoin;
      }
      if (contextStrokeState.lineWidth != strokeState.lineWidth) {
        contextStrokeState.lineWidth = strokeState.lineWidth;
        context.lineWidth = strokeState.lineWidth;
      }
      if (contextStrokeState.miterLimit != strokeState.miterLimit) {
        contextStrokeState.miterLimit = strokeState.miterLimit;
        context.miterLimit = strokeState.miterLimit;
      }
      if (contextStrokeState.strokeStyle != strokeState.strokeStyle) {
        contextStrokeState.strokeStyle = strokeState.strokeStyle;
        context.strokeStyle = strokeState.strokeStyle;
      }
    }
  }
  /**
   * @param {import("../canvas.js").TextState} textState Text state.
   * @private
   */
  setContextTextState_(textState) {
    const context = this.context_;
    const contextTextState = this.contextTextState_;
    const textAlign = textState.textAlign ? textState.textAlign : defaultTextAlign;
    if (!contextTextState) {
      context.font = textState.font;
      context.textAlign = textAlign;
      context.textBaseline = textState.textBaseline;
      this.contextTextState_ = {
        font: textState.font,
        textAlign,
        textBaseline: textState.textBaseline
      };
    } else {
      if (contextTextState.font != textState.font) {
        contextTextState.font = textState.font;
        context.font = textState.font;
      }
      if (contextTextState.textAlign != textAlign) {
        contextTextState.textAlign = textAlign;
        context.textAlign = textAlign;
      }
      if (contextTextState.textBaseline != textState.textBaseline) {
        contextTextState.textBaseline = textState.textBaseline;
        context.textBaseline = textState.textBaseline;
      }
    }
  }
  /**
   * Set the fill and stroke style for subsequent draw operations.  To clear
   * either fill or stroke styles, pass null for the appropriate parameter.
   *
   * @param {import("../../style/Fill.js").default} fillStyle Fill style.
   * @param {import("../../style/Stroke.js").default} strokeStyle Stroke style.
   * @override
   */
  setFillStrokeStyle(fillStyle, strokeStyle) {
    if (!fillStyle) {
      this.fillState_ = null;
    } else {
      const fillStyleColor = fillStyle.getColor();
      this.fillState_ = {
        fillStyle: asColorLike(
          fillStyleColor ? fillStyleColor : defaultFillStyle
        )
      };
    }
    if (!strokeStyle) {
      this.strokeState_ = null;
    } else {
      const strokeStyleColor = strokeStyle.getColor();
      const strokeStyleLineCap = strokeStyle.getLineCap();
      const strokeStyleLineDash = strokeStyle.getLineDash();
      const strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
      const strokeStyleLineJoin = strokeStyle.getLineJoin();
      const strokeStyleWidth = strokeStyle.getWidth();
      const strokeStyleMiterLimit = strokeStyle.getMiterLimit();
      const lineDash = strokeStyleLineDash ? strokeStyleLineDash : defaultLineDash;
      this.strokeState_ = {
        lineCap: strokeStyleLineCap !== void 0 ? strokeStyleLineCap : defaultLineCap,
        lineDash: this.pixelRatio_ === 1 ? lineDash : lineDash.map((n) => n * this.pixelRatio_),
        lineDashOffset: (strokeStyleLineDashOffset ? strokeStyleLineDashOffset : defaultLineDashOffset) * this.pixelRatio_,
        lineJoin: strokeStyleLineJoin !== void 0 ? strokeStyleLineJoin : defaultLineJoin,
        lineWidth: (strokeStyleWidth !== void 0 ? strokeStyleWidth : defaultLineWidth) * this.pixelRatio_,
        miterLimit: strokeStyleMiterLimit !== void 0 ? strokeStyleMiterLimit : defaultMiterLimit,
        strokeStyle: asColorLike(
          strokeStyleColor ? strokeStyleColor : defaultStrokeStyle
        )
      };
    }
  }
  /**
   * Set the image style for subsequent draw operations.  Pass null to remove
   * the image style.
   *
   * @param {import("../../style/Image.js").default} imageStyle Image style.
   * @override
   */
  setImageStyle(imageStyle) {
    let imageSize;
    if (!imageStyle || !(imageSize = imageStyle.getSize())) {
      this.image_ = null;
      return;
    }
    const imagePixelRatio = imageStyle.getPixelRatio(this.pixelRatio_);
    const imageAnchor = imageStyle.getAnchor();
    const imageOrigin = imageStyle.getOrigin();
    this.image_ = imageStyle.getImage(this.pixelRatio_);
    this.imageAnchorX_ = imageAnchor[0] * imagePixelRatio;
    this.imageAnchorY_ = imageAnchor[1] * imagePixelRatio;
    this.imageHeight_ = imageSize[1] * imagePixelRatio;
    this.imageOpacity_ = imageStyle.getOpacity();
    this.imageOriginX_ = imageOrigin[0];
    this.imageOriginY_ = imageOrigin[1];
    this.imageRotateWithView_ = imageStyle.getRotateWithView();
    this.imageRotation_ = imageStyle.getRotation();
    const imageScale = imageStyle.getScaleArray();
    this.imageScale_ = [
      imageScale[0] * this.pixelRatio_ / imagePixelRatio,
      imageScale[1] * this.pixelRatio_ / imagePixelRatio
    ];
    this.imageWidth_ = imageSize[0] * imagePixelRatio;
  }
  /**
   * Set the text style for subsequent draw operations.  Pass null to
   * remove the text style.
   *
   * @param {import("../../style/Text.js").default} textStyle Text style.
   * @override
   */
  setTextStyle(textStyle) {
    if (!textStyle) {
      this.text_ = "";
    } else {
      const textFillStyle = textStyle.getFill();
      if (!textFillStyle) {
        this.textFillState_ = null;
      } else {
        const textFillStyleColor = textFillStyle.getColor();
        this.textFillState_ = {
          fillStyle: asColorLike(
            textFillStyleColor ? textFillStyleColor : defaultFillStyle
          )
        };
      }
      const textStrokeStyle = textStyle.getStroke();
      if (!textStrokeStyle) {
        this.textStrokeState_ = null;
      } else {
        const textStrokeStyleColor = textStrokeStyle.getColor();
        const textStrokeStyleLineCap = textStrokeStyle.getLineCap();
        const textStrokeStyleLineDash = textStrokeStyle.getLineDash();
        const textStrokeStyleLineDashOffset = textStrokeStyle.getLineDashOffset();
        const textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();
        const textStrokeStyleWidth = textStrokeStyle.getWidth();
        const textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
        this.textStrokeState_ = {
          lineCap: textStrokeStyleLineCap !== void 0 ? textStrokeStyleLineCap : defaultLineCap,
          lineDash: textStrokeStyleLineDash ? textStrokeStyleLineDash : defaultLineDash,
          lineDashOffset: textStrokeStyleLineDashOffset ? textStrokeStyleLineDashOffset : defaultLineDashOffset,
          lineJoin: textStrokeStyleLineJoin !== void 0 ? textStrokeStyleLineJoin : defaultLineJoin,
          lineWidth: textStrokeStyleWidth !== void 0 ? textStrokeStyleWidth : defaultLineWidth,
          miterLimit: textStrokeStyleMiterLimit !== void 0 ? textStrokeStyleMiterLimit : defaultMiterLimit,
          strokeStyle: asColorLike(
            textStrokeStyleColor ? textStrokeStyleColor : defaultStrokeStyle
          )
        };
      }
      const textFont = textStyle.getFont();
      const textOffsetX = textStyle.getOffsetX();
      const textOffsetY = textStyle.getOffsetY();
      const textRotateWithView = textStyle.getRotateWithView();
      const textRotation = textStyle.getRotation();
      const textScale = textStyle.getScaleArray();
      const textText = textStyle.getText();
      const textTextAlign = textStyle.getTextAlign();
      const textTextBaseline = textStyle.getTextBaseline();
      this.textState_ = {
        font: textFont !== void 0 ? textFont : defaultFont,
        textAlign: textTextAlign !== void 0 ? textTextAlign : defaultTextAlign,
        textBaseline: textTextBaseline !== void 0 ? textTextBaseline : defaultTextBaseline
      };
      this.text_ = textText !== void 0 ? Array.isArray(textText) ? textText.reduce((acc, t, i) => acc += i % 2 ? " " : t, "") : textText : "";
      this.textOffsetX_ = textOffsetX !== void 0 ? this.pixelRatio_ * textOffsetX : 0;
      this.textOffsetY_ = textOffsetY !== void 0 ? this.pixelRatio_ * textOffsetY : 0;
      this.textRotateWithView_ = textRotateWithView !== void 0 ? textRotateWithView : false;
      this.textRotation_ = textRotation !== void 0 ? textRotation : 0;
      this.textScale_ = [
        this.pixelRatio_ * textScale[0],
        this.pixelRatio_ * textScale[1]
      ];
    }
  }
}
const HIT_DETECT_RESOLUTION = 0.5;
function createHitDetectionImageData(size, transforms2, features, styleFunction, extent, resolution, rotation, squaredTolerance, projection) {
  const userExtent = projection ? toUserExtent(extent, projection) : extent;
  const width = size[0] * HIT_DETECT_RESOLUTION;
  const height = size[1] * HIT_DETECT_RESOLUTION;
  const context = createCanvasContext2D(width, height);
  context.imageSmoothingEnabled = false;
  const canvas = context.canvas;
  const renderer = new CanvasImmediateRenderer(
    context,
    HIT_DETECT_RESOLUTION,
    extent,
    null,
    rotation,
    squaredTolerance,
    projection ? getTransformFromProjections(getUserProjection(), projection) : null
  );
  const featureCount = features.length;
  const indexFactor = Math.floor((256 * 256 * 256 - 1) / featureCount);
  const featuresByZIndex = {};
  for (let i = 1; i <= featureCount; ++i) {
    const feature = features[i - 1];
    const featureStyleFunction = feature.getStyleFunction() || styleFunction;
    if (!featureStyleFunction) {
      continue;
    }
    let styles = featureStyleFunction(feature, resolution);
    if (!styles) {
      continue;
    }
    if (!Array.isArray(styles)) {
      styles = [styles];
    }
    const index = i * indexFactor;
    const color2 = index.toString(16).padStart(7, "#00000");
    for (let j = 0, jj = styles.length; j < jj; ++j) {
      const originalStyle = styles[j];
      const geometry = originalStyle.getGeometryFunction()(feature);
      if (!geometry || !intersects$1(userExtent, geometry.getExtent())) {
        continue;
      }
      const style = originalStyle.clone();
      const fill = style.getFill();
      if (fill) {
        fill.setColor(color2);
      }
      const stroke = style.getStroke();
      if (stroke) {
        stroke.setColor(color2);
        stroke.setLineDash(null);
      }
      style.setText(void 0);
      const image = originalStyle.getImage();
      if (image) {
        const imgSize = image.getImageSize();
        if (!imgSize) {
          continue;
        }
        const imgContext = createCanvasContext2D(
          imgSize[0],
          imgSize[1],
          void 0,
          { alpha: false }
        );
        const img = imgContext.canvas;
        imgContext.fillStyle = color2;
        imgContext.fillRect(0, 0, img.width, img.height);
        style.setImage(
          new Icon({
            img,
            anchor: image.getAnchor(),
            anchorXUnits: "pixels",
            anchorYUnits: "pixels",
            offset: image.getOrigin(),
            opacity: 1,
            size: image.getSize(),
            scale: image.getScale(),
            rotation: image.getRotation(),
            rotateWithView: image.getRotateWithView()
          })
        );
      }
      const zIndex = style.getZIndex() || 0;
      let byGeometryType = featuresByZIndex[zIndex];
      if (!byGeometryType) {
        byGeometryType = {};
        featuresByZIndex[zIndex] = byGeometryType;
        byGeometryType["Polygon"] = [];
        byGeometryType["Circle"] = [];
        byGeometryType["LineString"] = [];
        byGeometryType["Point"] = [];
      }
      const type = geometry.getType();
      if (type === "GeometryCollection") {
        const geometries = (
          /** @type {import("../../geom/GeometryCollection.js").default} */
          geometry.getGeometriesArrayRecursive()
        );
        for (let i2 = 0, ii = geometries.length; i2 < ii; ++i2) {
          const geometry2 = geometries[i2];
          byGeometryType[geometry2.getType().replace("Multi", "")].push(
            geometry2,
            style
          );
        }
      } else {
        byGeometryType[type.replace("Multi", "")].push(geometry, style);
      }
    }
  }
  const zIndexKeys = Object.keys(featuresByZIndex).map(Number).sort(ascending);
  for (let i = 0, ii = zIndexKeys.length; i < ii; ++i) {
    const byGeometryType = featuresByZIndex[zIndexKeys[i]];
    for (const type in byGeometryType) {
      const geomAndStyle = byGeometryType[type];
      for (let j = 0, jj = geomAndStyle.length; j < jj; j += 2) {
        renderer.setStyle(geomAndStyle[j + 1]);
        for (let k = 0, kk = transforms2.length; k < kk; ++k) {
          renderer.setTransform(transforms2[k]);
          renderer.drawGeometry(geomAndStyle[j]);
        }
      }
    }
  }
  return context.getImageData(0, 0, canvas.width, canvas.height);
}
function hitDetect(pixel, features, imageData) {
  const resultFeatures = [];
  if (imageData) {
    const x = Math.floor(Math.round(pixel[0]) * HIT_DETECT_RESOLUTION);
    const y = Math.floor(Math.round(pixel[1]) * HIT_DETECT_RESOLUTION);
    const index = (clamp(x, 0, imageData.width - 1) + clamp(y, 0, imageData.height - 1) * imageData.width) * 4;
    const r = imageData.data[index];
    const g = imageData.data[index + 1];
    const b = imageData.data[index + 2];
    const i = b + 256 * (g + 256 * r);
    const indexFactor = Math.floor((256 * 256 * 256 - 1) / features.length);
    if (i && i % indexFactor === 0) {
      resultFeatures.push(features[i / indexFactor - 1]);
    }
  }
  return resultFeatures;
}
const SIMPLIFY_TOLERANCE = 0.5;
const GEOMETRY_RENDERERS = {
  "Point": renderPointGeometry,
  "LineString": renderLineStringGeometry,
  "Polygon": renderPolygonGeometry,
  "MultiPoint": renderMultiPointGeometry,
  "MultiLineString": renderMultiLineStringGeometry,
  "MultiPolygon": renderMultiPolygonGeometry,
  "GeometryCollection": renderGeometryCollectionGeometry,
  "Circle": renderCircleGeometry
};
function defaultOrder(feature1, feature2) {
  return parseInt(getUid(feature1), 10) - parseInt(getUid(feature2), 10);
}
function getSquaredTolerance(resolution, pixelRatio) {
  const tolerance = getTolerance(resolution, pixelRatio);
  return tolerance * tolerance;
}
function getTolerance(resolution, pixelRatio) {
  return SIMPLIFY_TOLERANCE * resolution / pixelRatio;
}
function renderCircleGeometry(builderGroup, geometry, style, feature, index) {
  const fillStyle = style.getFill();
  const strokeStyle = style.getStroke();
  if (fillStyle || strokeStyle) {
    const circleReplay = builderGroup.getBuilder(style.getZIndex(), "Circle");
    circleReplay.setFillStrokeStyle(fillStyle, strokeStyle);
    circleReplay.drawCircle(geometry, feature, index);
  }
  const textStyle = style.getText();
  if (textStyle && textStyle.getText()) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle);
    textReplay.drawText(geometry, feature);
  }
}
function renderFeature(replayGroup, feature, style, squaredTolerance, listener, transform2, declutter, index) {
  const loadingPromises = [];
  const imageStyle = style.getImage();
  if (imageStyle) {
    let loading2 = true;
    const imageState = imageStyle.getImageState();
    if (imageState == ImageState.LOADED || imageState == ImageState.ERROR) {
      loading2 = false;
    } else {
      if (imageState == ImageState.IDLE) {
        imageStyle.load();
      }
    }
    if (loading2) {
      loadingPromises.push(imageStyle.ready());
    }
  }
  const fillStyle = style.getFill();
  if (fillStyle && fillStyle.loading()) {
    loadingPromises.push(fillStyle.ready());
  }
  const loading = loadingPromises.length > 0;
  if (loading) {
    Promise.all(loadingPromises).then(() => listener(null));
  }
  renderFeatureInternal(
    replayGroup,
    feature,
    style,
    squaredTolerance,
    transform2,
    declutter,
    index
  );
  return loading;
}
function renderFeatureInternal(replayGroup, feature, style, squaredTolerance, transform2, declutter, index) {
  const geometry = style.getGeometryFunction()(feature);
  if (!geometry) {
    return;
  }
  const simplifiedGeometry = geometry.simplifyTransformed(
    squaredTolerance,
    transform2
  );
  const renderer = style.getRenderer();
  if (renderer) {
    renderGeometry(replayGroup, simplifiedGeometry, style, feature, index);
  } else {
    const geometryRenderer = GEOMETRY_RENDERERS[simplifiedGeometry.getType()];
    geometryRenderer(
      replayGroup,
      simplifiedGeometry,
      style,
      feature,
      index,
      declutter
    );
  }
}
function renderGeometry(replayGroup, geometry, style, feature, index) {
  if (geometry.getType() == "GeometryCollection") {
    const geometries = (
      /** @type {import("../geom/GeometryCollection.js").default} */
      geometry.getGeometries()
    );
    for (let i = 0, ii = geometries.length; i < ii; ++i) {
      renderGeometry(replayGroup, geometries[i], style, feature, index);
    }
    return;
  }
  const replay = replayGroup.getBuilder(style.getZIndex(), "Default");
  replay.drawCustom(
    /** @type {import("../geom/SimpleGeometry.js").default} */
    geometry,
    feature,
    style.getRenderer(),
    style.getHitDetectionRenderer(),
    index
  );
}
function renderGeometryCollectionGeometry(replayGroup, geometry, style, feature, declutterBuilderGroup, index) {
  const geometries = geometry.getGeometriesArray();
  let i, ii;
  for (i = 0, ii = geometries.length; i < ii; ++i) {
    const geometryRenderer = GEOMETRY_RENDERERS[geometries[i].getType()];
    geometryRenderer(
      replayGroup,
      geometries[i],
      style,
      feature,
      declutterBuilderGroup,
      index
    );
  }
}
function renderLineStringGeometry(builderGroup, geometry, style, feature, index) {
  const strokeStyle = style.getStroke();
  if (strokeStyle) {
    const lineStringReplay = builderGroup.getBuilder(
      style.getZIndex(),
      "LineString"
    );
    lineStringReplay.setFillStrokeStyle(null, strokeStyle);
    lineStringReplay.drawLineString(geometry, feature, index);
  }
  const textStyle = style.getText();
  if (textStyle && textStyle.getText()) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle);
    textReplay.drawText(geometry, feature, index);
  }
}
function renderMultiLineStringGeometry(builderGroup, geometry, style, feature, index) {
  const strokeStyle = style.getStroke();
  if (strokeStyle) {
    const lineStringReplay = builderGroup.getBuilder(
      style.getZIndex(),
      "LineString"
    );
    lineStringReplay.setFillStrokeStyle(null, strokeStyle);
    lineStringReplay.drawMultiLineString(geometry, feature, index);
  }
  const textStyle = style.getText();
  if (textStyle && textStyle.getText()) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle);
    textReplay.drawText(geometry, feature, index);
  }
}
function renderMultiPolygonGeometry(builderGroup, geometry, style, feature, index) {
  const fillStyle = style.getFill();
  const strokeStyle = style.getStroke();
  if (strokeStyle || fillStyle) {
    const polygonReplay = builderGroup.getBuilder(style.getZIndex(), "Polygon");
    polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
    polygonReplay.drawMultiPolygon(geometry, feature, index);
  }
  const textStyle = style.getText();
  if (textStyle && textStyle.getText()) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle);
    textReplay.drawText(geometry, feature, index);
  }
}
function renderPointGeometry(builderGroup, geometry, style, feature, index, declutter) {
  const imageStyle = style.getImage();
  const textStyle = style.getText();
  const hasText = textStyle && textStyle.getText();
  const declutterImageWithText = declutter && imageStyle && hasText ? {} : void 0;
  if (imageStyle) {
    if (imageStyle.getImageState() != ImageState.LOADED) {
      return;
    }
    const imageReplay = builderGroup.getBuilder(style.getZIndex(), "Image");
    imageReplay.setImageStyle(imageStyle, declutterImageWithText);
    imageReplay.drawPoint(geometry, feature, index);
  }
  if (hasText) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle, declutterImageWithText);
    textReplay.drawText(geometry, feature, index);
  }
}
function renderMultiPointGeometry(builderGroup, geometry, style, feature, index, declutter) {
  const imageStyle = style.getImage();
  const hasImage = imageStyle && imageStyle.getOpacity() !== 0;
  const textStyle = style.getText();
  const hasText = textStyle && textStyle.getText();
  const declutterImageWithText = declutter && hasImage && hasText ? {} : void 0;
  if (hasImage) {
    if (imageStyle.getImageState() != ImageState.LOADED) {
      return;
    }
    const imageReplay = builderGroup.getBuilder(style.getZIndex(), "Image");
    imageReplay.setImageStyle(imageStyle, declutterImageWithText);
    imageReplay.drawMultiPoint(geometry, feature, index);
  }
  if (hasText) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle, declutterImageWithText);
    textReplay.drawText(geometry, feature, index);
  }
}
function renderPolygonGeometry(builderGroup, geometry, style, feature, index) {
  const fillStyle = style.getFill();
  const strokeStyle = style.getStroke();
  if (fillStyle || strokeStyle) {
    const polygonReplay = builderGroup.getBuilder(style.getZIndex(), "Polygon");
    polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
    polygonReplay.drawPolygon(geometry, feature, index);
  }
  const textStyle = style.getText();
  if (textStyle && textStyle.getText()) {
    const textReplay = builderGroup.getBuilder(style.getZIndex(), "Text");
    textReplay.setTextStyle(textStyle);
    textReplay.drawText(geometry, feature, index);
  }
}
const maxStaleKeys = 5;
class LayerRenderer extends Observable {
  /**
   * @param {LayerType} layer Layer.
   */
  constructor(layer) {
    super();
    this.ready = true;
    this.boundHandleImageChange_ = this.handleImageChange_.bind(this);
    this.layer_ = layer;
    this.staleKeys_ = new Array();
    this.maxStaleKeys = maxStaleKeys;
  }
  /**
   * @return {Array<string>} Get the list of stale keys.
   */
  getStaleKeys() {
    return this.staleKeys_;
  }
  /**
   * @param {string} key The new stale key.
   */
  prependStaleKey(key2) {
    this.staleKeys_.unshift(key2);
    if (this.staleKeys_.length > this.maxStaleKeys) {
      this.staleKeys_.length = this.maxStaleKeys;
    }
  }
  /**
   * Asynchronous layer level hit detection.
   * @param {import("../pixel.js").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../Feature").FeatureLike>>} Promise that resolves with
   * an array of features.
   */
  getFeatures(pixel) {
    return abstract();
  }
  /**
   * @param {import("../pixel.js").Pixel} pixel Pixel.
   * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data.
   */
  getData(pixel) {
    return null;
  }
  /**
   * Determine whether render should be called.
   * @abstract
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @return {boolean} Layer is ready to be rendered.
   */
  prepareFrame(frameState) {
    return abstract();
  }
  /**
   * Render the layer.
   * @abstract
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @param {HTMLElement|null} target Target that may be used to render content to.
   * @return {HTMLElement} The rendered element.
   */
  renderFrame(frameState, target) {
    return abstract();
  }
  /**
   * @abstract
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("../Map.js").FrameState} frameState Frame state.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {import("./vector.js").FeatureCallback<T>} callback Feature callback.
   * @param {Array<import("./Map.js").HitMatch<T>>} matches The hit detected matches with tolerance.
   * @return {T|undefined} Callback result.
   * @template T
   */
  forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, matches) {
    return void 0;
  }
  /**
   * @return {LayerType} Layer.
   */
  getLayer() {
    return this.layer_;
  }
  /**
   * Perform action necessary to get the layer rendered after new fonts have loaded
   * @abstract
   */
  handleFontsChanged() {
  }
  /**
   * Handle changes in image state.
   * @param {import("../events/Event.js").default} event Image change event.
   * @private
   */
  handleImageChange_(event) {
    const image = (
      /** @type {import("../Image.js").default} */
      event.target
    );
    if (image.getState() === ImageState.LOADED || image.getState() === ImageState.ERROR) {
      this.renderIfReadyAndVisible();
    }
  }
  /**
   * Load the image if not already loaded, and register the image change
   * listener if needed.
   * @param {import("../Image.js").default} image Image.
   * @return {boolean} `true` if the image is already loaded, `false` otherwise.
   * @protected
   */
  loadImage(image) {
    let imageState = image.getState();
    if (imageState != ImageState.LOADED && imageState != ImageState.ERROR) {
      image.addEventListener(EventType.CHANGE, this.boundHandleImageChange_);
    }
    if (imageState == ImageState.IDLE) {
      image.load();
      imageState = image.getState();
    }
    return imageState == ImageState.LOADED;
  }
  /**
   * @protected
   */
  renderIfReadyAndVisible() {
    const layer = this.getLayer();
    if (layer && layer.getVisible() && layer.getSourceState() === "ready") {
      layer.changed();
    }
  }
  /**
   * @param {import("../Map.js").FrameState} frameState Frame state.
   */
  renderDeferred(frameState) {
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    delete this.layer_;
    super.disposeInternal();
  }
}
const canvasPool$1 = [];
let pixelContext = null;
function createPixelContext() {
  pixelContext = createCanvasContext2D(1, 1, void 0, {
    willReadFrequently: true
  });
}
class CanvasLayerRenderer extends LayerRenderer {
  /**
   * @param {LayerType} layer Layer.
   */
  constructor(layer) {
    super(layer);
    this.container = null;
    this.renderedResolution;
    this.tempTransform = create();
    this.pixelTransform = create();
    this.inversePixelTransform = create();
    this.context = null;
    this.deferredContext_ = null;
    this.containerReused = false;
    this.frameState = null;
  }
  /**
   * @param {import('../../DataTile.js').ImageLike} image Image.
   * @param {number} col The column index.
   * @param {number} row The row index.
   * @return {Uint8ClampedArray|null} The image data.
   */
  getImageData(image, col, row) {
    if (!pixelContext) {
      createPixelContext();
    }
    pixelContext.clearRect(0, 0, 1, 1);
    let data;
    try {
      pixelContext.drawImage(image, col, row, 1, 1, 0, 0, 1, 1);
      data = pixelContext.getImageData(0, 0, 1, 1).data;
    } catch {
      pixelContext = null;
      return null;
    }
    return data;
  }
  /**
   * @param {import('../../Map.js').FrameState} frameState Frame state.
   * @return {string} Background color.
   */
  getBackground(frameState) {
    const layer = this.getLayer();
    let background2 = layer.getBackground();
    if (typeof background2 === "function") {
      background2 = background2(frameState.viewState.resolution);
    }
    return background2 || void 0;
  }
  /**
   * Get a rendering container from an existing target, if compatible.
   * @param {HTMLElement} target Potential render target.
   * @param {string} transform CSS transform matrix.
   * @param {string} [backgroundColor] Background color.
   */
  useContainer(target, transform2, backgroundColor) {
    const layerClassName = this.getLayer().getClassName();
    let container, context;
    if (target && target.className === layerClassName && (!backgroundColor || target && target.style.backgroundColor && equals$2(
      asArray(target.style.backgroundColor),
      asArray(backgroundColor)
    ))) {
      const canvas = target.firstElementChild;
      if (canvas instanceof HTMLCanvasElement) {
        context = canvas.getContext("2d");
      }
    }
    if (context && equivalent(context.canvas.style.transform, transform2)) {
      this.container = target;
      this.context = context;
      this.containerReused = true;
    } else if (this.containerReused) {
      this.container = null;
      this.context = null;
      this.containerReused = false;
    } else if (this.container) {
      this.container.style.backgroundColor = null;
    }
    if (!this.container) {
      container = document.createElement("div");
      container.className = layerClassName;
      let style = container.style;
      style.position = "absolute";
      style.width = "100%";
      style.height = "100%";
      context = createCanvasContext2D();
      const canvas = context.canvas;
      container.appendChild(canvas);
      style = canvas.style;
      style.position = "absolute";
      style.left = "0";
      style.transformOrigin = "top left";
      this.container = container;
      this.context = context;
    }
    if (!this.containerReused && backgroundColor && !this.container.style.backgroundColor) {
      this.container.style.backgroundColor = backgroundColor;
    }
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {import("../../extent.js").Extent} extent Clip extent.
   * @protected
   */
  clipUnrotated(context, frameState, extent) {
    const topLeft = getTopLeft(extent);
    const topRight = getTopRight(extent);
    const bottomRight = getBottomRight(extent);
    const bottomLeft = getBottomLeft(extent);
    apply(frameState.coordinateToPixelTransform, topLeft);
    apply(frameState.coordinateToPixelTransform, topRight);
    apply(frameState.coordinateToPixelTransform, bottomRight);
    apply(frameState.coordinateToPixelTransform, bottomLeft);
    const inverted = this.inversePixelTransform;
    apply(inverted, topLeft);
    apply(inverted, topRight);
    apply(inverted, bottomRight);
    apply(inverted, bottomLeft);
    context.save();
    context.beginPath();
    context.moveTo(Math.round(topLeft[0]), Math.round(topLeft[1]));
    context.lineTo(Math.round(topRight[0]), Math.round(topRight[1]));
    context.lineTo(Math.round(bottomRight[0]), Math.round(bottomRight[1]));
    context.lineTo(Math.round(bottomLeft[0]), Math.round(bottomLeft[1]));
    context.clip();
  }
  /**
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {HTMLElement} target Target that may be used to render content to.
   * @protected
   */
  prepareContainer(frameState, target) {
    const extent = frameState.extent;
    const resolution = frameState.viewState.resolution;
    const rotation = frameState.viewState.rotation;
    const pixelRatio = frameState.pixelRatio;
    const width = Math.round(getWidth(extent) / resolution * pixelRatio);
    const height = Math.round(getHeight(extent) / resolution * pixelRatio);
    compose(
      this.pixelTransform,
      frameState.size[0] / 2,
      frameState.size[1] / 2,
      1 / pixelRatio,
      1 / pixelRatio,
      rotation,
      -width / 2,
      -height / 2
    );
    makeInverse(this.inversePixelTransform, this.pixelTransform);
    const canvasTransform = toString$1(this.pixelTransform);
    this.useContainer(target, canvasTransform, this.getBackground(frameState));
    if (!this.containerReused) {
      const canvas = this.context.canvas;
      if (canvas.width != width || canvas.height != height) {
        canvas.width = width;
        canvas.height = height;
      } else {
        this.context.clearRect(0, 0, width, height);
      }
      if (canvasTransform !== canvas.style.transform) {
        canvas.style.transform = canvasTransform;
      }
    }
  }
  /**
   * @param {import("../../render/EventType.js").default} type Event type.
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @private
   */
  dispatchRenderEvent_(type, context, frameState) {
    const layer = this.getLayer();
    if (layer.hasListener(type)) {
      const event = new RenderEvent(
        type,
        this.inversePixelTransform,
        frameState,
        context
      );
      layer.dispatchEvent(event);
    }
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @protected
   */
  preRender(context, frameState) {
    this.frameState = frameState;
    if (frameState.declutter) {
      return;
    }
    this.dispatchRenderEvent_(RenderEventType.PRERENDER, context, frameState);
  }
  /**
   * @param {CanvasRenderingContext2D} context Context.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @protected
   */
  postRender(context, frameState) {
    if (frameState.declutter) {
      return;
    }
    this.dispatchRenderEvent_(RenderEventType.POSTRENDER, context, frameState);
  }
  /**
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   */
  renderDeferredInternal(frameState) {
  }
  /**
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @return {import('../../render/canvas/ZIndexContext.js').ZIndexContextProxy} Context.
   */
  getRenderContext(frameState) {
    if (frameState.declutter && !this.deferredContext_) {
      this.deferredContext_ = new ZIndexContext();
    }
    return frameState.declutter ? this.deferredContext_.getContext() : this.context;
  }
  /**
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @override
   */
  renderDeferred(frameState) {
    if (!frameState.declutter) {
      return;
    }
    this.dispatchRenderEvent_(
      RenderEventType.PRERENDER,
      this.context,
      frameState
    );
    if (frameState.declutter && this.deferredContext_) {
      this.deferredContext_.draw(this.context);
      this.deferredContext_.clear();
    }
    this.renderDeferredInternal(frameState);
    this.dispatchRenderEvent_(
      RenderEventType.POSTRENDER,
      this.context,
      frameState
    );
  }
  /**
   * Creates a transform for rendering to an element that will be rotated after rendering.
   * @param {import("../../coordinate.js").Coordinate} center Center.
   * @param {number} resolution Resolution.
   * @param {number} rotation Rotation.
   * @param {number} pixelRatio Pixel ratio.
   * @param {number} width Width of the rendered element (in pixels).
   * @param {number} height Height of the rendered element (in pixels).
   * @param {number} offsetX Offset on the x-axis in view coordinates.
   * @protected
   * @return {!import("../../transform.js").Transform} Transform.
   */
  getRenderTransform(center, resolution, rotation, pixelRatio, width, height, offsetX) {
    const dx1 = width / 2;
    const dy1 = height / 2;
    const sx = pixelRatio / resolution;
    const sy = -sx;
    const dx2 = -center[0] + offsetX;
    const dy2 = -center[1];
    return compose(
      this.tempTransform,
      dx1,
      dy1,
      sx,
      sy,
      -rotation,
      dx2,
      dy2
    );
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    delete this.frameState;
    super.disposeInternal();
  }
}
class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
  /**
   * @param {import("../../layer/BaseVector.js").default} vectorLayer Vector layer.
   */
  constructor(vectorLayer) {
    super(vectorLayer);
    this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this);
    this.animatingOrInteracting_;
    this.hitDetectionImageData_ = null;
    this.clipped_ = false;
    this.renderedFeatures_ = null;
    this.renderedRevision_ = -1;
    this.renderedResolution_ = NaN;
    this.renderedExtent_ = createEmpty();
    this.wrappedRenderedExtent_ = createEmpty();
    this.renderedRotation_;
    this.renderedCenter_ = null;
    this.renderedProjection_ = null;
    this.renderedPixelRatio_ = 1;
    this.renderedRenderOrder_ = null;
    this.renderedFrameDeclutter_;
    this.replayGroup_ = null;
    this.replayGroupChanged = true;
    this.clipping = true;
    this.targetContext_ = null;
    this.opacity_ = 1;
  }
  /**
   * @param {ExecutorGroup} executorGroup Executor group.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {boolean} [declutterable] `true` to only render declutterable items,
   *     `false` to only render non-declutterable items, `undefined` to render all.
   */
  renderWorlds(executorGroup, frameState, declutterable) {
    const extent = frameState.extent;
    const viewState = frameState.viewState;
    const center = viewState.center;
    const resolution = viewState.resolution;
    const projection = viewState.projection;
    const rotation = viewState.rotation;
    const projectionExtent = projection.getExtent();
    const vectorSource = this.getLayer().getSource();
    const declutter = this.getLayer().getDeclutter();
    const pixelRatio = frameState.pixelRatio;
    const viewHints = frameState.viewHints;
    const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
    const context = this.context;
    const width = Math.round(getWidth(extent) / resolution * pixelRatio);
    const height = Math.round(getHeight(extent) / resolution * pixelRatio);
    const multiWorld = vectorSource.getWrapX() && projection.canWrapX();
    const worldWidth = multiWorld ? getWidth(projectionExtent) : null;
    const endWorld = multiWorld ? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1 : 1;
    let world = multiWorld ? Math.floor((extent[0] - projectionExtent[0]) / worldWidth) : 0;
    do {
      let transform2 = this.getRenderTransform(
        center,
        resolution,
        0,
        pixelRatio,
        width,
        height,
        world * worldWidth
      );
      if (frameState.declutter) {
        transform2 = transform2.slice(0);
      }
      executorGroup.execute(
        context,
        [context.canvas.width, context.canvas.height],
        transform2,
        rotation,
        snapToPixel,
        declutterable === void 0 ? ALL : declutterable ? DECLUTTER : NON_DECLUTTER,
        declutterable ? declutter && frameState.declutter[declutter] : void 0
      );
    } while (++world < endWorld);
  }
  /**
   * @private
   */
  setDrawContext_() {
    if (this.opacity_ !== 1) {
      this.targetContext_ = this.context;
      this.context = createCanvasContext2D(
        this.context.canvas.width,
        this.context.canvas.height,
        canvasPool$1
      );
    }
  }
  /**
   * @private
   */
  resetDrawContext_() {
    if (this.opacity_ !== 1 && this.targetContext_) {
      const alpha = this.targetContext_.globalAlpha;
      this.targetContext_.globalAlpha = this.opacity_;
      this.targetContext_.drawImage(this.context.canvas, 0, 0);
      this.targetContext_.globalAlpha = alpha;
      releaseCanvas(this.context);
      canvasPool$1.push(this.context.canvas);
      this.context = this.targetContext_;
      this.targetContext_ = null;
    }
  }
  /**
   * Render declutter items for this layer
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   */
  renderDeclutter(frameState) {
    if (!this.replayGroup_ || !this.getLayer().getDeclutter()) {
      return;
    }
    this.renderWorlds(this.replayGroup_, frameState, true);
  }
  /**
   * Render deferred instructions.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @override
   */
  renderDeferredInternal(frameState) {
    if (!this.replayGroup_) {
      return;
    }
    this.replayGroup_.renderDeferred();
    if (this.clipped_) {
      this.context.restore();
    }
    this.resetDrawContext_();
  }
  /**
   * Render the layer.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {HTMLElement|null} target Target that may be used to render content to.
   * @return {HTMLElement} The rendered element.
   * @override
   */
  renderFrame(frameState, target) {
    const layerState = frameState.layerStatesArray[frameState.layerIndex];
    this.opacity_ = layerState.opacity;
    const viewState = frameState.viewState;
    this.prepareContainer(frameState, target);
    const context = this.context;
    const replayGroup = this.replayGroup_;
    let render2 = replayGroup && !replayGroup.isEmpty();
    if (!render2) {
      const hasRenderListeners = this.getLayer().hasListener(RenderEventType.PRERENDER) || this.getLayer().hasListener(RenderEventType.POSTRENDER);
      if (!hasRenderListeners) {
        return this.container;
      }
    }
    this.setDrawContext_();
    this.preRender(context, frameState);
    const projection = viewState.projection;
    this.clipped_ = false;
    if (render2 && layerState.extent && this.clipping) {
      const layerExtent = fromUserExtent(layerState.extent, projection);
      render2 = intersects$1(layerExtent, frameState.extent);
      this.clipped_ = render2 && !containsExtent(layerExtent, frameState.extent);
      if (this.clipped_) {
        this.clipUnrotated(context, frameState, layerExtent);
      }
    }
    if (render2) {
      this.renderWorlds(
        replayGroup,
        frameState,
        this.getLayer().getDeclutter() ? false : void 0
      );
    }
    if (!frameState.declutter && this.clipped_) {
      context.restore();
    }
    this.postRender(context, frameState);
    if (this.renderedRotation_ !== viewState.rotation) {
      this.renderedRotation_ = viewState.rotation;
      this.hitDetectionImageData_ = null;
    }
    if (!frameState.declutter) {
      this.resetDrawContext_();
    }
    return this.container;
  }
  /**
   * Asynchronous layer level hit detection.
   * @param {import("../../pixel.js").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../../Feature").default>>} Promise
   * that resolves with an array of features.
   * @override
   */
  getFeatures(pixel) {
    return new Promise((resolve) => {
      if (this.frameState && !this.hitDetectionImageData_ && !this.animatingOrInteracting_) {
        const size = this.frameState.size.slice();
        const center = this.renderedCenter_;
        const resolution = this.renderedResolution_;
        const rotation = this.renderedRotation_;
        const projection = this.renderedProjection_;
        const extent = this.wrappedRenderedExtent_;
        const layer = this.getLayer();
        const transforms2 = [];
        const width = size[0] * HIT_DETECT_RESOLUTION;
        const height = size[1] * HIT_DETECT_RESOLUTION;
        transforms2.push(
          this.getRenderTransform(
            center,
            resolution,
            rotation,
            HIT_DETECT_RESOLUTION,
            width,
            height,
            0
          ).slice()
        );
        const source = layer.getSource();
        const projectionExtent = projection.getExtent();
        if (source.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, extent)) {
          let startX = extent[0];
          const worldWidth = getWidth(projectionExtent);
          let world = 0;
          let offsetX;
          while (startX < projectionExtent[0]) {
            --world;
            offsetX = worldWidth * world;
            transforms2.push(
              this.getRenderTransform(
                center,
                resolution,
                rotation,
                HIT_DETECT_RESOLUTION,
                width,
                height,
                offsetX
              ).slice()
            );
            startX += worldWidth;
          }
          world = 0;
          startX = extent[2];
          while (startX > projectionExtent[2]) {
            ++world;
            offsetX = worldWidth * world;
            transforms2.push(
              this.getRenderTransform(
                center,
                resolution,
                rotation,
                HIT_DETECT_RESOLUTION,
                width,
                height,
                offsetX
              ).slice()
            );
            startX -= worldWidth;
          }
        }
        const userProjection2 = getUserProjection();
        this.hitDetectionImageData_ = createHitDetectionImageData(
          size,
          transforms2,
          this.renderedFeatures_,
          layer.getStyleFunction(),
          extent,
          resolution,
          rotation,
          getSquaredTolerance(resolution, this.renderedPixelRatio_),
          userProjection2 ? projection : null
        );
      }
      resolve(
        hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_)
      );
    });
  }
  /**
   * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @param {import("../vector.js").FeatureCallback<T>} callback Feature callback.
   * @param {Array<import("../Map.js").HitMatch<T>>} matches The hit detected matches with tolerance.
   * @return {T|undefined} Callback result.
   * @template T
   * @override
   */
  forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, matches) {
    if (!this.replayGroup_) {
      return void 0;
    }
    const resolution = frameState.viewState.resolution;
    const rotation = frameState.viewState.rotation;
    const layer = this.getLayer();
    const features = {};
    const featureCallback = function(feature, geometry, distanceSq) {
      const key2 = getUid(feature);
      const match2 = features[key2];
      if (!match2) {
        if (distanceSq === 0) {
          features[key2] = true;
          return callback(feature, layer, geometry);
        }
        matches.push(
          features[key2] = {
            feature,
            layer,
            geometry,
            distanceSq,
            callback
          }
        );
      } else if (match2 !== true && distanceSq < match2.distanceSq) {
        if (distanceSq === 0) {
          features[key2] = true;
          matches.splice(matches.lastIndexOf(match2), 1);
          return callback(feature, layer, geometry);
        }
        match2.geometry = geometry;
        match2.distanceSq = distanceSq;
      }
      return void 0;
    };
    const declutter = this.getLayer().getDeclutter();
    return this.replayGroup_.forEachFeatureAtCoordinate(
      coordinate,
      resolution,
      rotation,
      hitTolerance,
      featureCallback,
      declutter ? frameState.declutter?.[declutter]?.all().map((item) => item.value) : null
    );
  }
  /**
   * Perform action necessary to get the layer rendered after new fonts have loaded
   * @override
   */
  handleFontsChanged() {
    const layer = this.getLayer();
    if (layer.getVisible() && this.replayGroup_) {
      layer.changed();
    }
  }
  /**
   * Handle changes in image style state.
   * @param {import("../../events/Event.js").default} event Image style change event.
   * @private
   */
  handleStyleImageChange_(event) {
    this.renderIfReadyAndVisible();
  }
  /**
   * Determine whether render should be called.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @return {boolean} Layer is ready to be rendered.
   * @override
   */
  prepareFrame(frameState) {
    const vectorLayer = this.getLayer();
    const vectorSource = vectorLayer.getSource();
    if (!vectorSource) {
      return false;
    }
    const animating = frameState.viewHints[ViewHint.ANIMATING];
    const interacting = frameState.viewHints[ViewHint.INTERACTING];
    const updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();
    const updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();
    if (this.ready && !updateWhileAnimating && animating || !updateWhileInteracting && interacting) {
      this.animatingOrInteracting_ = true;
      return true;
    }
    this.animatingOrInteracting_ = false;
    const frameStateExtent = frameState.extent;
    const viewState = frameState.viewState;
    const projection = viewState.projection;
    const resolution = viewState.resolution;
    const pixelRatio = frameState.pixelRatio;
    const vectorLayerRevision = vectorLayer.getRevision();
    const vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();
    let vectorLayerRenderOrder = vectorLayer.getRenderOrder();
    if (vectorLayerRenderOrder === void 0) {
      vectorLayerRenderOrder = defaultOrder;
    }
    const center = viewState.center.slice();
    const extent = buffer(
      frameStateExtent,
      vectorLayerRenderBuffer * resolution
    );
    const renderedExtent = extent.slice();
    const loadExtents = [extent.slice()];
    const projectionExtent = projection.getExtent();
    if (vectorSource.getWrapX() && projection.canWrapX() && !containsExtent(projectionExtent, frameState.extent)) {
      const worldWidth = getWidth(projectionExtent);
      const gutter = Math.max(getWidth(extent) / 2, worldWidth);
      extent[0] = projectionExtent[0] - gutter;
      extent[2] = projectionExtent[2] + gutter;
      wrapX$1(center, projection);
      const loadExtent = wrapX$2(loadExtents[0], projection);
      if (loadExtent[0] < projectionExtent[0] && loadExtent[2] < projectionExtent[2]) {
        loadExtents.push([
          loadExtent[0] + worldWidth,
          loadExtent[1],
          loadExtent[2] + worldWidth,
          loadExtent[3]
        ]);
      } else if (loadExtent[0] > projectionExtent[0] && loadExtent[2] > projectionExtent[2]) {
        loadExtents.push([
          loadExtent[0] - worldWidth,
          loadExtent[1],
          loadExtent[2] - worldWidth,
          loadExtent[3]
        ]);
      }
    }
    if (this.ready && this.renderedResolution_ == resolution && this.renderedRevision_ == vectorLayerRevision && this.renderedRenderOrder_ == vectorLayerRenderOrder && this.renderedFrameDeclutter_ === !!frameState.declutter && containsExtent(this.wrappedRenderedExtent_, extent)) {
      if (!equals$2(this.renderedExtent_, renderedExtent)) {
        this.hitDetectionImageData_ = null;
        this.renderedExtent_ = renderedExtent;
      }
      this.renderedCenter_ = center;
      this.replayGroupChanged = false;
      return true;
    }
    this.replayGroup_ = null;
    const replayGroup = new BuilderGroup(
      getTolerance(resolution, pixelRatio),
      extent,
      resolution,
      pixelRatio
    );
    const userProjection2 = getUserProjection();
    let userTransform;
    if (userProjection2) {
      for (let i = 0, ii = loadExtents.length; i < ii; ++i) {
        const extent2 = loadExtents[i];
        const userExtent2 = toUserExtent(extent2, projection);
        vectorSource.loadFeatures(
          userExtent2,
          toUserResolution(resolution, projection),
          userProjection2
        );
      }
      userTransform = getTransformFromProjections(userProjection2, projection);
    } else {
      for (let i = 0, ii = loadExtents.length; i < ii; ++i) {
        vectorSource.loadFeatures(loadExtents[i], resolution, projection);
      }
    }
    const squaredTolerance = getSquaredTolerance(resolution, pixelRatio);
    let ready = true;
    const render2 = (
      /**
       * @param {import("../../Feature.js").default} feature Feature.
       * @param {number} index Index.
       */
      (feature, index) => {
        let styles;
        const styleFunction = feature.getStyleFunction() || vectorLayer.getStyleFunction();
        if (styleFunction) {
          styles = styleFunction(feature, resolution);
        }
        if (styles) {
          const dirty = this.renderFeature(
            feature,
            squaredTolerance,
            styles,
            replayGroup,
            userTransform,
            this.getLayer().getDeclutter(),
            index
          );
          ready = ready && !dirty;
        }
      }
    );
    const userExtent = toUserExtent(extent, projection);
    const features = vectorSource.getFeaturesInExtent(userExtent);
    if (vectorLayerRenderOrder) {
      features.sort(vectorLayerRenderOrder);
    }
    for (let i = 0, ii = features.length; i < ii; ++i) {
      render2(features[i], i);
    }
    this.renderedFeatures_ = features;
    this.ready = ready;
    const replayGroupInstructions = replayGroup.finish();
    const executorGroup = new ExecutorGroup(
      extent,
      resolution,
      pixelRatio,
      vectorSource.getOverlaps(),
      replayGroupInstructions,
      vectorLayer.getRenderBuffer(),
      !!frameState.declutter
    );
    this.renderedResolution_ = resolution;
    this.renderedRevision_ = vectorLayerRevision;
    this.renderedRenderOrder_ = vectorLayerRenderOrder;
    this.renderedFrameDeclutter_ = !!frameState.declutter;
    this.renderedExtent_ = renderedExtent;
    this.wrappedRenderedExtent_ = extent;
    this.renderedCenter_ = center;
    this.renderedProjection_ = projection;
    this.renderedPixelRatio_ = pixelRatio;
    this.replayGroup_ = executorGroup;
    this.hitDetectionImageData_ = null;
    this.replayGroupChanged = true;
    return true;
  }
  /**
   * @param {import("../../Feature.js").default} feature Feature.
   * @param {number} squaredTolerance Squared render tolerance.
   * @param {import("../../style/Style.js").default|Array<import("../../style/Style.js").default>} styles The style or array of styles.
   * @param {import("../../render/canvas/BuilderGroup.js").default} builderGroup Builder group.
   * @param {import("../../proj.js").TransformFunction} [transform] Transform from user to view projection.
   * @param {boolean} [declutter] Enable decluttering.
   * @param {number} [index] Render order index.
   * @return {boolean} `true` if an image is loading.
   */
  renderFeature(feature, squaredTolerance, styles, builderGroup, transform2, declutter, index) {
    if (!styles) {
      return false;
    }
    let loading = false;
    if (Array.isArray(styles)) {
      for (let i = 0, ii = styles.length; i < ii; ++i) {
        loading = renderFeature(
          builderGroup,
          feature,
          styles[i],
          squaredTolerance,
          this.boundHandleStyleImageChange_,
          transform2,
          declutter,
          index
        ) || loading;
      }
    } else {
      loading = renderFeature(
        builderGroup,
        feature,
        styles,
        squaredTolerance,
        this.boundHandleStyleImageChange_,
        transform2,
        declutter,
        index
      );
    }
    return loading;
  }
}
class VectorLayer extends BaseVectorLayer {
  /**
   * @param {Options<VectorSourceType, FeatureType>} [options] Options.
   */
  constructor(options2) {
    super(options2);
  }
  /**
   * @override
   */
  createRenderer() {
    return new CanvasVectorLayerRenderer(this);
  }
}
let withCredentials = false;
function loadFeaturesXhr(url, format2, extent, resolution, projection, success, failure) {
  const xhr2 = new XMLHttpRequest();
  xhr2.open(
    "GET",
    typeof url === "function" ? url(extent, resolution, projection) : url,
    true
  );
  if (format2.getType() == "arraybuffer") {
    xhr2.responseType = "arraybuffer";
  }
  xhr2.withCredentials = withCredentials;
  xhr2.onload = function(event) {
    if (!xhr2.status || xhr2.status >= 200 && xhr2.status < 300) {
      const type = format2.getType();
      try {
        let source;
        if (type == "text" || type == "json") {
          source = xhr2.responseText;
        } else if (type == "xml") {
          source = xhr2.responseXML || xhr2.responseText;
        } else if (type == "arraybuffer") {
          source = /** @type {ArrayBuffer} */
          xhr2.response;
        }
        if (source) {
          success(
            /** @type {Array<FeatureType>} */
            format2.readFeatures(source, {
              extent,
              featureProjection: projection
            }),
            format2.readProjection(source)
          );
        } else {
          failure();
        }
      } catch {
        failure();
      }
    } else {
      failure();
    }
  };
  xhr2.onerror = failure;
  xhr2.send();
}
function xhr(url, format2) {
  return function(extent, resolution, projection, success, failure) {
    loadFeaturesXhr(
      url,
      format2,
      extent,
      resolution,
      projection,
      /**
       * @param {Array<FeatureType>} features The loaded features.
       * @param {import("./proj/Projection.js").default} dataProjection Data
       * projection.
       */
      (features, dataProjection) => {
        this.addFeatures(features);
        if (success !== void 0) {
          success(features);
        }
      },
      () => {
        this.changed();
        if (failure !== void 0) {
          failure();
        }
      }
    );
  };
}
function all(extent, resolution) {
  return [[-Infinity, -Infinity, Infinity, Infinity]];
}
const tmpTransform = create();
class RenderFeature {
  /**
   * @param {Type} type Geometry type.
   * @param {Array<number>} flatCoordinates Flat coordinates. These always need
   *     to be right-handed for polygons.
   * @param {Array<number>} ends Ends.
   * @param {number} stride Stride.
   * @param {Object<string, *>} properties Properties.
   * @param {number|string|undefined} id Feature id.
   */
  constructor(type, flatCoordinates, ends, stride, properties, id) {
    this.styleFunction;
    this.extent_;
    this.id_ = id;
    this.type_ = type;
    this.flatCoordinates_ = flatCoordinates;
    this.flatInteriorPoints_ = null;
    this.flatMidpoints_ = null;
    this.ends_ = ends || null;
    this.properties_ = properties;
    this.squaredTolerance_;
    this.stride_ = stride;
    this.simplifiedGeometry_;
  }
  /**
   * Get a feature property by its key.
   * @param {string} key Key
   * @return {*} Value for the requested key.
   * @api
   */
  get(key2) {
    return this.properties_[key2];
  }
  /**
   * Get the extent of this feature's geometry.
   * @return {import("../extent.js").Extent} Extent.
   * @api
   */
  getExtent() {
    if (!this.extent_) {
      this.extent_ = this.type_ === "Point" ? createOrUpdateFromCoordinate(this.flatCoordinates_) : createOrUpdateFromFlatCoordinates(
        this.flatCoordinates_,
        0,
        this.flatCoordinates_.length,
        2
      );
    }
    return this.extent_;
  }
  /**
   * @return {Array<number>} Flat interior points.
   */
  getFlatInteriorPoint() {
    if (!this.flatInteriorPoints_) {
      const flatCenter = getCenter(this.getExtent());
      this.flatInteriorPoints_ = getInteriorPointOfArray(
        this.flatCoordinates_,
        0,
        this.ends_,
        2,
        flatCenter,
        0
      );
    }
    return this.flatInteriorPoints_;
  }
  /**
   * @return {Array<number>} Flat interior points.
   */
  getFlatInteriorPoints() {
    if (!this.flatInteriorPoints_) {
      const ends = inflateEnds(this.flatCoordinates_, this.ends_);
      const flatCenters = linearRingss(this.flatCoordinates_, 0, ends, 2);
      this.flatInteriorPoints_ = getInteriorPointsOfMultiArray(
        this.flatCoordinates_,
        0,
        ends,
        2,
        flatCenters
      );
    }
    return this.flatInteriorPoints_;
  }
  /**
   * @return {Array<number>} Flat midpoint.
   */
  getFlatMidpoint() {
    if (!this.flatMidpoints_) {
      this.flatMidpoints_ = interpolatePoint(
        this.flatCoordinates_,
        0,
        this.flatCoordinates_.length,
        2,
        0.5
      );
    }
    return this.flatMidpoints_;
  }
  /**
   * @return {Array<number>} Flat midpoints.
   */
  getFlatMidpoints() {
    if (!this.flatMidpoints_) {
      this.flatMidpoints_ = [];
      const flatCoordinates = this.flatCoordinates_;
      let offset2 = 0;
      const ends = (
        /** @type {Array<number>} */
        this.ends_
      );
      for (let i = 0, ii = ends.length; i < ii; ++i) {
        const end = ends[i];
        const midpoint = interpolatePoint(flatCoordinates, offset2, end, 2, 0.5);
        extend$3(this.flatMidpoints_, midpoint);
        offset2 = end;
      }
    }
    return this.flatMidpoints_;
  }
  /**
   * Get the feature identifier.  This is a stable identifier for the feature and
   * is set when reading data from a remote source.
   * @return {number|string|undefined} Id.
   * @api
   */
  getId() {
    return this.id_;
  }
  /**
   * @return {Array<number>} Flat coordinates.
   */
  getOrientedFlatCoordinates() {
    return this.flatCoordinates_;
  }
  /**
   * For API compatibility with {@link module:ol/Feature~Feature}, this method is useful when
   * determining the geometry type in style function (see {@link #getType}).
   * @return {RenderFeature} Feature.
   * @api
   */
  getGeometry() {
    return this;
  }
  /**
   * @param {number} squaredTolerance Squared tolerance.
   * @return {RenderFeature} Simplified geometry.
   */
  getSimplifiedGeometry(squaredTolerance) {
    return this;
  }
  /**
   * Get a transformed and simplified version of the geometry.
   * @param {number} squaredTolerance Squared tolerance.
   * @param {import("../proj.js").TransformFunction} [transform] Optional transform function.
   * @return {RenderFeature} Simplified geometry.
   */
  simplifyTransformed(squaredTolerance, transform2) {
    return this;
  }
  /**
   * Get the feature properties.
   * @return {Object<string, *>} Feature properties.
   * @api
   */
  getProperties() {
    return this.properties_;
  }
  /**
   * Get an object of all property names and values.  This has the same behavior as getProperties,
   * but is here to conform with the {@link module:ol/Feature~Feature} interface.
   * @return {Object<string, *>?} Object.
   */
  getPropertiesInternal() {
    return this.properties_;
  }
  /**
   * @return {number} Stride.
   */
  getStride() {
    return this.stride_;
  }
  /**
   * @return {import('../style/Style.js').StyleFunction|undefined} Style
   */
  getStyleFunction() {
    return this.styleFunction;
  }
  /**
   * Get the type of this feature's geometry.
   * @return {Type} Geometry type.
   * @api
   */
  getType() {
    return this.type_;
  }
  /**
   * Transform geometry coordinates from tile pixel space to projected.
   *
   * @param {import("../proj.js").ProjectionLike} projection The data projection
   */
  transform(projection) {
    projection = get$2(projection);
    const pixelExtent = projection.getExtent();
    const projectedExtent = projection.getWorldExtent();
    if (pixelExtent && projectedExtent) {
      const scale2 = getHeight(projectedExtent) / getHeight(pixelExtent);
      compose(
        tmpTransform,
        projectedExtent[0],
        projectedExtent[3],
        scale2,
        -scale2,
        0,
        0,
        0
      );
      transform2D(
        this.flatCoordinates_,
        0,
        this.flatCoordinates_.length,
        2,
        tmpTransform,
        this.flatCoordinates_
      );
    }
  }
  /**
   * Apply a transform function to the coordinates of the geometry.
   * The geometry is modified in place.
   * If you do not want the geometry modified in place, first `clone()` it and
   * then use this function on the clone.
   * @param {import("../proj.js").TransformFunction} transformFn Transform function.
   */
  applyTransform(transformFn) {
    transformFn(this.flatCoordinates_, this.flatCoordinates_, this.stride_);
  }
  /**
   * @return {RenderFeature} A cloned render feature.
   */
  clone() {
    return new RenderFeature(
      this.type_,
      this.flatCoordinates_.slice(),
      this.ends_?.slice(),
      this.stride_,
      Object.assign({}, this.properties_),
      this.id_
    );
  }
  /**
   * @return {Array<number>|null} Ends.
   */
  getEnds() {
    return this.ends_;
  }
  /**
   * Add transform and resolution based geometry simplification to this instance.
   * @return {RenderFeature} This render feature.
   */
  enableSimplifyTransformed() {
    this.simplifyTransformed = memoizeOne((squaredTolerance, transform2) => {
      if (squaredTolerance === this.squaredTolerance_) {
        return this.simplifiedGeometry_;
      }
      this.simplifiedGeometry_ = this.clone();
      if (transform2) {
        this.simplifiedGeometry_.applyTransform(transform2);
      }
      const simplifiedFlatCoordinates = this.simplifiedGeometry_.getFlatCoordinates();
      let simplifiedEnds;
      switch (this.type_) {
        case "LineString":
          simplifiedFlatCoordinates.length = douglasPeucker(
            simplifiedFlatCoordinates,
            0,
            this.simplifiedGeometry_.flatCoordinates_.length,
            this.simplifiedGeometry_.stride_,
            squaredTolerance,
            simplifiedFlatCoordinates,
            0
          );
          simplifiedEnds = [simplifiedFlatCoordinates.length];
          break;
        case "MultiLineString":
          simplifiedEnds = [];
          simplifiedFlatCoordinates.length = douglasPeuckerArray(
            simplifiedFlatCoordinates,
            0,
            this.simplifiedGeometry_.ends_,
            this.simplifiedGeometry_.stride_,
            squaredTolerance,
            simplifiedFlatCoordinates,
            0,
            simplifiedEnds
          );
          break;
        case "Polygon":
          simplifiedEnds = [];
          simplifiedFlatCoordinates.length = quantizeArray(
            simplifiedFlatCoordinates,
            0,
            this.simplifiedGeometry_.ends_,
            this.simplifiedGeometry_.stride_,
            Math.sqrt(squaredTolerance),
            simplifiedFlatCoordinates,
            0,
            simplifiedEnds
          );
          break;
      }
      if (simplifiedEnds) {
        this.simplifiedGeometry_ = new RenderFeature(
          this.type_,
          simplifiedFlatCoordinates,
          simplifiedEnds,
          2,
          this.properties_,
          this.id_
        );
      }
      this.squaredTolerance_ = squaredTolerance;
      return this.simplifiedGeometry_;
    });
    return this;
  }
}
RenderFeature.prototype.getFlatCoordinates = RenderFeature.prototype.getOrientedFlatCoordinates;
class RBush {
  /**
   * @param {number} [maxEntries] Max entries.
   */
  constructor(maxEntries) {
    this.rbush_ = new RBush$1(maxEntries);
    this.items_ = {};
  }
  /**
   * Insert a value into the RBush.
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {T} value Value.
   */
  insert(extent, value) {
    const item = {
      minX: extent[0],
      minY: extent[1],
      maxX: extent[2],
      maxY: extent[3],
      value
    };
    this.rbush_.insert(item);
    this.items_[getUid(value)] = item;
  }
  /**
   * Bulk-insert values into the RBush.
   * @param {Array<import("../extent.js").Extent>} extents Extents.
   * @param {Array<T>} values Values.
   */
  load(extents, values) {
    const items = new Array(values.length);
    for (let i = 0, l = values.length; i < l; i++) {
      const extent = extents[i];
      const value = values[i];
      const item = {
        minX: extent[0],
        minY: extent[1],
        maxX: extent[2],
        maxY: extent[3],
        value
      };
      items[i] = item;
      this.items_[getUid(value)] = item;
    }
    this.rbush_.load(items);
  }
  /**
   * Remove a value from the RBush.
   * @param {T} value Value.
   * @return {boolean} Removed.
   */
  remove(value) {
    const uid = getUid(value);
    const item = this.items_[uid];
    delete this.items_[uid];
    return this.rbush_.remove(item) !== null;
  }
  /**
   * Update the extent of a value in the RBush.
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {T} value Value.
   */
  update(extent, value) {
    const item = this.items_[getUid(value)];
    const bbox = [item.minX, item.minY, item.maxX, item.maxY];
    if (!equals$1(bbox, extent)) {
      this.remove(value);
      this.insert(extent, value);
    }
  }
  /**
   * Return all values in the RBush.
   * @return {Array<T>} All.
   */
  getAll() {
    const items = this.rbush_.all();
    return items.map(function(item) {
      return item.value;
    });
  }
  /**
   * Return all values in the given extent.
   * @param {import("../extent.js").Extent} extent Extent.
   * @return {Array<T>} All in extent.
   */
  getInExtent(extent) {
    const bbox = {
      minX: extent[0],
      minY: extent[1],
      maxX: extent[2],
      maxY: extent[3]
    };
    const items = this.rbush_.search(bbox);
    return items.map(function(item) {
      return item.value;
    });
  }
  /**
   * Calls a callback function with each value in the tree.
   * If the callback returns a truthy value, this value is returned without
   * checking the rest of the tree.
   * @param {function(T): R} callback Callback.
   * @return {R|undefined} Callback return value.
   * @template R
   */
  forEach(callback) {
    return this.forEach_(this.getAll(), callback);
  }
  /**
   * Calls a callback function with each value in the provided extent.
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {function(T): R} callback Callback.
   * @return {R|undefined} Callback return value.
   * @template R
   */
  forEachInExtent(extent, callback) {
    return this.forEach_(this.getInExtent(extent), callback);
  }
  /**
   * @param {Array<T>} values Values.
   * @param {function(T): R} callback Callback.
   * @return {R|undefined} Callback return value.
   * @template R
   * @private
   */
  forEach_(values, callback) {
    let result;
    for (let i = 0, l = values.length; i < l; i++) {
      result = callback(values[i]);
      if (result) {
        return result;
      }
    }
    return result;
  }
  /**
   * @return {boolean} Is empty.
   */
  isEmpty() {
    return isEmpty$1(this.items_);
  }
  /**
   * Remove all values from the RBush.
   */
  clear() {
    this.rbush_.clear();
    this.items_ = {};
  }
  /**
   * @param {import("../extent.js").Extent} [extent] Extent.
   * @return {import("../extent.js").Extent} Extent.
   */
  getExtent(extent) {
    const data = this.rbush_.toJSON();
    return createOrUpdate$2(data.minX, data.minY, data.maxX, data.maxY, extent);
  }
  /**
   * @param {RBush<T>} rbush R-Tree.
   */
  concat(rbush) {
    this.rbush_.load(rbush.rbush_.all());
    for (const i in rbush.items_) {
      this.items_[i] = rbush.items_[i];
    }
  }
}
class Source extends BaseObject {
  /**
   * @param {Options} options Source options.
   */
  constructor(options2) {
    super();
    this.projection = get$2(options2.projection);
    this.attributions_ = adaptAttributions(options2.attributions);
    this.attributionsCollapsible_ = options2.attributionsCollapsible ?? true;
    this.loading = false;
    this.state_ = options2.state !== void 0 ? options2.state : "ready";
    this.wrapX_ = options2.wrapX !== void 0 ? options2.wrapX : false;
    this.interpolate_ = !!options2.interpolate;
    this.viewResolver = null;
    this.viewRejector = null;
    const self2 = this;
    this.viewPromise_ = new Promise(function(resolve, reject) {
      self2.viewResolver = resolve;
      self2.viewRejector = reject;
    });
  }
  /**
   * Get the attribution function for the source.
   * @return {?Attribution} Attribution function.
   * @api
   */
  getAttributions() {
    return this.attributions_;
  }
  /**
   * @return {boolean} Attributions are collapsible.
   * @api
   */
  getAttributionsCollapsible() {
    return this.attributionsCollapsible_;
  }
  /**
   * Get the projection of the source.
   * @return {import("../proj/Projection.js").default|null} Projection.
   * @api
   */
  getProjection() {
    return this.projection;
  }
  /**
   * @param {import("../proj/Projection").default} [projection] Projection.
   * @return {Array<number>|null} Resolutions.
   */
  getResolutions(projection) {
    return null;
  }
  /**
   * @return {Promise<import("../View.js").ViewOptions>} A promise for view-related properties.
   */
  getView() {
    return this.viewPromise_;
  }
  /**
   * Get the state of the source, see {@link import("./Source.js").State} for possible states.
   * @return {import("./Source.js").State} State.
   * @api
   */
  getState() {
    return this.state_;
  }
  /**
   * @return {boolean|undefined} Wrap X.
   */
  getWrapX() {
    return this.wrapX_;
  }
  /**
   * @return {boolean} Use linear interpolation when resampling.
   */
  getInterpolate() {
    return this.interpolate_;
  }
  /**
   * Refreshes the source. The source will be cleared, and data from the server will be reloaded.
   * @api
   */
  refresh() {
    this.changed();
  }
  /**
   * Set the attributions of the source.
   * @param {AttributionLike|undefined} attributions Attributions.
   *     Can be passed as `string`, `Array<string>`, {@link module:ol/source/Source~Attribution},
   *     or `undefined`.
   * @api
   */
  setAttributions(attributions) {
    this.attributions_ = adaptAttributions(attributions);
    this.changed();
  }
  /**
   * Set the state of the source.
   * @param {import("./Source.js").State} state State.
   */
  setState(state) {
    this.state_ = state;
    this.changed();
  }
}
function adaptAttributions(attributionLike) {
  if (!attributionLike) {
    return null;
  }
  if (typeof attributionLike === "function") {
    return attributionLike;
  }
  if (!Array.isArray(attributionLike)) {
    attributionLike = [attributionLike];
  }
  return (frameState) => attributionLike;
}
const VectorEventType = {
  /**
   * Triggered when a feature is added to the source.
   * @event module:ol/source/Vector.VectorSourceEvent#addfeature
   * @api
   */
  ADDFEATURE: "addfeature",
  /**
   * Triggered when a feature is updated.
   * @event module:ol/source/Vector.VectorSourceEvent#changefeature
   * @api
   */
  CHANGEFEATURE: "changefeature",
  /**
   * Triggered when the clear method is called on the source.
   * @event module:ol/source/Vector.VectorSourceEvent#clear
   * @api
   */
  CLEAR: "clear",
  /**
   * Triggered when a feature is removed from the source.
   * See {@link module:ol/source/Vector~VectorSource#clear source.clear()} for exceptions.
   * @event module:ol/source/Vector.VectorSourceEvent#removefeature
   * @api
   */
  REMOVEFEATURE: "removefeature",
  /**
   * Triggered when features starts loading.
   * @event module:ol/source/Vector.VectorSourceEvent#featuresloadstart
   * @api
   */
  FEATURESLOADSTART: "featuresloadstart",
  /**
   * Triggered when features finishes loading.
   * @event module:ol/source/Vector.VectorSourceEvent#featuresloadend
   * @api
   */
  FEATURESLOADEND: "featuresloadend",
  /**
   * Triggered if feature loading results in an error.
   * @event module:ol/source/Vector.VectorSourceEvent#featuresloaderror
   * @api
   */
  FEATURESLOADERROR: "featuresloaderror"
};
class VectorSourceEvent extends BaseEvent {
  /**
   * @param {string} type Type.
   * @param {FeatureType} [feature] Feature.
   * @param {Array<FeatureType>} [features] Features.
   */
  constructor(type, feature, features) {
    super(type);
    this.feature = feature;
    this.features = features;
  }
}
class VectorSource extends Source {
  /**
   * @param {Options<FeatureType>} [options] Vector source options.
   */
  constructor(options2) {
    options2 = options2 || {};
    super({
      attributions: options2.attributions,
      interpolate: true,
      projection: void 0,
      state: "ready",
      wrapX: options2.wrapX !== void 0 ? options2.wrapX : true
    });
    this.on;
    this.once;
    this.un;
    this.loader_ = VOID;
    this.format_ = options2.format || null;
    this.overlaps_ = options2.overlaps === void 0 ? true : options2.overlaps;
    this.url_ = options2.url;
    if (options2.loader !== void 0) {
      this.loader_ = options2.loader;
    } else if (this.url_ !== void 0) {
      assert(this.format_, "`format` must be set when `url` is set");
      this.loader_ = xhr(this.url_, this.format_);
    }
    this.strategy_ = options2.strategy !== void 0 ? options2.strategy : all;
    const useSpatialIndex = options2.useSpatialIndex !== void 0 ? options2.useSpatialIndex : true;
    this.featuresRtree_ = useSpatialIndex ? new RBush() : null;
    this.loadedExtentsRtree_ = new RBush();
    this.loadingExtentsCount_ = 0;
    this.nullGeometryFeatures_ = {};
    this.idIndex_ = {};
    this.uidIndex_ = {};
    this.featureChangeKeys_ = {};
    this.featuresCollection_ = null;
    let collection;
    let features;
    if (Array.isArray(options2.features)) {
      features = options2.features;
    } else if (options2.features) {
      collection = options2.features;
      features = collection.getArray();
    }
    if (!useSpatialIndex && collection === void 0) {
      collection = new Collection(features);
    }
    if (features !== void 0) {
      this.addFeaturesInternal(features);
    }
    if (collection !== void 0) {
      this.bindFeaturesCollection_(collection);
    }
  }
  /**
   * Add a single feature to the source.  If you want to add a batch of features
   * at once, call {@link module:ol/source/Vector~VectorSource#addFeatures #addFeatures()}
   * instead. A feature will not be added to the source if feature with
   * the same id is already there. The reason for this behavior is to avoid
   * feature duplication when using bbox or tile loading strategies.
   * Note: this also applies if a {@link module:ol/Collection~Collection} is used for features,
   * meaning that if a feature with a duplicate id is added in the collection, it will
   * be removed from it right away.
   * @param {FeatureType} feature Feature to add.
   * @api
   */
  addFeature(feature) {
    this.addFeatureInternal(feature);
    this.changed();
  }
  /**
   * Add a feature without firing a `change` event.
   * @param {FeatureType} feature Feature.
   * @protected
   */
  addFeatureInternal(feature) {
    const featureKey = getUid(feature);
    if (!this.addToIndex_(featureKey, feature)) {
      if (this.featuresCollection_) {
        this.featuresCollection_.remove(feature);
      }
      return;
    }
    this.setupChangeEvents_(featureKey, feature);
    const geometry = feature.getGeometry();
    if (geometry) {
      const extent = geometry.getExtent();
      if (this.featuresRtree_) {
        this.featuresRtree_.insert(extent, feature);
      }
    } else {
      this.nullGeometryFeatures_[featureKey] = feature;
    }
    this.dispatchEvent(
      new VectorSourceEvent(VectorEventType.ADDFEATURE, feature)
    );
  }
  /**
   * @param {string} featureKey Unique identifier for the feature.
   * @param {FeatureType} feature The feature.
   * @private
   */
  setupChangeEvents_(featureKey, feature) {
    if (feature instanceof RenderFeature) {
      return;
    }
    this.featureChangeKeys_[featureKey] = [
      listen(feature, EventType.CHANGE, this.handleFeatureChange_, this),
      listen(
        feature,
        ObjectEventType.PROPERTYCHANGE,
        this.handleFeatureChange_,
        this
      )
    ];
  }
  /**
   * @param {string} featureKey Unique identifier for the feature.
   * @param {FeatureType} feature The feature.
   * @return {boolean} The feature is "valid", in the sense that it is also a
   *     candidate for insertion into the Rtree.
   * @private
   */
  addToIndex_(featureKey, feature) {
    let valid = true;
    if (feature.getId() !== void 0) {
      const id = String(feature.getId());
      if (!(id in this.idIndex_)) {
        this.idIndex_[id] = feature;
      } else if (feature instanceof RenderFeature) {
        const indexedFeature = this.idIndex_[id];
        if (!(indexedFeature instanceof RenderFeature)) {
          valid = false;
        } else if (!Array.isArray(indexedFeature)) {
          this.idIndex_[id] = [indexedFeature, feature];
        } else {
          indexedFeature.push(feature);
        }
      } else {
        valid = false;
      }
    }
    if (valid) {
      assert(
        !(featureKey in this.uidIndex_),
        "The passed `feature` was already added to the source"
      );
      this.uidIndex_[featureKey] = feature;
    }
    return valid;
  }
  /**
   * Add a batch of features to the source.
   * @param {Array<FeatureType>} features Features to add.
   * @api
   */
  addFeatures(features) {
    this.addFeaturesInternal(features);
    this.changed();
  }
  /**
   * Add features without firing a `change` event.
   * @param {Array<FeatureType>} features Features.
   * @protected
   */
  addFeaturesInternal(features) {
    const extents = [];
    const newFeatures = [];
    const geometryFeatures = [];
    for (let i = 0, length = features.length; i < length; i++) {
      const feature = features[i];
      const featureKey = getUid(feature);
      if (this.addToIndex_(featureKey, feature)) {
        newFeatures.push(feature);
      }
    }
    for (let i = 0, length = newFeatures.length; i < length; i++) {
      const feature = newFeatures[i];
      const featureKey = getUid(feature);
      this.setupChangeEvents_(featureKey, feature);
      const geometry = feature.getGeometry();
      if (geometry) {
        const extent = geometry.getExtent();
        extents.push(extent);
        geometryFeatures.push(feature);
      } else {
        this.nullGeometryFeatures_[featureKey] = feature;
      }
    }
    if (this.featuresRtree_) {
      this.featuresRtree_.load(extents, geometryFeatures);
    }
    if (this.hasListener(VectorEventType.ADDFEATURE)) {
      for (let i = 0, length = newFeatures.length; i < length; i++) {
        this.dispatchEvent(
          new VectorSourceEvent(VectorEventType.ADDFEATURE, newFeatures[i])
        );
      }
    }
  }
  /**
   * @param {!Collection<FeatureType>} collection Collection.
   * @private
   */
  bindFeaturesCollection_(collection) {
    let modifyingCollection = false;
    this.addEventListener(
      VectorEventType.ADDFEATURE,
      /**
       * @param {VectorSourceEvent<FeatureType>} evt The vector source event
       */
      function(evt) {
        if (!modifyingCollection) {
          modifyingCollection = true;
          collection.push(evt.feature);
          modifyingCollection = false;
        }
      }
    );
    this.addEventListener(
      VectorEventType.REMOVEFEATURE,
      /**
       * @param {VectorSourceEvent<FeatureType>} evt The vector source event
       */
      function(evt) {
        if (!modifyingCollection) {
          modifyingCollection = true;
          collection.remove(evt.feature);
          modifyingCollection = false;
        }
      }
    );
    collection.addEventListener(
      CollectionEventType.ADD,
      /**
       * @param {import("../Collection.js").CollectionEvent<FeatureType>} evt The collection event
       */
      (evt) => {
        if (!modifyingCollection) {
          modifyingCollection = true;
          this.addFeature(evt.element);
          modifyingCollection = false;
        }
      }
    );
    collection.addEventListener(
      CollectionEventType.REMOVE,
      /**
       * @param {import("../Collection.js").CollectionEvent<FeatureType>} evt The collection event
       */
      (evt) => {
        if (!modifyingCollection) {
          modifyingCollection = true;
          this.removeFeature(evt.element);
          modifyingCollection = false;
        }
      }
    );
    this.featuresCollection_ = collection;
  }
  /**
   * Remove all features from the source.
   * @param {boolean} [fast] Skip dispatching of {@link module:ol/source/Vector.VectorSourceEvent#event:removefeature} events.
   * @api
   */
  clear(fast) {
    if (fast) {
      for (const featureId in this.featureChangeKeys_) {
        const keys = this.featureChangeKeys_[featureId];
        keys.forEach(unlistenByKey);
      }
      if (!this.featuresCollection_) {
        this.featureChangeKeys_ = {};
        this.idIndex_ = {};
        this.uidIndex_ = {};
      }
    } else {
      if (this.featuresRtree_) {
        this.featuresRtree_.forEach((feature) => {
          this.removeFeatureInternal(feature);
        });
        for (const id in this.nullGeometryFeatures_) {
          this.removeFeatureInternal(this.nullGeometryFeatures_[id]);
        }
      }
    }
    if (this.featuresCollection_) {
      this.featuresCollection_.clear();
    }
    if (this.featuresRtree_) {
      this.featuresRtree_.clear();
    }
    this.nullGeometryFeatures_ = {};
    const clearEvent = new VectorSourceEvent(VectorEventType.CLEAR);
    this.dispatchEvent(clearEvent);
    this.changed();
  }
  /**
   * Iterate through all features on the source, calling the provided callback
   * with each one.  If the callback returns any "truthy" value, iteration will
   * stop and the function will return the same value.
   * Note: this function only iterate through the feature that have a defined geometry.
   *
   * @param {function(FeatureType): T} callback Called with each feature
   *     on the source.  Return a truthy value to stop iteration.
   * @return {T|undefined} The return value from the last call to the callback.
   * @template T
   * @api
   */
  forEachFeature(callback) {
    if (this.featuresRtree_) {
      return this.featuresRtree_.forEach(callback);
    }
    if (this.featuresCollection_) {
      this.featuresCollection_.forEach(callback);
    }
  }
  /**
   * Iterate through all features whose geometries contain the provided
   * coordinate, calling the callback with each feature.  If the callback returns
   * a "truthy" value, iteration will stop and the function will return the same
   * value.
   *
   * For {@link module:ol/render/Feature~RenderFeature} features, the callback will be
   * called for all features.
   *
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {function(FeatureType): T} callback Called with each feature
   *     whose goemetry contains the provided coordinate.
   * @return {T|undefined} The return value from the last call to the callback.
   * @template T
   */
  forEachFeatureAtCoordinateDirect(coordinate, callback) {
    const extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]];
    return this.forEachFeatureInExtent(extent, function(feature) {
      const geometry = feature.getGeometry();
      if (geometry instanceof RenderFeature || geometry.intersectsCoordinate(coordinate)) {
        return callback(feature);
      }
      return void 0;
    });
  }
  /**
   * Iterate through all features whose bounding box intersects the provided
   * extent (note that the feature's geometry may not intersect the extent),
   * calling the callback with each feature.  If the callback returns a "truthy"
   * value, iteration will stop and the function will return the same value.
   *
   * If you are interested in features whose geometry intersects an extent, call
   * the {@link module:ol/source/Vector~VectorSource#forEachFeatureIntersectingExtent #forEachFeatureIntersectingExtent()} method instead.
   *
   * When `useSpatialIndex` is set to false, this method will loop through all
   * features, equivalent to {@link module:ol/source/Vector~VectorSource#forEachFeature #forEachFeature()}.
   *
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {function(FeatureType): T} callback Called with each feature
   *     whose bounding box intersects the provided extent.
   * @return {T|undefined} The return value from the last call to the callback.
   * @template T
   * @api
   */
  forEachFeatureInExtent(extent, callback) {
    if (this.featuresRtree_) {
      return this.featuresRtree_.forEachInExtent(extent, callback);
    }
    if (this.featuresCollection_) {
      this.featuresCollection_.forEach(callback);
    }
  }
  /**
   * Iterate through all features whose geometry intersects the provided extent,
   * calling the callback with each feature.  If the callback returns a "truthy"
   * value, iteration will stop and the function will return the same value.
   *
   * If you only want to test for bounding box intersection, call the
   * {@link module:ol/source/Vector~VectorSource#forEachFeatureInExtent #forEachFeatureInExtent()} method instead.
   *
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {function(FeatureType): T} callback Called with each feature
   *     whose geometry intersects the provided extent.
   * @return {T|undefined} The return value from the last call to the callback.
   * @template T
   * @api
   */
  forEachFeatureIntersectingExtent(extent, callback) {
    return this.forEachFeatureInExtent(
      extent,
      /**
       * @param {FeatureType} feature Feature.
       * @return {T|undefined} The return value from the last call to the callback.
       */
      function(feature) {
        const geometry = feature.getGeometry();
        if (geometry instanceof RenderFeature || geometry.intersectsExtent(extent)) {
          const result = callback(feature);
          if (result) {
            return result;
          }
        }
      }
    );
  }
  /**
   * Get the features collection associated with this source. Will be `null`
   * unless the source was configured with `useSpatialIndex` set to `false`, or
   * with a {@link module:ol/Collection~Collection} as `features`.
   * @return {Collection<FeatureType>|null} The collection of features.
   * @api
   */
  getFeaturesCollection() {
    return this.featuresCollection_;
  }
  /**
   * Get a snapshot of the features currently on the source in random order. The returned array
   * is a copy, the features are references to the features in the source.
   * @return {Array<FeatureType>} Features.
   * @api
   */
  getFeatures() {
    let features;
    if (this.featuresCollection_) {
      features = this.featuresCollection_.getArray().slice(0);
    } else if (this.featuresRtree_) {
      features = this.featuresRtree_.getAll();
      if (!isEmpty$1(this.nullGeometryFeatures_)) {
        extend$3(features, Object.values(this.nullGeometryFeatures_));
      }
    }
    return features;
  }
  /**
   * Get all features whose geometry intersects the provided coordinate.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @return {Array<FeatureType>} Features.
   * @api
   */
  getFeaturesAtCoordinate(coordinate) {
    const features = [];
    this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) {
      features.push(feature);
    });
    return features;
  }
  /**
   * Get all features whose bounding box intersects the provided extent.  Note that this returns an array of
   * all features intersecting the given extent in random order (so it may include
   * features whose geometries do not intersect the extent).
   *
   * When `useSpatialIndex` is set to false, this method will return all
   * features.
   *
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {import("../proj/Projection.js").default} [projection] Include features
   * where `extent` exceeds the x-axis bounds of `projection` and wraps around the world.
   * @return {Array<FeatureType>} Features.
   * @api
   */
  getFeaturesInExtent(extent, projection) {
    if (this.featuresRtree_) {
      const multiWorld = projection && projection.canWrapX() && this.getWrapX();
      if (!multiWorld) {
        return this.featuresRtree_.getInExtent(extent);
      }
      const extents = wrapAndSliceX(extent, projection);
      return [].concat(
        ...extents.map((anExtent) => this.featuresRtree_.getInExtent(anExtent))
      );
    }
    if (this.featuresCollection_) {
      return this.featuresCollection_.getArray().slice(0);
    }
    return [];
  }
  /**
   * Get the closest feature to the provided coordinate.
   *
   * This method is not available when the source is configured with
   * `useSpatialIndex` set to `false` and the features in this source are of type
   * {@link module:ol/Feature~Feature}.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {function(FeatureType):boolean} [filter] Feature filter function.
   *     The filter function will receive one argument, the {@link module:ol/Feature~Feature feature}
   *     and it should return a boolean value. By default, no filtering is made.
   * @return {FeatureType|null} Closest feature (or `null` if none found).
   * @api
   */
  getClosestFeatureToCoordinate(coordinate, filter) {
    const x = coordinate[0];
    const y = coordinate[1];
    let closestFeature = null;
    const closestPoint = [NaN, NaN];
    let minSquaredDistance = Infinity;
    const extent = [-Infinity, -Infinity, Infinity, Infinity];
    filter = filter ? filter : TRUE;
    this.featuresRtree_.forEachInExtent(
      extent,
      /**
       * @param {FeatureType} feature Feature.
       */
      function(feature) {
        if (filter(feature)) {
          const geometry = feature.getGeometry();
          const previousMinSquaredDistance = minSquaredDistance;
          minSquaredDistance = geometry instanceof RenderFeature ? 0 : geometry.closestPointXY(x, y, closestPoint, minSquaredDistance);
          if (minSquaredDistance < previousMinSquaredDistance) {
            closestFeature = feature;
            const minDistance = Math.sqrt(minSquaredDistance);
            extent[0] = x - minDistance;
            extent[1] = y - minDistance;
            extent[2] = x + minDistance;
            extent[3] = y + minDistance;
          }
        }
      }
    );
    return closestFeature;
  }
  /**
   * Get the extent of the features currently in the source.
   *
   * This method is not available when the source is configured with
   * `useSpatialIndex` set to `false`.
   * @param {import("../extent.js").Extent} [extent] Destination extent. If provided, no new extent
   *     will be created. Instead, that extent's coordinates will be overwritten.
   * @return {import("../extent.js").Extent} Extent.
   * @api
   */
  getExtent(extent) {
    return this.featuresRtree_.getExtent(extent);
  }
  /**
   * Get a feature by its identifier (the value returned by feature.getId()). When `RenderFeature`s
   * are used, `getFeatureById()` can return an array of `RenderFeature`s. This allows for handling
   * of `GeometryCollection` geometries, where format readers create one `RenderFeature` per
   * `GeometryCollection` member.
   * Note that the index treats string and numeric identifiers as the same.  So
   * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`.
   *
   * @param {string|number} id Feature identifier.
   * @return {FeatureClassOrArrayOfRenderFeatures<FeatureType>|null} The feature (or `null` if not found).
   * @api
   */
  getFeatureById(id) {
    const feature = this.idIndex_[id.toString()];
    return feature !== void 0 ? (
      /** @type {FeatureClassOrArrayOfRenderFeatures<FeatureType>} */
      feature
    ) : null;
  }
  /**
   * Get a feature by its internal unique identifier (using `getUid`).
   *
   * @param {string} uid Feature identifier.
   * @return {FeatureType|null} The feature (or `null` if not found).
   */
  getFeatureByUid(uid) {
    const feature = this.uidIndex_[uid];
    return feature !== void 0 ? feature : null;
  }
  /**
   * Get the format associated with this source.
   *
   * @return {import("../format/Feature.js").default<FeatureType>|null}} The feature format.
   * @api
   */
  getFormat() {
    return this.format_;
  }
  /**
   * @return {boolean} The source can have overlapping geometries.
   */
  getOverlaps() {
    return this.overlaps_;
  }
  /**
   * Get the url associated with this source.
   *
   * @return {string|import("../featureloader.js").FeatureUrlFunction|undefined} The url.
   * @api
   */
  getUrl() {
    return this.url_;
  }
  /**
   * @param {Event} event Event.
   * @private
   */
  handleFeatureChange_(event) {
    const feature = (
      /** @type {FeatureType} */
      event.target
    );
    const featureKey = getUid(feature);
    const geometry = feature.getGeometry();
    if (!geometry) {
      if (!(featureKey in this.nullGeometryFeatures_)) {
        if (this.featuresRtree_) {
          this.featuresRtree_.remove(feature);
        }
        this.nullGeometryFeatures_[featureKey] = feature;
      }
    } else {
      const extent = geometry.getExtent();
      if (featureKey in this.nullGeometryFeatures_) {
        delete this.nullGeometryFeatures_[featureKey];
        if (this.featuresRtree_) {
          this.featuresRtree_.insert(extent, feature);
        }
      } else {
        if (this.featuresRtree_) {
          this.featuresRtree_.update(extent, feature);
        }
      }
    }
    const id = feature.getId();
    if (id !== void 0) {
      const sid = id.toString();
      if (this.idIndex_[sid] !== feature) {
        this.removeFromIdIndex_(feature);
        this.idIndex_[sid] = feature;
      }
    } else {
      this.removeFromIdIndex_(feature);
      this.uidIndex_[featureKey] = feature;
    }
    this.changed();
    this.dispatchEvent(
      new VectorSourceEvent(VectorEventType.CHANGEFEATURE, feature)
    );
  }
  /**
   * Returns true if the feature is contained within the source.
   * @param {FeatureType} feature Feature.
   * @return {boolean} Has feature.
   * @api
   */
  hasFeature(feature) {
    const id = feature.getId();
    if (id !== void 0) {
      return id in this.idIndex_;
    }
    return getUid(feature) in this.uidIndex_;
  }
  /**
   * @return {boolean} Is empty.
   */
  isEmpty() {
    if (this.featuresRtree_) {
      return this.featuresRtree_.isEmpty() && isEmpty$1(this.nullGeometryFeatures_);
    }
    if (this.featuresCollection_) {
      return this.featuresCollection_.getLength() === 0;
    }
    return true;
  }
  /**
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} resolution Resolution.
   * @param {import("../proj/Projection.js").default} projection Projection.
   */
  loadFeatures(extent, resolution, projection) {
    const loadedExtentsRtree = this.loadedExtentsRtree_;
    const extentsToLoad = this.strategy_(extent, resolution, projection);
    for (let i = 0, ii = extentsToLoad.length; i < ii; ++i) {
      const extentToLoad = extentsToLoad[i];
      const alreadyLoaded = loadedExtentsRtree.forEachInExtent(
        extentToLoad,
        /**
         * @param {{extent: import("../extent.js").Extent}} object Object.
         * @return {boolean} Contains.
         */
        function(object) {
          return containsExtent(object.extent, extentToLoad);
        }
      );
      if (!alreadyLoaded) {
        ++this.loadingExtentsCount_;
        this.dispatchEvent(
          new VectorSourceEvent(VectorEventType.FEATURESLOADSTART)
        );
        this.loader_.call(
          this,
          extentToLoad,
          resolution,
          projection,
          /**
           * @param {Array<FeatureType>} features Loaded features
           */
          (features) => {
            --this.loadingExtentsCount_;
            this.dispatchEvent(
              new VectorSourceEvent(
                VectorEventType.FEATURESLOADEND,
                void 0,
                features
              )
            );
          },
          () => {
            --this.loadingExtentsCount_;
            this.dispatchEvent(
              new VectorSourceEvent(VectorEventType.FEATURESLOADERROR)
            );
          }
        );
        loadedExtentsRtree.insert(extentToLoad, { extent: extentToLoad.slice() });
      }
    }
    this.loading = this.loader_.length < 4 ? false : this.loadingExtentsCount_ > 0;
  }
  /**
   * @override
   */
  refresh() {
    this.clear(true);
    this.loadedExtentsRtree_.clear();
    super.refresh();
  }
  /**
   * Remove an extent from the list of loaded extents.
   * @param {import("../extent.js").Extent} extent Extent.
   * @api
   */
  removeLoadedExtent(extent) {
    const loadedExtentsRtree = this.loadedExtentsRtree_;
    const obj = loadedExtentsRtree.forEachInExtent(extent, function(object) {
      if (equals$1(object.extent, extent)) {
        return object;
      }
    });
    if (obj) {
      loadedExtentsRtree.remove(obj);
    }
  }
  /**
   * Batch remove features from the source.  If you want to remove all features
   * at once, use the {@link module:ol/source/Vector~VectorSource#clear #clear()} method
   * instead.
   * @param {Array<FeatureType>} features Features to remove.
   * @api
   */
  removeFeatures(features) {
    let removed = false;
    for (let i = 0, ii = features.length; i < ii; ++i) {
      removed = this.removeFeatureInternal(features[i]) || removed;
    }
    if (removed) {
      this.changed();
    }
  }
  /**
   * Remove a single feature from the source. If you want to batch remove
   * features, use the {@link module:ol/source/Vector~VectorSource#removeFeatures #removeFeatures()} method
   * instead.
   * @param {FeatureType} feature Feature to remove.
   * @api
   */
  removeFeature(feature) {
    if (!feature) {
      return;
    }
    const removed = this.removeFeatureInternal(feature);
    if (removed) {
      this.changed();
    }
  }
  /**
   * Remove feature without firing a `change` event.
   * @param {FeatureType} feature Feature.
   * @return {boolean} True if the feature was removed, false if it was not found.
   * @protected
   */
  removeFeatureInternal(feature) {
    const featureKey = getUid(feature);
    if (!(featureKey in this.uidIndex_)) {
      return false;
    }
    if (featureKey in this.nullGeometryFeatures_) {
      delete this.nullGeometryFeatures_[featureKey];
    } else {
      if (this.featuresRtree_) {
        this.featuresRtree_.remove(feature);
      }
    }
    const featureChangeKeys = this.featureChangeKeys_[featureKey];
    featureChangeKeys?.forEach(unlistenByKey);
    delete this.featureChangeKeys_[featureKey];
    const id = feature.getId();
    if (id !== void 0) {
      const idString = id.toString();
      const indexedFeature = this.idIndex_[idString];
      if (indexedFeature === feature) {
        delete this.idIndex_[idString];
      } else if (Array.isArray(indexedFeature)) {
        indexedFeature.splice(indexedFeature.indexOf(feature), 1);
        if (indexedFeature.length === 1) {
          this.idIndex_[idString] = indexedFeature[0];
        }
      }
    }
    delete this.uidIndex_[featureKey];
    if (this.hasListener(VectorEventType.REMOVEFEATURE)) {
      this.dispatchEvent(
        new VectorSourceEvent(VectorEventType.REMOVEFEATURE, feature)
      );
    }
    return true;
  }
  /**
   * Remove a feature from the id index.  Called internally when the feature id
   * may have changed.
   * @param {FeatureType} feature The feature.
   * @private
   */
  removeFromIdIndex_(feature) {
    for (const id in this.idIndex_) {
      if (this.idIndex_[id] === feature) {
        delete this.idIndex_[id];
        break;
      }
    }
  }
  /**
   * Set the new loader of the source. The next render cycle will use the
   * new loader.
   * @param {import("../featureloader.js").FeatureLoader} loader The loader to set.
   * @api
   */
  setLoader(loader) {
    this.loader_ = loader;
  }
  /**
   * Points the source to a new url. The next render cycle will use the new url.
   * @param {string|import("../featureloader.js").FeatureUrlFunction} url Url.
   * @api
   */
  setUrl(url) {
    assert(this.format_, "`format` must be set when `url` is set");
    this.url_ = url;
    this.setLoader(xhr(url, this.format_));
  }
  /**
   * @param {boolean} overlaps The source can have overlapping geometries.
   */
  setOverlaps(overlaps) {
    this.overlaps_ = overlaps;
    this.changed();
  }
}
const TranslateEventType = {
  /**
   * Triggered upon feature translation start.
   * @event TranslateEvent#translatestart
   * @api
   */
  TRANSLATESTART: "translatestart",
  /**
   * Triggered upon feature translation.
   * @event TranslateEvent#translating
   * @api
   */
  TRANSLATING: "translating",
  /**
   * Triggered upon feature translation end.
   * @event TranslateEvent#translateend
   * @api
   */
  TRANSLATEEND: "translateend"
};
class TranslateEvent extends BaseEvent {
  /**
   * @param {TranslateEventType} type Type.
   * @param {Collection<Feature>} features The features translated.
   * @param {import("../coordinate.js").Coordinate} coordinate The event coordinate.
   * @param {import("../coordinate.js").Coordinate} startCoordinate The original coordinates before.translation started
   * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
   */
  constructor(type, features, coordinate, startCoordinate, mapBrowserEvent) {
    super(type);
    this.features = features;
    this.coordinate = coordinate;
    this.startCoordinate = startCoordinate;
    this.mapBrowserEvent = mapBrowserEvent;
  }
}
class Translate extends PointerInteraction {
  /**
   * @param {Options} [options] Options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super(
      /** @type {import("./Pointer.js").Options} */
      options2
    );
    this.on;
    this.once;
    this.un;
    this.lastCoordinate_ = null;
    this.startCoordinate_ = null;
    this.features_ = options2.features !== void 0 ? options2.features : null;
    let layerFilter;
    if (options2.layers && !this.features_) {
      if (typeof options2.layers === "function") {
        layerFilter = options2.layers;
      } else {
        const layers = options2.layers;
        layerFilter = function(layer) {
          return layers.includes(layer);
        };
      }
    } else {
      layerFilter = TRUE;
    }
    this.layerFilter_ = layerFilter;
    this.filter_ = options2.filter && !this.features_ ? options2.filter : TRUE;
    this.hitTolerance_ = options2.hitTolerance ? options2.hitTolerance : 0;
    this.condition_ = options2.condition ? options2.condition : always$1;
    this.lastFeature_ = null;
    this.addChangeListener(
      InteractionProperty.ACTIVE,
      this.handleActiveChanged_
    );
  }
  /**
   * Handle pointer down events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleDownEvent(event) {
    if (!event.originalEvent || !this.condition_(event)) {
      return false;
    }
    this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
    if (!this.lastCoordinate_ && this.lastFeature_) {
      this.startCoordinate_ = event.coordinate;
      this.lastCoordinate_ = event.coordinate;
      this.handleMoveEvent(event);
      const features = this.features_ || new Collection([this.lastFeature_]);
      this.dispatchEvent(
        new TranslateEvent(
          TranslateEventType.TRANSLATESTART,
          features,
          event.coordinate,
          this.startCoordinate_,
          event
        )
      );
      return true;
    }
    return false;
  }
  /**
   * Handle pointer up events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @return {boolean} If the event was consumed.
   * @override
   */
  handleUpEvent(event) {
    if (this.lastCoordinate_) {
      this.lastCoordinate_ = null;
      this.handleMoveEvent(event);
      const features = this.features_ || new Collection([this.lastFeature_]);
      this.dispatchEvent(
        new TranslateEvent(
          TranslateEventType.TRANSLATEEND,
          features,
          event.coordinate,
          this.startCoordinate_,
          event
        )
      );
      this.startCoordinate_ = null;
      return true;
    }
    return false;
  }
  /**
   * Handle pointer drag events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @override
   */
  handleDragEvent(event) {
    if (this.lastCoordinate_) {
      const newCoordinate = event.coordinate;
      const projection = event.map.getView().getProjection();
      const newViewCoordinate = fromUserCoordinate(newCoordinate, projection);
      const lastViewCoordinate = fromUserCoordinate(
        this.lastCoordinate_,
        projection
      );
      const deltaX = newViewCoordinate[0] - lastViewCoordinate[0];
      const deltaY = newViewCoordinate[1] - lastViewCoordinate[1];
      const features = this.features_ || new Collection([this.lastFeature_]);
      const userProjection2 = getUserProjection();
      features.forEach(function(feature) {
        const geom = feature.getGeometry();
        if (userProjection2) {
          geom.transform(userProjection2, projection);
          geom.translate(deltaX, deltaY);
          geom.transform(projection, userProjection2);
        } else {
          geom.translate(deltaX, deltaY);
        }
        feature.setGeometry(geom);
      });
      this.lastCoordinate_ = newCoordinate;
      this.dispatchEvent(
        new TranslateEvent(
          TranslateEventType.TRANSLATING,
          features,
          newCoordinate,
          this.startCoordinate_,
          event
        )
      );
    }
  }
  /**
   * Handle pointer move events.
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @override
   */
  handleMoveEvent(event) {
    const elem = event.map.getViewport();
    if (this.featuresAtPixel_(event.pixel, event.map)) {
      elem.classList.remove(this.lastCoordinate_ ? "ol-grab" : "ol-grabbing");
      elem.classList.add(this.lastCoordinate_ ? "ol-grabbing" : "ol-grab");
    } else {
      elem.classList.remove("ol-grab", "ol-grabbing");
    }
  }
  /**
   * Tests to see if the given coordinates intersects any of our selected
   * features.
   * @param {import("../pixel.js").Pixel} pixel Pixel coordinate to test for intersection.
   * @param {import("../Map.js").default} map Map to test the intersection on.
   * @return {Feature} Returns the feature found at the specified pixel
   * coordinates.
   * @private
   */
  featuresAtPixel_(pixel, map) {
    return map.forEachFeatureAtPixel(
      pixel,
      (feature, layer) => {
        if (!(feature instanceof Feature) || !this.filter_(feature, layer)) {
          return void 0;
        }
        if (this.features_ && !this.features_.getArray().includes(feature)) {
          return void 0;
        }
        return feature;
      },
      {
        layerFilter: this.layerFilter_,
        hitTolerance: this.hitTolerance_
      }
    );
  }
  /**
   * Returns the Hit-detection tolerance.
   * @return {number} Hit tolerance in pixels.
   * @api
   */
  getHitTolerance() {
    return this.hitTolerance_;
  }
  /**
   * Hit-detection tolerance. Pixels inside the radius around the given position
   * will be checked for features.
   * @param {number} hitTolerance Hit tolerance in pixels.
   * @api
   */
  setHitTolerance(hitTolerance) {
    this.hitTolerance_ = hitTolerance;
  }
  /**
   * Remove the interaction from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {import("../Map.js").default} map Map.
   * @override
   */
  setMap(map) {
    const oldMap = this.getMap();
    super.setMap(map);
    this.updateState_(oldMap);
  }
  /**
   * @private
   */
  handleActiveChanged_() {
    this.updateState_(null);
  }
  /**
   * @param {import("../Map.js").default} oldMap Old map.
   * @private
   */
  updateState_(oldMap) {
    let map = this.getMap();
    const active = this.getActive();
    if (!map || !active) {
      map = map || oldMap;
      if (map) {
        const elem = map.getViewport();
        elem.classList.remove("ol-grab", "ol-grabbing");
      }
    }
  }
}
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const MapMixin = (superClass) => class extends FocusMixin(ResizeMixin(superClass)) {
  constructor() {
    super();
    this._mapTarget = document.createElement("div");
    this._mapTarget.id = "map";
    this._mapTarget.setAttribute("tabindex", "0");
    const options2 = {
      // Override default controls to remove default labels, which is required to
      // correctly display icons through pseudo-element
      controls: defaults$1({
        rotate: false,
        zoomOptions: { zoomInLabel: "", zoomOutLabel: "" }
      }),
      // Override default interactions to allow mouse-wheel zoom + drag-pan when not focused
      interactions: defaults({ onFocusOnly: false }),
      target: this._mapTarget
    };
    this._configuration = new Map$2(options2);
  }
  /**
   * The internal OpenLayers map instance used to configure the map.
   * See the OpenLayers [API](https://openlayers.org/en/latest/apidoc/) and
   * [examples](https://openlayers.org/en/latest/examples/) for further information.
   * @returns {*}
   */
  get configuration() {
    return this._configuration;
  }
  /** @protected */
  ready() {
    super.ready();
    this.shadowRoot.appendChild(this._mapTarget);
    this.__addMapFocusListeners();
  }
  /**
   * Implements resize callback from ResizeMixin to update size of OL map instance
   * @override
   * @protected
   */
  _onResize(_contentRect) {
    this._configuration.updateSize();
  }
  /**
   * Registers focus listeners on the map container to manually manage focus in
   * FocusMixin. FocusMixin currently assumes that the focusable element will
   * be in the light DOM and is available as event target.
   * The map container however is in the shadow DOM and thus focus events will
   * always have the host element as target.
   * @private
   */
  __addMapFocusListeners() {
    this._mapTarget.addEventListener("focusin", (e) => {
      if (e.target === this._mapTarget) {
        this._setFocused(true);
      }
    });
    this._mapTarget.addEventListener("focusout", () => {
      this._setFocused(false);
    });
  }
  /**
   * Overrides method from `FocusMixin` to disable automatic focus management.
   * See custom logic in __addMapFocusListeners
   *
   * @param {FocusEvent} _event
   * @return {boolean}
   * @override
   * @protected
   */
  _shouldSetFocus(_event) {
    return false;
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
let Map$1 = class Map3 extends MapMixin(ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-map";
  }
  static get cvdlName() {
    return "vaadin-map";
  }
  static get styles() {
    return mapStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html``;
  }
};
defineCustomElement(Map$1);
function register(proj42) {
  const projCodes = Object.keys(proj42.defs);
  const len = projCodes.length;
  let i, j;
  for (i = 0; i < len; ++i) {
    const code = projCodes[i];
    if (!get$4(code)) {
      const def = proj42.defs(code);
      let units2 = (
        /** @type {import("./Units.js").Units} */
        def.units
      );
      if (!units2 && def.projName === "longlat") {
        units2 = "degrees";
      }
      addProjection(
        new Projection$1({
          code,
          axisOrientation: def.axis,
          metersPerUnit: def.to_meter,
          units: units2
        })
      );
    }
  }
  for (i = 0; i < len; ++i) {
    const code1 = projCodes[i];
    const proj1 = get$4(code1);
    for (j = 0; j < len; ++j) {
      const code2 = projCodes[j];
      const proj2 = get$4(code2);
      if (!get$3(code1, code2)) {
        if (proj42.defs[code1] === proj42.defs[code2]) {
          addEquivalentProjections([proj1, proj2]);
        } else {
          const transform2 = proj42(code1, code2);
          addCoordinateTransforms(
            proj1,
            proj2,
            createSafeCoordinateTransform(proj1, proj2, transform2.forward),
            createSafeCoordinateTransform(proj2, proj1, transform2.inverse)
          );
        }
      }
    }
  }
}
function globals(defs2) {
  defs2("EPSG:4326", "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees");
  defs2("EPSG:4269", "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees");
  defs2("EPSG:3857", "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs");
  for (var i = 1; i <= 60; ++i) {
    defs2("EPSG:" + (32600 + i), "+proj=utm +zone=" + i + " +datum=WGS84 +units=m");
    defs2("EPSG:" + (32700 + i), "+proj=utm +zone=" + i + " +south +datum=WGS84 +units=m");
  }
  defs2.WGS84 = defs2["EPSG:4326"];
  defs2["EPSG:3785"] = defs2["EPSG:3857"];
  defs2.GOOGLE = defs2["EPSG:3857"];
  defs2["EPSG:900913"] = defs2["EPSG:3857"];
  defs2["EPSG:102113"] = defs2["EPSG:3857"];
}
var PJD_3PARAM = 1;
var PJD_7PARAM = 2;
var PJD_GRIDSHIFT = 3;
var PJD_WGS84 = 4;
var PJD_NODATUM = 5;
var SRS_WGS84_SEMIMAJOR = 6378137;
var SRS_WGS84_SEMIMINOR = 6356752314e-3;
var SRS_WGS84_ESQUARED = 0.0066943799901413165;
var SEC_TO_RAD = 484813681109536e-20;
var HALF_PI = Math.PI / 2;
var SIXTH = 0.16666666666666666;
var RA4 = 0.04722222222222222;
var RA6 = 0.022156084656084655;
var EPSLN = 1e-10;
var D2R$1 = 0.017453292519943295;
var R2D = 57.29577951308232;
var FORTPI = Math.PI / 4;
var TWO_PI = Math.PI * 2;
var SPI = 3.14159265359;
var exports$1 = {};
exports$1.greenwich = 0;
exports$1.lisbon = -9.131906111111;
exports$1.paris = 2.337229166667;
exports$1.bogota = -74.080916666667;
exports$1.madrid = -3.687938888889;
exports$1.rome = 12.452333333333;
exports$1.bern = 7.439583333333;
exports$1.jakarta = 106.807719444444;
exports$1.ferro = -17.666666666667;
exports$1.brussels = 4.367975;
exports$1.stockholm = 18.058277777778;
exports$1.athens = 23.7163375;
exports$1.oslo = 10.722916666667;
const units = {
  mm: { to_meter: 1e-3 },
  cm: { to_meter: 0.01 },
  ft: { to_meter: 0.3048 },
  "us-ft": { to_meter: 1200 / 3937 },
  fath: { to_meter: 1.8288 },
  kmi: { to_meter: 1852 },
  "us-ch": { to_meter: 20.1168402336805 },
  "us-mi": { to_meter: 1609.34721869444 },
  km: { to_meter: 1e3 },
  "ind-ft": { to_meter: 0.30479841 },
  "ind-yd": { to_meter: 0.91439523 },
  mi: { to_meter: 1609.344 },
  yd: { to_meter: 0.9144 },
  ch: { to_meter: 20.1168 },
  link: { to_meter: 0.201168 },
  dm: { to_meter: 0.1 },
  in: { to_meter: 0.0254 },
  "ind-ch": { to_meter: 20.11669506 },
  "us-in": { to_meter: 0.025400050800101 },
  "us-yd": { to_meter: 0.914401828803658 }
};
var ignoredChar = /[\s_\-\/\(\)]/g;
function match(obj, key2) {
  if (obj[key2]) {
    return obj[key2];
  }
  var keys = Object.keys(obj);
  var lkey = key2.toLowerCase().replace(ignoredChar, "");
  var i = -1;
  var testkey, processedKey;
  while (++i < keys.length) {
    testkey = keys[i];
    processedKey = testkey.toLowerCase().replace(ignoredChar, "");
    if (processedKey === lkey) {
      return obj[testkey];
    }
  }
}
function projStr(defData) {
  var self2 = {};
  var paramObj = defData.split("+").map(function(v) {
    return v.trim();
  }).filter(function(a) {
    return a;
  }).reduce(function(p, a) {
    var split = a.split("=");
    split.push(true);
    p[split[0].toLowerCase()] = split[1];
    return p;
  }, {});
  var paramName, paramVal, paramOutname;
  var params2 = {
    proj: "projName",
    datum: "datumCode",
    rf: function(v) {
      self2.rf = parseFloat(v);
    },
    lat_0: function(v) {
      self2.lat0 = v * D2R$1;
    },
    lat_1: function(v) {
      self2.lat1 = v * D2R$1;
    },
    lat_2: function(v) {
      self2.lat2 = v * D2R$1;
    },
    lat_ts: function(v) {
      self2.lat_ts = v * D2R$1;
    },
    lon_0: function(v) {
      self2.long0 = v * D2R$1;
    },
    lon_1: function(v) {
      self2.long1 = v * D2R$1;
    },
    lon_2: function(v) {
      self2.long2 = v * D2R$1;
    },
    alpha: function(v) {
      self2.alpha = parseFloat(v) * D2R$1;
    },
    gamma: function(v) {
      self2.rectified_grid_angle = parseFloat(v) * D2R$1;
    },
    lonc: function(v) {
      self2.longc = v * D2R$1;
    },
    x_0: function(v) {
      self2.x0 = parseFloat(v);
    },
    y_0: function(v) {
      self2.y0 = parseFloat(v);
    },
    k_0: function(v) {
      self2.k0 = parseFloat(v);
    },
    k: function(v) {
      self2.k0 = parseFloat(v);
    },
    a: function(v) {
      self2.a = parseFloat(v);
    },
    b: function(v) {
      self2.b = parseFloat(v);
    },
    r: function(v) {
      self2.a = self2.b = parseFloat(v);
    },
    r_a: function() {
      self2.R_A = true;
    },
    zone: function(v) {
      self2.zone = parseInt(v, 10);
    },
    south: function() {
      self2.utmSouth = true;
    },
    towgs84: function(v) {
      self2.datum_params = v.split(",").map(function(a) {
        return parseFloat(a);
      });
    },
    to_meter: function(v) {
      self2.to_meter = parseFloat(v);
    },
    units: function(v) {
      self2.units = v;
      var unit = match(units, v);
      if (unit) {
        self2.to_meter = unit.to_meter;
      }
    },
    from_greenwich: function(v) {
      self2.from_greenwich = v * D2R$1;
    },
    pm: function(v) {
      var pm = match(exports$1, v);
      self2.from_greenwich = (pm ? pm : parseFloat(v)) * D2R$1;
    },
    nadgrids: function(v) {
      if (v === "@null") {
        self2.datumCode = "none";
      } else {
        self2.nadgrids = v;
      }
    },
    axis: function(v) {
      var legalAxis = "ewnsud";
      if (v.length === 3 && legalAxis.indexOf(v.substr(0, 1)) !== -1 && legalAxis.indexOf(v.substr(1, 1)) !== -1 && legalAxis.indexOf(v.substr(2, 1)) !== -1) {
        self2.axis = v;
      }
    },
    approx: function() {
      self2.approx = true;
    }
  };
  for (paramName in paramObj) {
    paramVal = paramObj[paramName];
    if (paramName in params2) {
      paramOutname = params2[paramName];
      if (typeof paramOutname === "function") {
        paramOutname(paramVal);
      } else {
        self2[paramOutname] = paramVal;
      }
    } else {
      self2[paramName] = paramVal;
    }
  }
  if (typeof self2.datumCode === "string" && self2.datumCode !== "WGS84") {
    self2.datumCode = self2.datumCode.toLowerCase();
  }
  return self2;
}
class PROJJSONBuilderBase {
  static getId(node) {
    const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID");
    if (idNode && idNode.length >= 3) {
      return {
        authority: idNode[1],
        code: parseInt(idNode[2], 10)
      };
    }
    return null;
  }
  static convertUnit(node, type = "unit") {
    if (!node || node.length < 3) {
      return { type, name: "unknown", conversion_factor: null };
    }
    const name = node[1];
    const conversionFactor = parseFloat(node[2]) || null;
    const idNode = node.find((child) => Array.isArray(child) && child[0] === "ID");
    const id = idNode ? {
      authority: idNode[1],
      code: parseInt(idNode[2], 10)
    } : null;
    return {
      type,
      name,
      conversion_factor: conversionFactor,
      id
    };
  }
  static convertAxis(node) {
    const name = node[1] || "Unknown";
    let direction;
    const abbreviationMatch = name.match(/^\((.)\)$/);
    if (abbreviationMatch) {
      const abbreviation = abbreviationMatch[1].toUpperCase();
      if (abbreviation === "E") direction = "east";
      else if (abbreviation === "N") direction = "north";
      else if (abbreviation === "U") direction = "up";
      else if (node[2]) direction = node[2];
      else throw new Error(`Unknown axis abbreviation: ${abbreviation}`);
    } else {
      direction = node[2] || "unknown";
    }
    const orderNode = node.find((child) => Array.isArray(child) && child[0] === "ORDER");
    const order = orderNode ? parseInt(orderNode[1], 10) : null;
    const unitNode = node.find(
      (child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT")
    );
    const unit = this.convertUnit(unitNode);
    return {
      name,
      direction,
      // Use the valid PROJJSON direction value
      unit,
      order
    };
  }
  static extractAxes(node) {
    return node.filter((child) => Array.isArray(child) && child[0] === "AXIS").map((axis) => this.convertAxis(axis)).sort((a, b) => (a.order || 0) - (b.order || 0));
  }
  static convert(node, result = {}) {
    switch (node[0]) {
      case "PROJCRS":
        result.type = "ProjectedCRS";
        result.name = node[1];
        result.base_crs = node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "BASEGEOGCRS")) : null;
        result.conversion = node.find((child) => Array.isArray(child) && child[0] === "CONVERSION") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "CONVERSION")) : null;
        const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS");
        if (csNode) {
          result.coordinate_system = {
            type: csNode[1],
            axis: this.extractAxes(node)
          };
        }
        const lengthUnitNode = node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT");
        if (lengthUnitNode) {
          const unit2 = this.convertUnit(lengthUnitNode);
          result.coordinate_system.unit = unit2;
        }
        result.id = this.getId(node);
        break;
      case "BASEGEOGCRS":
      case "GEOGCRS":
      case "GEODCRS":
        result.type = node[0] === "GEODCRS" ? "GeodeticCRS" : "GeographicCRS";
        result.name = node[1];
        const datumOrEnsembleNode = node.find(
          (child) => Array.isArray(child) && (child[0] === "DATUM" || child[0] === "ENSEMBLE")
        );
        if (datumOrEnsembleNode) {
          const datumOrEnsemble = this.convert(datumOrEnsembleNode);
          if (datumOrEnsembleNode[0] === "ENSEMBLE") {
            result.datum_ensemble = datumOrEnsemble;
          } else {
            result.datum = datumOrEnsemble;
          }
          const primem = node.find((child) => Array.isArray(child) && child[0] === "PRIMEM");
          if (primem && primem[1] !== "Greenwich") {
            datumOrEnsemble.prime_meridian = {
              name: primem[1],
              longitude: parseFloat(primem[2])
            };
          }
        }
        result.coordinate_system = {
          type: "ellipsoidal",
          axis: this.extractAxes(node)
        };
        result.id = this.getId(node);
        break;
      case "DATUM":
        result.type = "GeodeticReferenceFrame";
        result.name = node[1];
        result.ellipsoid = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID")) : null;
        break;
      case "ENSEMBLE":
        result.type = "DatumEnsemble";
        result.name = node[1];
        result.members = node.filter((child) => Array.isArray(child) && child[0] === "MEMBER").map((member) => ({
          type: "DatumEnsembleMember",
          name: member[1],
          id: this.getId(member)
          // Extract ID as { authority, code }
        }));
        const accuracyNode = node.find((child) => Array.isArray(child) && child[0] === "ENSEMBLEACCURACY");
        if (accuracyNode) {
          result.accuracy = parseFloat(accuracyNode[1]);
        }
        const ellipsoidNode = node.find((child) => Array.isArray(child) && child[0] === "ELLIPSOID");
        if (ellipsoidNode) {
          result.ellipsoid = this.convert(ellipsoidNode);
        }
        result.id = this.getId(node);
        break;
      case "ELLIPSOID":
        result.type = "Ellipsoid";
        result.name = node[1];
        result.semi_major_axis = parseFloat(node[2]);
        result.inverse_flattening = parseFloat(node[3]);
        node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "LENGTHUNIT"), result) : null;
        break;
      case "CONVERSION":
        result.type = "Conversion";
        result.name = node[1];
        result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null;
        result.parameters = node.filter((child) => Array.isArray(child) && child[0] === "PARAMETER").map((param) => this.convert(param));
        break;
      case "METHOD":
        result.type = "Method";
        result.name = node[1];
        result.id = this.getId(node);
        break;
      case "PARAMETER":
        result.type = "Parameter";
        result.name = node[1];
        result.value = parseFloat(node[2]);
        result.unit = this.convertUnit(
          node.find(
            (child) => Array.isArray(child) && (child[0] === "LENGTHUNIT" || child[0] === "ANGLEUNIT" || child[0] === "SCALEUNIT")
          )
        );
        result.id = this.getId(node);
        break;
      case "BOUNDCRS":
        result.type = "BoundCRS";
        const sourceCrsNode = node.find((child) => Array.isArray(child) && child[0] === "SOURCECRS");
        if (sourceCrsNode) {
          const sourceCrsContent = sourceCrsNode.find((child) => Array.isArray(child));
          result.source_crs = sourceCrsContent ? this.convert(sourceCrsContent) : null;
        }
        const targetCrsNode = node.find((child) => Array.isArray(child) && child[0] === "TARGETCRS");
        if (targetCrsNode) {
          const targetCrsContent = targetCrsNode.find((child) => Array.isArray(child));
          result.target_crs = targetCrsContent ? this.convert(targetCrsContent) : null;
        }
        const transformationNode = node.find((child) => Array.isArray(child) && child[0] === "ABRIDGEDTRANSFORMATION");
        if (transformationNode) {
          result.transformation = this.convert(transformationNode);
        } else {
          result.transformation = null;
        }
        break;
      case "ABRIDGEDTRANSFORMATION":
        result.type = "Transformation";
        result.name = node[1];
        result.method = node.find((child) => Array.isArray(child) && child[0] === "METHOD") ? this.convert(node.find((child) => Array.isArray(child) && child[0] === "METHOD")) : null;
        result.parameters = node.filter((child) => Array.isArray(child) && (child[0] === "PARAMETER" || child[0] === "PARAMETERFILE")).map((param) => {
          if (param[0] === "PARAMETER") {
            return this.convert(param);
          } else if (param[0] === "PARAMETERFILE") {
            return {
              name: param[1],
              value: param[2],
              id: {
                "authority": "EPSG",
                "code": 8656
              }
            };
          }
        });
        if (result.parameters.length === 7) {
          const scaleDifference = result.parameters[6];
          if (scaleDifference.name === "Scale difference") {
            scaleDifference.value = Math.round((scaleDifference.value - 1) * 1e12) / 1e6;
          }
        }
        result.id = this.getId(node);
        break;
      case "AXIS":
        if (!result.coordinate_system) {
          result.coordinate_system = { type: "unspecified", axis: [] };
        }
        result.coordinate_system.axis.push(this.convertAxis(node));
        break;
      case "LENGTHUNIT":
        const unit = this.convertUnit(node, "LinearUnit");
        if (result.coordinate_system && result.coordinate_system.axis) {
          result.coordinate_system.axis.forEach((axis) => {
            if (!axis.unit) {
              axis.unit = unit;
            }
          });
        }
        if (unit.conversion_factor && unit.conversion_factor !== 1) {
          if (result.semi_major_axis) {
            result.semi_major_axis = {
              value: result.semi_major_axis,
              unit
            };
          }
        }
        break;
      default:
        result.keyword = node[0];
        break;
    }
    return result;
  }
}
class PROJJSONBuilder2015 extends PROJJSONBuilderBase {
  static convert(node, result = {}) {
    super.convert(node, result);
    if (result.coordinate_system && result.coordinate_system.subtype === "Cartesian") {
      delete result.coordinate_system;
    }
    if (result.usage) {
      delete result.usage;
    }
    return result;
  }
}
class PROJJSONBuilder2019 extends PROJJSONBuilderBase {
  static convert(node, result = {}) {
    super.convert(node, result);
    const csNode = node.find((child) => Array.isArray(child) && child[0] === "CS");
    if (csNode) {
      result.coordinate_system = {
        subtype: csNode[1],
        axis: this.extractAxes(node)
      };
    }
    const usageNode = node.find((child) => Array.isArray(child) && child[0] === "USAGE");
    if (usageNode) {
      const scope = usageNode.find((child) => Array.isArray(child) && child[0] === "SCOPE");
      const area = usageNode.find((child) => Array.isArray(child) && child[0] === "AREA");
      const bbox = usageNode.find((child) => Array.isArray(child) && child[0] === "BBOX");
      result.usage = {};
      if (scope) {
        result.usage.scope = scope[1];
      }
      if (area) {
        result.usage.area = area[1];
      }
      if (bbox) {
        result.usage.bbox = bbox.slice(1);
      }
    }
    return result;
  }
}
function detectWKT2Version(root) {
  if (root.find((child) => Array.isArray(child) && child[0] === "USAGE")) {
    return "2019";
  }
  if (root.find((child) => Array.isArray(child) && child[0] === "CS")) {
    return "2015";
  }
  if (root[0] === "BOUNDCRS" || root[0] === "PROJCRS" || root[0] === "GEOGCRS") {
    return "2015";
  }
  return "2015";
}
function buildPROJJSON(root) {
  const version = detectWKT2Version(root);
  const builder = version === "2019" ? PROJJSONBuilder2019 : PROJJSONBuilder2015;
  return builder.convert(root);
}
function detectWKTVersion(wkt2) {
  const normalizedWKT = wkt2.toUpperCase();
  if (normalizedWKT.includes("PROJCRS") || normalizedWKT.includes("GEOGCRS") || normalizedWKT.includes("BOUNDCRS") || normalizedWKT.includes("VERTCRS") || normalizedWKT.includes("LENGTHUNIT") || normalizedWKT.includes("ANGLEUNIT") || normalizedWKT.includes("SCALEUNIT")) {
    return "WKT2";
  }
  if (normalizedWKT.includes("PROJCS") || normalizedWKT.includes("GEOGCS") || normalizedWKT.includes("LOCAL_CS") || normalizedWKT.includes("VERT_CS") || normalizedWKT.includes("UNIT")) {
    return "WKT1";
  }
  return "WKT1";
}
var NEUTRAL = 1;
var KEYWORD = 2;
var NUMBER = 3;
var QUOTED = 4;
var AFTERQUOTE = 5;
var ENDED = -1;
var whitespace = /\s/;
var latin = /[A-Za-z]/;
var keyword = /[A-Za-z84_]/;
var endThings = /[,\]]/;
var digets = /[\d\.E\-\+]/;
function Parser(text) {
  if (typeof text !== "string") {
    throw new Error("not a string");
  }
  this.text = text.trim();
  this.level = 0;
  this.place = 0;
  this.root = null;
  this.stack = [];
  this.currentObject = null;
  this.state = NEUTRAL;
}
Parser.prototype.readCharicter = function() {
  var char = this.text[this.place++];
  if (this.state !== QUOTED) {
    while (whitespace.test(char)) {
      if (this.place >= this.text.length) {
        return;
      }
      char = this.text[this.place++];
    }
  }
  switch (this.state) {
    case NEUTRAL:
      return this.neutral(char);
    case KEYWORD:
      return this.keyword(char);
    case QUOTED:
      return this.quoted(char);
    case AFTERQUOTE:
      return this.afterquote(char);
    case NUMBER:
      return this.number(char);
    case ENDED:
      return;
  }
};
Parser.prototype.afterquote = function(char) {
  if (char === '"') {
    this.word += '"';
    this.state = QUOTED;
    return;
  }
  if (endThings.test(char)) {
    this.word = this.word.trim();
    this.afterItem(char);
    return;
  }
  throw new Error(`havn't handled "` + char + '" in afterquote yet, index ' + this.place);
};
Parser.prototype.afterItem = function(char) {
  if (char === ",") {
    if (this.word !== null) {
      this.currentObject.push(this.word);
    }
    this.word = null;
    this.state = NEUTRAL;
    return;
  }
  if (char === "]") {
    this.level--;
    if (this.word !== null) {
      this.currentObject.push(this.word);
      this.word = null;
    }
    this.state = NEUTRAL;
    this.currentObject = this.stack.pop();
    if (!this.currentObject) {
      this.state = ENDED;
    }
    return;
  }
};
Parser.prototype.number = function(char) {
  if (digets.test(char)) {
    this.word += char;
    return;
  }
  if (endThings.test(char)) {
    this.word = parseFloat(this.word);
    this.afterItem(char);
    return;
  }
  throw new Error(`havn't handled "` + char + '" in number yet, index ' + this.place);
};
Parser.prototype.quoted = function(char) {
  if (char === '"') {
    this.state = AFTERQUOTE;
    return;
  }
  this.word += char;
  return;
};
Parser.prototype.keyword = function(char) {
  if (keyword.test(char)) {
    this.word += char;
    return;
  }
  if (char === "[") {
    var newObjects = [];
    newObjects.push(this.word);
    this.level++;
    if (this.root === null) {
      this.root = newObjects;
    } else {
      this.currentObject.push(newObjects);
    }
    this.stack.push(this.currentObject);
    this.currentObject = newObjects;
    this.state = NEUTRAL;
    return;
  }
  if (endThings.test(char)) {
    this.afterItem(char);
    return;
  }
  throw new Error(`havn't handled "` + char + '" in keyword yet, index ' + this.place);
};
Parser.prototype.neutral = function(char) {
  if (latin.test(char)) {
    this.word = char;
    this.state = KEYWORD;
    return;
  }
  if (char === '"') {
    this.word = "";
    this.state = QUOTED;
    return;
  }
  if (digets.test(char)) {
    this.word = char;
    this.state = NUMBER;
    return;
  }
  if (endThings.test(char)) {
    this.afterItem(char);
    return;
  }
  throw new Error(`havn't handled "` + char + '" in neutral yet, index ' + this.place);
};
Parser.prototype.output = function() {
  while (this.place < this.text.length) {
    this.readCharicter();
  }
  if (this.state === ENDED) {
    return this.root;
  }
  throw new Error('unable to parse string "' + this.text + '". State is ' + this.state);
};
function parseString(txt) {
  var parser = new Parser(txt);
  return parser.output();
}
function mapit(obj, key2, value) {
  if (Array.isArray(key2)) {
    value.unshift(key2);
    key2 = null;
  }
  var thing = key2 ? {} : obj;
  var out = value.reduce(function(newObj, item) {
    sExpr(item, newObj);
    return newObj;
  }, thing);
  if (key2) {
    obj[key2] = out;
  }
}
function sExpr(v, obj) {
  if (!Array.isArray(v)) {
    obj[v] = true;
    return;
  }
  var key2 = v.shift();
  if (key2 === "PARAMETER") {
    key2 = v.shift();
  }
  if (v.length === 1) {
    if (Array.isArray(v[0])) {
      obj[key2] = {};
      sExpr(v[0], obj[key2]);
      return;
    }
    obj[key2] = v[0];
    return;
  }
  if (!v.length) {
    obj[key2] = true;
    return;
  }
  if (key2 === "TOWGS84") {
    obj[key2] = v;
    return;
  }
  if (key2 === "AXIS") {
    if (!(key2 in obj)) {
      obj[key2] = [];
    }
    obj[key2].push(v);
    return;
  }
  if (!Array.isArray(key2)) {
    obj[key2] = {};
  }
  var i;
  switch (key2) {
    case "UNIT":
    case "PRIMEM":
    case "VERT_DATUM":
      obj[key2] = {
        name: v[0].toLowerCase(),
        convert: v[1]
      };
      if (v.length === 3) {
        sExpr(v[2], obj[key2]);
      }
      return;
    case "SPHEROID":
    case "ELLIPSOID":
      obj[key2] = {
        name: v[0],
        a: v[1],
        rf: v[2]
      };
      if (v.length === 4) {
        sExpr(v[3], obj[key2]);
      }
      return;
    case "EDATUM":
    case "ENGINEERINGDATUM":
    case "LOCAL_DATUM":
    case "DATUM":
    case "VERT_CS":
    case "VERTCRS":
    case "VERTICALCRS":
      v[0] = ["name", v[0]];
      mapit(obj, key2, v);
      return;
    case "COMPD_CS":
    case "COMPOUNDCRS":
    case "FITTED_CS":
    // the followings are the crs defined in
    // https://github.com/proj4js/proj4js/blob/1da4ed0b865d0fcb51c136090569210cdcc9019e/lib/parseCode.js#L11
    case "PROJECTEDCRS":
    case "PROJCRS":
    case "GEOGCS":
    case "GEOCCS":
    case "PROJCS":
    case "LOCAL_CS":
    case "GEODCRS":
    case "GEODETICCRS":
    case "GEODETICDATUM":
    case "ENGCRS":
    case "ENGINEERINGCRS":
      v[0] = ["name", v[0]];
      mapit(obj, key2, v);
      obj[key2].type = key2;
      return;
    default:
      i = -1;
      while (++i < v.length) {
        if (!Array.isArray(v[i])) {
          return sExpr(v, obj[key2]);
        }
      }
      return mapit(obj, key2, v);
  }
}
var D2R = 0.017453292519943295;
function d2r(input) {
  return input * D2R;
}
function applyProjectionDefaults(wkt2) {
  const normalizedProjName = (wkt2.projName || "").toLowerCase().replace(/_/g, " ");
  if (!wkt2.long0 && wkt2.longc && (normalizedProjName === "albers conic equal area" || normalizedProjName === "lambert azimuthal equal area")) {
    wkt2.long0 = wkt2.longc;
  }
  if (!wkt2.lat_ts && wkt2.lat1 && (normalizedProjName === "stereographic south pole" || normalizedProjName === "polar stereographic (variant b)")) {
    wkt2.lat0 = d2r(wkt2.lat1 > 0 ? 90 : -90);
    wkt2.lat_ts = wkt2.lat1;
    delete wkt2.lat1;
  } else if (!wkt2.lat_ts && wkt2.lat0 && (normalizedProjName === "polar stereographic" || normalizedProjName === "polar stereographic (variant a)")) {
    wkt2.lat_ts = wkt2.lat0;
    wkt2.lat0 = d2r(wkt2.lat0 > 0 ? 90 : -90);
    delete wkt2.lat1;
  }
}
function processUnit(unit) {
  let result = { units: null, to_meter: void 0 };
  if (typeof unit === "string") {
    result.units = unit.toLowerCase();
    if (result.units === "metre") {
      result.units = "meter";
    }
    if (result.units === "meter") {
      result.to_meter = 1;
    }
  } else if (unit && unit.name) {
    result.units = unit.name.toLowerCase();
    if (result.units === "metre") {
      result.units = "meter";
    }
    result.to_meter = unit.conversion_factor;
  }
  return result;
}
function toValue(valueOrObject) {
  if (typeof valueOrObject === "object") {
    return valueOrObject.value * valueOrObject.unit.conversion_factor;
  }
  return valueOrObject;
}
function calculateEllipsoid(value, result) {
  if (value.ellipsoid.radius) {
    result.a = value.ellipsoid.radius;
    result.rf = 0;
  } else {
    result.a = toValue(value.ellipsoid.semi_major_axis);
    if (value.ellipsoid.inverse_flattening !== void 0) {
      result.rf = value.ellipsoid.inverse_flattening;
    } else if (value.ellipsoid.semi_major_axis !== void 0 && value.ellipsoid.semi_minor_axis !== void 0) {
      result.rf = result.a / (result.a - toValue(value.ellipsoid.semi_minor_axis));
    }
  }
}
function transformPROJJSON(projjson, result = {}) {
  if (!projjson || typeof projjson !== "object") {
    return projjson;
  }
  if (projjson.type === "BoundCRS") {
    transformPROJJSON(projjson.source_crs, result);
    if (projjson.transformation) {
      if (projjson.transformation.method && projjson.transformation.method.name === "NTv2") {
        result.nadgrids = projjson.transformation.parameters[0].value;
      } else {
        result.datum_params = projjson.transformation.parameters.map((param) => param.value);
      }
    }
    return result;
  }
  Object.keys(projjson).forEach((key2) => {
    const value = projjson[key2];
    if (value === null) {
      return;
    }
    switch (key2) {
      case "name":
        if (result.srsCode) {
          break;
        }
        result.name = value;
        result.srsCode = value;
        break;
      case "type":
        if (value === "GeographicCRS") {
          result.projName = "longlat";
        } else if (value === "GeodeticCRS") {
          if (projjson.coordinate_system && projjson.coordinate_system.subtype === "Cartesian") {
            result.projName = "geocent";
          } else {
            result.projName = "longlat";
          }
        } else if (value === "ProjectedCRS" && projjson.conversion && projjson.conversion.method) {
          result.projName = projjson.conversion.method.name;
        }
        break;
      case "datum":
      case "datum_ensemble":
        if (value.ellipsoid) {
          result.ellps = value.ellipsoid.name;
          calculateEllipsoid(value, result);
        }
        if (value.prime_meridian) {
          result.from_greenwich = value.prime_meridian.longitude * Math.PI / 180;
        }
        break;
      case "ellipsoid":
        result.ellps = value.name;
        calculateEllipsoid(value, result);
        break;
      case "prime_meridian":
        result.long0 = (value.longitude || 0) * Math.PI / 180;
        break;
      case "coordinate_system":
        if (value.axis) {
          const directionMap = {
            "east": "e",
            "north": "n",
            "west": "w",
            "south": "s",
            "up": "u",
            "down": "d",
            "geocentricx": "e",
            "geocentricy": "n",
            "geocentricz": "u"
          };
          const mapped = value.axis.map((axis) => directionMap[axis.direction.toLowerCase()]);
          if (mapped.every(Boolean)) {
            result.axis = mapped.join("");
            if (result.axis.length === 2) {
              result.axis += "u";
            }
          }
          if (value.unit) {
            const { units: units2, to_meter } = processUnit(value.unit);
            result.units = units2;
            result.to_meter = to_meter;
          } else if (value.axis[0] && value.axis[0].unit) {
            const { units: units2, to_meter } = processUnit(value.axis[0].unit);
            result.units = units2;
            result.to_meter = to_meter;
          }
        }
        break;
      case "id":
        if (value.authority && value.code) {
          result.title = value.authority + ":" + value.code;
        }
        break;
      case "conversion":
        if (value.method && value.method.name) {
          result.projName = value.method.name;
        }
        if (value.parameters) {
          value.parameters.forEach((param) => {
            const paramName = param.name.toLowerCase().replace(/\s+/g, "_");
            const paramValue = param.value;
            if (param.unit && param.unit.conversion_factor) {
              result[paramName] = paramValue * param.unit.conversion_factor;
            } else if (param.unit === "degree") {
              result[paramName] = paramValue * Math.PI / 180;
            } else {
              result[paramName] = paramValue;
            }
          });
        }
        break;
      case "unit":
        if (value.name) {
          result.units = value.name.toLowerCase();
          if (result.units === "metre") {
            result.units = "meter";
          }
        }
        if (value.conversion_factor) {
          result.to_meter = value.conversion_factor;
        }
        break;
      case "base_crs":
        transformPROJJSON(value, result);
        result.datumCode = value.id ? value.id.authority + "_" + value.id.code : value.name;
        break;
    }
  });
  if (result.latitude_of_false_origin !== void 0) {
    result.lat0 = result.latitude_of_false_origin;
  }
  if (result.longitude_of_false_origin !== void 0) {
    result.long0 = result.longitude_of_false_origin;
  }
  if (result.latitude_of_standard_parallel !== void 0) {
    result.lat0 = result.latitude_of_standard_parallel;
    result.lat1 = result.latitude_of_standard_parallel;
  }
  if (result.latitude_of_1st_standard_parallel !== void 0) {
    result.lat1 = result.latitude_of_1st_standard_parallel;
  }
  if (result.latitude_of_2nd_standard_parallel !== void 0) {
    result.lat2 = result.latitude_of_2nd_standard_parallel;
  }
  if (result.latitude_of_projection_centre !== void 0) {
    result.lat0 = result.latitude_of_projection_centre;
  }
  if (result.longitude_of_projection_centre !== void 0) {
    result.longc = result.longitude_of_projection_centre;
  }
  if (result.easting_at_false_origin !== void 0) {
    result.x0 = result.easting_at_false_origin;
  }
  if (result.northing_at_false_origin !== void 0) {
    result.y0 = result.northing_at_false_origin;
  }
  if (result.latitude_of_natural_origin !== void 0) {
    result.lat0 = result.latitude_of_natural_origin;
  }
  if (result.longitude_of_natural_origin !== void 0) {
    result.long0 = result.longitude_of_natural_origin;
  }
  if (result.longitude_of_origin !== void 0) {
    result.long0 = result.longitude_of_origin;
  }
  if (result.false_easting !== void 0) {
    result.x0 = result.false_easting;
  }
  if (result.easting_at_projection_centre) {
    result.x0 = result.easting_at_projection_centre;
  }
  if (result.false_northing !== void 0) {
    result.y0 = result.false_northing;
  }
  if (result.northing_at_projection_centre) {
    result.y0 = result.northing_at_projection_centre;
  }
  if (result.standard_parallel_1 !== void 0) {
    result.lat1 = result.standard_parallel_1;
  }
  if (result.standard_parallel_2 !== void 0) {
    result.lat2 = result.standard_parallel_2;
  }
  if (result.scale_factor_at_natural_origin !== void 0) {
    result.k0 = result.scale_factor_at_natural_origin;
  }
  if (result.scale_factor_at_projection_centre !== void 0) {
    result.k0 = result.scale_factor_at_projection_centre;
  }
  if (result.scale_factor_on_pseudo_standard_parallel !== void 0) {
    result.k0 = result.scale_factor_on_pseudo_standard_parallel;
  }
  if (result.azimuth !== void 0) {
    result.alpha = result.azimuth;
  }
  if (result.azimuth_at_projection_centre !== void 0) {
    result.alpha = result.azimuth_at_projection_centre;
  }
  if (result.angle_from_rectified_to_skew_grid) {
    result.rectified_grid_angle = result.angle_from_rectified_to_skew_grid;
  }
  applyProjectionDefaults(result);
  return result;
}
var knownTypes = [
  "PROJECTEDCRS",
  "PROJCRS",
  "GEOGCS",
  "GEOCCS",
  "PROJCS",
  "LOCAL_CS",
  "GEODCRS",
  "GEODETICCRS",
  "GEODETICDATUM",
  "ENGCRS",
  "ENGINEERINGCRS"
];
function rename(obj, params2) {
  var outName = params2[0];
  var inName = params2[1];
  if (!(outName in obj) && inName in obj) {
    obj[outName] = obj[inName];
    if (params2.length === 3) {
      obj[outName] = params2[2](obj[outName]);
    }
  }
}
function cleanWKT(wkt2) {
  var keys = Object.keys(wkt2);
  for (var i = 0, ii = keys.length; i < ii; ++i) {
    var key2 = keys[i];
    if (knownTypes.indexOf(key2) !== -1) {
      setPropertiesFromWkt(wkt2[key2]);
    }
    if (typeof wkt2[key2] === "object") {
      cleanWKT(wkt2[key2]);
    }
  }
}
function setPropertiesFromWkt(wkt2) {
  if (wkt2.AUTHORITY) {
    var authority = Object.keys(wkt2.AUTHORITY)[0];
    if (authority && authority in wkt2.AUTHORITY) {
      wkt2.title = authority + ":" + wkt2.AUTHORITY[authority];
    }
  }
  if (wkt2.type === "GEOGCS") {
    wkt2.projName = "longlat";
  } else if (wkt2.type === "LOCAL_CS") {
    wkt2.projName = "identity";
    wkt2.local = true;
  } else {
    if (typeof wkt2.PROJECTION === "object") {
      wkt2.projName = Object.keys(wkt2.PROJECTION)[0];
    } else {
      wkt2.projName = wkt2.PROJECTION;
    }
  }
  if (wkt2.AXIS) {
    var axisOrder = "";
    for (var i = 0, ii = wkt2.AXIS.length; i < ii; ++i) {
      var axis = [wkt2.AXIS[i][0].toLowerCase(), wkt2.AXIS[i][1].toLowerCase()];
      if (axis[0].indexOf("north") !== -1 || (axis[0] === "y" || axis[0] === "lat") && axis[1] === "north") {
        axisOrder += "n";
      } else if (axis[0].indexOf("south") !== -1 || (axis[0] === "y" || axis[0] === "lat") && axis[1] === "south") {
        axisOrder += "s";
      } else if (axis[0].indexOf("east") !== -1 || (axis[0] === "x" || axis[0] === "lon") && axis[1] === "east") {
        axisOrder += "e";
      } else if (axis[0].indexOf("west") !== -1 || (axis[0] === "x" || axis[0] === "lon") && axis[1] === "west") {
        axisOrder += "w";
      }
    }
    if (axisOrder.length === 2) {
      axisOrder += "u";
    }
    if (axisOrder.length === 3) {
      wkt2.axis = axisOrder;
    }
  }
  if (wkt2.UNIT) {
    wkt2.units = wkt2.UNIT.name.toLowerCase();
    if (wkt2.units === "metre") {
      wkt2.units = "meter";
    }
    if (wkt2.UNIT.convert) {
      if (wkt2.type === "GEOGCS") {
        if (wkt2.DATUM && wkt2.DATUM.SPHEROID) {
          wkt2.to_meter = wkt2.UNIT.convert * wkt2.DATUM.SPHEROID.a;
        }
      } else {
        wkt2.to_meter = wkt2.UNIT.convert;
      }
    }
  }
  var geogcs = wkt2.GEOGCS;
  if (wkt2.type === "GEOGCS") {
    geogcs = wkt2;
  }
  if (geogcs) {
    if (geogcs.DATUM) {
      wkt2.datumCode = geogcs.DATUM.name.toLowerCase();
    } else {
      wkt2.datumCode = geogcs.name.toLowerCase();
    }
    if (wkt2.datumCode.slice(0, 2) === "d_") {
      wkt2.datumCode = wkt2.datumCode.slice(2);
    }
    if (wkt2.datumCode === "new_zealand_1949") {
      wkt2.datumCode = "nzgd49";
    }
    if (wkt2.datumCode === "wgs_1984" || wkt2.datumCode === "world_geodetic_system_1984") {
      if (wkt2.PROJECTION === "Mercator_Auxiliary_Sphere") {
        wkt2.sphere = true;
      }
      wkt2.datumCode = "wgs84";
    }
    if (wkt2.datumCode === "belge_1972") {
      wkt2.datumCode = "rnb72";
    }
    if (geogcs.DATUM && geogcs.DATUM.SPHEROID) {
      wkt2.ellps = geogcs.DATUM.SPHEROID.name.replace("_19", "").replace(/[Cc]larke\_18/, "clrk");
      if (wkt2.ellps.toLowerCase().slice(0, 13) === "international") {
        wkt2.ellps = "intl";
      }
      wkt2.a = geogcs.DATUM.SPHEROID.a;
      wkt2.rf = parseFloat(geogcs.DATUM.SPHEROID.rf);
    }
    if (geogcs.DATUM && geogcs.DATUM.TOWGS84) {
      wkt2.datum_params = geogcs.DATUM.TOWGS84;
    }
    if (~wkt2.datumCode.indexOf("osgb_1936")) {
      wkt2.datumCode = "osgb36";
    }
    if (~wkt2.datumCode.indexOf("osni_1952")) {
      wkt2.datumCode = "osni52";
    }
    if (~wkt2.datumCode.indexOf("tm65") || ~wkt2.datumCode.indexOf("geodetic_datum_of_1965")) {
      wkt2.datumCode = "ire65";
    }
    if (wkt2.datumCode === "ch1903+") {
      wkt2.datumCode = "ch1903";
    }
    if (~wkt2.datumCode.indexOf("israel")) {
      wkt2.datumCode = "isr93";
    }
  }
  if (wkt2.b && !isFinite(wkt2.b)) {
    wkt2.b = wkt2.a;
  }
  if (wkt2.rectified_grid_angle) {
    wkt2.rectified_grid_angle = d2r(wkt2.rectified_grid_angle);
  }
  function toMeter(input) {
    var ratio = wkt2.to_meter || 1;
    return input * ratio;
  }
  var renamer = function(a) {
    return rename(wkt2, a);
  };
  var list = [
    ["standard_parallel_1", "Standard_Parallel_1"],
    ["standard_parallel_1", "Latitude of 1st standard parallel"],
    ["standard_parallel_2", "Standard_Parallel_2"],
    ["standard_parallel_2", "Latitude of 2nd standard parallel"],
    ["false_easting", "False_Easting"],
    ["false_easting", "False easting"],
    ["false-easting", "Easting at false origin"],
    ["false_northing", "False_Northing"],
    ["false_northing", "False northing"],
    ["false_northing", "Northing at false origin"],
    ["central_meridian", "Central_Meridian"],
    ["central_meridian", "Longitude of natural origin"],
    ["central_meridian", "Longitude of false origin"],
    ["latitude_of_origin", "Latitude_Of_Origin"],
    ["latitude_of_origin", "Central_Parallel"],
    ["latitude_of_origin", "Latitude of natural origin"],
    ["latitude_of_origin", "Latitude of false origin"],
    ["scale_factor", "Scale_Factor"],
    ["k0", "scale_factor"],
    ["latitude_of_center", "Latitude_Of_Center"],
    ["latitude_of_center", "Latitude_of_center"],
    ["lat0", "latitude_of_center", d2r],
    ["longitude_of_center", "Longitude_Of_Center"],
    ["longitude_of_center", "Longitude_of_center"],
    ["longc", "longitude_of_center", d2r],
    ["x0", "false_easting", toMeter],
    ["y0", "false_northing", toMeter],
    ["long0", "central_meridian", d2r],
    ["lat0", "latitude_of_origin", d2r],
    ["lat0", "standard_parallel_1", d2r],
    ["lat1", "standard_parallel_1", d2r],
    ["lat2", "standard_parallel_2", d2r],
    ["azimuth", "Azimuth"],
    ["alpha", "azimuth", d2r],
    ["srsCode", "name"]
  ];
  list.forEach(renamer);
  applyProjectionDefaults(wkt2);
}
function wkt(wkt2) {
  if (typeof wkt2 === "object") {
    return transformPROJJSON(wkt2);
  }
  const version = detectWKTVersion(wkt2);
  var lisp = parseString(wkt2);
  if (version === "WKT2") {
    const projjson = buildPROJJSON(lisp);
    return transformPROJJSON(projjson);
  }
  var type = lisp[0];
  var obj = {};
  sExpr(lisp, obj);
  cleanWKT(obj);
  return obj[type];
}
function defs(name) {
  var that = this;
  if (arguments.length === 2) {
    var def = arguments[1];
    if (typeof def === "string") {
      if (def.charAt(0) === "+") {
        defs[name] = projStr(arguments[1]);
      } else {
        defs[name] = wkt(arguments[1]);
      }
    } else {
      defs[name] = def;
    }
  } else if (arguments.length === 1) {
    if (Array.isArray(name)) {
      return name.map(function(v) {
        if (Array.isArray(v)) {
          defs.apply(that, v);
        } else {
          defs(v);
        }
      });
    } else if (typeof name === "string") {
      if (name in defs) {
        return defs[name];
      }
    } else if ("EPSG" in name) {
      defs["EPSG:" + name.EPSG] = name;
    } else if ("ESRI" in name) {
      defs["ESRI:" + name.ESRI] = name;
    } else if ("IAU2000" in name) {
      defs["IAU2000:" + name.IAU2000] = name;
    } else {
      console.log(name);
    }
    return;
  }
}
globals(defs);
function testObj(code) {
  return typeof code === "string";
}
function testDef(code) {
  return code in defs;
}
function testWKT(code) {
  return code.indexOf("+") !== 0 && code.indexOf("[") !== -1 || typeof code === "object" && !("srsCode" in code);
}
var codes = ["3857", "900913", "3785", "102113"];
function checkMercator(item) {
  var auth = match(item, "authority");
  if (!auth) {
    return;
  }
  var code = match(auth, "epsg");
  return code && codes.indexOf(code) > -1;
}
function checkProjStr(item) {
  var ext = match(item, "extension");
  if (!ext) {
    return;
  }
  return match(ext, "proj4");
}
function testProj(code) {
  return code[0] === "+";
}
function parse(code) {
  if (testObj(code)) {
    if (testDef(code)) {
      return defs[code];
    }
    if (testWKT(code)) {
      var out = wkt(code);
      if (checkMercator(out)) {
        return defs["EPSG:3857"];
      }
      var maybeProjStr = checkProjStr(out);
      if (maybeProjStr) {
        return projStr(maybeProjStr);
      }
      return out;
    }
    if (testProj(code)) {
      return projStr(code);
    }
  } else if (!code.projName) {
    return wkt(code);
  } else {
    return code;
  }
}
function extend(destination, source) {
  destination = destination || {};
  var value, property;
  if (!source) {
    return destination;
  }
  for (property in source) {
    value = source[property];
    if (value !== void 0) {
      destination[property] = value;
    }
  }
  return destination;
}
function msfnz(eccent, sinphi, cosphi) {
  var con = eccent * sinphi;
  return cosphi / Math.sqrt(1 - con * con);
}
function sign(x) {
  return x < 0 ? -1 : 1;
}
function adjust_lon(x) {
  return Math.abs(x) <= SPI ? x : x - sign(x) * TWO_PI;
}
function tsfnz(eccent, phi, sinphi) {
  var con = eccent * sinphi;
  var com = 0.5 * eccent;
  con = Math.pow((1 - con) / (1 + con), com);
  return Math.tan(0.5 * (HALF_PI - phi)) / con;
}
function phi2z(eccent, ts) {
  var eccnth = 0.5 * eccent;
  var con, dphi;
  var phi = HALF_PI - 2 * Math.atan(ts);
  for (var i = 0; i <= 15; i++) {
    con = eccent * Math.sin(phi);
    dphi = HALF_PI - 2 * Math.atan(ts * Math.pow((1 - con) / (1 + con), eccnth)) - phi;
    phi += dphi;
    if (Math.abs(dphi) <= 1e-10) {
      return phi;
    }
  }
  return -9999;
}
function init$y() {
  var con = this.b / this.a;
  this.es = 1 - con * con;
  if (!("x0" in this)) {
    this.x0 = 0;
  }
  if (!("y0" in this)) {
    this.y0 = 0;
  }
  this.e = Math.sqrt(this.es);
  if (this.lat_ts) {
    if (this.sphere) {
      this.k0 = Math.cos(this.lat_ts);
    } else {
      this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
    }
  } else {
    if (!this.k0) {
      if (this.k) {
        this.k0 = this.k;
      } else {
        this.k0 = 1;
      }
    }
  }
}
function forward$v(p) {
  var lon = p.x;
  var lat = p.y;
  if (lat * R2D > 90 && lat * R2D < -90 && lon * R2D > 180 && lon * R2D < -180) {
    return null;
  }
  var x, y;
  if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
    return null;
  } else {
    if (this.sphere) {
      x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
      y = this.y0 + this.a * this.k0 * Math.log(Math.tan(FORTPI + 0.5 * lat));
    } else {
      var sinphi = Math.sin(lat);
      var ts = tsfnz(this.e, lat, sinphi);
      x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
      y = this.y0 - this.a * this.k0 * Math.log(ts);
    }
    p.x = x;
    p.y = y;
    return p;
  }
}
function inverse$v(p) {
  var x = p.x - this.x0;
  var y = p.y - this.y0;
  var lon, lat;
  if (this.sphere) {
    lat = HALF_PI - 2 * Math.atan(Math.exp(-y / (this.a * this.k0)));
  } else {
    var ts = Math.exp(-y / (this.a * this.k0));
    lat = phi2z(this.e, ts);
    if (lat === -9999) {
      return null;
    }
  }
  lon = adjust_lon(this.long0 + x / (this.a * this.k0));
  p.x = lon;
  p.y = lat;
  return p;
}
var names$x = ["Mercator", "Popular Visualisation Pseudo Mercator", "Mercator_1SP", "Mercator_Auxiliary_Sphere", "Mercator_Variant_A", "merc"];
const merc = {
  init: init$y,
  forward: forward$v,
  inverse: inverse$v,
  names: names$x
};
function init$x() {
}
function identity(pt) {
  return pt;
}
var names$w = ["longlat", "identity"];
const longlat = {
  init: init$x,
  forward: identity,
  inverse: identity,
  names: names$w
};
var projs = [merc, longlat];
var names$v = {};
var projStore = [];
function add(proj, i) {
  var len = projStore.length;
  if (!proj.names) {
    console.log(i);
    return true;
  }
  projStore[len] = proj;
  proj.names.forEach(function(n) {
    names$v[n.toLowerCase()] = len;
  });
  return this;
}
function getNormalizedProjName(n) {
  return n.replace(/[-\(\)\s]+/g, " ").trim().replace(/ /g, "_");
}
function get(name) {
  if (!name) {
    return false;
  }
  var n = name.toLowerCase();
  if (typeof names$v[n] !== "undefined" && projStore[names$v[n]]) {
    return projStore[names$v[n]];
  }
  n = getNormalizedProjName(n);
  if (n in names$v && projStore[names$v[n]]) {
    return projStore[names$v[n]];
  }
}
function start() {
  projs.forEach(add);
}
const projections = {
  start,
  add,
  get
};
var ellipsoids = {
  MERIT: {
    a: 6378137,
    rf: 298.257,
    ellipseName: "MERIT 1983"
  },
  SGS85: {
    a: 6378136,
    rf: 298.257,
    ellipseName: "Soviet Geodetic System 85"
  },
  GRS80: {
    a: 6378137,
    rf: 298.257222101,
    ellipseName: "GRS 1980(IUGG, 1980)"
  },
  IAU76: {
    a: 6378140,
    rf: 298.257,
    ellipseName: "IAU 1976"
  },
  airy: {
    a: 6377563396e-3,
    b: 635625691e-2,
    ellipseName: "Airy 1830"
  },
  APL4: {
    a: 6378137,
    rf: 298.25,
    ellipseName: "Appl. Physics. 1965"
  },
  NWL9D: {
    a: 6378145,
    rf: 298.25,
    ellipseName: "Naval Weapons Lab., 1965"
  },
  mod_airy: {
    a: 6377340189e-3,
    b: 6356034446e-3,
    ellipseName: "Modified Airy"
  },
  andrae: {
    a: 637710443e-2,
    rf: 300,
    ellipseName: "Andrae 1876 (Den., Iclnd.)"
  },
  aust_SA: {
    a: 6378160,
    rf: 298.25,
    ellipseName: "Australian Natl & S. Amer. 1969"
  },
  GRS67: {
    a: 6378160,
    rf: 298.247167427,
    ellipseName: "GRS 67(IUGG 1967)"
  },
  bessel: {
    a: 6377397155e-3,
    rf: 299.1528128,
    ellipseName: "Bessel 1841"
  },
  bess_nam: {
    a: 6377483865e-3,
    rf: 299.1528128,
    ellipseName: "Bessel 1841 (Namibia)"
  },
  clrk66: {
    a: 63782064e-1,
    b: 63565838e-1,
    ellipseName: "Clarke 1866"
  },
  clrk80: {
    a: 6378249145e-3,
    rf: 293.4663,
    ellipseName: "Clarke 1880 mod."
  },
  clrk80ign: {
    a: 63782492e-1,
    b: 6356515,
    rf: 293.4660213,
    ellipseName: "Clarke 1880 (IGN)"
  },
  clrk58: {
    a: 6378293645208759e-9,
    rf: 294.2606763692654,
    ellipseName: "Clarke 1858"
  },
  CPM: {
    a: 63757387e-1,
    rf: 334.29,
    ellipseName: "Comm. des Poids et Mesures 1799"
  },
  delmbr: {
    a: 6376428,
    rf: 311.5,
    ellipseName: "Delambre 1810 (Belgium)"
  },
  engelis: {
    a: 637813605e-2,
    rf: 298.2566,
    ellipseName: "Engelis 1985"
  },
  evrst30: {
    a: 6377276345e-3,
    rf: 300.8017,
    ellipseName: "Everest 1830"
  },
  evrst48: {
    a: 6377304063e-3,
    rf: 300.8017,
    ellipseName: "Everest 1948"
  },
  evrst56: {
    a: 6377301243e-3,
    rf: 300.8017,
    ellipseName: "Everest 1956"
  },
  evrst69: {
    a: 6377295664e-3,
    rf: 300.8017,
    ellipseName: "Everest 1969"
  },
  evrstSS: {
    a: 6377298556e-3,
    rf: 300.8017,
    ellipseName: "Everest (Sabah & Sarawak)"
  },
  fschr60: {
    a: 6378166,
    rf: 298.3,
    ellipseName: "Fischer (Mercury Datum) 1960"
  },
  fschr60m: {
    a: 6378155,
    rf: 298.3,
    ellipseName: "Fischer 1960"
  },
  fschr68: {
    a: 6378150,
    rf: 298.3,
    ellipseName: "Fischer 1968"
  },
  helmert: {
    a: 6378200,
    rf: 298.3,
    ellipseName: "Helmert 1906"
  },
  hough: {
    a: 6378270,
    rf: 297,
    ellipseName: "Hough"
  },
  intl: {
    a: 6378388,
    rf: 297,
    ellipseName: "International 1909 (Hayford)"
  },
  kaula: {
    a: 6378163,
    rf: 298.24,
    ellipseName: "Kaula 1961"
  },
  lerch: {
    a: 6378139,
    rf: 298.257,
    ellipseName: "Lerch 1979"
  },
  mprts: {
    a: 6397300,
    rf: 191,
    ellipseName: "Maupertius 1738"
  },
  new_intl: {
    a: 63781575e-1,
    b: 63567722e-1,
    ellipseName: "New International 1967"
  },
  plessis: {
    a: 6376523,
    rf: 6355863,
    ellipseName: "Plessis 1817 (France)"
  },
  krass: {
    a: 6378245,
    rf: 298.3,
    ellipseName: "Krassovsky, 1942"
  },
  SEasia: {
    a: 6378155,
    b: 63567733205e-4,
    ellipseName: "Southeast Asia"
  },
  walbeck: {
    a: 6376896,
    b: 63558348467e-4,
    ellipseName: "Walbeck"
  },
  WGS60: {
    a: 6378165,
    rf: 298.3,
    ellipseName: "WGS 60"
  },
  WGS66: {
    a: 6378145,
    rf: 298.25,
    ellipseName: "WGS 66"
  },
  WGS7: {
    a: 6378135,
    rf: 298.26,
    ellipseName: "WGS 72"
  },
  WGS84: {
    a: 6378137,
    rf: 298.257223563,
    ellipseName: "WGS 84"
  },
  sphere: {
    a: 6370997,
    b: 6370997,
    ellipseName: "Normal Sphere (r=6370997)"
  }
};
const WGS84 = ellipsoids.WGS84;
function eccentricity(a, b, rf, R_A) {
  var a22 = a * a;
  var b22 = b * b;
  var es = (a22 - b22) / a22;
  var e = 0;
  if (R_A) {
    a *= 1 - es * (SIXTH + es * (RA4 + es * RA6));
    a22 = a * a;
    es = 0;
  } else {
    e = Math.sqrt(es);
  }
  var ep2 = (a22 - b22) / b22;
  return {
    es,
    e,
    ep2
  };
}
function sphere(a, b, rf, ellps, sphere2) {
  if (!a) {
    var ellipse = match(ellipsoids, ellps);
    if (!ellipse) {
      ellipse = WGS84;
    }
    a = ellipse.a;
    b = ellipse.b;
    rf = ellipse.rf;
  }
  if (rf && !b) {
    b = (1 - 1 / rf) * a;
  }
  if (rf === 0 || Math.abs(a - b) < EPSLN) {
    sphere2 = true;
    b = a;
  }
  return {
    a,
    b,
    rf,
    sphere: sphere2
  };
}
var datums = {
  wgs84: {
    towgs84: "0,0,0",
    ellipse: "WGS84",
    datumName: "WGS84"
  },
  ch1903: {
    towgs84: "674.374,15.056,405.346",
    ellipse: "bessel",
    datumName: "swiss"
  },
  ggrs87: {
    towgs84: "-199.87,74.79,246.62",
    ellipse: "GRS80",
    datumName: "Greek_Geodetic_Reference_System_1987"
  },
  nad83: {
    towgs84: "0,0,0",
    ellipse: "GRS80",
    datumName: "North_American_Datum_1983"
  },
  nad27: {
    nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
    ellipse: "clrk66",
    datumName: "North_American_Datum_1927"
  },
  potsdam: {
    towgs84: "598.1,73.7,418.2,0.202,0.045,-2.455,6.7",
    ellipse: "bessel",
    datumName: "Potsdam Rauenberg 1950 DHDN"
  },
  carthage: {
    towgs84: "-263.0,6.0,431.0",
    ellipse: "clark80",
    datumName: "Carthage 1934 Tunisia"
  },
  hermannskogel: {
    towgs84: "577.326,90.129,463.919,5.137,1.474,5.297,2.4232",
    ellipse: "bessel",
    datumName: "Hermannskogel"
  },
  mgi: {
    towgs84: "577.326,90.129,463.919,5.137,1.474,5.297,2.4232",
    ellipse: "bessel",
    datumName: "Militar-Geographische Institut"
  },
  osni52: {
    towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
    ellipse: "airy",
    datumName: "Irish National"
  },
  ire65: {
    towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
    ellipse: "mod_airy",
    datumName: "Ireland 1965"
  },
  rassadiran: {
    towgs84: "-133.63,-157.5,-158.62",
    ellipse: "intl",
    datumName: "Rassadiran"
  },
  nzgd49: {
    towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",
    ellipse: "intl",
    datumName: "New Zealand Geodetic Datum 1949"
  },
  osgb36: {
    towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",
    ellipse: "airy",
    datumName: "Ordnance Survey of Great Britain 1936"
  },
  s_jtsk: {
    towgs84: "589,76,480",
    ellipse: "bessel",
    datumName: "S-JTSK (Ferro)"
  },
  beduaram: {
    towgs84: "-106,-87,188",
    ellipse: "clrk80",
    datumName: "Beduaram"
  },
  gunung_segara: {
    towgs84: "-403,684,41",
    ellipse: "bessel",
    datumName: "Gunung Segara Jakarta"
  },
  rnb72: {
    towgs84: "106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1",
    ellipse: "intl",
    datumName: "Reseau National Belge 1972"
  },
  EPSG_5451: {
    towgs84: "6.41,-49.05,-11.28,1.5657,0.5242,6.9718,-5.7649"
  },
  IGNF_LURESG: {
    towgs84: "-192.986,13.673,-39.309,-0.4099,-2.9332,2.6881,0.43"
  },
  EPSG_4614: {
    towgs84: "-119.4248,-303.65872,-11.00061,1.164298,0.174458,1.096259,3.657065"
  },
  EPSG_4615: {
    towgs84: "-494.088,-312.129,279.877,-1.423,-1.013,1.59,-0.748"
  },
  ESRI_37241: {
    towgs84: "-76.822,257.457,-12.817,2.136,-0.033,-2.392,-0.031"
  },
  ESRI_37249: {
    towgs84: "-440.296,58.548,296.265,1.128,10.202,4.559,-0.438"
  },
  ESRI_37245: {
    towgs84: "-511.151,-181.269,139.609,1.05,2.703,1.798,3.071"
  },
  EPSG_4178: {
    towgs84: "24.9,-126.4,-93.2,-0.063,-0.247,-0.041,1.01"
  },
  EPSG_4622: {
    towgs84: "-472.29,-5.63,-304.12,0.4362,-0.8374,0.2563,1.8984"
  },
  EPSG_4625: {
    towgs84: "126.93,547.94,130.41,-2.7867,5.1612,-0.8584,13.8227"
  },
  EPSG_5252: {
    towgs84: "0.023,0.036,-0.068,0.00176,0.00912,-0.01136,0.00439"
  },
  EPSG_4314: {
    towgs84: "597.1,71.4,412.1,0.894,0.068,-1.563,7.58"
  },
  EPSG_4282: {
    towgs84: "-178.3,-316.7,-131.5,5.278,6.077,10.979,19.166"
  },
  EPSG_4231: {
    towgs84: "-83.11,-97.38,-117.22,0.0276,-0.2167,0.2147,0.1218"
  },
  EPSG_4274: {
    towgs84: "-230.994,102.591,25.199,0.633,-0.239,0.9,1.95"
  },
  EPSG_4134: {
    towgs84: "-180.624,-225.516,173.919,-0.81,-1.898,8.336,16.71006"
  },
  EPSG_4254: {
    towgs84: "18.38,192.45,96.82,0.056,-0.142,-0.2,-0.0013"
  },
  EPSG_4159: {
    towgs84: "-194.513,-63.978,-25.759,-3.4027,3.756,-3.352,-0.9175"
  },
  EPSG_4687: {
    towgs84: "0.072,-0.507,-0.245,0.0183,-0.0003,0.007,-0.0093"
  },
  EPSG_4227: {
    towgs84: "-83.58,-397.54,458.78,-17.595,-2.847,4.256,3.225"
  },
  EPSG_4746: {
    towgs84: "599.4,72.4,419.2,-0.062,-0.022,-2.723,6.46"
  },
  EPSG_4745: {
    towgs84: "612.4,77,440.2,-0.054,0.057,-2.797,2.55"
  },
  EPSG_6311: {
    towgs84: "8.846,-4.394,-1.122,-0.00237,-0.146528,0.130428,0.783926"
  },
  EPSG_4289: {
    towgs84: "565.7381,50.4018,465.2904,-1.91514,1.60363,-9.09546,4.07244"
  },
  EPSG_4230: {
    towgs84: "-68.863,-134.888,-111.49,-0.53,-0.14,0.57,-3.4"
  },
  EPSG_4154: {
    towgs84: "-123.02,-158.95,-168.47"
  },
  EPSG_4156: {
    towgs84: "570.8,85.7,462.8,4.998,1.587,5.261,3.56"
  },
  EPSG_4299: {
    towgs84: "482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15"
  },
  EPSG_4179: {
    towgs84: "33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"
  },
  EPSG_4313: {
    towgs84: "-106.8686,52.2978,-103.7239,0.3366,-0.457,1.8422,-1.2747"
  },
  EPSG_4194: {
    towgs84: "163.511,127.533,-159.789"
  },
  EPSG_4195: {
    towgs84: "105,326,-102.5"
  },
  EPSG_4196: {
    towgs84: "-45,417,-3.5"
  },
  EPSG_4611: {
    towgs84: "-162.619,-276.959,-161.764,0.067753,-2.243649,-1.158827,-1.094246"
  },
  EPSG_4633: {
    towgs84: "137.092,131.66,91.475,-1.9436,-11.5993,-4.3321,-7.4824"
  },
  EPSG_4641: {
    towgs84: "-408.809,366.856,-412.987,1.8842,-0.5308,2.1655,-121.0993"
  },
  EPSG_4643: {
    towgs84: "-480.26,-438.32,-643.429,16.3119,20.1721,-4.0349,-111.7002"
  },
  EPSG_4300: {
    towgs84: "482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15"
  },
  EPSG_4188: {
    towgs84: "482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15"
  },
  EPSG_4660: {
    towgs84: "982.6087,552.753,-540.873,32.39344,-153.25684,-96.2266,16.805"
  },
  EPSG_4662: {
    towgs84: "97.295,-263.247,310.882,-1.5999,0.8386,3.1409,13.3259"
  },
  EPSG_3906: {
    towgs84: "577.88891,165.22205,391.18289,4.9145,-0.94729,-13.05098,7.78664"
  },
  EPSG_4307: {
    towgs84: "-209.3622,-87.8162,404.6198,0.0046,3.4784,0.5805,-1.4547"
  },
  EPSG_6892: {
    towgs84: "-76.269,-16.683,68.562,-6.275,10.536,-4.286,-13.686"
  },
  EPSG_4690: {
    towgs84: "221.597,152.441,176.523,2.403,1.3893,0.884,11.4648"
  },
  EPSG_4691: {
    towgs84: "218.769,150.75,176.75,3.5231,2.0037,1.288,10.9817"
  },
  EPSG_4629: {
    towgs84: "72.51,345.411,79.241,-1.5862,-0.8826,-0.5495,1.3653"
  },
  EPSG_4630: {
    towgs84: "165.804,216.213,180.26,-0.6251,-0.4515,-0.0721,7.4111"
  },
  EPSG_4692: {
    towgs84: "217.109,86.452,23.711,0.0183,-0.0003,0.007,-0.0093"
  },
  EPSG_9333: {
    towgs84: "0,0,0,-8.393,0.749,-10.276,0"
  },
  EPSG_9059: {
    towgs84: "0,0,0"
  },
  EPSG_4312: {
    towgs84: "601.705,84.263,485.227,4.7354,1.3145,5.393,-2.3887"
  },
  EPSG_4123: {
    towgs84: "-96.062,-82.428,-121.753,4.801,0.345,-1.376,1.496"
  },
  EPSG_4309: {
    towgs84: "-124.45,183.74,44.64,-0.4384,0.5446,-0.9706,-2.1365"
  },
  ESRI_104106: {
    towgs84: "-283.088,-70.693,117.445,-1.157,0.059,-0.652,-4.058"
  },
  EPSG_4281: {
    towgs84: "-219.247,-73.802,269.529"
  },
  EPSG_4322: {
    towgs84: "0,0,4.5"
  },
  EPSG_4324: {
    towgs84: "0,0,1.9"
  },
  EPSG_4284: {
    towgs84: "43.822,-108.842,-119.585,1.455,-0.761,0.737,0.549"
  },
  EPSG_4277: {
    towgs84: "446.448,-125.157,542.06,0.15,0.247,0.842,-20.489"
  },
  EPSG_4207: {
    towgs84: "-282.1,-72.2,120,-1.529,0.145,-0.89,-4.46"
  },
  EPSG_4688: {
    towgs84: "347.175,1077.618,2623.677,33.9058,-70.6776,9.4013,186.0647"
  },
  EPSG_4689: {
    towgs84: "410.793,54.542,80.501,-2.5596,-2.3517,-0.6594,17.3218"
  },
  EPSG_4720: {
    towgs84: "0,0,4.5"
  },
  EPSG_4273: {
    towgs84: "278.3,93,474.5,7.889,0.05,-6.61,6.21"
  },
  EPSG_4240: {
    towgs84: "204.64,834.74,293.8"
  },
  EPSG_4817: {
    towgs84: "278.3,93,474.5,7.889,0.05,-6.61,6.21"
  },
  ESRI_104131: {
    towgs84: "426.62,142.62,460.09,4.98,4.49,-12.42,-17.1"
  },
  EPSG_4265: {
    towgs84: "-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68"
  },
  EPSG_4263: {
    towgs84: "-111.92,-87.85,114.5,1.875,0.202,0.219,0.032"
  },
  EPSG_4298: {
    towgs84: "-689.5937,623.84046,-65.93566,-0.02331,1.17094,-0.80054,5.88536"
  },
  EPSG_4270: {
    towgs84: "-253.4392,-148.452,386.5267,0.15605,0.43,-0.1013,-0.0424"
  },
  EPSG_4229: {
    towgs84: "-121.8,98.1,-10.7"
  },
  EPSG_4220: {
    towgs84: "-55.5,-348,-229.2"
  },
  EPSG_4214: {
    towgs84: "12.646,-155.176,-80.863"
  },
  EPSG_4232: {
    towgs84: "-345,3,223"
  },
  EPSG_4238: {
    towgs84: "-1.977,-13.06,-9.993,0.364,0.254,0.689,-1.037"
  },
  EPSG_4168: {
    towgs84: "-170,33,326"
  },
  EPSG_4131: {
    towgs84: "199,931,318.9"
  },
  EPSG_4152: {
    towgs84: "-0.9102,2.0141,0.5602,0.029039,0.010065,0.010101,0"
  },
  EPSG_5228: {
    towgs84: "572.213,85.334,461.94,4.9732,1.529,5.2484,3.5378"
  },
  EPSG_8351: {
    towgs84: "485.021,169.465,483.839,7.786342,4.397554,4.102655,0"
  },
  EPSG_4683: {
    towgs84: "-127.62,-67.24,-47.04,-3.068,4.903,1.578,-1.06"
  },
  EPSG_4133: {
    towgs84: "0,0,0"
  },
  EPSG_7373: {
    towgs84: "0.819,-0.5762,-1.6446,-0.00378,-0.03317,0.00318,0.0693"
  },
  EPSG_9075: {
    towgs84: "-0.9102,2.0141,0.5602,0.029039,0.010065,0.010101,0"
  },
  EPSG_9072: {
    towgs84: "-0.9102,2.0141,0.5602,0.029039,0.010065,0.010101,0"
  },
  EPSG_9294: {
    towgs84: "1.16835,-1.42001,-2.24431,-0.00822,-0.05508,0.01818,0.23388"
  },
  EPSG_4212: {
    towgs84: "-267.434,173.496,181.814,-13.4704,8.7154,7.3926,14.7492"
  },
  EPSG_4191: {
    towgs84: "-44.183,-0.58,-38.489,2.3867,2.7072,-3.5196,-8.2703"
  },
  EPSG_4237: {
    towgs84: "52.684,-71.194,-13.975,-0.312,-0.1063,-0.3729,1.0191"
  },
  EPSG_4740: {
    towgs84: "-1.08,-0.27,-0.9"
  },
  EPSG_4124: {
    towgs84: "419.3836,99.3335,591.3451,0.850389,1.817277,-7.862238,-0.99496"
  },
  EPSG_5681: {
    towgs84: "584.9636,107.7175,413.8067,1.1155,0.2824,-3.1384,7.9922"
  },
  EPSG_4141: {
    towgs84: "23.772,17.49,17.859,-0.3132,-1.85274,1.67299,-5.4262"
  },
  EPSG_4204: {
    towgs84: "-85.645,-273.077,-79.708,2.289,-1.421,2.532,3.194"
  },
  EPSG_4319: {
    towgs84: "226.702,-193.337,-35.371,-2.229,-4.391,9.238,0.9798"
  },
  EPSG_4200: {
    towgs84: "24.82,-131.21,-82.66"
  },
  EPSG_4130: {
    towgs84: "0,0,0"
  },
  EPSG_4127: {
    towgs84: "-82.875,-57.097,-156.768,-2.158,1.524,-0.982,-0.359"
  },
  EPSG_4149: {
    towgs84: "674.374,15.056,405.346"
  },
  EPSG_4617: {
    towgs84: "-0.991,1.9072,0.5129,1.25033e-7,4.6785e-8,5.6529e-8,0"
  },
  EPSG_4663: {
    towgs84: "-210.502,-66.902,-48.476,2.094,-15.067,-5.817,0.485"
  },
  EPSG_4664: {
    towgs84: "-211.939,137.626,58.3,-0.089,0.251,0.079,0.384"
  },
  EPSG_4665: {
    towgs84: "-105.854,165.589,-38.312,-0.003,-0.026,0.024,-0.048"
  },
  EPSG_4666: {
    towgs84: "631.392,-66.551,481.442,1.09,-4.445,-4.487,-4.43"
  },
  EPSG_4756: {
    towgs84: "-192.873,-39.382,-111.202,-0.00205,-0.0005,0.00335,0.0188"
  },
  EPSG_4723: {
    towgs84: "-179.483,-69.379,-27.584,-7.862,8.163,6.042,-13.925"
  },
  EPSG_4726: {
    towgs84: "8.853,-52.644,180.304,-0.393,-2.323,2.96,-24.081"
  },
  EPSG_4267: {
    towgs84: "-8.0,160.0,176.0"
  },
  EPSG_5365: {
    towgs84: "-0.16959,0.35312,0.51846,0.03385,-0.16325,0.03446,0.03693"
  },
  EPSG_4218: {
    towgs84: "304.5,306.5,-318.1"
  },
  EPSG_4242: {
    towgs84: "-33.722,153.789,94.959,-8.581,-4.478,4.54,8.95"
  },
  EPSG_4216: {
    towgs84: "-292.295,248.758,429.447,4.9971,2.99,6.6906,1.0289"
  },
  ESRI_104105: {
    towgs84: "631.392,-66.551,481.442,1.09,-4.445,-4.487,-4.43"
  },
  ESRI_104129: {
    towgs84: "0,0,0"
  },
  EPSG_4673: {
    towgs84: "174.05,-25.49,112.57"
  },
  EPSG_4202: {
    towgs84: "-124,-60,154"
  },
  EPSG_4203: {
    towgs84: "-117.763,-51.51,139.061,0.292,0.443,0.277,-0.191"
  },
  EPSG_3819: {
    towgs84: "595.48,121.69,515.35,4.115,-2.9383,0.853,-3.408"
  },
  EPSG_8694: {
    towgs84: "-93.799,-132.737,-219.073,-1.844,0.648,-6.37,-0.169"
  },
  EPSG_4145: {
    towgs84: "275.57,676.78,229.6"
  },
  EPSG_4283: {
    towgs84: "61.55,-10.87,-40.19,39.4924,32.7221,32.8979,-9.994"
  },
  EPSG_4317: {
    towgs84: "2.3287,-147.0425,-92.0802,-0.3092483,0.32482185,0.49729934,5.68906266"
  },
  EPSG_4272: {
    towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993"
  },
  EPSG_4248: {
    towgs84: "-307.7,265.3,-363.5"
  },
  EPSG_5561: {
    towgs84: "24,-121,-76"
  },
  EPSG_5233: {
    towgs84: "-0.293,766.95,87.713,0.195704,1.695068,3.473016,-0.039338"
  },
  ESRI_104130: {
    towgs84: "-86,-98,-119"
  },
  ESRI_104102: {
    towgs84: "682,-203,480"
  },
  ESRI_37207: {
    towgs84: "7,-10,-26"
  },
  EPSG_4675: {
    towgs84: "59.935,118.4,-10.871"
  },
  ESRI_104109: {
    towgs84: "-89.121,-348.182,260.871"
  },
  ESRI_104112: {
    towgs84: "-185.583,-230.096,281.361"
  },
  ESRI_104113: {
    towgs84: "25.1,-275.6,222.6"
  },
  IGNF_WGS72G: {
    towgs84: "0,12,6"
  },
  IGNF_NTFG: {
    towgs84: "-168,-60,320"
  },
  IGNF_EFATE57G: {
    towgs84: "-127,-769,472"
  },
  IGNF_PGP50G: {
    towgs84: "324.8,153.6,172.1"
  },
  IGNF_REUN47G: {
    towgs84: "94,-948,-1262"
  },
  IGNF_CSG67G: {
    towgs84: "-186,230,110"
  },
  IGNF_GUAD48G: {
    towgs84: "-467,-16,-300"
  },
  IGNF_TAHI51G: {
    towgs84: "162,117,154"
  },
  IGNF_TAHAAG: {
    towgs84: "65,342,77"
  },
  IGNF_NUKU72G: {
    towgs84: "84,274,65"
  },
  IGNF_PETRELS72G: {
    towgs84: "365,194,166"
  },
  IGNF_WALL78G: {
    towgs84: "253,-133,-127"
  },
  IGNF_MAYO50G: {
    towgs84: "-382,-59,-262"
  },
  IGNF_TANNAG: {
    towgs84: "-139,-967,436"
  },
  IGNF_IGN72G: {
    towgs84: "-13,-348,292"
  },
  IGNF_ATIGG: {
    towgs84: "1118,23,66"
  },
  IGNF_FANGA84G: {
    towgs84: "150.57,158.33,118.32"
  },
  IGNF_RUSAT84G: {
    towgs84: "202.13,174.6,-15.74"
  },
  IGNF_KAUE70G: {
    towgs84: "126.74,300.1,-75.49"
  },
  IGNF_MOP90G: {
    towgs84: "-10.8,-1.8,12.77"
  },
  IGNF_MHPF67G: {
    towgs84: "338.08,212.58,-296.17"
  },
  IGNF_TAHI79G: {
    towgs84: "160.61,116.05,153.69"
  },
  IGNF_ANAA92G: {
    towgs84: "1.5,3.84,4.81"
  },
  IGNF_MARQUI72G: {
    towgs84: "330.91,-13.92,58.56"
  },
  IGNF_APAT86G: {
    towgs84: "143.6,197.82,74.05"
  },
  IGNF_TUBU69G: {
    towgs84: "237.17,171.61,-77.84"
  },
  IGNF_STPM50G: {
    towgs84: "11.363,424.148,373.13"
  },
  EPSG_4150: {
    towgs84: "674.374,15.056,405.346"
  },
  EPSG_4754: {
    towgs84: "-208.4058,-109.8777,-2.5764"
  },
  ESRI_104101: {
    towgs84: "374,150,588"
  },
  EPSG_4693: {
    towgs84: "0,-0.15,0.68"
  },
  EPSG_6207: {
    towgs84: "293.17,726.18,245.36"
  },
  EPSG_4153: {
    towgs84: "-133.63,-157.5,-158.62"
  },
  EPSG_4132: {
    towgs84: "-241.54,-163.64,396.06"
  },
  EPSG_4221: {
    towgs84: "-154.5,150.7,100.4"
  },
  EPSG_4266: {
    towgs84: "-80.7,-132.5,41.1"
  },
  EPSG_4193: {
    towgs84: "-70.9,-151.8,-41.4"
  },
  EPSG_5340: {
    towgs84: "-0.41,0.46,-0.35"
  },
  EPSG_4246: {
    towgs84: "-294.7,-200.1,525.5"
  },
  EPSG_4318: {
    towgs84: "-3.2,-5.7,2.8"
  },
  EPSG_4121: {
    towgs84: "-199.87,74.79,246.62"
  },
  EPSG_4223: {
    towgs84: "-260.1,5.5,432.2"
  },
  EPSG_4158: {
    towgs84: "-0.465,372.095,171.736"
  },
  EPSG_4285: {
    towgs84: "-128.16,-282.42,21.93"
  },
  EPSG_4613: {
    towgs84: "-404.78,685.68,45.47"
  },
  EPSG_4607: {
    towgs84: "195.671,332.517,274.607"
  },
  EPSG_4475: {
    towgs84: "-381.788,-57.501,-256.673"
  },
  EPSG_4208: {
    towgs84: "-157.84,308.54,-146.6"
  },
  EPSG_4743: {
    towgs84: "70.995,-335.916,262.898"
  },
  EPSG_4710: {
    towgs84: "-323.65,551.39,-491.22"
  },
  EPSG_7881: {
    towgs84: "-0.077,0.079,0.086"
  },
  EPSG_4682: {
    towgs84: "283.729,735.942,261.143"
  },
  EPSG_4739: {
    towgs84: "-156,-271,-189"
  },
  EPSG_4679: {
    towgs84: "-80.01,253.26,291.19"
  },
  EPSG_4750: {
    towgs84: "-56.263,16.136,-22.856"
  },
  EPSG_4644: {
    towgs84: "-10.18,-350.43,291.37"
  },
  EPSG_4695: {
    towgs84: "-103.746,-9.614,-255.95"
  },
  EPSG_4292: {
    towgs84: "-355,21,72"
  },
  EPSG_4302: {
    towgs84: "-61.702,284.488,472.052"
  },
  EPSG_4143: {
    towgs84: "-124.76,53,466.79"
  },
  EPSG_4606: {
    towgs84: "-153,153,307"
  },
  EPSG_4699: {
    towgs84: "-770.1,158.4,-498.2"
  },
  EPSG_4247: {
    towgs84: "-273.5,110.6,-357.9"
  },
  EPSG_4160: {
    towgs84: "8.88,184.86,106.69"
  },
  EPSG_4161: {
    towgs84: "-233.43,6.65,173.64"
  },
  EPSG_9251: {
    towgs84: "-9.5,122.9,138.2"
  },
  EPSG_9253: {
    towgs84: "-78.1,101.6,133.3"
  },
  EPSG_4297: {
    towgs84: "-198.383,-240.517,-107.909"
  },
  EPSG_4269: {
    towgs84: "0,0,0"
  },
  EPSG_4301: {
    towgs84: "-147,506,687"
  },
  EPSG_4618: {
    towgs84: "-59,-11,-52"
  },
  EPSG_4612: {
    towgs84: "0,0,0"
  },
  EPSG_4678: {
    towgs84: "44.585,-131.212,-39.544"
  },
  EPSG_4250: {
    towgs84: "-130,29,364"
  },
  EPSG_4144: {
    towgs84: "214,804,268"
  },
  EPSG_4147: {
    towgs84: "-17.51,-108.32,-62.39"
  },
  EPSG_4259: {
    towgs84: "-254.1,-5.36,-100.29"
  },
  EPSG_4164: {
    towgs84: "-76,-138,67"
  },
  EPSG_4211: {
    towgs84: "-378.873,676.002,-46.255"
  },
  EPSG_4182: {
    towgs84: "-422.651,-172.995,84.02"
  },
  EPSG_4224: {
    towgs84: "-143.87,243.37,-33.52"
  },
  EPSG_4225: {
    towgs84: "-205.57,168.77,-4.12"
  },
  EPSG_5527: {
    towgs84: "-67.35,3.88,-38.22"
  },
  EPSG_4752: {
    towgs84: "98,390,-22"
  },
  EPSG_4310: {
    towgs84: "-30,190,89"
  },
  EPSG_9248: {
    towgs84: "-192.26,65.72,132.08"
  },
  EPSG_4680: {
    towgs84: "124.5,-63.5,-281"
  },
  EPSG_4701: {
    towgs84: "-79.9,-158,-168.9"
  },
  EPSG_4706: {
    towgs84: "-146.21,112.63,4.05"
  },
  EPSG_4805: {
    towgs84: "682,-203,480"
  },
  EPSG_4201: {
    towgs84: "-165,-11,206"
  },
  EPSG_4210: {
    towgs84: "-157,-2,-299"
  },
  EPSG_4183: {
    towgs84: "-104,167,-38"
  },
  EPSG_4139: {
    towgs84: "11,72,-101"
  },
  EPSG_4668: {
    towgs84: "-86,-98,-119"
  },
  EPSG_4717: {
    towgs84: "-2,151,181"
  },
  EPSG_4732: {
    towgs84: "102,52,-38"
  },
  EPSG_4280: {
    towgs84: "-377,681,-50"
  },
  EPSG_4209: {
    towgs84: "-138,-105,-289"
  },
  EPSG_4261: {
    towgs84: "31,146,47"
  },
  EPSG_4658: {
    towgs84: "-73,46,-86"
  },
  EPSG_4721: {
    towgs84: "265.025,384.929,-194.046"
  },
  EPSG_4222: {
    towgs84: "-136,-108,-292"
  },
  EPSG_4601: {
    towgs84: "-255,-15,71"
  },
  EPSG_4602: {
    towgs84: "725,685,536"
  },
  EPSG_4603: {
    towgs84: "72,213.7,93"
  },
  EPSG_4605: {
    towgs84: "9,183,236"
  },
  EPSG_4621: {
    towgs84: "137,248,-430"
  },
  EPSG_4657: {
    towgs84: "-28,199,5"
  },
  EPSG_4316: {
    towgs84: "103.25,-100.4,-307.19"
  },
  EPSG_4642: {
    towgs84: "-13,-348,292"
  },
  EPSG_4698: {
    towgs84: "145,-187,103"
  },
  EPSG_4192: {
    towgs84: "-206.1,-174.7,-87.7"
  },
  EPSG_4311: {
    towgs84: "-265,120,-358"
  },
  EPSG_4135: {
    towgs84: "58,-283,-182"
  },
  ESRI_104138: {
    towgs84: "198,-226,-347"
  },
  EPSG_4245: {
    towgs84: "-11,851,5"
  },
  EPSG_4142: {
    towgs84: "-125,53,467"
  },
  EPSG_4213: {
    towgs84: "-106,-87,188"
  },
  EPSG_4253: {
    towgs84: "-133,-77,-51"
  },
  EPSG_4129: {
    towgs84: "-132,-110,-335"
  },
  EPSG_4713: {
    towgs84: "-77,-128,142"
  },
  EPSG_4239: {
    towgs84: "217,823,299"
  },
  EPSG_4146: {
    towgs84: "295,736,257"
  },
  EPSG_4155: {
    towgs84: "-83,37,124"
  },
  EPSG_4165: {
    towgs84: "-173,253,27"
  },
  EPSG_4672: {
    towgs84: "175,-38,113"
  },
  EPSG_4236: {
    towgs84: "-637,-549,-203"
  },
  EPSG_4251: {
    towgs84: "-90,40,88"
  },
  EPSG_4271: {
    towgs84: "-2,374,172"
  },
  EPSG_4175: {
    towgs84: "-88,4,101"
  },
  EPSG_4716: {
    towgs84: "298,-304,-375"
  },
  EPSG_4315: {
    towgs84: "-23,259,-9"
  },
  EPSG_4744: {
    towgs84: "-242.2,-144.9,370.3"
  },
  EPSG_4244: {
    towgs84: "-97,787,86"
  },
  EPSG_4293: {
    towgs84: "616,97,-251"
  },
  EPSG_4714: {
    towgs84: "-127,-769,472"
  },
  EPSG_4736: {
    towgs84: "260,12,-147"
  },
  EPSG_6883: {
    towgs84: "-235,-110,393"
  },
  EPSG_6894: {
    towgs84: "-63,176,185"
  },
  EPSG_4205: {
    towgs84: "-43,-163,45"
  },
  EPSG_4256: {
    towgs84: "41,-220,-134"
  },
  EPSG_4262: {
    towgs84: "639,405,60"
  },
  EPSG_4604: {
    towgs84: "174,359,365"
  },
  EPSG_4169: {
    towgs84: "-115,118,426"
  },
  EPSG_4620: {
    towgs84: "-106,-129,165"
  },
  EPSG_4184: {
    towgs84: "-203,141,53"
  },
  EPSG_4616: {
    towgs84: "-289,-124,60"
  },
  EPSG_9403: {
    towgs84: "-307,-92,127"
  },
  EPSG_4684: {
    towgs84: "-133,-321,50"
  },
  EPSG_4708: {
    towgs84: "-491,-22,435"
  },
  EPSG_4707: {
    towgs84: "114,-116,-333"
  },
  EPSG_4709: {
    towgs84: "145,75,-272"
  },
  EPSG_4712: {
    towgs84: "-205,107,53"
  },
  EPSG_4711: {
    towgs84: "124,-234,-25"
  },
  EPSG_4718: {
    towgs84: "230,-199,-752"
  },
  EPSG_4719: {
    towgs84: "211,147,111"
  },
  EPSG_4724: {
    towgs84: "208,-435,-229"
  },
  EPSG_4725: {
    towgs84: "189,-79,-202"
  },
  EPSG_4735: {
    towgs84: "647,1777,-1124"
  },
  EPSG_4722: {
    towgs84: "-794,119,-298"
  },
  EPSG_4728: {
    towgs84: "-307,-92,127"
  },
  EPSG_4734: {
    towgs84: "-632,438,-609"
  },
  EPSG_4727: {
    towgs84: "912,-58,1227"
  },
  EPSG_4729: {
    towgs84: "185,165,42"
  },
  EPSG_4730: {
    towgs84: "170,42,84"
  },
  EPSG_4733: {
    towgs84: "276,-57,149"
  },
  ESRI_37218: {
    towgs84: "230,-199,-752"
  },
  ESRI_37240: {
    towgs84: "-7,215,225"
  },
  ESRI_37221: {
    towgs84: "252,-209,-751"
  },
  ESRI_4305: {
    towgs84: "-123,-206,219"
  },
  ESRI_104139: {
    towgs84: "-73,-247,227"
  },
  EPSG_4748: {
    towgs84: "51,391,-36"
  },
  EPSG_4219: {
    towgs84: "-384,664,-48"
  },
  EPSG_4255: {
    towgs84: "-333,-222,114"
  },
  EPSG_4257: {
    towgs84: "-587.8,519.75,145.76"
  },
  EPSG_4646: {
    towgs84: "-963,510,-359"
  },
  EPSG_6881: {
    towgs84: "-24,-203,268"
  },
  EPSG_6882: {
    towgs84: "-183,-15,273"
  },
  EPSG_4715: {
    towgs84: "-104,-129,239"
  },
  IGNF_RGF93GDD: {
    towgs84: "0,0,0"
  },
  IGNF_RGM04GDD: {
    towgs84: "0,0,0"
  },
  IGNF_RGSPM06GDD: {
    towgs84: "0,0,0"
  },
  IGNF_RGTAAF07GDD: {
    towgs84: "0,0,0"
  },
  IGNF_RGFG95GDD: {
    towgs84: "0,0,0"
  },
  IGNF_RGNCG: {
    towgs84: "0,0,0"
  },
  IGNF_RGPFGDD: {
    towgs84: "0,0,0"
  },
  IGNF_ETRS89G: {
    towgs84: "0,0,0"
  },
  IGNF_RGR92GDD: {
    towgs84: "0,0,0"
  },
  EPSG_4173: {
    towgs84: "0,0,0"
  },
  EPSG_4180: {
    towgs84: "0,0,0"
  },
  EPSG_4619: {
    towgs84: "0,0,0"
  },
  EPSG_4667: {
    towgs84: "0,0,0"
  },
  EPSG_4075: {
    towgs84: "0,0,0"
  },
  EPSG_6706: {
    towgs84: "0,0,0"
  },
  EPSG_7798: {
    towgs84: "0,0,0"
  },
  EPSG_4661: {
    towgs84: "0,0,0"
  },
  EPSG_4669: {
    towgs84: "0,0,0"
  },
  EPSG_8685: {
    towgs84: "0,0,0"
  },
  EPSG_4151: {
    towgs84: "0,0,0"
  },
  EPSG_9702: {
    towgs84: "0,0,0"
  },
  EPSG_4758: {
    towgs84: "0,0,0"
  },
  EPSG_4761: {
    towgs84: "0,0,0"
  },
  EPSG_4765: {
    towgs84: "0,0,0"
  },
  EPSG_8997: {
    towgs84: "0,0,0"
  },
  EPSG_4023: {
    towgs84: "0,0,0"
  },
  EPSG_4670: {
    towgs84: "0,0,0"
  },
  EPSG_4694: {
    towgs84: "0,0,0"
  },
  EPSG_4148: {
    towgs84: "0,0,0"
  },
  EPSG_4163: {
    towgs84: "0,0,0"
  },
  EPSG_4167: {
    towgs84: "0,0,0"
  },
  EPSG_4189: {
    towgs84: "0,0,0"
  },
  EPSG_4190: {
    towgs84: "0,0,0"
  },
  EPSG_4176: {
    towgs84: "0,0,0"
  },
  EPSG_4659: {
    towgs84: "0,0,0"
  },
  EPSG_3824: {
    towgs84: "0,0,0"
  },
  EPSG_3889: {
    towgs84: "0,0,0"
  },
  EPSG_4046: {
    towgs84: "0,0,0"
  },
  EPSG_4081: {
    towgs84: "0,0,0"
  },
  EPSG_4558: {
    towgs84: "0,0,0"
  },
  EPSG_4483: {
    towgs84: "0,0,0"
  },
  EPSG_5013: {
    towgs84: "0,0,0"
  },
  EPSG_5264: {
    towgs84: "0,0,0"
  },
  EPSG_5324: {
    towgs84: "0,0,0"
  },
  EPSG_5354: {
    towgs84: "0,0,0"
  },
  EPSG_5371: {
    towgs84: "0,0,0"
  },
  EPSG_5373: {
    towgs84: "0,0,0"
  },
  EPSG_5381: {
    towgs84: "0,0,0"
  },
  EPSG_5393: {
    towgs84: "0,0,0"
  },
  EPSG_5489: {
    towgs84: "0,0,0"
  },
  EPSG_5593: {
    towgs84: "0,0,0"
  },
  EPSG_6135: {
    towgs84: "0,0,0"
  },
  EPSG_6365: {
    towgs84: "0,0,0"
  },
  EPSG_5246: {
    towgs84: "0,0,0"
  },
  EPSG_7886: {
    towgs84: "0,0,0"
  },
  EPSG_8431: {
    towgs84: "0,0,0"
  },
  EPSG_8427: {
    towgs84: "0,0,0"
  },
  EPSG_8699: {
    towgs84: "0,0,0"
  },
  EPSG_8818: {
    towgs84: "0,0,0"
  },
  EPSG_4757: {
    towgs84: "0,0,0"
  },
  EPSG_9140: {
    towgs84: "0,0,0"
  },
  EPSG_8086: {
    towgs84: "0,0,0"
  },
  EPSG_4686: {
    towgs84: "0,0,0"
  },
  EPSG_4737: {
    towgs84: "0,0,0"
  },
  EPSG_4702: {
    towgs84: "0,0,0"
  },
  EPSG_4747: {
    towgs84: "0,0,0"
  },
  EPSG_4749: {
    towgs84: "0,0,0"
  },
  EPSG_4674: {
    towgs84: "0,0,0"
  },
  EPSG_4755: {
    towgs84: "0,0,0"
  },
  EPSG_4759: {
    towgs84: "0,0,0"
  },
  EPSG_4762: {
    towgs84: "0,0,0"
  },
  EPSG_4763: {
    towgs84: "0,0,0"
  },
  EPSG_4764: {
    towgs84: "0,0,0"
  },
  EPSG_4166: {
    towgs84: "0,0,0"
  },
  EPSG_4170: {
    towgs84: "0,0,0"
  },
  EPSG_5546: {
    towgs84: "0,0,0"
  },
  EPSG_7844: {
    towgs84: "0,0,0"
  },
  EPSG_4818: {
    towgs84: "589,76,480"
  }
};
for (var key in datums) {
  var datum$1 = datums[key];
  if (!datum$1.datumName) {
    continue;
  }
  datums[datum$1.datumName] = datum$1;
}
function datum(datumCode, datum_params, a, b, es, ep2, nadgrids) {
  var out = {};
  if (datumCode === void 0 || datumCode === "none") {
    out.datum_type = PJD_NODATUM;
  } else {
    out.datum_type = PJD_WGS84;
  }
  if (datum_params) {
    out.datum_params = datum_params.map(parseFloat);
    if (out.datum_params[0] !== 0 || out.datum_params[1] !== 0 || out.datum_params[2] !== 0) {
      out.datum_type = PJD_3PARAM;
    }
    if (out.datum_params.length > 3) {
      if (out.datum_params[3] !== 0 || out.datum_params[4] !== 0 || out.datum_params[5] !== 0 || out.datum_params[6] !== 0) {
        out.datum_type = PJD_7PARAM;
        out.datum_params[3] *= SEC_TO_RAD;
        out.datum_params[4] *= SEC_TO_RAD;
        out.datum_params[5] *= SEC_TO_RAD;
        out.datum_params[6] = out.datum_params[6] / 1e6 + 1;
      }
    }
  }
  if (nadgrids) {
    out.datum_type = PJD_GRIDSHIFT;
    out.grids = nadgrids;
  }
  out.a = a;
  out.b = b;
  out.es = es;
  out.ep2 = ep2;
  return out;
}
var loadedNadgrids = {};
function nadgrid(key2, data, options2) {
  if (data instanceof ArrayBuffer) {
    return readNTV2Grid(key2, data, options2);
  }
  return { ready: readGeotiffGrid(key2, data) };
}
function readNTV2Grid(key2, data, options2) {
  var includeErrorFields = true;
  if (options2 !== void 0 && options2.includeErrorFields === false) {
    includeErrorFields = false;
  }
  var view = new DataView(data);
  var isLittleEndian = detectLittleEndian(view);
  var header = readHeader(view, isLittleEndian);
  var subgrids = readSubgrids(view, header, isLittleEndian, includeErrorFields);
  var nadgrid2 = { header, subgrids };
  loadedNadgrids[key2] = nadgrid2;
  return nadgrid2;
}
async function readGeotiffGrid(key2, tiff) {
  var subgrids = [];
  var subGridCount = await tiff.getImageCount();
  for (var subgridIndex = subGridCount - 1; subgridIndex >= 0; subgridIndex--) {
    var image = await tiff.getImage(subgridIndex);
    var rasters = await image.readRasters();
    var data = rasters;
    var lim = [image.getWidth(), image.getHeight()];
    var imageBBoxRadians = image.getBoundingBox().map(degreesToRadians);
    var del = [image.fileDirectory.ModelPixelScale[0], image.fileDirectory.ModelPixelScale[1]].map(degreesToRadians);
    var maxX = imageBBoxRadians[0] + (lim[0] - 1) * del[0];
    var minY = imageBBoxRadians[3] - (lim[1] - 1) * del[1];
    var latitudeOffsetBand = data[0];
    var longitudeOffsetBand = data[1];
    var nodes = [];
    for (let i = lim[1] - 1; i >= 0; i--) {
      for (let j = lim[0] - 1; j >= 0; j--) {
        var index = i * lim[0] + j;
        nodes.push([-secondsToRadians(longitudeOffsetBand[index]), secondsToRadians(latitudeOffsetBand[index])]);
      }
    }
    subgrids.push({
      del,
      lim,
      ll: [-maxX, minY],
      cvs: nodes
    });
  }
  var tifGrid = {
    header: {
      nSubgrids: subGridCount
    },
    subgrids
  };
  loadedNadgrids[key2] = tifGrid;
  return tifGrid;
}
function getNadgrids(nadgrids) {
  if (nadgrids === void 0) {
    return null;
  }
  var grids = nadgrids.split(",");
  return grids.map(parseNadgridString);
}
function parseNadgridString(value) {
  if (value.length === 0) {
    return null;
  }
  var optional = value[0] === "@";
  if (optional) {
    value = value.slice(1);
  }
  if (value === "null") {
    return { name: "null", mandatory: !optional, grid: null, isNull: true };
  }
  return {
    name: value,
    mandatory: !optional,
    grid: loadedNadgrids[value] || null,
    isNull: false
  };
}
function degreesToRadians(degrees) {
  return degrees * Math.PI / 180;
}
function secondsToRadians(seconds) {
  return seconds / 3600 * Math.PI / 180;
}
function detectLittleEndian(view) {
  var nFields = view.getInt32(8, false);
  if (nFields === 11) {
    return false;
  }
  nFields = view.getInt32(8, true);
  if (nFields !== 11) {
    console.warn("Failed to detect nadgrid endian-ness, defaulting to little-endian");
  }
  return true;
}
function readHeader(view, isLittleEndian) {
  return {
    nFields: view.getInt32(8, isLittleEndian),
    nSubgridFields: view.getInt32(24, isLittleEndian),
    nSubgrids: view.getInt32(40, isLittleEndian),
    shiftType: decodeString(view, 56, 56 + 8).trim(),
    fromSemiMajorAxis: view.getFloat64(120, isLittleEndian),
    fromSemiMinorAxis: view.getFloat64(136, isLittleEndian),
    toSemiMajorAxis: view.getFloat64(152, isLittleEndian),
    toSemiMinorAxis: view.getFloat64(168, isLittleEndian)
  };
}
function decodeString(view, start2, end) {
  return String.fromCharCode.apply(null, new Uint8Array(view.buffer.slice(start2, end)));
}
function readSubgrids(view, header, isLittleEndian, includeErrorFields) {
  var gridOffset = 176;
  var grids = [];
  for (var i = 0; i < header.nSubgrids; i++) {
    var subHeader = readGridHeader(view, gridOffset, isLittleEndian);
    var nodes = readGridNodes(view, gridOffset, subHeader, isLittleEndian, includeErrorFields);
    var lngColumnCount = Math.round(
      1 + (subHeader.upperLongitude - subHeader.lowerLongitude) / subHeader.longitudeInterval
    );
    var latColumnCount = Math.round(
      1 + (subHeader.upperLatitude - subHeader.lowerLatitude) / subHeader.latitudeInterval
    );
    grids.push({
      ll: [secondsToRadians(subHeader.lowerLongitude), secondsToRadians(subHeader.lowerLatitude)],
      del: [secondsToRadians(subHeader.longitudeInterval), secondsToRadians(subHeader.latitudeInterval)],
      lim: [lngColumnCount, latColumnCount],
      count: subHeader.gridNodeCount,
      cvs: mapNodes(nodes)
    });
    var rowSize = 16;
    if (includeErrorFields === false) {
      rowSize = 8;
    }
    gridOffset += 176 + subHeader.gridNodeCount * rowSize;
  }
  return grids;
}
function mapNodes(nodes) {
  return nodes.map(function(r) {
    return [secondsToRadians(r.longitudeShift), secondsToRadians(r.latitudeShift)];
  });
}
function readGridHeader(view, offset2, isLittleEndian) {
  return {
    name: decodeString(view, offset2 + 8, offset2 + 16).trim(),
    parent: decodeString(view, offset2 + 24, offset2 + 24 + 8).trim(),
    lowerLatitude: view.getFloat64(offset2 + 72, isLittleEndian),
    upperLatitude: view.getFloat64(offset2 + 88, isLittleEndian),
    lowerLongitude: view.getFloat64(offset2 + 104, isLittleEndian),
    upperLongitude: view.getFloat64(offset2 + 120, isLittleEndian),
    latitudeInterval: view.getFloat64(offset2 + 136, isLittleEndian),
    longitudeInterval: view.getFloat64(offset2 + 152, isLittleEndian),
    gridNodeCount: view.getInt32(offset2 + 168, isLittleEndian)
  };
}
function readGridNodes(view, offset2, gridHeader, isLittleEndian, includeErrorFields) {
  var nodesOffset = offset2 + 176;
  var gridRecordLength = 16;
  if (includeErrorFields === false) {
    gridRecordLength = 8;
  }
  var gridShiftRecords = [];
  for (var i = 0; i < gridHeader.gridNodeCount; i++) {
    var record = {
      latitudeShift: view.getFloat32(nodesOffset + i * gridRecordLength, isLittleEndian),
      longitudeShift: view.getFloat32(nodesOffset + i * gridRecordLength + 4, isLittleEndian)
    };
    if (includeErrorFields !== false) {
      record.latitudeAccuracy = view.getFloat32(nodesOffset + i * gridRecordLength + 8, isLittleEndian);
      record.longitudeAccuracy = view.getFloat32(nodesOffset + i * gridRecordLength + 12, isLittleEndian);
    }
    gridShiftRecords.push(record);
  }
  return gridShiftRecords;
}
function Projection(srsCode, callback) {
  if (!(this instanceof Projection)) {
    return new Projection(srsCode);
  }
  callback = callback || function(error2) {
    if (error2) {
      throw error2;
    }
  };
  var json = parse(srsCode);
  if (typeof json !== "object") {
    callback("Could not parse to valid json: " + srsCode);
    return;
  }
  var ourProj = Projection.projections.get(json.projName);
  if (!ourProj) {
    callback("Could not get projection name from: " + srsCode);
    return;
  }
  if (json.datumCode && json.datumCode !== "none") {
    var datumDef = match(datums, json.datumCode);
    if (datumDef) {
      json.datum_params = json.datum_params || (datumDef.towgs84 ? datumDef.towgs84.split(",") : null);
      json.ellps = datumDef.ellipse;
      json.datumName = datumDef.datumName ? datumDef.datumName : json.datumCode;
    }
  }
  json.k0 = json.k0 || 1;
  json.axis = json.axis || "enu";
  json.ellps = json.ellps || "wgs84";
  json.lat1 = json.lat1 || json.lat0;
  var sphere_ = sphere(json.a, json.b, json.rf, json.ellps, json.sphere);
  var ecc = eccentricity(sphere_.a, sphere_.b, sphere_.rf, json.R_A);
  var nadgrids = getNadgrids(json.nadgrids);
  var datumObj = json.datum || datum(
    json.datumCode,
    json.datum_params,
    sphere_.a,
    sphere_.b,
    ecc.es,
    ecc.ep2,
    nadgrids
  );
  extend(this, json);
  extend(this, ourProj);
  this.a = sphere_.a;
  this.b = sphere_.b;
  this.rf = sphere_.rf;
  this.sphere = sphere_.sphere;
  this.es = ecc.es;
  this.e = ecc.e;
  this.ep2 = ecc.ep2;
  this.datum = datumObj;
  this.init();
  callback(null, this);
}
Projection.projections = projections;
Projection.projections.start();
function compareDatums(source, dest) {
  if (source.datum_type !== dest.datum_type) {
    return false;
  } else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 5e-11) {
    return false;
  } else if (source.datum_type === PJD_3PARAM) {
    return source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2];
  } else if (source.datum_type === PJD_7PARAM) {
    return source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6];
  } else {
    return true;
  }
}
function geodeticToGeocentric(p, es, a) {
  var Longitude = p.x;
  var Latitude = p.y;
  var Height = p.z ? p.z : 0;
  var Rn;
  var Sin_Lat;
  var Sin2_Lat;
  var Cos_Lat;
  if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) {
    Latitude = -HALF_PI;
  } else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) {
    Latitude = HALF_PI;
  } else if (Latitude < -HALF_PI) {
    return { x: -Infinity, y: -Infinity, z: p.z };
  } else if (Latitude > HALF_PI) {
    return { x: Infinity, y: Infinity, z: p.z };
  }
  if (Longitude > Math.PI) {
    Longitude -= 2 * Math.PI;
  }
  Sin_Lat = Math.sin(Latitude);
  Cos_Lat = Math.cos(Latitude);
  Sin2_Lat = Sin_Lat * Sin_Lat;
  Rn = a / Math.sqrt(1 - es * Sin2_Lat);
  return {
    x: (Rn + Height) * Cos_Lat * Math.cos(Longitude),
    y: (Rn + Height) * Cos_Lat * Math.sin(Longitude),
    z: (Rn * (1 - es) + Height) * Sin_Lat
  };
}
function geocentricToGeodetic(p, es, a, b) {
  var genau = 1e-12;
  var genau2 = genau * genau;
  var maxiter = 30;
  var P;
  var RR;
  var CT;
  var ST;
  var RX;
  var RK;
  var RN;
  var CPHI0;
  var SPHI0;
  var CPHI;
  var SPHI;
  var SDPHI;
  var iter;
  var X = p.x;
  var Y = p.y;
  var Z2 = p.z ? p.z : 0;
  var Longitude;
  var Latitude;
  var Height;
  P = Math.sqrt(X * X + Y * Y);
  RR = Math.sqrt(X * X + Y * Y + Z2 * Z2);
  if (P / a < genau) {
    Longitude = 0;
    if (RR / a < genau) {
      Latitude = HALF_PI;
      Height = -b;
      return {
        x: p.x,
        y: p.y,
        z: p.z
      };
    }
  } else {
    Longitude = Math.atan2(Y, X);
  }
  CT = Z2 / RR;
  ST = P / RR;
  RX = 1 / Math.sqrt(1 - es * (2 - es) * ST * ST);
  CPHI0 = ST * (1 - es) * RX;
  SPHI0 = CT * RX;
  iter = 0;
  do {
    iter++;
    RN = a / Math.sqrt(1 - es * SPHI0 * SPHI0);
    Height = P * CPHI0 + Z2 * SPHI0 - RN * (1 - es * SPHI0 * SPHI0);
    RK = es * RN / (RN + Height);
    RX = 1 / Math.sqrt(1 - RK * (2 - RK) * ST * ST);
    CPHI = ST * (1 - RK) * RX;
    SPHI = CT * RX;
    SDPHI = SPHI * CPHI0 - CPHI * SPHI0;
    CPHI0 = CPHI;
    SPHI0 = SPHI;
  } while (SDPHI * SDPHI > genau2 && iter < maxiter);
  Latitude = Math.atan(SPHI / Math.abs(CPHI));
  return {
    x: Longitude,
    y: Latitude,
    z: Height
  };
}
function geocentricToWgs84(p, datum_type, datum_params) {
  if (datum_type === PJD_3PARAM) {
    return {
      x: p.x + datum_params[0],
      y: p.y + datum_params[1],
      z: p.z + datum_params[2]
    };
  } else if (datum_type === PJD_7PARAM) {
    var Dx_BF = datum_params[0];
    var Dy_BF = datum_params[1];
    var Dz_BF = datum_params[2];
    var Rx_BF = datum_params[3];
    var Ry_BF = datum_params[4];
    var Rz_BF = datum_params[5];
    var M_BF = datum_params[6];
    return {
      x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF,
      y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF,
      z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF
    };
  }
}
function geocentricFromWgs84(p, datum_type, datum_params) {
  if (datum_type === PJD_3PARAM) {
    return {
      x: p.x - datum_params[0],
      y: p.y - datum_params[1],
      z: p.z - datum_params[2]
    };
  } else if (datum_type === PJD_7PARAM) {
    var Dx_BF = datum_params[0];
    var Dy_BF = datum_params[1];
    var Dz_BF = datum_params[2];
    var Rx_BF = datum_params[3];
    var Ry_BF = datum_params[4];
    var Rz_BF = datum_params[5];
    var M_BF = datum_params[6];
    var x_tmp = (p.x - Dx_BF) / M_BF;
    var y_tmp = (p.y - Dy_BF) / M_BF;
    var z_tmp = (p.z - Dz_BF) / M_BF;
    return {
      x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp,
      y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp,
      z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp
    };
  }
}
function checkParams(type) {
  return type === PJD_3PARAM || type === PJD_7PARAM;
}
function datum_transform(source, dest, point) {
  if (compareDatums(source, dest)) {
    return point;
  }
  if (source.datum_type === PJD_NODATUM || dest.datum_type === PJD_NODATUM) {
    return point;
  }
  var source_a = source.a;
  var source_es = source.es;
  if (source.datum_type === PJD_GRIDSHIFT) {
    var gridShiftCode = applyGridShift(source, false, point);
    if (gridShiftCode !== 0) {
      return void 0;
    }
    source_a = SRS_WGS84_SEMIMAJOR;
    source_es = SRS_WGS84_ESQUARED;
  }
  var dest_a = dest.a;
  var dest_b = dest.b;
  var dest_es = dest.es;
  if (dest.datum_type === PJD_GRIDSHIFT) {
    dest_a = SRS_WGS84_SEMIMAJOR;
    dest_b = SRS_WGS84_SEMIMINOR;
    dest_es = SRS_WGS84_ESQUARED;
  }
  if (source_es === dest_es && source_a === dest_a && !checkParams(source.datum_type) && !checkParams(dest.datum_type)) {
    return point;
  }
  point = geodeticToGeocentric(point, source_es, source_a);
  if (checkParams(source.datum_type)) {
    point = geocentricToWgs84(point, source.datum_type, source.datum_params);
  }
  if (checkParams(dest.datum_type)) {
    point = geocentricFromWgs84(point, dest.datum_type, dest.datum_params);
  }
  point = geocentricToGeodetic(point, dest_es, dest_a, dest_b);
  if (dest.datum_type === PJD_GRIDSHIFT) {
    var destGridShiftResult = applyGridShift(dest, true, point);
    if (destGridShiftResult !== 0) {
      return void 0;
    }
  }
  return point;
}
function applyGridShift(source, inverse2, point) {
  if (source.grids === null || source.grids.length === 0) {
    console.log("Grid shift grids not found");
    return -1;
  }
  var input = { x: -point.x, y: point.y };
  var output = { x: Number.NaN, y: Number.NaN };
  var attemptedGrids = [];
  outer:
    for (var i = 0; i < source.grids.length; i++) {
      var grid = source.grids[i];
      attemptedGrids.push(grid.name);
      if (grid.isNull) {
        output = input;
        break;
      }
      if (grid.grid === null) {
        if (grid.mandatory) {
          console.log("Unable to find mandatory grid '" + grid.name + "'");
          return -1;
        }
        continue;
      }
      var subgrids = grid.grid.subgrids;
      for (var j = 0, jj = subgrids.length; j < jj; j++) {
        var subgrid = subgrids[j];
        var epsilon = (Math.abs(subgrid.del[1]) + Math.abs(subgrid.del[0])) / 1e4;
        var minX = subgrid.ll[0] - epsilon;
        var minY = subgrid.ll[1] - epsilon;
        var maxX = subgrid.ll[0] + (subgrid.lim[0] - 1) * subgrid.del[0] + epsilon;
        var maxY = subgrid.ll[1] + (subgrid.lim[1] - 1) * subgrid.del[1] + epsilon;
        if (minY > input.y || minX > input.x || maxY < input.y || maxX < input.x) {
          continue;
        }
        output = applySubgridShift(input, inverse2, subgrid);
        if (!isNaN(output.x)) {
          break outer;
        }
      }
    }
  if (isNaN(output.x)) {
    console.log("Failed to find a grid shift table for location '" + -input.x * R2D + " " + input.y * R2D + " tried: '" + attemptedGrids + "'");
    return -1;
  }
  point.x = -output.x;
  point.y = output.y;
  return 0;
}
function applySubgridShift(pin, inverse2, ct) {
  var val = { x: Number.NaN, y: Number.NaN };
  if (isNaN(pin.x)) {
    return val;
  }
  var tb = { x: pin.x, y: pin.y };
  tb.x -= ct.ll[0];
  tb.y -= ct.ll[1];
  tb.x = adjust_lon(tb.x - Math.PI) + Math.PI;
  var t = nadInterpolate(tb, ct);
  if (inverse2) {
    if (isNaN(t.x)) {
      return val;
    }
    t.x = tb.x - t.x;
    t.y = tb.y - t.y;
    var i = 9, tol = 1e-12;
    var dif, del;
    do {
      del = nadInterpolate(t, ct);
      if (isNaN(del.x)) {
        console.log("Inverse grid shift iteration failed, presumably at grid edge.  Using first approximation.");
        break;
      }
      dif = { x: tb.x - (del.x + t.x), y: tb.y - (del.y + t.y) };
      t.x += dif.x;
      t.y += dif.y;
    } while (i-- && Math.abs(dif.x) > tol && Math.abs(dif.y) > tol);
    if (i < 0) {
      console.log("Inverse grid shift iterator failed to converge.");
      return val;
    }
    val.x = adjust_lon(t.x + ct.ll[0]);
    val.y = t.y + ct.ll[1];
  } else {
    if (!isNaN(t.x)) {
      val.x = pin.x + t.x;
      val.y = pin.y + t.y;
    }
  }
  return val;
}
function nadInterpolate(pin, ct) {
  var t = { x: pin.x / ct.del[0], y: pin.y / ct.del[1] };
  var indx = { x: Math.floor(t.x), y: Math.floor(t.y) };
  var frct = { x: t.x - 1 * indx.x, y: t.y - 1 * indx.y };
  var val = { x: Number.NaN, y: Number.NaN };
  var inx;
  if (indx.x < 0 || indx.x >= ct.lim[0]) {
    return val;
  }
  if (indx.y < 0 || indx.y >= ct.lim[1]) {
    return val;
  }
  inx = indx.y * ct.lim[0] + indx.x;
  var f00 = { x: ct.cvs[inx][0], y: ct.cvs[inx][1] };
  inx++;
  var f10 = { x: ct.cvs[inx][0], y: ct.cvs[inx][1] };
  inx += ct.lim[0];
  var f11 = { x: ct.cvs[inx][0], y: ct.cvs[inx][1] };
  inx--;
  var f01 = { x: ct.cvs[inx][0], y: ct.cvs[inx][1] };
  var m11 = frct.x * frct.y, m10 = frct.x * (1 - frct.y), m00 = (1 - frct.x) * (1 - frct.y), m01 = (1 - frct.x) * frct.y;
  val.x = m00 * f00.x + m10 * f10.x + m01 * f01.x + m11 * f11.x;
  val.y = m00 * f00.y + m10 * f10.y + m01 * f01.y + m11 * f11.y;
  return val;
}
function adjust_axis(crs, denorm, point) {
  var xin = point.x, yin = point.y, zin = point.z || 0;
  var v, t, i;
  var out = {};
  for (i = 0; i < 3; i++) {
    if (denorm && i === 2 && point.z === void 0) {
      continue;
    }
    if (i === 0) {
      v = xin;
      if ("ew".indexOf(crs.axis[i]) !== -1) {
        t = "x";
      } else {
        t = "y";
      }
    } else if (i === 1) {
      v = yin;
      if ("ns".indexOf(crs.axis[i]) !== -1) {
        t = "y";
      } else {
        t = "x";
      }
    } else {
      v = zin;
      t = "z";
    }
    switch (crs.axis[i]) {
      case "e":
        out[t] = v;
        break;
      case "w":
        out[t] = -v;
        break;
      case "n":
        out[t] = v;
        break;
      case "s":
        out[t] = -v;
        break;
      case "u":
        if (point[t] !== void 0) {
          out.z = v;
        }
        break;
      case "d":
        if (point[t] !== void 0) {
          out.z = -v;
        }
        break;
      default:
        return null;
    }
  }
  return out;
}
function common(array) {
  var out = {
    x: array[0],
    y: array[1]
  };
  if (array.length > 2) {
    out.z = array[2];
  }
  if (array.length > 3) {
    out.m = array[3];
  }
  return out;
}
function checkSanity(point) {
  checkCoord(point.x);
  checkCoord(point.y);
}
function checkCoord(num) {
  if (typeof Number.isFinite === "function") {
    if (Number.isFinite(num)) {
      return;
    }
    throw new TypeError("coordinates must be finite numbers");
  }
  if (typeof num !== "number" || num !== num || !isFinite(num)) {
    throw new TypeError("coordinates must be finite numbers");
  }
}
function checkNotWGS(source, dest) {
  return (source.datum.datum_type === PJD_3PARAM || source.datum.datum_type === PJD_7PARAM || source.datum.datum_type === PJD_GRIDSHIFT) && dest.datumCode !== "WGS84" || (dest.datum.datum_type === PJD_3PARAM || dest.datum.datum_type === PJD_7PARAM || dest.datum.datum_type === PJD_GRIDSHIFT) && source.datumCode !== "WGS84";
}
function transform(source, dest, point, enforceAxis) {
  var wgs842;
  if (Array.isArray(point)) {
    point = common(point);
  } else {
    point = {
      x: point.x,
      y: point.y,
      z: point.z,
      m: point.m
    };
  }
  var hasZ = point.z !== void 0;
  checkSanity(point);
  if (source.datum && dest.datum && checkNotWGS(source, dest)) {
    wgs842 = new Projection("WGS84");
    point = transform(source, wgs842, point, enforceAxis);
    source = wgs842;
  }
  if (enforceAxis && source.axis !== "enu") {
    point = adjust_axis(source, false, point);
  }
  if (source.projName === "longlat") {
    point = {
      x: point.x * D2R$1,
      y: point.y * D2R$1,
      z: point.z || 0
    };
  } else {
    if (source.to_meter) {
      point = {
        x: point.x * source.to_meter,
        y: point.y * source.to_meter,
        z: point.z || 0
      };
    }
    point = source.inverse(point);
    if (!point) {
      return;
    }
  }
  if (source.from_greenwich) {
    point.x += source.from_greenwich;
  }
  point = datum_transform(source.datum, dest.datum, point);
  if (!point) {
    return;
  }
  if (dest.from_greenwich) {
    point = {
      x: point.x - dest.from_greenwich,
      y: point.y,
      z: point.z || 0
    };
  }
  if (dest.projName === "longlat") {
    point = {
      x: point.x * R2D,
      y: point.y * R2D,
      z: point.z || 0
    };
  } else {
    point = dest.forward(point);
    if (dest.to_meter) {
      point = {
        x: point.x / dest.to_meter,
        y: point.y / dest.to_meter,
        z: point.z || 0
      };
    }
  }
  if (enforceAxis && dest.axis !== "enu") {
    return adjust_axis(dest, true, point);
  }
  if (point && !hasZ) {
    delete point.z;
  }
  return point;
}
var wgs84 = Projection("WGS84");
function transformer(from, to, coords, enforceAxis) {
  var transformedArray, out, keys;
  if (Array.isArray(coords)) {
    transformedArray = transform(from, to, coords, enforceAxis) || { x: NaN, y: NaN };
    if (coords.length > 2) {
      if (typeof from.name !== "undefined" && from.name === "geocent" || typeof to.name !== "undefined" && to.name === "geocent") {
        if (typeof transformedArray.z === "number") {
          return [transformedArray.x, transformedArray.y, transformedArray.z].concat(coords.slice(3));
        } else {
          return [transformedArray.x, transformedArray.y, coords[2]].concat(coords.slice(3));
        }
      } else {
        return [transformedArray.x, transformedArray.y].concat(coords.slice(2));
      }
    } else {
      return [transformedArray.x, transformedArray.y];
    }
  } else {
    out = transform(from, to, coords, enforceAxis);
    keys = Object.keys(coords);
    if (keys.length === 2) {
      return out;
    }
    keys.forEach(function(key2) {
      if (typeof from.name !== "undefined" && from.name === "geocent" || typeof to.name !== "undefined" && to.name === "geocent") {
        if (key2 === "x" || key2 === "y" || key2 === "z") {
          return;
        }
      } else {
        if (key2 === "x" || key2 === "y") {
          return;
        }
      }
      out[key2] = coords[key2];
    });
    return out;
  }
}
function checkProj(item) {
  if (item instanceof Projection) {
    return item;
  }
  if (item.oProj) {
    return item.oProj;
  }
  return Projection(item);
}
function proj4(fromProj, toProj, coord) {
  fromProj = checkProj(fromProj);
  var single = false;
  var obj;
  if (typeof toProj === "undefined") {
    toProj = fromProj;
    fromProj = wgs84;
    single = true;
  } else if (typeof toProj.x !== "undefined" || Array.isArray(toProj)) {
    coord = toProj;
    toProj = fromProj;
    fromProj = wgs84;
    single = true;
  }
  toProj = checkProj(toProj);
  if (coord) {
    return transformer(fromProj, toProj, coord);
  } else {
    obj = {
      forward: function(coords, enforceAxis) {
        return transformer(fromProj, toProj, coords, enforceAxis);
      },
      inverse: function(coords, enforceAxis) {
        return transformer(toProj, fromProj, coords, enforceAxis);
      }
    };
    if (single) {
      obj.oProj = toProj;
    }
    return obj;
  }
}
var NUM_100K_SETS = 6;
var SET_ORIGIN_COLUMN_LETTERS = "AJSAJS";
var SET_ORIGIN_ROW_LETTERS = "AFAFAF";
var A = 65;
var I = 73;
var O = 79;
var V = 86;
var Z = 90;
const mgrs = {
  forward: forward$u,
  inverse: inverse$u,
  toPoint
};
function forward$u(ll, accuracy) {
  accuracy = accuracy || 5;
  return encode(LLtoUTM({
    lat: ll[1],
    lon: ll[0]
  }), accuracy);
}
function inverse$u(mgrs2) {
  var bbox = UTMtoLL(decode(mgrs2.toUpperCase()));
  if (bbox.lat && bbox.lon) {
    return [bbox.lon, bbox.lat, bbox.lon, bbox.lat];
  }
  return [bbox.left, bbox.bottom, bbox.right, bbox.top];
}
function toPoint(mgrs2) {
  var bbox = UTMtoLL(decode(mgrs2.toUpperCase()));
  if (bbox.lat && bbox.lon) {
    return [bbox.lon, bbox.lat];
  }
  return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];
}
function degToRad(deg) {
  return deg * (Math.PI / 180);
}
function radToDeg(rad) {
  return 180 * (rad / Math.PI);
}
function LLtoUTM(ll) {
  var Lat = ll.lat;
  var Long = ll.lon;
  var a = 6378137;
  var eccSquared = 669438e-8;
  var k0 = 0.9996;
  var LongOrigin;
  var eccPrimeSquared;
  var N, T, C, A5, M5;
  var LatRad = degToRad(Lat);
  var LongRad = degToRad(Long);
  var LongOriginRad;
  var ZoneNumber;
  ZoneNumber = Math.floor((Long + 180) / 6) + 1;
  if (Long === 180) {
    ZoneNumber = 60;
  }
  if (Lat >= 56 && Lat < 64 && Long >= 3 && Long < 12) {
    ZoneNumber = 32;
  }
  if (Lat >= 72 && Lat < 84) {
    if (Long >= 0 && Long < 9) {
      ZoneNumber = 31;
    } else if (Long >= 9 && Long < 21) {
      ZoneNumber = 33;
    } else if (Long >= 21 && Long < 33) {
      ZoneNumber = 35;
    } else if (Long >= 33 && Long < 42) {
      ZoneNumber = 37;
    }
  }
  LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3;
  LongOriginRad = degToRad(LongOrigin);
  eccPrimeSquared = eccSquared / (1 - eccSquared);
  N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad));
  T = Math.tan(LatRad) * Math.tan(LatRad);
  C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);
  A5 = Math.cos(LatRad) * (LongRad - LongOriginRad);
  M5 = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad) - 35 * eccSquared * eccSquared * eccSquared / 3072 * Math.sin(6 * LatRad));
  var UTMEasting = k0 * N * (A5 + (1 - T + C) * A5 * A5 * A5 / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A5 * A5 * A5 * A5 * A5 / 120) + 5e5;
  var UTMNorthing = k0 * (M5 + N * Math.tan(LatRad) * (A5 * A5 / 2 + (5 - T + 9 * C + 4 * C * C) * A5 * A5 * A5 * A5 / 24 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A5 * A5 * A5 * A5 * A5 * A5 / 720));
  if (Lat < 0) {
    UTMNorthing += 1e7;
  }
  return {
    northing: Math.round(UTMNorthing),
    easting: Math.round(UTMEasting),
    zoneNumber: ZoneNumber,
    zoneLetter: getLetterDesignator(Lat)
  };
}
function UTMtoLL(utm2) {
  var UTMNorthing = utm2.northing;
  var UTMEasting = utm2.easting;
  var zoneLetter = utm2.zoneLetter;
  var zoneNumber = utm2.zoneNumber;
  if (zoneNumber < 0 || zoneNumber > 60) {
    return null;
  }
  var k0 = 0.9996;
  var a = 6378137;
  var eccSquared = 669438e-8;
  var eccPrimeSquared;
  var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared));
  var N1, T1, C12, R1, D, M5;
  var LongOrigin;
  var mu, phi1Rad;
  var x = UTMEasting - 5e5;
  var y = UTMNorthing;
  if (zoneLetter < "N") {
    y -= 1e7;
  }
  LongOrigin = (zoneNumber - 1) * 6 - 180 + 3;
  eccPrimeSquared = eccSquared / (1 - eccSquared);
  M5 = y / k0;
  mu = M5 / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
  phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + 151 * e1 * e1 * e1 / 96 * Math.sin(6 * mu);
  N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad));
  T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
  C12 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
  R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
  D = x / (N1 * k0);
  var lat = phi1Rad - N1 * Math.tan(phi1Rad) / R1 * (D * D / 2 - (5 + 3 * T1 + 10 * C12 - 4 * C12 * C12 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C12 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C12 * C12) * D * D * D * D * D * D / 720);
  lat = radToDeg(lat);
  var lon = (D - (1 + 2 * T1 + C12) * D * D * D / 6 + (5 - 2 * C12 + 28 * T1 - 3 * C12 * C12 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad);
  lon = LongOrigin + radToDeg(lon);
  var result;
  if (utm2.accuracy) {
    var topRight = UTMtoLL({
      northing: utm2.northing + utm2.accuracy,
      easting: utm2.easting + utm2.accuracy,
      zoneLetter: utm2.zoneLetter,
      zoneNumber: utm2.zoneNumber
    });
    result = {
      top: topRight.lat,
      right: topRight.lon,
      bottom: lat,
      left: lon
    };
  } else {
    result = {
      lat,
      lon
    };
  }
  return result;
}
function getLetterDesignator(lat) {
  var LetterDesignator = "Z";
  if (84 >= lat && lat >= 72) {
    LetterDesignator = "X";
  } else if (72 > lat && lat >= 64) {
    LetterDesignator = "W";
  } else if (64 > lat && lat >= 56) {
    LetterDesignator = "V";
  } else if (56 > lat && lat >= 48) {
    LetterDesignator = "U";
  } else if (48 > lat && lat >= 40) {
    LetterDesignator = "T";
  } else if (40 > lat && lat >= 32) {
    LetterDesignator = "S";
  } else if (32 > lat && lat >= 24) {
    LetterDesignator = "R";
  } else if (24 > lat && lat >= 16) {
    LetterDesignator = "Q";
  } else if (16 > lat && lat >= 8) {
    LetterDesignator = "P";
  } else if (8 > lat && lat >= 0) {
    LetterDesignator = "N";
  } else if (0 > lat && lat >= -8) {
    LetterDesignator = "M";
  } else if (-8 > lat && lat >= -16) {
    LetterDesignator = "L";
  } else if (-16 > lat && lat >= -24) {
    LetterDesignator = "K";
  } else if (-24 > lat && lat >= -32) {
    LetterDesignator = "J";
  } else if (-32 > lat && lat >= -40) {
    LetterDesignator = "H";
  } else if (-40 > lat && lat >= -48) {
    LetterDesignator = "G";
  } else if (-48 > lat && lat >= -56) {
    LetterDesignator = "F";
  } else if (-56 > lat && lat >= -64) {
    LetterDesignator = "E";
  } else if (-64 > lat && lat >= -72) {
    LetterDesignator = "D";
  } else if (-72 > lat && lat >= -80) {
    LetterDesignator = "C";
  }
  return LetterDesignator;
}
function encode(utm2, accuracy) {
  var seasting = "00000" + utm2.easting, snorthing = "00000" + utm2.northing;
  return utm2.zoneNumber + utm2.zoneLetter + get100kID(utm2.easting, utm2.northing, utm2.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);
}
function get100kID(easting, northing, zoneNumber) {
  var setParm = get100kSetForZone(zoneNumber);
  var setColumn = Math.floor(easting / 1e5);
  var setRow = Math.floor(northing / 1e5) % 20;
  return getLetter100kID(setColumn, setRow, setParm);
}
function get100kSetForZone(i) {
  var setParm = i % NUM_100K_SETS;
  if (setParm === 0) {
    setParm = NUM_100K_SETS;
  }
  return setParm;
}
function getLetter100kID(column2, row, parm) {
  var index = parm - 1;
  var colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index);
  var rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index);
  var colInt = colOrigin + column2 - 1;
  var rowInt = rowOrigin + row;
  var rollover = false;
  if (colInt > Z) {
    colInt = colInt - Z + A - 1;
    rollover = true;
  }
  if (colInt === I || colOrigin < I && colInt > I || (colInt > I || colOrigin < I) && rollover) {
    colInt++;
  }
  if (colInt === O || colOrigin < O && colInt > O || (colInt > O || colOrigin < O) && rollover) {
    colInt++;
    if (colInt === I) {
      colInt++;
    }
  }
  if (colInt > Z) {
    colInt = colInt - Z + A - 1;
  }
  if (rowInt > V) {
    rowInt = rowInt - V + A - 1;
    rollover = true;
  } else {
    rollover = false;
  }
  if (rowInt === I || rowOrigin < I && rowInt > I || (rowInt > I || rowOrigin < I) && rollover) {
    rowInt++;
  }
  if (rowInt === O || rowOrigin < O && rowInt > O || (rowInt > O || rowOrigin < O) && rollover) {
    rowInt++;
    if (rowInt === I) {
      rowInt++;
    }
  }
  if (rowInt > V) {
    rowInt = rowInt - V + A - 1;
  }
  var twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt);
  return twoLetter;
}
function decode(mgrsString) {
  if (mgrsString && mgrsString.length === 0) {
    throw "MGRSPoint coverting from nothing";
  }
  var length = mgrsString.length;
  var hunK = null;
  var sb = "";
  var testChar;
  var i = 0;
  while (!/[A-Z]/.test(testChar = mgrsString.charAt(i))) {
    if (i >= 2) {
      throw "MGRSPoint bad conversion from: " + mgrsString;
    }
    sb += testChar;
    i++;
  }
  var zoneNumber = parseInt(sb, 10);
  if (i === 0 || i + 3 > length) {
    throw "MGRSPoint bad conversion from: " + mgrsString;
  }
  var zoneLetter = mgrsString.charAt(i++);
  if (zoneLetter <= "A" || zoneLetter === "B" || zoneLetter === "Y" || zoneLetter >= "Z" || zoneLetter === "I" || zoneLetter === "O") {
    throw "MGRSPoint zone letter " + zoneLetter + " not handled: " + mgrsString;
  }
  hunK = mgrsString.substring(i, i += 2);
  var set2 = get100kSetForZone(zoneNumber);
  var east100k = getEastingFromChar(hunK.charAt(0), set2);
  var north100k = getNorthingFromChar(hunK.charAt(1), set2);
  while (north100k < getMinNorthing(zoneLetter)) {
    north100k += 2e6;
  }
  var remainder = length - i;
  if (remainder % 2 !== 0) {
    throw "MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters" + mgrsString;
  }
  var sep = remainder / 2;
  var sepEasting = 0;
  var sepNorthing = 0;
  var accuracyBonus, sepEastingString, sepNorthingString, easting, northing;
  if (sep > 0) {
    accuracyBonus = 1e5 / Math.pow(10, sep);
    sepEastingString = mgrsString.substring(i, i + sep);
    sepEasting = parseFloat(sepEastingString) * accuracyBonus;
    sepNorthingString = mgrsString.substring(i + sep);
    sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;
  }
  easting = sepEasting + east100k;
  northing = sepNorthing + north100k;
  return {
    easting,
    northing,
    zoneLetter,
    zoneNumber,
    accuracy: accuracyBonus
  };
}
function getEastingFromChar(e, set2) {
  var curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set2 - 1);
  var eastingValue = 1e5;
  var rewindMarker = false;
  while (curCol !== e.charCodeAt(0)) {
    curCol++;
    if (curCol === I) {
      curCol++;
    }
    if (curCol === O) {
      curCol++;
    }
    if (curCol > Z) {
      if (rewindMarker) {
        throw "Bad character: " + e;
      }
      curCol = A;
      rewindMarker = true;
    }
    eastingValue += 1e5;
  }
  return eastingValue;
}
function getNorthingFromChar(n, set2) {
  if (n > "V") {
    throw "MGRSPoint given invalid Northing " + n;
  }
  var curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set2 - 1);
  var northingValue = 0;
  var rewindMarker = false;
  while (curRow !== n.charCodeAt(0)) {
    curRow++;
    if (curRow === I) {
      curRow++;
    }
    if (curRow === O) {
      curRow++;
    }
    if (curRow > V) {
      if (rewindMarker) {
        throw "Bad character: " + n;
      }
      curRow = A;
      rewindMarker = true;
    }
    northingValue += 1e5;
  }
  return northingValue;
}
function getMinNorthing(zoneLetter) {
  var northing;
  switch (zoneLetter) {
    case "C":
      northing = 11e5;
      break;
    case "D":
      northing = 2e6;
      break;
    case "E":
      northing = 28e5;
      break;
    case "F":
      northing = 37e5;
      break;
    case "G":
      northing = 46e5;
      break;
    case "H":
      northing = 55e5;
      break;
    case "J":
      northing = 64e5;
      break;
    case "K":
      northing = 73e5;
      break;
    case "L":
      northing = 82e5;
      break;
    case "M":
      northing = 91e5;
      break;
    case "N":
      northing = 0;
      break;
    case "P":
      northing = 8e5;
      break;
    case "Q":
      northing = 17e5;
      break;
    case "R":
      northing = 26e5;
      break;
    case "S":
      northing = 35e5;
      break;
    case "T":
      northing = 44e5;
      break;
    case "U":
      northing = 53e5;
      break;
    case "V":
      northing = 62e5;
      break;
    case "W":
      northing = 7e6;
      break;
    case "X":
      northing = 79e5;
      break;
    default:
      northing = -1;
  }
  if (northing >= 0) {
    return northing;
  } else {
    throw "Invalid zone letter: " + zoneLetter;
  }
}
function Point(x, y, z) {
  if (!(this instanceof Point)) {
    return new Point(x, y, z);
  }
  if (Array.isArray(x)) {
    this.x = x[0];
    this.y = x[1];
    this.z = x[2] || 0;
  } else if (typeof x === "object") {
    this.x = x.x;
    this.y = x.y;
    this.z = x.z || 0;
  } else if (typeof x === "string" && typeof y === "undefined") {
    var coords = x.split(",");
    this.x = parseFloat(coords[0], 10);
    this.y = parseFloat(coords[1], 10);
    this.z = parseFloat(coords[2], 10) || 0;
  } else {
    this.x = x;
    this.y = y;
    this.z = z || 0;
  }
  console.warn("proj4.Point will be removed in version 3, use proj4.toPoint");
}
Point.fromMGRS = function(mgrsStr) {
  return new Point(toPoint(mgrsStr));
};
Point.prototype.toMGRS = function(accuracy) {
  return forward$u([this.x, this.y], accuracy);
};
var C00 = 1;
var C02 = 0.25;
var C04 = 0.046875;
var C06 = 0.01953125;
var C08 = 0.01068115234375;
var C22 = 0.75;
var C44 = 0.46875;
var C46 = 0.013020833333333334;
var C48 = 0.007120768229166667;
var C66 = 0.3645833333333333;
var C68 = 0.005696614583333333;
var C88 = 0.3076171875;
function pj_enfn(es) {
  var en = [];
  en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08)));
  en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08)));
  var t = es * es;
  en[2] = t * (C44 - es * (C46 + es * C48));
  t *= es;
  en[3] = t * (C66 - es * C68);
  en[4] = t * es * C88;
  return en;
}
function pj_mlfn(phi, sphi, cphi, en) {
  cphi *= sphi;
  sphi *= sphi;
  return en[0] * phi - cphi * (en[1] + sphi * (en[2] + sphi * (en[3] + sphi * en[4])));
}
var MAX_ITER$3 = 20;
function pj_inv_mlfn(arg, es, en) {
  var k = 1 / (1 - es);
  var phi = arg;
  for (var i = MAX_ITER$3; i; --i) {
    var s = Math.sin(phi);
    var t = 1 - es * s * s;
    t = (pj_mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k;
    phi -= t;
    if (Math.abs(t) < EPSLN) {
      return phi;
    }
  }
  return phi;
}
function init$w() {
  this.x0 = this.x0 !== void 0 ? this.x0 : 0;
  this.y0 = this.y0 !== void 0 ? this.y0 : 0;
  this.long0 = this.long0 !== void 0 ? this.long0 : 0;
  this.lat0 = this.lat0 !== void 0 ? this.lat0 : 0;
  if (this.es) {
    this.en = pj_enfn(this.es);
    this.ml0 = pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en);
  }
}
function forward$t(p) {
  var lon = p.x;
  var lat = p.y;
  var delta_lon = adjust_lon(lon - this.long0);
  var con;
  var x, y;
  var sin_phi = Math.sin(lat);
  var cos_phi = Math.cos(lat);
  if (!this.es) {
    var b = cos_phi * Math.sin(delta_lon);
    if (Math.abs(Math.abs(b) - 1) < EPSLN) {
      return 93;
    } else {
      x = 0.5 * this.a * this.k0 * Math.log((1 + b) / (1 - b)) + this.x0;
      y = cos_phi * Math.cos(delta_lon) / Math.sqrt(1 - Math.pow(b, 2));
      b = Math.abs(y);
      if (b >= 1) {
        if (b - 1 > EPSLN) {
          return 93;
        } else {
          y = 0;
        }
      } else {
        y = Math.acos(y);
      }
      if (lat < 0) {
        y = -y;
      }
      y = this.a * this.k0 * (y - this.lat0) + this.y0;
    }
  } else {
    var al = cos_phi * delta_lon;
    var als = Math.pow(al, 2);
    var c = this.ep2 * Math.pow(cos_phi, 2);
    var cs = Math.pow(c, 2);
    var tq = Math.abs(cos_phi) > EPSLN ? Math.tan(lat) : 0;
    var t = Math.pow(tq, 2);
    var ts = Math.pow(t, 2);
    con = 1 - this.es * Math.pow(sin_phi, 2);
    al = al / Math.sqrt(con);
    var ml = pj_mlfn(lat, sin_phi, cos_phi, this.en);
    x = this.a * (this.k0 * al * (1 + als / 6 * (1 - t + c + als / 20 * (5 - 18 * t + ts + 14 * c - 58 * t * c + als / 42 * (61 + 179 * ts - ts * t - 479 * t))))) + this.x0;
    y = this.a * (this.k0 * (ml - this.ml0 + sin_phi * delta_lon * al / 2 * (1 + als / 12 * (5 - t + 9 * c + 4 * cs + als / 30 * (61 + ts - 58 * t + 270 * c - 330 * t * c + als / 56 * (1385 + 543 * ts - ts * t - 3111 * t)))))) + this.y0;
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$t(p) {
  var con, phi;
  var lat, lon;
  var x = (p.x - this.x0) * (1 / this.a);
  var y = (p.y - this.y0) * (1 / this.a);
  if (!this.es) {
    var f = Math.exp(x / this.k0);
    var g = 0.5 * (f - 1 / f);
    var temp = this.lat0 + y / this.k0;
    var h = Math.cos(temp);
    con = Math.sqrt((1 - Math.pow(h, 2)) / (1 + Math.pow(g, 2)));
    lat = Math.asin(con);
    if (y < 0) {
      lat = -lat;
    }
    if (g === 0 && h === 0) {
      lon = 0;
    } else {
      lon = adjust_lon(Math.atan2(g, h) + this.long0);
    }
  } else {
    con = this.ml0 + y / this.k0;
    phi = pj_inv_mlfn(con, this.es, this.en);
    if (Math.abs(phi) < HALF_PI) {
      var sin_phi = Math.sin(phi);
      var cos_phi = Math.cos(phi);
      var tan_phi = Math.abs(cos_phi) > EPSLN ? Math.tan(phi) : 0;
      var c = this.ep2 * Math.pow(cos_phi, 2);
      var cs = Math.pow(c, 2);
      var t = Math.pow(tan_phi, 2);
      var ts = Math.pow(t, 2);
      con = 1 - this.es * Math.pow(sin_phi, 2);
      var d = x * Math.sqrt(con) / this.k0;
      var ds = Math.pow(d, 2);
      con = con * tan_phi;
      lat = phi - con * ds / (1 - this.es) * 0.5 * (1 - ds / 12 * (5 + 3 * t - 9 * c * t + c - 4 * cs - ds / 30 * (61 + 90 * t - 252 * c * t + 45 * ts + 46 * c - ds / 56 * (1385 + 3633 * t + 4095 * ts + 1574 * ts * t))));
      lon = adjust_lon(this.long0 + d * (1 - ds / 6 * (1 + 2 * t + c - ds / 20 * (5 + 28 * t + 24 * ts + 8 * c * t + 6 * c - ds / 42 * (61 + 662 * t + 1320 * ts + 720 * ts * t)))) / cos_phi);
    } else {
      lat = HALF_PI * sign(y);
      lon = 0;
    }
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$u = ["Fast_Transverse_Mercator", "Fast Transverse Mercator"];
const tmerc = {
  init: init$w,
  forward: forward$t,
  inverse: inverse$t,
  names: names$u
};
function sinh(x) {
  var r = Math.exp(x);
  r = (r - 1 / r) / 2;
  return r;
}
function hypot(x, y) {
  x = Math.abs(x);
  y = Math.abs(y);
  var a = Math.max(x, y);
  var b = Math.min(x, y) / (a ? a : 1);
  return a * Math.sqrt(1 + Math.pow(b, 2));
}
function log1py(x) {
  var y = 1 + x;
  var z = y - 1;
  return z === 0 ? x : x * Math.log(y) / z;
}
function asinhy(x) {
  var y = Math.abs(x);
  y = log1py(y * (1 + y / (hypot(1, y) + 1)));
  return x < 0 ? -y : y;
}
function gatg(pp, B) {
  var cos_2B = 2 * Math.cos(2 * B);
  var i = pp.length - 1;
  var h1 = pp[i];
  var h2 = 0;
  var h;
  while (--i >= 0) {
    h = -h2 + cos_2B * h1 + pp[i];
    h2 = h1;
    h1 = h;
  }
  return B + h * Math.sin(2 * B);
}
function clens(pp, arg_r) {
  var r = 2 * Math.cos(arg_r);
  var i = pp.length - 1;
  var hr1 = pp[i];
  var hr2 = 0;
  var hr;
  while (--i >= 0) {
    hr = -hr2 + r * hr1 + pp[i];
    hr2 = hr1;
    hr1 = hr;
  }
  return Math.sin(arg_r) * hr;
}
function cosh(x) {
  var r = Math.exp(x);
  r = (r + 1 / r) / 2;
  return r;
}
function clens_cmplx(pp, arg_r, arg_i) {
  var sin_arg_r = Math.sin(arg_r);
  var cos_arg_r = Math.cos(arg_r);
  var sinh_arg_i = sinh(arg_i);
  var cosh_arg_i = cosh(arg_i);
  var r = 2 * cos_arg_r * cosh_arg_i;
  var i = -2 * sin_arg_r * sinh_arg_i;
  var j = pp.length - 1;
  var hr = pp[j];
  var hi1 = 0;
  var hr1 = 0;
  var hi = 0;
  var hr2;
  var hi2;
  while (--j >= 0) {
    hr2 = hr1;
    hi2 = hi1;
    hr1 = hr;
    hi1 = hi;
    hr = -hr2 + r * hr1 - i * hi1 + pp[j];
    hi = -hi2 + i * hr1 + r * hi1;
  }
  r = sin_arg_r * cosh_arg_i;
  i = cos_arg_r * sinh_arg_i;
  return [r * hr - i * hi, r * hi + i * hr];
}
function init$v() {
  if (!this.approx && (isNaN(this.es) || this.es <= 0)) {
    throw new Error('Incorrect elliptical usage. Try using the +approx option in the proj string, or PROJECTION["Fast_Transverse_Mercator"] in the WKT.');
  }
  if (this.approx) {
    tmerc.init.apply(this);
    this.forward = tmerc.forward;
    this.inverse = tmerc.inverse;
  }
  this.x0 = this.x0 !== void 0 ? this.x0 : 0;
  this.y0 = this.y0 !== void 0 ? this.y0 : 0;
  this.long0 = this.long0 !== void 0 ? this.long0 : 0;
  this.lat0 = this.lat0 !== void 0 ? this.lat0 : 0;
  this.cgb = [];
  this.cbg = [];
  this.utg = [];
  this.gtu = [];
  var f = this.es / (1 + Math.sqrt(1 - this.es));
  var n = f / (2 - f);
  var np = n;
  this.cgb[0] = n * (2 + n * (-2 / 3 + n * (-2 + n * (116 / 45 + n * (26 / 45 + n * (-2854 / 675))))));
  this.cbg[0] = n * (-2 + n * (2 / 3 + n * (4 / 3 + n * (-82 / 45 + n * (32 / 45 + n * (4642 / 4725))))));
  np = np * n;
  this.cgb[1] = np * (7 / 3 + n * (-8 / 5 + n * (-227 / 45 + n * (2704 / 315 + n * (2323 / 945)))));
  this.cbg[1] = np * (5 / 3 + n * (-16 / 15 + n * (-13 / 9 + n * (904 / 315 + n * (-1522 / 945)))));
  np = np * n;
  this.cgb[2] = np * (56 / 15 + n * (-136 / 35 + n * (-1262 / 105 + n * (73814 / 2835))));
  this.cbg[2] = np * (-26 / 15 + n * (34 / 21 + n * (8 / 5 + n * (-12686 / 2835))));
  np = np * n;
  this.cgb[3] = np * (4279 / 630 + n * (-332 / 35 + n * (-399572 / 14175)));
  this.cbg[3] = np * (1237 / 630 + n * (-12 / 5 + n * (-24832 / 14175)));
  np = np * n;
  this.cgb[4] = np * (4174 / 315 + n * (-144838 / 6237));
  this.cbg[4] = np * (-734 / 315 + n * (109598 / 31185));
  np = np * n;
  this.cgb[5] = np * (601676 / 22275);
  this.cbg[5] = np * (444337 / 155925);
  np = Math.pow(n, 2);
  this.Qn = this.k0 / (1 + n) * (1 + np * (1 / 4 + np * (1 / 64 + np / 256)));
  this.utg[0] = n * (-0.5 + n * (2 / 3 + n * (-37 / 96 + n * (1 / 360 + n * (81 / 512 + n * (-96199 / 604800))))));
  this.gtu[0] = n * (0.5 + n * (-2 / 3 + n * (5 / 16 + n * (41 / 180 + n * (-127 / 288 + n * (7891 / 37800))))));
  this.utg[1] = np * (-1 / 48 + n * (-1 / 15 + n * (437 / 1440 + n * (-46 / 105 + n * (1118711 / 3870720)))));
  this.gtu[1] = np * (13 / 48 + n * (-3 / 5 + n * (557 / 1440 + n * (281 / 630 + n * (-1983433 / 1935360)))));
  np = np * n;
  this.utg[2] = np * (-17 / 480 + n * (37 / 840 + n * (209 / 4480 + n * (-5569 / 90720))));
  this.gtu[2] = np * (61 / 240 + n * (-103 / 140 + n * (15061 / 26880 + n * (167603 / 181440))));
  np = np * n;
  this.utg[3] = np * (-4397 / 161280 + n * (11 / 504 + n * (830251 / 7257600)));
  this.gtu[3] = np * (49561 / 161280 + n * (-179 / 168 + n * (6601661 / 7257600)));
  np = np * n;
  this.utg[4] = np * (-4583 / 161280 + n * (108847 / 3991680));
  this.gtu[4] = np * (34729 / 80640 + n * (-3418889 / 1995840));
  np = np * n;
  this.utg[5] = np * (-20648693 / 638668800);
  this.gtu[5] = np * (212378941 / 319334400);
  var Z2 = gatg(this.cbg, this.lat0);
  this.Zb = -this.Qn * (Z2 + clens(this.gtu, 2 * Z2));
}
function forward$s(p) {
  var Ce = adjust_lon(p.x - this.long0);
  var Cn = p.y;
  Cn = gatg(this.cbg, Cn);
  var sin_Cn = Math.sin(Cn);
  var cos_Cn = Math.cos(Cn);
  var sin_Ce = Math.sin(Ce);
  var cos_Ce = Math.cos(Ce);
  Cn = Math.atan2(sin_Cn, cos_Ce * cos_Cn);
  Ce = Math.atan2(sin_Ce * cos_Cn, hypot(sin_Cn, cos_Cn * cos_Ce));
  Ce = asinhy(Math.tan(Ce));
  var tmp = clens_cmplx(this.gtu, 2 * Cn, 2 * Ce);
  Cn = Cn + tmp[0];
  Ce = Ce + tmp[1];
  var x;
  var y;
  if (Math.abs(Ce) <= 2.623395162778) {
    x = this.a * (this.Qn * Ce) + this.x0;
    y = this.a * (this.Qn * Cn + this.Zb) + this.y0;
  } else {
    x = Infinity;
    y = Infinity;
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$s(p) {
  var Ce = (p.x - this.x0) * (1 / this.a);
  var Cn = (p.y - this.y0) * (1 / this.a);
  Cn = (Cn - this.Zb) / this.Qn;
  Ce = Ce / this.Qn;
  var lon;
  var lat;
  if (Math.abs(Ce) <= 2.623395162778) {
    var tmp = clens_cmplx(this.utg, 2 * Cn, 2 * Ce);
    Cn = Cn + tmp[0];
    Ce = Ce + tmp[1];
    Ce = Math.atan(sinh(Ce));
    var sin_Cn = Math.sin(Cn);
    var cos_Cn = Math.cos(Cn);
    var sin_Ce = Math.sin(Ce);
    var cos_Ce = Math.cos(Ce);
    Cn = Math.atan2(sin_Cn * cos_Ce, hypot(sin_Ce, cos_Ce * cos_Cn));
    Ce = Math.atan2(sin_Ce, cos_Ce * cos_Cn);
    lon = adjust_lon(Ce + this.long0);
    lat = gatg(this.cgb, Cn);
  } else {
    lon = Infinity;
    lat = Infinity;
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$t = ["Extended_Transverse_Mercator", "Extended Transverse Mercator", "etmerc", "Transverse_Mercator", "Transverse Mercator", "Gauss Kruger", "Gauss_Kruger", "tmerc"];
const etmerc = {
  init: init$v,
  forward: forward$s,
  inverse: inverse$s,
  names: names$t
};
function adjust_zone(zone, lon) {
  if (zone === void 0) {
    zone = Math.floor((adjust_lon(lon) + Math.PI) * 30 / Math.PI) + 1;
    if (zone < 0) {
      return 0;
    } else if (zone > 60) {
      return 60;
    }
  }
  return zone;
}
var dependsOn = "etmerc";
function init$u() {
  var zone = adjust_zone(this.zone, this.long0);
  if (zone === void 0) {
    throw new Error("unknown utm zone");
  }
  this.lat0 = 0;
  this.long0 = (6 * Math.abs(zone) - 183) * D2R$1;
  this.x0 = 5e5;
  this.y0 = this.utmSouth ? 1e7 : 0;
  this.k0 = 0.9996;
  etmerc.init.apply(this);
  this.forward = etmerc.forward;
  this.inverse = etmerc.inverse;
}
var names$s = ["Universal Transverse Mercator System", "utm"];
const utm = {
  init: init$u,
  names: names$s,
  dependsOn
};
function srat(esinp, exp) {
  return Math.pow((1 - esinp) / (1 + esinp), exp);
}
var MAX_ITER$2 = 20;
function init$t() {
  var sphi = Math.sin(this.lat0);
  var cphi = Math.cos(this.lat0);
  cphi *= cphi;
  this.rc = Math.sqrt(1 - this.es) / (1 - this.es * sphi * sphi);
  this.C = Math.sqrt(1 + this.es * cphi * cphi / (1 - this.es));
  this.phic0 = Math.asin(sphi / this.C);
  this.ratexp = 0.5 * this.C * this.e;
  this.K = Math.tan(0.5 * this.phic0 + FORTPI) / (Math.pow(Math.tan(0.5 * this.lat0 + FORTPI), this.C) * srat(this.e * sphi, this.ratexp));
}
function forward$r(p) {
  var lon = p.x;
  var lat = p.y;
  p.y = 2 * Math.atan(this.K * Math.pow(Math.tan(0.5 * lat + FORTPI), this.C) * srat(this.e * Math.sin(lat), this.ratexp)) - HALF_PI;
  p.x = this.C * lon;
  return p;
}
function inverse$r(p) {
  var DEL_TOL = 1e-14;
  var lon = p.x / this.C;
  var lat = p.y;
  var num = Math.pow(Math.tan(0.5 * lat + FORTPI) / this.K, 1 / this.C);
  for (var i = MAX_ITER$2; i > 0; --i) {
    lat = 2 * Math.atan(num * srat(this.e * Math.sin(p.y), -0.5 * this.e)) - HALF_PI;
    if (Math.abs(lat - p.y) < DEL_TOL) {
      break;
    }
    p.y = lat;
  }
  if (!i) {
    return null;
  }
  p.x = lon;
  p.y = lat;
  return p;
}
const gauss = {
  init: init$t,
  forward: forward$r,
  inverse: inverse$r
};
function init$s() {
  gauss.init.apply(this);
  if (!this.rc) {
    return;
  }
  this.sinc0 = Math.sin(this.phic0);
  this.cosc0 = Math.cos(this.phic0);
  this.R2 = 2 * this.rc;
  if (!this.title) {
    this.title = "Oblique Stereographic Alternative";
  }
}
function forward$q(p) {
  var sinc, cosc, cosl, k;
  p.x = adjust_lon(p.x - this.long0);
  gauss.forward.apply(this, [p]);
  sinc = Math.sin(p.y);
  cosc = Math.cos(p.y);
  cosl = Math.cos(p.x);
  k = this.k0 * this.R2 / (1 + this.sinc0 * sinc + this.cosc0 * cosc * cosl);
  p.x = k * cosc * Math.sin(p.x);
  p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl);
  p.x = this.a * p.x + this.x0;
  p.y = this.a * p.y + this.y0;
  return p;
}
function inverse$q(p) {
  var sinc, cosc, lon, lat, rho;
  p.x = (p.x - this.x0) / this.a;
  p.y = (p.y - this.y0) / this.a;
  p.x /= this.k0;
  p.y /= this.k0;
  if (rho = hypot(p.x, p.y)) {
    var c = 2 * Math.atan2(rho, this.R2);
    sinc = Math.sin(c);
    cosc = Math.cos(c);
    lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho);
    lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc);
  } else {
    lat = this.phic0;
    lon = 0;
  }
  p.x = lon;
  p.y = lat;
  gauss.inverse.apply(this, [p]);
  p.x = adjust_lon(p.x + this.long0);
  return p;
}
var names$r = ["Stereographic_North_Pole", "Oblique_Stereographic", "sterea", "Oblique Stereographic Alternative", "Double_Stereographic"];
const sterea = {
  init: init$s,
  forward: forward$q,
  inverse: inverse$q,
  names: names$r
};
function ssfn_(phit, sinphi, eccen) {
  sinphi *= eccen;
  return Math.tan(0.5 * (HALF_PI + phit)) * Math.pow((1 - sinphi) / (1 + sinphi), 0.5 * eccen);
}
function init$r() {
  this.x0 = this.x0 || 0;
  this.y0 = this.y0 || 0;
  this.lat0 = this.lat0 || 0;
  this.long0 = this.long0 || 0;
  this.coslat0 = Math.cos(this.lat0);
  this.sinlat0 = Math.sin(this.lat0);
  if (this.sphere) {
    if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
      this.k0 = 0.5 * (1 + sign(this.lat0) * Math.sin(this.lat_ts));
    }
  } else {
    if (Math.abs(this.coslat0) <= EPSLN) {
      if (this.lat0 > 0) {
        this.con = 1;
      } else {
        this.con = -1;
      }
    }
    this.cons = Math.sqrt(Math.pow(1 + this.e, 1 + this.e) * Math.pow(1 - this.e, 1 - this.e));
    if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN && Math.abs(Math.cos(this.lat_ts)) > EPSLN) {
      this.k0 = 0.5 * this.cons * msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)) / tsfnz(this.e, this.con * this.lat_ts, this.con * Math.sin(this.lat_ts));
    }
    this.ms1 = msfnz(this.e, this.sinlat0, this.coslat0);
    this.X0 = 2 * Math.atan(this.ssfn_(this.lat0, this.sinlat0, this.e)) - HALF_PI;
    this.cosX0 = Math.cos(this.X0);
    this.sinX0 = Math.sin(this.X0);
  }
}
function forward$p(p) {
  var lon = p.x;
  var lat = p.y;
  var sinlat = Math.sin(lat);
  var coslat = Math.cos(lat);
  var A5, X, sinX, cosX, ts, rh;
  var dlon = adjust_lon(lon - this.long0);
  if (Math.abs(Math.abs(lon - this.long0) - Math.PI) <= EPSLN && Math.abs(lat + this.lat0) <= EPSLN) {
    p.x = NaN;
    p.y = NaN;
    return p;
  }
  if (this.sphere) {
    A5 = 2 * this.k0 / (1 + this.sinlat0 * sinlat + this.coslat0 * coslat * Math.cos(dlon));
    p.x = this.a * A5 * coslat * Math.sin(dlon) + this.x0;
    p.y = this.a * A5 * (this.coslat0 * sinlat - this.sinlat0 * coslat * Math.cos(dlon)) + this.y0;
    return p;
  } else {
    X = 2 * Math.atan(this.ssfn_(lat, sinlat, this.e)) - HALF_PI;
    cosX = Math.cos(X);
    sinX = Math.sin(X);
    if (Math.abs(this.coslat0) <= EPSLN) {
      ts = tsfnz(this.e, lat * this.con, this.con * sinlat);
      rh = 2 * this.a * this.k0 * ts / this.cons;
      p.x = this.x0 + rh * Math.sin(lon - this.long0);
      p.y = this.y0 - this.con * rh * Math.cos(lon - this.long0);
      return p;
    } else if (Math.abs(this.sinlat0) < EPSLN) {
      A5 = 2 * this.a * this.k0 / (1 + cosX * Math.cos(dlon));
      p.y = A5 * sinX;
    } else {
      A5 = 2 * this.a * this.k0 * this.ms1 / (this.cosX0 * (1 + this.sinX0 * sinX + this.cosX0 * cosX * Math.cos(dlon)));
      p.y = A5 * (this.cosX0 * sinX - this.sinX0 * cosX * Math.cos(dlon)) + this.y0;
    }
    p.x = A5 * cosX * Math.sin(dlon) + this.x0;
  }
  return p;
}
function inverse$p(p) {
  p.x -= this.x0;
  p.y -= this.y0;
  var lon, lat, ts, ce, Chi;
  var rh = Math.sqrt(p.x * p.x + p.y * p.y);
  if (this.sphere) {
    var c = 2 * Math.atan(rh / (2 * this.a * this.k0));
    lon = this.long0;
    lat = this.lat0;
    if (rh <= EPSLN) {
      p.x = lon;
      p.y = lat;
      return p;
    }
    lat = Math.asin(Math.cos(c) * this.sinlat0 + p.y * Math.sin(c) * this.coslat0 / rh);
    if (Math.abs(this.coslat0) < EPSLN) {
      if (this.lat0 > 0) {
        lon = adjust_lon(this.long0 + Math.atan2(p.x, -1 * p.y));
      } else {
        lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
      }
    } else {
      lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(c), rh * this.coslat0 * Math.cos(c) - p.y * this.sinlat0 * Math.sin(c)));
    }
    p.x = lon;
    p.y = lat;
    return p;
  } else {
    if (Math.abs(this.coslat0) <= EPSLN) {
      if (rh <= EPSLN) {
        lat = this.lat0;
        lon = this.long0;
        p.x = lon;
        p.y = lat;
        return p;
      }
      p.x *= this.con;
      p.y *= this.con;
      ts = rh * this.cons / (2 * this.a * this.k0);
      lat = this.con * phi2z(this.e, ts);
      lon = this.con * adjust_lon(this.con * this.long0 + Math.atan2(p.x, -1 * p.y));
    } else {
      ce = 2 * Math.atan(rh * this.cosX0 / (2 * this.a * this.k0 * this.ms1));
      lon = this.long0;
      if (rh <= EPSLN) {
        Chi = this.X0;
      } else {
        Chi = Math.asin(Math.cos(ce) * this.sinX0 + p.y * Math.sin(ce) * this.cosX0 / rh);
        lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(ce), rh * this.cosX0 * Math.cos(ce) - p.y * this.sinX0 * Math.sin(ce)));
      }
      lat = -1 * phi2z(this.e, Math.tan(0.5 * (HALF_PI + Chi)));
    }
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$q = ["stere", "Stereographic_South_Pole", "Polar_Stereographic_variant_A", "Polar_Stereographic_variant_B", "Polar_Stereographic"];
const stere = {
  init: init$r,
  forward: forward$p,
  inverse: inverse$p,
  names: names$q,
  ssfn_
};
function init$q() {
  var phy0 = this.lat0;
  this.lambda0 = this.long0;
  var sinPhy0 = Math.sin(phy0);
  var semiMajorAxis = this.a;
  var invF = this.rf;
  var flattening = 1 / invF;
  var e2 = 2 * flattening - Math.pow(flattening, 2);
  var e = this.e = Math.sqrt(e2);
  this.R = this.k0 * semiMajorAxis * Math.sqrt(1 - e2) / (1 - e2 * Math.pow(sinPhy0, 2));
  this.alpha = Math.sqrt(1 + e2 / (1 - e2) * Math.pow(Math.cos(phy0), 4));
  this.b0 = Math.asin(sinPhy0 / this.alpha);
  var k1 = Math.log(Math.tan(Math.PI / 4 + this.b0 / 2));
  var k2 = Math.log(Math.tan(Math.PI / 4 + phy0 / 2));
  var k3 = Math.log((1 + e * sinPhy0) / (1 - e * sinPhy0));
  this.K = k1 - this.alpha * k2 + this.alpha * e / 2 * k3;
}
function forward$o(p) {
  var Sa1 = Math.log(Math.tan(Math.PI / 4 - p.y / 2));
  var Sa2 = this.e / 2 * Math.log((1 + this.e * Math.sin(p.y)) / (1 - this.e * Math.sin(p.y)));
  var S = -this.alpha * (Sa1 + Sa2) + this.K;
  var b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4);
  var I2 = this.alpha * (p.x - this.lambda0);
  var rotI = Math.atan(Math.sin(I2) / (Math.sin(this.b0) * Math.tan(b) + Math.cos(this.b0) * Math.cos(I2)));
  var rotB = Math.asin(Math.cos(this.b0) * Math.sin(b) - Math.sin(this.b0) * Math.cos(b) * Math.cos(I2));
  p.y = this.R / 2 * Math.log((1 + Math.sin(rotB)) / (1 - Math.sin(rotB))) + this.y0;
  p.x = this.R * rotI + this.x0;
  return p;
}
function inverse$o(p) {
  var Y = p.x - this.x0;
  var X = p.y - this.y0;
  var rotI = Y / this.R;
  var rotB = 2 * (Math.atan(Math.exp(X / this.R)) - Math.PI / 4);
  var b = Math.asin(Math.cos(this.b0) * Math.sin(rotB) + Math.sin(this.b0) * Math.cos(rotB) * Math.cos(rotI));
  var I2 = Math.atan(Math.sin(rotI) / (Math.cos(this.b0) * Math.cos(rotI) - Math.sin(this.b0) * Math.tan(rotB)));
  var lambda = this.lambda0 + I2 / this.alpha;
  var S = 0;
  var phy = b;
  var prevPhy = -1e3;
  var iteration = 0;
  while (Math.abs(phy - prevPhy) > 1e-7) {
    if (++iteration > 20) {
      return;
    }
    S = 1 / this.alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - this.K) + this.e * Math.log(Math.tan(Math.PI / 4 + Math.asin(this.e * Math.sin(phy)) / 2));
    prevPhy = phy;
    phy = 2 * Math.atan(Math.exp(S)) - Math.PI / 2;
  }
  p.x = lambda;
  p.y = phy;
  return p;
}
var names$p = ["somerc"];
const somerc = {
  init: init$q,
  forward: forward$o,
  inverse: inverse$o,
  names: names$p
};
var TOL = 1e-7;
function isTypeA(P) {
  var typeAProjections = ["Hotine_Oblique_Mercator", "Hotine_Oblique_Mercator_variant_A", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin"];
  var projectionName = typeof P.projName === "object" ? Object.keys(P.projName)[0] : P.projName;
  return "no_uoff" in P || "no_off" in P || typeAProjections.indexOf(projectionName) !== -1 || typeAProjections.indexOf(getNormalizedProjName(projectionName)) !== -1;
}
function init$p() {
  var con, com, cosph0, D, F, H, L, sinph0, p, J, gamma = 0, gamma0, lamc = 0, lam1 = 0, lam2 = 0, phi1 = 0, phi2 = 0, alpha_c = 0;
  this.no_off = isTypeA(this);
  this.no_rot = "no_rot" in this;
  var alp = false;
  if ("alpha" in this) {
    alp = true;
  }
  var gam = false;
  if ("rectified_grid_angle" in this) {
    gam = true;
  }
  if (alp) {
    alpha_c = this.alpha;
  }
  if (gam) {
    gamma = this.rectified_grid_angle;
  }
  if (alp || gam) {
    lamc = this.longc;
  } else {
    lam1 = this.long1;
    phi1 = this.lat1;
    lam2 = this.long2;
    phi2 = this.lat2;
    if (Math.abs(phi1 - phi2) <= TOL || (con = Math.abs(phi1)) <= TOL || Math.abs(con - HALF_PI) <= TOL || Math.abs(Math.abs(this.lat0) - HALF_PI) <= TOL || Math.abs(Math.abs(phi2) - HALF_PI) <= TOL) {
      throw new Error();
    }
  }
  var one_es = 1 - this.es;
  com = Math.sqrt(one_es);
  if (Math.abs(this.lat0) > EPSLN) {
    sinph0 = Math.sin(this.lat0);
    cosph0 = Math.cos(this.lat0);
    con = 1 - this.es * sinph0 * sinph0;
    this.B = cosph0 * cosph0;
    this.B = Math.sqrt(1 + this.es * this.B * this.B / one_es);
    this.A = this.B * this.k0 * com / con;
    D = this.B * com / (cosph0 * Math.sqrt(con));
    F = D * D - 1;
    if (F <= 0) {
      F = 0;
    } else {
      F = Math.sqrt(F);
      if (this.lat0 < 0) {
        F = -F;
      }
    }
    this.E = F += D;
    this.E *= Math.pow(tsfnz(this.e, this.lat0, sinph0), this.B);
  } else {
    this.B = 1 / com;
    this.A = this.k0;
    this.E = D = F = 1;
  }
  if (alp || gam) {
    if (alp) {
      gamma0 = Math.asin(Math.sin(alpha_c) / D);
      if (!gam) {
        gamma = alpha_c;
      }
    } else {
      gamma0 = gamma;
      alpha_c = Math.asin(D * Math.sin(gamma0));
    }
    this.lam0 = lamc - Math.asin(0.5 * (F - 1 / F) * Math.tan(gamma0)) / this.B;
  } else {
    H = Math.pow(tsfnz(this.e, phi1, Math.sin(phi1)), this.B);
    L = Math.pow(tsfnz(this.e, phi2, Math.sin(phi2)), this.B);
    F = this.E / H;
    p = (L - H) / (L + H);
    J = this.E * this.E;
    J = (J - L * H) / (J + L * H);
    con = lam1 - lam2;
    if (con < -Math.pi) {
      lam2 -= TWO_PI;
    } else if (con > Math.pi) {
      lam2 += TWO_PI;
    }
    this.lam0 = adjust_lon(0.5 * (lam1 + lam2) - Math.atan(J * Math.tan(0.5 * this.B * (lam1 - lam2)) / p) / this.B);
    gamma0 = Math.atan(2 * Math.sin(this.B * adjust_lon(lam1 - this.lam0)) / (F - 1 / F));
    gamma = alpha_c = Math.asin(D * Math.sin(gamma0));
  }
  this.singam = Math.sin(gamma0);
  this.cosgam = Math.cos(gamma0);
  this.sinrot = Math.sin(gamma);
  this.cosrot = Math.cos(gamma);
  this.rB = 1 / this.B;
  this.ArB = this.A * this.rB;
  this.BrA = 1 / this.ArB;
  if (this.no_off) {
    this.u_0 = 0;
  } else {
    this.u_0 = Math.abs(this.ArB * Math.atan(Math.sqrt(D * D - 1) / Math.cos(alpha_c)));
    if (this.lat0 < 0) {
      this.u_0 = -this.u_0;
    }
  }
  F = 0.5 * gamma0;
  this.v_pole_n = this.ArB * Math.log(Math.tan(FORTPI - F));
  this.v_pole_s = this.ArB * Math.log(Math.tan(FORTPI + F));
}
function forward$n(p) {
  var coords = {};
  var S, T, U, V2, W, temp, u, v;
  p.x = p.x - this.lam0;
  if (Math.abs(Math.abs(p.y) - HALF_PI) > EPSLN) {
    W = this.E / Math.pow(tsfnz(this.e, p.y, Math.sin(p.y)), this.B);
    temp = 1 / W;
    S = 0.5 * (W - temp);
    T = 0.5 * (W + temp);
    V2 = Math.sin(this.B * p.x);
    U = (S * this.singam - V2 * this.cosgam) / T;
    if (Math.abs(Math.abs(U) - 1) < EPSLN) {
      throw new Error();
    }
    v = 0.5 * this.ArB * Math.log((1 - U) / (1 + U));
    temp = Math.cos(this.B * p.x);
    if (Math.abs(temp) < TOL) {
      u = this.A * p.x;
    } else {
      u = this.ArB * Math.atan2(S * this.cosgam + V2 * this.singam, temp);
    }
  } else {
    v = p.y > 0 ? this.v_pole_n : this.v_pole_s;
    u = this.ArB * p.y;
  }
  if (this.no_rot) {
    coords.x = u;
    coords.y = v;
  } else {
    u -= this.u_0;
    coords.x = v * this.cosrot + u * this.sinrot;
    coords.y = u * this.cosrot - v * this.sinrot;
  }
  coords.x = this.a * coords.x + this.x0;
  coords.y = this.a * coords.y + this.y0;
  return coords;
}
function inverse$n(p) {
  var u, v, Qp, Sp, Tp, Vp, Up;
  var coords = {};
  p.x = (p.x - this.x0) * (1 / this.a);
  p.y = (p.y - this.y0) * (1 / this.a);
  if (this.no_rot) {
    v = p.y;
    u = p.x;
  } else {
    v = p.x * this.cosrot - p.y * this.sinrot;
    u = p.y * this.cosrot + p.x * this.sinrot + this.u_0;
  }
  Qp = Math.exp(-this.BrA * v);
  Sp = 0.5 * (Qp - 1 / Qp);
  Tp = 0.5 * (Qp + 1 / Qp);
  Vp = Math.sin(this.BrA * u);
  Up = (Vp * this.cosgam + Sp * this.singam) / Tp;
  if (Math.abs(Math.abs(Up) - 1) < EPSLN) {
    coords.x = 0;
    coords.y = Up < 0 ? -HALF_PI : HALF_PI;
  } else {
    coords.y = this.E / Math.sqrt((1 + Up) / (1 - Up));
    coords.y = phi2z(this.e, Math.pow(coords.y, 1 / this.B));
    if (coords.y === Infinity) {
      throw new Error();
    }
    coords.x = -this.rB * Math.atan2(Sp * this.cosgam - Vp * this.singam, Math.cos(this.BrA * u));
  }
  coords.x += this.lam0;
  return coords;
}
var names$o = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_variant_A", "Hotine_Oblique_Mercator_Variant_B", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "Oblique_Mercator", "omerc"];
const omerc = {
  init: init$p,
  forward: forward$n,
  inverse: inverse$n,
  names: names$o
};
function init$o() {
  if (!this.lat2) {
    this.lat2 = this.lat1;
  }
  if (!this.k0) {
    this.k0 = 1;
  }
  this.x0 = this.x0 || 0;
  this.y0 = this.y0 || 0;
  if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
    return;
  }
  var temp = this.b / this.a;
  this.e = Math.sqrt(1 - temp * temp);
  var sin1 = Math.sin(this.lat1);
  var cos1 = Math.cos(this.lat1);
  var ms1 = msfnz(this.e, sin1, cos1);
  var ts1 = tsfnz(this.e, this.lat1, sin1);
  var sin2 = Math.sin(this.lat2);
  var cos2 = Math.cos(this.lat2);
  var ms2 = msfnz(this.e, sin2, cos2);
  var ts2 = tsfnz(this.e, this.lat2, sin2);
  var ts0 = Math.abs(Math.abs(this.lat0) - HALF_PI) < EPSLN ? 0 : tsfnz(this.e, this.lat0, Math.sin(this.lat0));
  if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
    this.ns = Math.log(ms1 / ms2) / Math.log(ts1 / ts2);
  } else {
    this.ns = sin1;
  }
  if (isNaN(this.ns)) {
    this.ns = sin1;
  }
  this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns));
  this.rh = this.a * this.f0 * Math.pow(ts0, this.ns);
  if (!this.title) {
    this.title = "Lambert Conformal Conic";
  }
}
function forward$m(p) {
  var lon = p.x;
  var lat = p.y;
  if (Math.abs(2 * Math.abs(lat) - Math.PI) <= EPSLN) {
    lat = sign(lat) * (HALF_PI - 2 * EPSLN);
  }
  var con = Math.abs(Math.abs(lat) - HALF_PI);
  var ts, rh1;
  if (con > EPSLN) {
    ts = tsfnz(this.e, lat, Math.sin(lat));
    rh1 = this.a * this.f0 * Math.pow(ts, this.ns);
  } else {
    con = lat * this.ns;
    if (con <= 0) {
      return null;
    }
    rh1 = 0;
  }
  var theta = this.ns * adjust_lon(lon - this.long0);
  p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0;
  p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0;
  return p;
}
function inverse$m(p) {
  var rh1, con, ts;
  var lat, lon;
  var x = (p.x - this.x0) / this.k0;
  var y = this.rh - (p.y - this.y0) / this.k0;
  if (this.ns > 0) {
    rh1 = Math.sqrt(x * x + y * y);
    con = 1;
  } else {
    rh1 = -Math.sqrt(x * x + y * y);
    con = -1;
  }
  var theta = 0;
  if (rh1 !== 0) {
    theta = Math.atan2(con * x, con * y);
  }
  if (rh1 !== 0 || this.ns > 0) {
    con = 1 / this.ns;
    ts = Math.pow(rh1 / (this.a * this.f0), con);
    lat = phi2z(this.e, ts);
    if (lat === -9999) {
      return null;
    }
  } else {
    lat = -HALF_PI;
  }
  lon = adjust_lon(theta / this.ns + this.long0);
  p.x = lon;
  p.y = lat;
  return p;
}
var names$n = [
  "Lambert Tangential Conformal Conic Projection",
  "Lambert_Conformal_Conic",
  "Lambert_Conformal_Conic_1SP",
  "Lambert_Conformal_Conic_2SP",
  "lcc",
  "Lambert Conic Conformal (1SP)",
  "Lambert Conic Conformal (2SP)"
];
const lcc = {
  init: init$o,
  forward: forward$m,
  inverse: inverse$m,
  names: names$n
};
function init$n() {
  this.a = 6377397155e-3;
  this.es = 0.006674372230614;
  this.e = Math.sqrt(this.es);
  if (!this.lat0) {
    this.lat0 = 0.863937979737193;
  }
  if (!this.long0) {
    this.long0 = 0.7417649320975901 - 0.308341501185665;
  }
  if (!this.k0) {
    this.k0 = 0.9999;
  }
  this.s45 = 0.785398163397448;
  this.s90 = 2 * this.s45;
  this.fi0 = this.lat0;
  this.e2 = this.es;
  this.e = Math.sqrt(this.e2);
  this.alfa = Math.sqrt(1 + this.e2 * Math.pow(Math.cos(this.fi0), 4) / (1 - this.e2));
  this.uq = 1.04216856380474;
  this.u0 = Math.asin(Math.sin(this.fi0) / this.alfa);
  this.g = Math.pow((1 + this.e * Math.sin(this.fi0)) / (1 - this.e * Math.sin(this.fi0)), this.alfa * this.e / 2);
  this.k = Math.tan(this.u0 / 2 + this.s45) / Math.pow(Math.tan(this.fi0 / 2 + this.s45), this.alfa) * this.g;
  this.k1 = this.k0;
  this.n0 = this.a * Math.sqrt(1 - this.e2) / (1 - this.e2 * Math.pow(Math.sin(this.fi0), 2));
  this.s0 = 1.37008346281555;
  this.n = Math.sin(this.s0);
  this.ro0 = this.k1 * this.n0 / Math.tan(this.s0);
  this.ad = this.s90 - this.uq;
}
function forward$l(p) {
  var gfi, u, deltav, s, d, eps, ro;
  var lon = p.x;
  var lat = p.y;
  var delta_lon = adjust_lon(lon - this.long0);
  gfi = Math.pow((1 + this.e * Math.sin(lat)) / (1 - this.e * Math.sin(lat)), this.alfa * this.e / 2);
  u = 2 * (Math.atan(this.k * Math.pow(Math.tan(lat / 2 + this.s45), this.alfa) / gfi) - this.s45);
  deltav = -delta_lon * this.alfa;
  s = Math.asin(Math.cos(this.ad) * Math.sin(u) + Math.sin(this.ad) * Math.cos(u) * Math.cos(deltav));
  d = Math.asin(Math.cos(u) * Math.sin(deltav) / Math.cos(s));
  eps = this.n * d;
  ro = this.ro0 * Math.pow(Math.tan(this.s0 / 2 + this.s45), this.n) / Math.pow(Math.tan(s / 2 + this.s45), this.n);
  p.y = ro * Math.cos(eps) / 1;
  p.x = ro * Math.sin(eps) / 1;
  if (!this.czech) {
    p.y *= -1;
    p.x *= -1;
  }
  return p;
}
function inverse$l(p) {
  var u, deltav, s, d, eps, ro, fi1;
  var ok;
  var tmp = p.x;
  p.x = p.y;
  p.y = tmp;
  if (!this.czech) {
    p.y *= -1;
    p.x *= -1;
  }
  ro = Math.sqrt(p.x * p.x + p.y * p.y);
  eps = Math.atan2(p.y, p.x);
  d = eps / Math.sin(this.s0);
  s = 2 * (Math.atan(Math.pow(this.ro0 / ro, 1 / this.n) * Math.tan(this.s0 / 2 + this.s45)) - this.s45);
  u = Math.asin(Math.cos(this.ad) * Math.sin(s) - Math.sin(this.ad) * Math.cos(s) * Math.cos(d));
  deltav = Math.asin(Math.cos(s) * Math.sin(d) / Math.cos(u));
  p.x = this.long0 - deltav / this.alfa;
  fi1 = u;
  ok = 0;
  var iter = 0;
  do {
    p.y = 2 * (Math.atan(Math.pow(this.k, -1 / this.alfa) * Math.pow(Math.tan(u / 2 + this.s45), 1 / this.alfa) * Math.pow((1 + this.e * Math.sin(fi1)) / (1 - this.e * Math.sin(fi1)), this.e / 2)) - this.s45);
    if (Math.abs(fi1 - p.y) < 1e-10) {
      ok = 1;
    }
    fi1 = p.y;
    iter += 1;
  } while (ok === 0 && iter < 15);
  if (iter >= 15) {
    return null;
  }
  return p;
}
var names$m = ["Krovak", "krovak"];
const krovak = {
  init: init$n,
  forward: forward$l,
  inverse: inverse$l,
  names: names$m
};
function mlfn(e0, e1, e2, e3, phi) {
  return e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi);
}
function e0fn(x) {
  return 1 - 0.25 * x * (1 + x / 16 * (3 + 1.25 * x));
}
function e1fn(x) {
  return 0.375 * x * (1 + 0.25 * x * (1 + 0.46875 * x));
}
function e2fn(x) {
  return 0.05859375 * x * x * (1 + 0.75 * x);
}
function e3fn(x) {
  return x * x * x * (35 / 3072);
}
function gN(a, e, sinphi) {
  var temp = e * sinphi;
  return a / Math.sqrt(1 - temp * temp);
}
function adjust_lat(x) {
  return Math.abs(x) < HALF_PI ? x : x - sign(x) * Math.PI;
}
function imlfn(ml, e0, e1, e2, e3) {
  var phi;
  var dphi;
  phi = ml / e0;
  for (var i = 0; i < 15; i++) {
    dphi = (ml - (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi))) / (e0 - 2 * e1 * Math.cos(2 * phi) + 4 * e2 * Math.cos(4 * phi) - 6 * e3 * Math.cos(6 * phi));
    phi += dphi;
    if (Math.abs(dphi) <= 1e-10) {
      return phi;
    }
  }
  return NaN;
}
function init$m() {
  if (!this.sphere) {
    this.e0 = e0fn(this.es);
    this.e1 = e1fn(this.es);
    this.e2 = e2fn(this.es);
    this.e3 = e3fn(this.es);
    this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
  }
}
function forward$k(p) {
  var x, y;
  var lam = p.x;
  var phi = p.y;
  lam = adjust_lon(lam - this.long0);
  if (this.sphere) {
    x = this.a * Math.asin(Math.cos(phi) * Math.sin(lam));
    y = this.a * (Math.atan2(Math.tan(phi), Math.cos(lam)) - this.lat0);
  } else {
    var sinphi = Math.sin(phi);
    var cosphi = Math.cos(phi);
    var nl = gN(this.a, this.e, sinphi);
    var tl = Math.tan(phi) * Math.tan(phi);
    var al = lam * Math.cos(phi);
    var asq = al * al;
    var cl = this.es * cosphi * cosphi / (1 - this.es);
    var ml = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
    x = nl * al * (1 - asq * tl * (1 / 6 - (8 - tl + 8 * cl) * asq / 120));
    y = ml - this.ml0 + nl * sinphi / cosphi * asq * (0.5 + (5 - tl + 6 * cl) * asq / 24);
  }
  p.x = x + this.x0;
  p.y = y + this.y0;
  return p;
}
function inverse$k(p) {
  p.x -= this.x0;
  p.y -= this.y0;
  var x = p.x / this.a;
  var y = p.y / this.a;
  var phi, lam;
  if (this.sphere) {
    var dd = y + this.lat0;
    phi = Math.asin(Math.sin(dd) * Math.cos(x));
    lam = Math.atan2(Math.tan(x), Math.cos(dd));
  } else {
    var ml1 = this.ml0 / this.a + y;
    var phi1 = imlfn(ml1, this.e0, this.e1, this.e2, this.e3);
    if (Math.abs(Math.abs(phi1) - HALF_PI) <= EPSLN) {
      p.x = this.long0;
      p.y = HALF_PI;
      if (y < 0) {
        p.y *= -1;
      }
      return p;
    }
    var nl1 = gN(this.a, this.e, Math.sin(phi1));
    var rl1 = nl1 * nl1 * nl1 / this.a / this.a * (1 - this.es);
    var tl1 = Math.pow(Math.tan(phi1), 2);
    var dl = x * this.a / nl1;
    var dsq = dl * dl;
    phi = phi1 - nl1 * Math.tan(phi1) / rl1 * dl * dl * (0.5 - (1 + 3 * tl1) * dl * dl / 24);
    lam = dl * (1 - dsq * (tl1 / 3 + (1 + 3 * tl1) * tl1 * dsq / 15)) / Math.cos(phi1);
  }
  p.x = adjust_lon(lam + this.long0);
  p.y = adjust_lat(phi);
  return p;
}
var names$l = ["Cassini", "Cassini_Soldner", "cass"];
const cass = {
  init: init$m,
  forward: forward$k,
  inverse: inverse$k,
  names: names$l
};
function qsfnz(eccent, sinphi) {
  var con;
  if (eccent > 1e-7) {
    con = eccent * sinphi;
    return (1 - eccent * eccent) * (sinphi / (1 - con * con) - 0.5 / eccent * Math.log((1 - con) / (1 + con)));
  } else {
    return 2 * sinphi;
  }
}
var S_POLE = 1;
var N_POLE = 2;
var EQUIT = 3;
var OBLIQ = 4;
function init$l() {
  var t = Math.abs(this.lat0);
  if (Math.abs(t - HALF_PI) < EPSLN) {
    this.mode = this.lat0 < 0 ? this.S_POLE : this.N_POLE;
  } else if (Math.abs(t) < EPSLN) {
    this.mode = this.EQUIT;
  } else {
    this.mode = this.OBLIQ;
  }
  if (this.es > 0) {
    var sinphi;
    this.qp = qsfnz(this.e, 1);
    this.mmf = 0.5 / (1 - this.es);
    this.apa = authset(this.es);
    switch (this.mode) {
      case this.N_POLE:
        this.dd = 1;
        break;
      case this.S_POLE:
        this.dd = 1;
        break;
      case this.EQUIT:
        this.rq = Math.sqrt(0.5 * this.qp);
        this.dd = 1 / this.rq;
        this.xmf = 1;
        this.ymf = 0.5 * this.qp;
        break;
      case this.OBLIQ:
        this.rq = Math.sqrt(0.5 * this.qp);
        sinphi = Math.sin(this.lat0);
        this.sinb1 = qsfnz(this.e, sinphi) / this.qp;
        this.cosb1 = Math.sqrt(1 - this.sinb1 * this.sinb1);
        this.dd = Math.cos(this.lat0) / (Math.sqrt(1 - this.es * sinphi * sinphi) * this.rq * this.cosb1);
        this.ymf = (this.xmf = this.rq) / this.dd;
        this.xmf *= this.dd;
        break;
    }
  } else {
    if (this.mode === this.OBLIQ) {
      this.sinph0 = Math.sin(this.lat0);
      this.cosph0 = Math.cos(this.lat0);
    }
  }
}
function forward$j(p) {
  var x, y, coslam, sinlam, sinphi, q, sinb, cosb, b, cosphi;
  var lam = p.x;
  var phi = p.y;
  lam = adjust_lon(lam - this.long0);
  if (this.sphere) {
    sinphi = Math.sin(phi);
    cosphi = Math.cos(phi);
    coslam = Math.cos(lam);
    if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
      y = this.mode === this.EQUIT ? 1 + cosphi * coslam : 1 + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
      if (y <= EPSLN) {
        return null;
      }
      y = Math.sqrt(2 / y);
      x = y * cosphi * Math.sin(lam);
      y *= this.mode === this.EQUIT ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
    } else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
      if (this.mode === this.N_POLE) {
        coslam = -coslam;
      }
      if (Math.abs(phi + this.lat0) < EPSLN) {
        return null;
      }
      y = FORTPI - phi * 0.5;
      y = 2 * (this.mode === this.S_POLE ? Math.cos(y) : Math.sin(y));
      x = y * Math.sin(lam);
      y *= coslam;
    }
  } else {
    sinb = 0;
    cosb = 0;
    b = 0;
    coslam = Math.cos(lam);
    sinlam = Math.sin(lam);
    sinphi = Math.sin(phi);
    q = qsfnz(this.e, sinphi);
    if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
      sinb = q / this.qp;
      cosb = Math.sqrt(1 - sinb * sinb);
    }
    switch (this.mode) {
      case this.OBLIQ:
        b = 1 + this.sinb1 * sinb + this.cosb1 * cosb * coslam;
        break;
      case this.EQUIT:
        b = 1 + cosb * coslam;
        break;
      case this.N_POLE:
        b = HALF_PI + phi;
        q = this.qp - q;
        break;
      case this.S_POLE:
        b = phi - HALF_PI;
        q = this.qp + q;
        break;
    }
    if (Math.abs(b) < EPSLN) {
      return null;
    }
    switch (this.mode) {
      case this.OBLIQ:
      case this.EQUIT:
        b = Math.sqrt(2 / b);
        if (this.mode === this.OBLIQ) {
          y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam);
        } else {
          y = (b = Math.sqrt(2 / (1 + cosb * coslam))) * sinb * this.ymf;
        }
        x = this.xmf * b * cosb * sinlam;
        break;
      case this.N_POLE:
      case this.S_POLE:
        if (q >= 0) {
          x = (b = Math.sqrt(q)) * sinlam;
          y = coslam * (this.mode === this.S_POLE ? b : -b);
        } else {
          x = y = 0;
        }
        break;
    }
  }
  p.x = this.a * x + this.x0;
  p.y = this.a * y + this.y0;
  return p;
}
function inverse$j(p) {
  p.x -= this.x0;
  p.y -= this.y0;
  var x = p.x / this.a;
  var y = p.y / this.a;
  var lam, phi, cCe, sCe, q, rho, ab;
  if (this.sphere) {
    var cosz = 0, rh, sinz = 0;
    rh = Math.sqrt(x * x + y * y);
    phi = rh * 0.5;
    if (phi > 1) {
      return null;
    }
    phi = 2 * Math.asin(phi);
    if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
      sinz = Math.sin(phi);
      cosz = Math.cos(phi);
    }
    switch (this.mode) {
      case this.EQUIT:
        phi = Math.abs(rh) <= EPSLN ? 0 : Math.asin(y * sinz / rh);
        x *= sinz;
        y = cosz * rh;
        break;
      case this.OBLIQ:
        phi = Math.abs(rh) <= EPSLN ? this.lat0 : Math.asin(cosz * this.sinph0 + y * sinz * this.cosph0 / rh);
        x *= sinz * this.cosph0;
        y = (cosz - Math.sin(phi) * this.sinph0) * rh;
        break;
      case this.N_POLE:
        y = -y;
        phi = HALF_PI - phi;
        break;
      case this.S_POLE:
        phi -= HALF_PI;
        break;
    }
    lam = y === 0 && (this.mode === this.EQUIT || this.mode === this.OBLIQ) ? 0 : Math.atan2(x, y);
  } else {
    ab = 0;
    if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
      x /= this.dd;
      y *= this.dd;
      rho = Math.sqrt(x * x + y * y);
      if (rho < EPSLN) {
        p.x = this.long0;
        p.y = this.lat0;
        return p;
      }
      sCe = 2 * Math.asin(0.5 * rho / this.rq);
      cCe = Math.cos(sCe);
      x *= sCe = Math.sin(sCe);
      if (this.mode === this.OBLIQ) {
        ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho;
        q = this.qp * ab;
        y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe;
      } else {
        ab = y * sCe / rho;
        q = this.qp * ab;
        y = rho * cCe;
      }
    } else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
      if (this.mode === this.N_POLE) {
        y = -y;
      }
      q = x * x + y * y;
      if (!q) {
        p.x = this.long0;
        p.y = this.lat0;
        return p;
      }
      ab = 1 - q / this.qp;
      if (this.mode === this.S_POLE) {
        ab = -ab;
      }
    }
    lam = Math.atan2(x, y);
    phi = authlat(Math.asin(ab), this.apa);
  }
  p.x = adjust_lon(this.long0 + lam);
  p.y = phi;
  return p;
}
var P00 = 0.3333333333333333;
var P01 = 0.17222222222222222;
var P02 = 0.10257936507936508;
var P10 = 0.06388888888888888;
var P11 = 0.0664021164021164;
var P20 = 0.016415012942191543;
function authset(es) {
  var t;
  var APA = [];
  APA[0] = es * P00;
  t = es * es;
  APA[0] += t * P01;
  APA[1] = t * P10;
  t *= es;
  APA[0] += t * P02;
  APA[1] += t * P11;
  APA[2] = t * P20;
  return APA;
}
function authlat(beta, APA) {
  var t = beta + beta;
  return beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t + t) + APA[2] * Math.sin(t + t + t);
}
var names$k = ["Lambert Azimuthal Equal Area", "Lambert_Azimuthal_Equal_Area", "laea"];
const laea = {
  init: init$l,
  forward: forward$j,
  inverse: inverse$j,
  names: names$k,
  S_POLE,
  N_POLE,
  EQUIT,
  OBLIQ
};
function asinz(x) {
  if (Math.abs(x) > 1) {
    x = x > 1 ? 1 : -1;
  }
  return Math.asin(x);
}
function init$k() {
  if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
    return;
  }
  this.temp = this.b / this.a;
  this.es = 1 - Math.pow(this.temp, 2);
  this.e3 = Math.sqrt(this.es);
  this.sin_po = Math.sin(this.lat1);
  this.cos_po = Math.cos(this.lat1);
  this.t1 = this.sin_po;
  this.con = this.sin_po;
  this.ms1 = msfnz(this.e3, this.sin_po, this.cos_po);
  this.qs1 = qsfnz(this.e3, this.sin_po);
  this.sin_po = Math.sin(this.lat2);
  this.cos_po = Math.cos(this.lat2);
  this.t2 = this.sin_po;
  this.ms2 = msfnz(this.e3, this.sin_po, this.cos_po);
  this.qs2 = qsfnz(this.e3, this.sin_po);
  this.sin_po = Math.sin(this.lat0);
  this.cos_po = Math.cos(this.lat0);
  this.t3 = this.sin_po;
  this.qs0 = qsfnz(this.e3, this.sin_po);
  if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
    this.ns0 = (this.ms1 * this.ms1 - this.ms2 * this.ms2) / (this.qs2 - this.qs1);
  } else {
    this.ns0 = this.con;
  }
  this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1;
  this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0) / this.ns0;
}
function forward$i(p) {
  var lon = p.x;
  var lat = p.y;
  this.sin_phi = Math.sin(lat);
  this.cos_phi = Math.cos(lat);
  var qs = qsfnz(this.e3, this.sin_phi);
  var rh1 = this.a * Math.sqrt(this.c - this.ns0 * qs) / this.ns0;
  var theta = this.ns0 * adjust_lon(lon - this.long0);
  var x = rh1 * Math.sin(theta) + this.x0;
  var y = this.rh - rh1 * Math.cos(theta) + this.y0;
  p.x = x;
  p.y = y;
  return p;
}
function inverse$i(p) {
  var rh1, qs, con, theta, lon, lat;
  p.x -= this.x0;
  p.y = this.rh - p.y + this.y0;
  if (this.ns0 >= 0) {
    rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
    con = 1;
  } else {
    rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
    con = -1;
  }
  theta = 0;
  if (rh1 !== 0) {
    theta = Math.atan2(con * p.x, con * p.y);
  }
  con = rh1 * this.ns0 / this.a;
  if (this.sphere) {
    lat = Math.asin((this.c - con * con) / (2 * this.ns0));
  } else {
    qs = (this.c - con * con) / this.ns0;
    lat = this.phi1z(this.e3, qs);
  }
  lon = adjust_lon(theta / this.ns0 + this.long0);
  p.x = lon;
  p.y = lat;
  return p;
}
function phi1z(eccent, qs) {
  var sinphi, cosphi, con, com, dphi;
  var phi = asinz(0.5 * qs);
  if (eccent < EPSLN) {
    return phi;
  }
  var eccnts = eccent * eccent;
  for (var i = 1; i <= 25; i++) {
    sinphi = Math.sin(phi);
    cosphi = Math.cos(phi);
    con = eccent * sinphi;
    com = 1 - con * con;
    dphi = 0.5 * com * com / cosphi * (qs / (1 - eccnts) - sinphi / com + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
    phi = phi + dphi;
    if (Math.abs(dphi) <= 1e-7) {
      return phi;
    }
  }
  return null;
}
var names$j = ["Albers_Conic_Equal_Area", "Albers_Equal_Area", "Albers", "aea"];
const aea = {
  init: init$k,
  forward: forward$i,
  inverse: inverse$i,
  names: names$j,
  phi1z
};
function init$j() {
  this.sin_p14 = Math.sin(this.lat0);
  this.cos_p14 = Math.cos(this.lat0);
  this.infinity_dist = 1e3 * this.a;
  this.rc = 1;
}
function forward$h(p) {
  var sinphi, cosphi;
  var dlon;
  var coslon;
  var ksp;
  var g;
  var x, y;
  var lon = p.x;
  var lat = p.y;
  dlon = adjust_lon(lon - this.long0);
  sinphi = Math.sin(lat);
  cosphi = Math.cos(lat);
  coslon = Math.cos(dlon);
  g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
  ksp = 1;
  if (g > 0 || Math.abs(g) <= EPSLN) {
    x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon) / g;
    y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon) / g;
  } else {
    x = this.x0 + this.infinity_dist * cosphi * Math.sin(dlon);
    y = this.y0 + this.infinity_dist * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$h(p) {
  var rh;
  var sinc, cosc;
  var c;
  var lon, lat;
  p.x = (p.x - this.x0) / this.a;
  p.y = (p.y - this.y0) / this.a;
  p.x /= this.k0;
  p.y /= this.k0;
  if (rh = Math.sqrt(p.x * p.x + p.y * p.y)) {
    c = Math.atan2(rh, this.rc);
    sinc = Math.sin(c);
    cosc = Math.cos(c);
    lat = asinz(cosc * this.sin_p14 + p.y * sinc * this.cos_p14 / rh);
    lon = Math.atan2(p.x * sinc, rh * this.cos_p14 * cosc - p.y * this.sin_p14 * sinc);
    lon = adjust_lon(this.long0 + lon);
  } else {
    lat = this.phic0;
    lon = 0;
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$i = ["gnom"];
const gnom = {
  init: init$j,
  forward: forward$h,
  inverse: inverse$h,
  names: names$i
};
function iqsfnz(eccent, q) {
  var temp = 1 - (1 - eccent * eccent) / (2 * eccent) * Math.log((1 - eccent) / (1 + eccent));
  if (Math.abs(Math.abs(q) - temp) < 1e-6) {
    if (q < 0) {
      return -1 * HALF_PI;
    } else {
      return HALF_PI;
    }
  }
  var phi = Math.asin(0.5 * q);
  var dphi;
  var sin_phi;
  var cos_phi;
  var con;
  for (var i = 0; i < 30; i++) {
    sin_phi = Math.sin(phi);
    cos_phi = Math.cos(phi);
    con = eccent * sin_phi;
    dphi = Math.pow(1 - con * con, 2) / (2 * cos_phi) * (q / (1 - eccent * eccent) - sin_phi / (1 - con * con) + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
    phi += dphi;
    if (Math.abs(dphi) <= 1e-10) {
      return phi;
    }
  }
  return NaN;
}
function init$i() {
  if (!this.sphere) {
    this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
  }
}
function forward$g(p) {
  var lon = p.x;
  var lat = p.y;
  var x, y;
  var dlon = adjust_lon(lon - this.long0);
  if (this.sphere) {
    x = this.x0 + this.a * dlon * Math.cos(this.lat_ts);
    y = this.y0 + this.a * Math.sin(lat) / Math.cos(this.lat_ts);
  } else {
    var qs = qsfnz(this.e, Math.sin(lat));
    x = this.x0 + this.a * this.k0 * dlon;
    y = this.y0 + this.a * qs * 0.5 / this.k0;
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$g(p) {
  p.x -= this.x0;
  p.y -= this.y0;
  var lon, lat;
  if (this.sphere) {
    lon = adjust_lon(this.long0 + p.x / this.a / Math.cos(this.lat_ts));
    lat = Math.asin(p.y / this.a * Math.cos(this.lat_ts));
  } else {
    lat = iqsfnz(this.e, 2 * p.y * this.k0 / this.a);
    lon = adjust_lon(this.long0 + p.x / (this.a * this.k0));
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$h = ["cea"];
const cea = {
  init: init$i,
  forward: forward$g,
  inverse: inverse$g,
  names: names$h
};
function init$h() {
  this.x0 = this.x0 || 0;
  this.y0 = this.y0 || 0;
  this.lat0 = this.lat0 || 0;
  this.long0 = this.long0 || 0;
  this.lat_ts = this.lat_ts || 0;
  this.title = this.title || "Equidistant Cylindrical (Plate Carre)";
  this.rc = Math.cos(this.lat_ts);
}
function forward$f(p) {
  var lon = p.x;
  var lat = p.y;
  var dlon = adjust_lon(lon - this.long0);
  var dlat = adjust_lat(lat - this.lat0);
  p.x = this.x0 + this.a * dlon * this.rc;
  p.y = this.y0 + this.a * dlat;
  return p;
}
function inverse$f(p) {
  var x = p.x;
  var y = p.y;
  p.x = adjust_lon(this.long0 + (x - this.x0) / (this.a * this.rc));
  p.y = adjust_lat(this.lat0 + (y - this.y0) / this.a);
  return p;
}
var names$g = ["Equirectangular", "Equidistant_Cylindrical", "Equidistant_Cylindrical_Spherical", "eqc"];
const eqc = {
  init: init$h,
  forward: forward$f,
  inverse: inverse$f,
  names: names$g
};
var MAX_ITER$1 = 20;
function init$g() {
  this.temp = this.b / this.a;
  this.es = 1 - Math.pow(this.temp, 2);
  this.e = Math.sqrt(this.es);
  this.e0 = e0fn(this.es);
  this.e1 = e1fn(this.es);
  this.e2 = e2fn(this.es);
  this.e3 = e3fn(this.es);
  this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
}
function forward$e(p) {
  var lon = p.x;
  var lat = p.y;
  var x, y, el;
  var dlon = adjust_lon(lon - this.long0);
  el = dlon * Math.sin(lat);
  if (this.sphere) {
    if (Math.abs(lat) <= EPSLN) {
      x = this.a * dlon;
      y = -1 * this.a * this.lat0;
    } else {
      x = this.a * Math.sin(el) / Math.tan(lat);
      y = this.a * (adjust_lat(lat - this.lat0) + (1 - Math.cos(el)) / Math.tan(lat));
    }
  } else {
    if (Math.abs(lat) <= EPSLN) {
      x = this.a * dlon;
      y = -1 * this.ml0;
    } else {
      var nl = gN(this.a, this.e, Math.sin(lat)) / Math.tan(lat);
      x = nl * Math.sin(el);
      y = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, lat) - this.ml0 + nl * (1 - Math.cos(el));
    }
  }
  p.x = x + this.x0;
  p.y = y + this.y0;
  return p;
}
function inverse$e(p) {
  var lon, lat, x, y, i;
  var al, bl;
  var phi, dphi;
  x = p.x - this.x0;
  y = p.y - this.y0;
  if (this.sphere) {
    if (Math.abs(y + this.a * this.lat0) <= EPSLN) {
      lon = adjust_lon(x / this.a + this.long0);
      lat = 0;
    } else {
      al = this.lat0 + y / this.a;
      bl = x * x / this.a / this.a + al * al;
      phi = al;
      var tanphi;
      for (i = MAX_ITER$1; i; --i) {
        tanphi = Math.tan(phi);
        dphi = -1 * (al * (phi * tanphi + 1) - phi - 0.5 * (phi * phi + bl) * tanphi) / ((phi - al) / tanphi - 1);
        phi += dphi;
        if (Math.abs(dphi) <= EPSLN) {
          lat = phi;
          break;
        }
      }
      lon = adjust_lon(this.long0 + Math.asin(x * Math.tan(phi) / this.a) / Math.sin(lat));
    }
  } else {
    if (Math.abs(y + this.ml0) <= EPSLN) {
      lat = 0;
      lon = adjust_lon(this.long0 + x / this.a);
    } else {
      al = (this.ml0 + y) / this.a;
      bl = x * x / this.a / this.a + al * al;
      phi = al;
      var cl, mln, mlnp, ma;
      var con;
      for (i = MAX_ITER$1; i; --i) {
        con = this.e * Math.sin(phi);
        cl = Math.sqrt(1 - con * con) * Math.tan(phi);
        mln = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
        mlnp = this.e0 - 2 * this.e1 * Math.cos(2 * phi) + 4 * this.e2 * Math.cos(4 * phi) - 6 * this.e3 * Math.cos(6 * phi);
        ma = mln / this.a;
        dphi = (al * (cl * ma + 1) - ma - 0.5 * cl * (ma * ma + bl)) / (this.es * Math.sin(2 * phi) * (ma * ma + bl - 2 * al * ma) / (4 * cl) + (al - ma) * (cl * mlnp - 2 / Math.sin(2 * phi)) - mlnp);
        phi -= dphi;
        if (Math.abs(dphi) <= EPSLN) {
          lat = phi;
          break;
        }
      }
      cl = Math.sqrt(1 - this.es * Math.pow(Math.sin(lat), 2)) * Math.tan(lat);
      lon = adjust_lon(this.long0 + Math.asin(x * cl / this.a) / Math.sin(lat));
    }
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$f = ["Polyconic", "American_Polyconic", "poly"];
const poly = {
  init: init$g,
  forward: forward$e,
  inverse: inverse$e,
  names: names$f
};
function init$f() {
  this.A = [];
  this.A[1] = 0.6399175073;
  this.A[2] = -0.1358797613;
  this.A[3] = 0.063294409;
  this.A[4] = -0.02526853;
  this.A[5] = 0.0117879;
  this.A[6] = -55161e-7;
  this.A[7] = 26906e-7;
  this.A[8] = -1333e-6;
  this.A[9] = 67e-5;
  this.A[10] = -34e-5;
  this.B_re = [];
  this.B_im = [];
  this.B_re[1] = 0.7557853228;
  this.B_im[1] = 0;
  this.B_re[2] = 0.249204646;
  this.B_im[2] = 3371507e-9;
  this.B_re[3] = -1541739e-9;
  this.B_im[3] = 0.04105856;
  this.B_re[4] = -0.10162907;
  this.B_im[4] = 0.01727609;
  this.B_re[5] = -0.26623489;
  this.B_im[5] = -0.36249218;
  this.B_re[6] = -0.6870983;
  this.B_im[6] = -1.1651967;
  this.C_re = [];
  this.C_im = [];
  this.C_re[1] = 1.3231270439;
  this.C_im[1] = 0;
  this.C_re[2] = -0.577245789;
  this.C_im[2] = -7809598e-9;
  this.C_re[3] = 0.508307513;
  this.C_im[3] = -0.112208952;
  this.C_re[4] = -0.15094762;
  this.C_im[4] = 0.18200602;
  this.C_re[5] = 1.01418179;
  this.C_im[5] = 1.64497696;
  this.C_re[6] = 1.9660549;
  this.C_im[6] = 2.5127645;
  this.D = [];
  this.D[1] = 1.5627014243;
  this.D[2] = 0.5185406398;
  this.D[3] = -0.03333098;
  this.D[4] = -0.1052906;
  this.D[5] = -0.0368594;
  this.D[6] = 7317e-6;
  this.D[7] = 0.0122;
  this.D[8] = 394e-5;
  this.D[9] = -13e-4;
}
function forward$d(p) {
  var n;
  var lon = p.x;
  var lat = p.y;
  var delta_lat = lat - this.lat0;
  var delta_lon = lon - this.long0;
  var d_phi = delta_lat / SEC_TO_RAD * 1e-5;
  var d_lambda = delta_lon;
  var d_phi_n = 1;
  var d_psi = 0;
  for (n = 1; n <= 10; n++) {
    d_phi_n = d_phi_n * d_phi;
    d_psi = d_psi + this.A[n] * d_phi_n;
  }
  var th_re = d_psi;
  var th_im = d_lambda;
  var th_n_re = 1;
  var th_n_im = 0;
  var th_n_re1;
  var th_n_im1;
  var z_re = 0;
  var z_im = 0;
  for (n = 1; n <= 6; n++) {
    th_n_re1 = th_n_re * th_re - th_n_im * th_im;
    th_n_im1 = th_n_im * th_re + th_n_re * th_im;
    th_n_re = th_n_re1;
    th_n_im = th_n_im1;
    z_re = z_re + this.B_re[n] * th_n_re - this.B_im[n] * th_n_im;
    z_im = z_im + this.B_im[n] * th_n_re + this.B_re[n] * th_n_im;
  }
  p.x = z_im * this.a + this.x0;
  p.y = z_re * this.a + this.y0;
  return p;
}
function inverse$d(p) {
  var n;
  var x = p.x;
  var y = p.y;
  var delta_x = x - this.x0;
  var delta_y = y - this.y0;
  var z_re = delta_y / this.a;
  var z_im = delta_x / this.a;
  var z_n_re = 1;
  var z_n_im = 0;
  var z_n_re1;
  var z_n_im1;
  var th_re = 0;
  var th_im = 0;
  for (n = 1; n <= 6; n++) {
    z_n_re1 = z_n_re * z_re - z_n_im * z_im;
    z_n_im1 = z_n_im * z_re + z_n_re * z_im;
    z_n_re = z_n_re1;
    z_n_im = z_n_im1;
    th_re = th_re + this.C_re[n] * z_n_re - this.C_im[n] * z_n_im;
    th_im = th_im + this.C_im[n] * z_n_re + this.C_re[n] * z_n_im;
  }
  for (var i = 0; i < this.iterations; i++) {
    var th_n_re = th_re;
    var th_n_im = th_im;
    var th_n_re1;
    var th_n_im1;
    var num_re = z_re;
    var num_im = z_im;
    for (n = 2; n <= 6; n++) {
      th_n_re1 = th_n_re * th_re - th_n_im * th_im;
      th_n_im1 = th_n_im * th_re + th_n_re * th_im;
      th_n_re = th_n_re1;
      th_n_im = th_n_im1;
      num_re = num_re + (n - 1) * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
      num_im = num_im + (n - 1) * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
    }
    th_n_re = 1;
    th_n_im = 0;
    var den_re = this.B_re[1];
    var den_im = this.B_im[1];
    for (n = 2; n <= 6; n++) {
      th_n_re1 = th_n_re * th_re - th_n_im * th_im;
      th_n_im1 = th_n_im * th_re + th_n_re * th_im;
      th_n_re = th_n_re1;
      th_n_im = th_n_im1;
      den_re = den_re + n * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
      den_im = den_im + n * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
    }
    var den2 = den_re * den_re + den_im * den_im;
    th_re = (num_re * den_re + num_im * den_im) / den2;
    th_im = (num_im * den_re - num_re * den_im) / den2;
  }
  var d_psi = th_re;
  var d_lambda = th_im;
  var d_psi_n = 1;
  var d_phi = 0;
  for (n = 1; n <= 9; n++) {
    d_psi_n = d_psi_n * d_psi;
    d_phi = d_phi + this.D[n] * d_psi_n;
  }
  var lat = this.lat0 + d_phi * SEC_TO_RAD * 1e5;
  var lon = this.long0 + d_lambda;
  p.x = lon;
  p.y = lat;
  return p;
}
var names$e = ["New_Zealand_Map_Grid", "nzmg"];
const nzmg = {
  init: init$f,
  forward: forward$d,
  inverse: inverse$d,
  names: names$e
};
function init$e() {
}
function forward$c(p) {
  var lon = p.x;
  var lat = p.y;
  var dlon = adjust_lon(lon - this.long0);
  var x = this.x0 + this.a * dlon;
  var y = this.y0 + this.a * Math.log(Math.tan(Math.PI / 4 + lat / 2.5)) * 1.25;
  p.x = x;
  p.y = y;
  return p;
}
function inverse$c(p) {
  p.x -= this.x0;
  p.y -= this.y0;
  var lon = adjust_lon(this.long0 + p.x / this.a);
  var lat = 2.5 * (Math.atan(Math.exp(0.8 * p.y / this.a)) - Math.PI / 4);
  p.x = lon;
  p.y = lat;
  return p;
}
var names$d = ["Miller_Cylindrical", "mill"];
const mill = {
  init: init$e,
  forward: forward$c,
  inverse: inverse$c,
  names: names$d
};
var MAX_ITER = 20;
function init$d() {
  if (!this.sphere) {
    this.en = pj_enfn(this.es);
  } else {
    this.n = 1;
    this.m = 0;
    this.es = 0;
    this.C_y = Math.sqrt((this.m + 1) / this.n);
    this.C_x = this.C_y / (this.m + 1);
  }
}
function forward$b(p) {
  var x, y;
  var lon = p.x;
  var lat = p.y;
  lon = adjust_lon(lon - this.long0);
  if (this.sphere) {
    if (!this.m) {
      lat = this.n !== 1 ? Math.asin(this.n * Math.sin(lat)) : lat;
    } else {
      var k = this.n * Math.sin(lat);
      for (var i = MAX_ITER; i; --i) {
        var V2 = (this.m * lat + Math.sin(lat) - k) / (this.m + Math.cos(lat));
        lat -= V2;
        if (Math.abs(V2) < EPSLN) {
          break;
        }
      }
    }
    x = this.a * this.C_x * lon * (this.m + Math.cos(lat));
    y = this.a * this.C_y * lat;
  } else {
    var s = Math.sin(lat);
    var c = Math.cos(lat);
    y = this.a * pj_mlfn(lat, s, c, this.en);
    x = this.a * lon * c / Math.sqrt(1 - this.es * s * s);
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$b(p) {
  var lat, temp, lon, s;
  p.x -= this.x0;
  lon = p.x / this.a;
  p.y -= this.y0;
  lat = p.y / this.a;
  if (this.sphere) {
    lat /= this.C_y;
    lon = lon / (this.C_x * (this.m + Math.cos(lat)));
    if (this.m) {
      lat = asinz((this.m * lat + Math.sin(lat)) / this.n);
    } else if (this.n !== 1) {
      lat = asinz(Math.sin(lat) / this.n);
    }
    lon = adjust_lon(lon + this.long0);
    lat = adjust_lat(lat);
  } else {
    lat = pj_inv_mlfn(p.y / this.a, this.es, this.en);
    s = Math.abs(lat);
    if (s < HALF_PI) {
      s = Math.sin(lat);
      temp = this.long0 + p.x * Math.sqrt(1 - this.es * s * s) / (this.a * Math.cos(lat));
      lon = adjust_lon(temp);
    } else if (s - EPSLN < HALF_PI) {
      lon = this.long0;
    }
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$c = ["Sinusoidal", "sinu"];
const sinu = {
  init: init$d,
  forward: forward$b,
  inverse: inverse$b,
  names: names$c
};
function init$c() {
}
function forward$a(p) {
  var lon = p.x;
  var lat = p.y;
  var delta_lon = adjust_lon(lon - this.long0);
  var theta = lat;
  var con = Math.PI * Math.sin(lat);
  while (true) {
    var delta_theta = -(theta + Math.sin(theta) - con) / (1 + Math.cos(theta));
    theta += delta_theta;
    if (Math.abs(delta_theta) < EPSLN) {
      break;
    }
  }
  theta /= 2;
  if (Math.PI / 2 - Math.abs(lat) < EPSLN) {
    delta_lon = 0;
  }
  var x = 0.900316316158 * this.a * delta_lon * Math.cos(theta) + this.x0;
  var y = 1.4142135623731 * this.a * Math.sin(theta) + this.y0;
  p.x = x;
  p.y = y;
  return p;
}
function inverse$a(p) {
  var theta;
  var arg;
  p.x -= this.x0;
  p.y -= this.y0;
  arg = p.y / (1.4142135623731 * this.a);
  if (Math.abs(arg) > 0.999999999999) {
    arg = 0.999999999999;
  }
  theta = Math.asin(arg);
  var lon = adjust_lon(this.long0 + p.x / (0.900316316158 * this.a * Math.cos(theta)));
  if (lon < -Math.PI) {
    lon = -Math.PI;
  }
  if (lon > Math.PI) {
    lon = Math.PI;
  }
  arg = (2 * theta + Math.sin(2 * theta)) / Math.PI;
  if (Math.abs(arg) > 1) {
    arg = 1;
  }
  var lat = Math.asin(arg);
  p.x = lon;
  p.y = lat;
  return p;
}
var names$b = ["Mollweide", "moll"];
const moll = {
  init: init$c,
  forward: forward$a,
  inverse: inverse$a,
  names: names$b
};
function init$b() {
  if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
    return;
  }
  this.lat2 = this.lat2 || this.lat1;
  this.temp = this.b / this.a;
  this.es = 1 - Math.pow(this.temp, 2);
  this.e = Math.sqrt(this.es);
  this.e0 = e0fn(this.es);
  this.e1 = e1fn(this.es);
  this.e2 = e2fn(this.es);
  this.e3 = e3fn(this.es);
  this.sinphi = Math.sin(this.lat1);
  this.cosphi = Math.cos(this.lat1);
  this.ms1 = msfnz(this.e, this.sinphi, this.cosphi);
  this.ml1 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat1);
  if (Math.abs(this.lat1 - this.lat2) < EPSLN) {
    this.ns = this.sinphi;
  } else {
    this.sinphi = Math.sin(this.lat2);
    this.cosphi = Math.cos(this.lat2);
    this.ms2 = msfnz(this.e, this.sinphi, this.cosphi);
    this.ml2 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2);
    this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1);
  }
  this.g = this.ml1 + this.ms1 / this.ns;
  this.ml0 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
  this.rh = this.a * (this.g - this.ml0);
}
function forward$9(p) {
  var lon = p.x;
  var lat = p.y;
  var rh1;
  if (this.sphere) {
    rh1 = this.a * (this.g - lat);
  } else {
    var ml = mlfn(this.e0, this.e1, this.e2, this.e3, lat);
    rh1 = this.a * (this.g - ml);
  }
  var theta = this.ns * adjust_lon(lon - this.long0);
  var x = this.x0 + rh1 * Math.sin(theta);
  var y = this.y0 + this.rh - rh1 * Math.cos(theta);
  p.x = x;
  p.y = y;
  return p;
}
function inverse$9(p) {
  p.x -= this.x0;
  p.y = this.rh - p.y + this.y0;
  var con, rh1, lat, lon;
  if (this.ns >= 0) {
    rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
    con = 1;
  } else {
    rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
    con = -1;
  }
  var theta = 0;
  if (rh1 !== 0) {
    theta = Math.atan2(con * p.x, con * p.y);
  }
  if (this.sphere) {
    lon = adjust_lon(this.long0 + theta / this.ns);
    lat = adjust_lat(this.g - rh1 / this.a);
    p.x = lon;
    p.y = lat;
    return p;
  } else {
    var ml = this.g - rh1 / this.a;
    lat = imlfn(ml, this.e0, this.e1, this.e2, this.e3);
    lon = adjust_lon(this.long0 + theta / this.ns);
    p.x = lon;
    p.y = lat;
    return p;
  }
}
var names$a = ["Equidistant_Conic", "eqdc"];
const eqdc = {
  init: init$b,
  forward: forward$9,
  inverse: inverse$9,
  names: names$a
};
function init$a() {
  this.R = this.a;
}
function forward$8(p) {
  var lon = p.x;
  var lat = p.y;
  var dlon = adjust_lon(lon - this.long0);
  var x, y;
  if (Math.abs(lat) <= EPSLN) {
    x = this.x0 + this.R * dlon;
    y = this.y0;
  }
  var theta = asinz(2 * Math.abs(lat / Math.PI));
  if (Math.abs(dlon) <= EPSLN || Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
    x = this.x0;
    if (lat >= 0) {
      y = this.y0 + Math.PI * this.R * Math.tan(0.5 * theta);
    } else {
      y = this.y0 + Math.PI * this.R * -Math.tan(0.5 * theta);
    }
  }
  var al = 0.5 * Math.abs(Math.PI / dlon - dlon / Math.PI);
  var asq = al * al;
  var sinth = Math.sin(theta);
  var costh = Math.cos(theta);
  var g = costh / (sinth + costh - 1);
  var gsq = g * g;
  var m = g * (2 / sinth - 1);
  var msq = m * m;
  var con = Math.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq);
  if (dlon < 0) {
    con = -con;
  }
  x = this.x0 + con;
  var q = asq + g;
  con = Math.PI * this.R * (m * q - al * Math.sqrt((msq + asq) * (asq + 1) - q * q)) / (msq + asq);
  if (lat >= 0) {
    y = this.y0 + con;
  } else {
    y = this.y0 - con;
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$8(p) {
  var lon, lat;
  var xx, yy, xys, c1, c2, c3;
  var a12;
  var m1;
  var con;
  var th1;
  var d;
  p.x -= this.x0;
  p.y -= this.y0;
  con = Math.PI * this.R;
  xx = p.x / con;
  yy = p.y / con;
  xys = xx * xx + yy * yy;
  c1 = -Math.abs(yy) * (1 + xys);
  c2 = c1 - 2 * yy * yy + xx * xx;
  c3 = -2 * c1 + 1 + 2 * yy * yy + xys * xys;
  d = yy * yy / c3 + (2 * c2 * c2 * c2 / c3 / c3 / c3 - 9 * c1 * c2 / c3 / c3) / 27;
  a12 = (c1 - c2 * c2 / 3 / c3) / c3;
  m1 = 2 * Math.sqrt(-a12 / 3);
  con = 3 * d / a12 / m1;
  if (Math.abs(con) > 1) {
    if (con >= 0) {
      con = 1;
    } else {
      con = -1;
    }
  }
  th1 = Math.acos(con) / 3;
  if (p.y >= 0) {
    lat = (-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
  } else {
    lat = -(-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
  }
  if (Math.abs(xx) < EPSLN) {
    lon = this.long0;
  } else {
    lon = adjust_lon(this.long0 + Math.PI * (xys - 1 + Math.sqrt(1 + 2 * (xx * xx - yy * yy) + xys * xys)) / 2 / xx);
  }
  p.x = lon;
  p.y = lat;
  return p;
}
var names$9 = ["Van_der_Grinten_I", "VanDerGrinten", "Van_der_Grinten", "vandg"];
const vandg = {
  init: init$a,
  forward: forward$8,
  inverse: inverse$8,
  names: names$9
};
var geographiclibGeodesic_min = { exports: {} };
var hasRequiredGeographiclibGeodesic_min;
function requireGeographiclibGeodesic_min() {
  if (hasRequiredGeographiclibGeodesic_min) return geographiclibGeodesic_min.exports;
  hasRequiredGeographiclibGeodesic_min = 1;
  (function(module) {
    (function(cb) {
      var geodesic = {};
      geodesic.Constants = {};
      geodesic.Math = {};
      geodesic.Accumulator = {};
      (function(c) {
        c.WGS84 = { a: 6378137, f: 1 / 298.257223563 };
        c.version = { major: 2, minor: 2, patch: 0 };
        c.version_string = "2.2.0";
      })(geodesic.Constants);
      (function(m) {
        m.digits = 53;
        m.epsilon = Math.pow(0.5, m.digits - 1);
        m.degree = Math.PI / 180;
        m.sq = function(x) {
          return x * x;
        };
        m.hypot = function(x, y) {
          return Math.sqrt(x * x + y * y);
        };
        m.cbrt = Math.cbrt || function(x) {
          var y = Math.pow(Math.abs(x), 1 / 3);
          return x > 0 ? y : x < 0 ? -y : x;
        };
        m.log1p = Math.log1p || function(x) {
          var y = 1 + x, z = y - 1;
          return z === 0 ? x : x * Math.log(y) / z;
        };
        m.atanh = Math.atanh || function(x) {
          var y = Math.abs(x);
          y = m.log1p(2 * y / (1 - y)) / 2;
          return x > 0 ? y : x < 0 ? -y : x;
        };
        m.copysign = function(x, y) {
          return Math.abs(x) * (y < 0 || y === 0 && 1 / y < 0 ? -1 : 1);
        };
        m.sum = function(u, v) {
          var s = u + v, up = s - v, vpp = s - up, t;
          up -= u;
          vpp -= v;
          t = s ? 0 - (up + vpp) : s;
          return { s, t };
        };
        m.polyval = function(N, p, s, x) {
          var y = N < 0 ? 0 : p[s++];
          while (--N >= 0) y = y * x + p[s++];
          return y;
        };
        m.AngRound = function(x) {
          var z = 1 / 16, y = Math.abs(x);
          y = y < z ? z - (z - y) : y;
          return m.copysign(y, x);
        };
        m.remainder = function(x, y) {
          x %= y;
          return x < -y / 2 ? x + y : x < y / 2 ? x : x - y;
        };
        m.AngNormalize = function(x) {
          var y = m.remainder(x, 360);
          return Math.abs(y) === 180 ? m.copysign(180, x) : y;
        };
        m.LatFix = function(x) {
          return Math.abs(x) > 90 ? NaN : x;
        };
        m.AngDiff = function(x, y) {
          var r = m.sum(m.remainder(-x, 360), m.remainder(y, 360)), d, e;
          r = m.sum(m.remainder(r.s, 360), r.t);
          d = r.s;
          e = r.t;
          if (d === 0 || Math.abs(d) === 180)
            d = m.copysign(d, e === 0 ? y - x : -e);
          return { d, e };
        };
        m.sincosd = function(x) {
          var d, r, q, s, c, sinx, cosx;
          d = x % 360;
          q = Math.round(d / 90);
          d -= 90 * q;
          r = d * this.degree;
          s = Math.sin(r);
          c = Math.cos(r);
          if (Math.abs(d) === 45) {
            c = Math.sqrt(0.5);
            s = m.copysign(c, r);
          } else if (Math.abs(d) === 30) {
            c = Math.sqrt(0.75);
            s = m.copysign(0.5, r);
          }
          switch (q & 3) {
            case 0:
              sinx = s;
              cosx = c;
              break;
            case 1:
              sinx = c;
              cosx = -s;
              break;
            case 2:
              sinx = -s;
              cosx = -c;
              break;
            default:
              sinx = -c;
              cosx = s;
              break;
          }
          cosx += 0;
          if (sinx === 0) sinx = m.copysign(sinx, x);
          return { s: sinx, c: cosx };
        };
        m.sincosde = function(x, t) {
          var d, r, q, s, c, sinx, cosx;
          d = x % 360;
          q = Math.round(d / 90);
          d = m.AngRound(d - 90 * q + t);
          r = d * this.degree;
          s = Math.sin(r);
          c = Math.cos(r);
          if (Math.abs(d) === 45) {
            c = Math.sqrt(0.5);
            s = m.copysign(c, r);
          } else if (Math.abs(d) === 30) {
            c = Math.sqrt(0.75);
            s = m.copysign(0.5, r);
          }
          switch (q & 3) {
            case 0:
              sinx = s;
              cosx = c;
              break;
            case 1:
              sinx = c;
              cosx = -s;
              break;
            case 2:
              sinx = -s;
              cosx = -c;
              break;
            default:
              sinx = -c;
              cosx = s;
              break;
          }
          cosx += 0;
          if (sinx === 0) sinx = m.copysign(sinx, x + t);
          return { s: sinx, c: cosx };
        };
        m.atan2d = function(y, x) {
          var q = 0, ang;
          if (Math.abs(y) > Math.abs(x)) {
            [y, x] = [x, y];
            q = 2;
          }
          if (m.copysign(1, x) < 0) {
            x = -x;
            ++q;
          }
          ang = Math.atan2(y, x) / this.degree;
          switch (q) {
            case 1:
              ang = m.copysign(180, y) - ang;
              break;
            case 2:
              ang = 90 - ang;
              break;
            case 3:
              ang = -90 + ang;
              break;
          }
          return ang;
        };
      })(geodesic.Math);
      (function(a, m) {
        a.Accumulator = function(y) {
          this.Set(y);
        };
        a.Accumulator.prototype.Set = function(y) {
          if (!y) y = 0;
          if (y.constructor === a.Accumulator) {
            this._s = y._s;
            this._t = y._t;
          } else {
            this._s = y;
            this._t = 0;
          }
        };
        a.Accumulator.prototype.Add = function(y) {
          var u = m.sum(y, this._t), v = m.sum(u.s, this._s);
          u = u.t;
          this._s = v.s;
          this._t = v.t;
          if (this._s === 0)
            this._s = u;
          else
            this._t += u;
        };
        a.Accumulator.prototype.Sum = function(y) {
          var b;
          if (!y)
            return this._s;
          else {
            b = new a.Accumulator(this);
            b.Add(y);
            return b._s;
          }
        };
        a.Accumulator.prototype.Negate = function() {
          this._s *= -1;
          this._t *= -1;
        };
        a.Accumulator.prototype.Remainder = function(y) {
          this._s = m.remainder(this._s, y);
          this.Add(0);
        };
      })(geodesic.Accumulator, geodesic.Math);
      geodesic.Geodesic = {};
      geodesic.GeodesicLine = {};
      geodesic.PolygonArea = {};
      (function(g, l, p, m, c) {
        var GEOGRAPHICLIB_GEODESIC_ORDER = 6, nA1_ = GEOGRAPHICLIB_GEODESIC_ORDER, nA2_ = GEOGRAPHICLIB_GEODESIC_ORDER, nA3_ = GEOGRAPHICLIB_GEODESIC_ORDER, nA3x_ = nA3_, nC3x_, nC4x_, maxit1_ = 20, maxit2_ = maxit1_ + m.digits + 10, tol0_ = m.epsilon, tol1_ = 200 * tol0_, tol2_ = Math.sqrt(tol0_), tolb_ = tol0_, xthresh_ = 1e3 * tol2_, CAP_NONE = 0, CAP_ALL = 31, OUT_ALL = 32640, astroid, A1m1f_coeff, C1f_coeff, C1pf_coeff, A2m1f_coeff, C2f_coeff, A3_coeff, C3_coeff, C4_coeff;
        g.tiny_ = Math.sqrt(Number.MIN_VALUE / Number.EPSILON);
        g.nC1_ = GEOGRAPHICLIB_GEODESIC_ORDER;
        g.nC1p_ = GEOGRAPHICLIB_GEODESIC_ORDER;
        g.nC2_ = GEOGRAPHICLIB_GEODESIC_ORDER;
        g.nC3_ = GEOGRAPHICLIB_GEODESIC_ORDER;
        g.nC4_ = GEOGRAPHICLIB_GEODESIC_ORDER;
        nC3x_ = g.nC3_ * (g.nC3_ - 1) / 2;
        nC4x_ = g.nC4_ * (g.nC4_ + 1) / 2;
        g.CAP_C1 = 1 << 0;
        g.CAP_C1p = 1 << 1;
        g.CAP_C2 = 1 << 2;
        g.CAP_C3 = 1 << 3;
        g.CAP_C4 = 1 << 4;
        g.NONE = 0;
        g.ARC = 1 << 6;
        g.LATITUDE = 1 << 7 | CAP_NONE;
        g.LONGITUDE = 1 << 8 | g.CAP_C3;
        g.AZIMUTH = 1 << 9 | CAP_NONE;
        g.DISTANCE = 1 << 10 | g.CAP_C1;
        g.STANDARD = g.LATITUDE | g.LONGITUDE | g.AZIMUTH | g.DISTANCE;
        g.DISTANCE_IN = 1 << 11 | g.CAP_C1 | g.CAP_C1p;
        g.REDUCEDLENGTH = 1 << 12 | g.CAP_C1 | g.CAP_C2;
        g.GEODESICSCALE = 1 << 13 | g.CAP_C1 | g.CAP_C2;
        g.AREA = 1 << 14 | g.CAP_C4;
        g.ALL = OUT_ALL | CAP_ALL;
        g.LONG_UNROLL = 1 << 15;
        g.OUT_MASK = OUT_ALL | g.LONG_UNROLL;
        g.SinCosSeries = function(sinp, sinx, cosx, c2) {
          var k = c2.length, n = k - (sinp ? 1 : 0), ar = 2 * (cosx - sinx) * (cosx + sinx), y0 = n & 1 ? c2[--k] : 0, y1 = 0;
          n = Math.floor(n / 2);
          while (n--) {
            y1 = ar * y0 - y1 + c2[--k];
            y0 = ar * y1 - y0 + c2[--k];
          }
          return sinp ? 2 * sinx * cosx * y0 : cosx * (y0 - y1);
        };
        astroid = function(x, y) {
          var k, p5 = m.sq(x), q = m.sq(y), r = (p5 + q - 1) / 6, S, r2, r3, disc, u, T3, T, ang, v, uv, w;
          if (!(q === 0 && r <= 0)) {
            S = p5 * q / 4;
            r2 = m.sq(r);
            r3 = r * r2;
            disc = S * (S + 2 * r3);
            u = r;
            if (disc >= 0) {
              T3 = S + r3;
              T3 += T3 < 0 ? -Math.sqrt(disc) : Math.sqrt(disc);
              T = m.cbrt(T3);
              u += T + (T !== 0 ? r2 / T : 0);
            } else {
              ang = Math.atan2(Math.sqrt(-disc), -(S + r3));
              u += 2 * r * Math.cos(ang / 3);
            }
            v = Math.sqrt(m.sq(u) + q);
            uv = u < 0 ? q / (v - u) : u + v;
            w = (uv - q) / (2 * v);
            k = uv / (Math.sqrt(uv + m.sq(w)) + w);
          } else {
            k = 0;
          }
          return k;
        };
        A1m1f_coeff = [1, 4, 64, 0, 256];
        g.A1m1f = function(eps) {
          var p5 = Math.floor(nA1_ / 2), t = m.polyval(p5, A1m1f_coeff, 0, m.sq(eps)) / A1m1f_coeff[p5 + 1];
          return (t + eps) / (1 - eps);
        };
        C1f_coeff = [-1, 6, -16, 32, -9, 64, -128, 2048, 9, -16, 768, 3, -5, 512, -7, 1280, -7, 2048];
        g.C1f = function(eps, c2) {
          var eps2 = m.sq(eps), d = eps, o = 0, l2, p5;
          for (l2 = 1; l2 <= g.nC1_; ++l2) {
            p5 = Math.floor((g.nC1_ - l2) / 2);
            c2[l2] = d * m.polyval(p5, C1f_coeff, o, eps2) / C1f_coeff[o + p5 + 1];
            o += p5 + 2;
            d *= eps;
          }
        };
        C1pf_coeff = [205, -432, 768, 1536, 4005, -4736, 3840, 12288, -225, 116, 384, -7173, 2695, 7680, 3467, 7680, 38081, 61440];
        g.C1pf = function(eps, c2) {
          var eps2 = m.sq(eps), d = eps, o = 0, l2, p5;
          for (l2 = 1; l2 <= g.nC1p_; ++l2) {
            p5 = Math.floor((g.nC1p_ - l2) / 2);
            c2[l2] = d * m.polyval(p5, C1pf_coeff, o, eps2) / C1pf_coeff[o + p5 + 1];
            o += p5 + 2;
            d *= eps;
          }
        };
        A2m1f_coeff = [-11, -28, -192, 0, 256];
        g.A2m1f = function(eps) {
          var p5 = Math.floor(nA2_ / 2), t = m.polyval(p5, A2m1f_coeff, 0, m.sq(eps)) / A2m1f_coeff[p5 + 1];
          return (t - eps) / (1 + eps);
        };
        C2f_coeff = [1, 2, 16, 32, 35, 64, 384, 2048, 15, 80, 768, 7, 35, 512, 63, 1280, 77, 2048];
        g.C2f = function(eps, c2) {
          var eps2 = m.sq(eps), d = eps, o = 0, l2, p5;
          for (l2 = 1; l2 <= g.nC2_; ++l2) {
            p5 = Math.floor((g.nC2_ - l2) / 2);
            c2[l2] = d * m.polyval(p5, C2f_coeff, o, eps2) / C2f_coeff[o + p5 + 1];
            o += p5 + 2;
            d *= eps;
          }
        };
        g.Geodesic = function(a, f) {
          this.a = a;
          this.f = f;
          this._f1 = 1 - this.f;
          this._e2 = this.f * (2 - this.f);
          this._ep2 = this._e2 / m.sq(this._f1);
          this._n = this.f / (2 - this.f);
          this._b = this.a * this._f1;
          this._c2 = (m.sq(this.a) + m.sq(this._b) * (this._e2 === 0 ? 1 : (this._e2 > 0 ? m.atanh(Math.sqrt(this._e2)) : Math.atan(Math.sqrt(-this._e2))) / Math.sqrt(Math.abs(this._e2)))) / 2;
          this._etol2 = 0.1 * tol2_ / Math.sqrt(Math.max(1e-3, Math.abs(this.f)) * Math.min(1, 1 - this.f / 2) / 2);
          if (!(isFinite(this.a) && this.a > 0))
            throw new Error("Equatorial radius is not positive");
          if (!(isFinite(this._b) && this._b > 0))
            throw new Error("Polar semi-axis is not positive");
          this._A3x = new Array(nA3x_);
          this._C3x = new Array(nC3x_);
          this._C4x = new Array(nC4x_);
          this.A3coeff();
          this.C3coeff();
          this.C4coeff();
        };
        A3_coeff = [-3, 128, -2, -3, 64, -1, -3, -1, 16, 3, -1, -2, 8, 1, -1, 2, 1, 1];
        g.Geodesic.prototype.A3coeff = function() {
          var o = 0, k = 0, j, p5;
          for (j = nA3_ - 1; j >= 0; --j) {
            p5 = Math.min(nA3_ - j - 1, j);
            this._A3x[k++] = m.polyval(p5, A3_coeff, o, this._n) / A3_coeff[o + p5 + 1];
            o += p5 + 2;
          }
        };
        C3_coeff = [3, 128, 2, 5, 128, -1, 3, 3, 64, -1, 0, 1, 8, -1, 1, 4, 5, 256, 1, 3, 128, -3, -2, 3, 64, 1, -3, 2, 32, 7, 512, -10, 9, 384, 5, -9, 5, 192, 7, 512, -14, 7, 512, 21, 2560];
        g.Geodesic.prototype.C3coeff = function() {
          var o = 0, k = 0, l2, j, p5;
          for (l2 = 1; l2 < g.nC3_; ++l2) {
            for (j = g.nC3_ - 1; j >= l2; --j) {
              p5 = Math.min(g.nC3_ - j - 1, j);
              this._C3x[k++] = m.polyval(p5, C3_coeff, o, this._n) / C3_coeff[o + p5 + 1];
              o += p5 + 2;
            }
          }
        };
        C4_coeff = [97, 15015, 1088, 156, 45045, -224, -4784, 1573, 45045, -10656, 14144, -4576, -858, 45045, 64, 624, -4576, 6864, -3003, 15015, 100, 208, 572, 3432, -12012, 30030, 45045, 1, 9009, -2944, 468, 135135, 5792, 1040, -1287, 135135, 5952, -11648, 9152, -2574, 135135, -64, -624, 4576, -6864, 3003, 135135, 8, 10725, 1856, -936, 225225, -8448, 4992, -1144, 225225, -1440, 4160, -4576, 1716, 225225, -136, 63063, 1024, -208, 105105, 3584, -3328, 1144, 315315, -128, 135135, -2560, 832, 405405, 128, 99099];
        g.Geodesic.prototype.C4coeff = function() {
          var o = 0, k = 0, l2, j, p5;
          for (l2 = 0; l2 < g.nC4_; ++l2) {
            for (j = g.nC4_ - 1; j >= l2; --j) {
              p5 = g.nC4_ - j - 1;
              this._C4x[k++] = m.polyval(p5, C4_coeff, o, this._n) / C4_coeff[o + p5 + 1];
              o += p5 + 2;
            }
          }
        };
        g.Geodesic.prototype.A3f = function(eps) {
          return m.polyval(nA3x_ - 1, this._A3x, 0, eps);
        };
        g.Geodesic.prototype.C3f = function(eps, c2) {
          var mult = 1, o = 0, l2, p5;
          for (l2 = 1; l2 < g.nC3_; ++l2) {
            p5 = g.nC3_ - l2 - 1;
            mult *= eps;
            c2[l2] = mult * m.polyval(p5, this._C3x, o, eps);
            o += p5 + 1;
          }
        };
        g.Geodesic.prototype.C4f = function(eps, c2) {
          var mult = 1, o = 0, l2, p5;
          for (l2 = 0; l2 < g.nC4_; ++l2) {
            p5 = g.nC4_ - l2 - 1;
            c2[l2] = mult * m.polyval(p5, this._C4x, o, eps);
            o += p5 + 1;
            mult *= eps;
          }
        };
        g.Geodesic.prototype.Lengths = function(eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, outmask, C1a, C2a) {
          outmask &= g.OUT_MASK;
          var vals = {}, m0x = 0, J12 = 0, A12 = 0, A22 = 0, B1, B2, l2, csig12, t;
          if (outmask & (g.DISTANCE | g.REDUCEDLENGTH | g.GEODESICSCALE)) {
            A12 = g.A1m1f(eps);
            g.C1f(eps, C1a);
            if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
              A22 = g.A2m1f(eps);
              g.C2f(eps, C2a);
              m0x = A12 - A22;
              A22 = 1 + A22;
            }
            A12 = 1 + A12;
          }
          if (outmask & g.DISTANCE) {
            B1 = g.SinCosSeries(true, ssig2, csig2, C1a) - g.SinCosSeries(true, ssig1, csig1, C1a);
            vals.s12b = A12 * (sig12 + B1);
            if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
              B2 = g.SinCosSeries(true, ssig2, csig2, C2a) - g.SinCosSeries(true, ssig1, csig1, C2a);
              J12 = m0x * sig12 + (A12 * B1 - A22 * B2);
            }
          } else if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
            for (l2 = 1; l2 <= g.nC2_; ++l2)
              C2a[l2] = A12 * C1a[l2] - A22 * C2a[l2];
            J12 = m0x * sig12 + (g.SinCosSeries(true, ssig2, csig2, C2a) - g.SinCosSeries(true, ssig1, csig1, C2a));
          }
          if (outmask & g.REDUCEDLENGTH) {
            vals.m0 = m0x;
            vals.m12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) - csig1 * csig2 * J12;
          } else
            vals.m12b = NaN;
          if (outmask & g.GEODESICSCALE) {
            csig12 = csig1 * csig2 + ssig1 * ssig2;
            t = this._ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2);
            vals.M12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1;
            vals.M21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2;
          }
          return vals;
        };
        g.Geodesic.prototype.InverseStart = function(sbet1, cbet1, dn1, sbet2, cbet2, dn2, lam12, slam12, clam12, C1a, C2a) {
          var vals = {}, sbet12 = sbet2 * cbet1 - cbet2 * sbet1, cbet12 = cbet2 * cbet1 + sbet2 * sbet1, sbet12a, shortline, omg12, sbetm2, somg12, comg12, t, ssig12, csig12, x, y, lamscale, betscale, k2, eps, cbet12a, bet12a, m12b, m0, nvals, k, omg12a, lam12x;
          vals.sig12 = -1;
          sbet12a = sbet2 * cbet1;
          sbet12a += cbet2 * sbet1;
          shortline = cbet12 >= 0 && sbet12 < 0.5 && cbet2 * lam12 < 0.5;
          if (shortline) {
            sbetm2 = m.sq(sbet1 + sbet2);
            sbetm2 /= sbetm2 + m.sq(cbet1 + cbet2);
            vals.dnm = Math.sqrt(1 + this._ep2 * sbetm2);
            omg12 = lam12 / (this._f1 * vals.dnm);
            somg12 = Math.sin(omg12);
            comg12 = Math.cos(omg12);
          } else {
            somg12 = slam12;
            comg12 = clam12;
          }
          vals.salp1 = cbet2 * somg12;
          vals.calp1 = comg12 >= 0 ? sbet12 + cbet2 * sbet1 * m.sq(somg12) / (1 + comg12) : sbet12a - cbet2 * sbet1 * m.sq(somg12) / (1 - comg12);
          ssig12 = m.hypot(vals.salp1, vals.calp1);
          csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12;
          if (shortline && ssig12 < this._etol2) {
            vals.salp2 = cbet1 * somg12;
            vals.calp2 = sbet12 - cbet1 * sbet2 * (comg12 >= 0 ? m.sq(somg12) / (1 + comg12) : 1 - comg12);
            t = m.hypot(vals.salp2, vals.calp2);
            vals.salp2 /= t;
            vals.calp2 /= t;
            vals.sig12 = Math.atan2(ssig12, csig12);
          } else if (Math.abs(this._n) > 0.1 || csig12 >= 0 || ssig12 >= 6 * Math.abs(this._n) * Math.PI * m.sq(cbet1)) ;
          else {
            lam12x = Math.atan2(-slam12, -clam12);
            if (this.f >= 0) {
              k2 = m.sq(sbet1) * this._ep2;
              eps = k2 / (2 * (1 + Math.sqrt(1 + k2)) + k2);
              lamscale = this.f * cbet1 * this.A3f(eps) * Math.PI;
              betscale = lamscale * cbet1;
              x = lam12x / lamscale;
              y = sbet12a / betscale;
            } else {
              cbet12a = cbet2 * cbet1 - sbet2 * sbet1;
              bet12a = Math.atan2(sbet12a, cbet12a);
              nvals = this.Lengths(this._n, Math.PI + bet12a, sbet1, -cbet1, dn1, sbet2, cbet2, dn2, cbet1, cbet2, g.REDUCEDLENGTH, C1a, C2a);
              m12b = nvals.m12b;
              m0 = nvals.m0;
              x = -1 + m12b / (cbet1 * cbet2 * m0 * Math.PI);
              betscale = x < -0.01 ? sbet12a / x : -this.f * m.sq(cbet1) * Math.PI;
              lamscale = betscale / cbet1;
              y = lam12 / lamscale;
            }
            if (y > -tol1_ && x > -1 - xthresh_) {
              if (this.f >= 0) {
                vals.salp1 = Math.min(1, -x);
                vals.calp1 = -Math.sqrt(1 - m.sq(vals.salp1));
              } else {
                vals.calp1 = Math.max(x > -tol1_ ? 0 : -1, x);
                vals.salp1 = Math.sqrt(1 - m.sq(vals.calp1));
              }
            } else {
              k = astroid(x, y);
              omg12a = lamscale * (this.f >= 0 ? -x * k / (1 + k) : -y * (1 + k) / k);
              somg12 = Math.sin(omg12a);
              comg12 = -Math.cos(omg12a);
              vals.salp1 = cbet2 * somg12;
              vals.calp1 = sbet12a - cbet2 * sbet1 * m.sq(somg12) / (1 - comg12);
            }
          }
          if (!(vals.salp1 <= 0)) {
            t = m.hypot(vals.salp1, vals.calp1);
            vals.salp1 /= t;
            vals.calp1 /= t;
          } else {
            vals.salp1 = 1;
            vals.calp1 = 0;
          }
          return vals;
        };
        g.Geodesic.prototype.Lambda12 = function(sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1, slam120, clam120, diffp, C1a, C2a, C3a) {
          var vals = {}, t, salp0, calp0, somg1, comg1, somg2, comg2, somg12, comg12, B312, eta, k2, nvals;
          if (sbet1 === 0 && calp1 === 0)
            calp1 = -g.tiny_;
          salp0 = salp1 * cbet1;
          calp0 = m.hypot(calp1, salp1 * sbet1);
          vals.ssig1 = sbet1;
          somg1 = salp0 * sbet1;
          vals.csig1 = comg1 = calp1 * cbet1;
          t = m.hypot(vals.ssig1, vals.csig1);
          vals.ssig1 /= t;
          vals.csig1 /= t;
          vals.salp2 = cbet2 !== cbet1 ? salp0 / cbet2 : salp1;
          vals.calp2 = cbet2 !== cbet1 || Math.abs(sbet2) !== -sbet1 ? Math.sqrt(m.sq(calp1 * cbet1) + (cbet1 < -sbet1 ? (cbet2 - cbet1) * (cbet1 + cbet2) : (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 : Math.abs(calp1);
          vals.ssig2 = sbet2;
          somg2 = salp0 * sbet2;
          vals.csig2 = comg2 = vals.calp2 * cbet2;
          t = m.hypot(vals.ssig2, vals.csig2);
          vals.ssig2 /= t;
          vals.csig2 /= t;
          vals.sig12 = Math.atan2(Math.max(0, vals.csig1 * vals.ssig2 - vals.ssig1 * vals.csig2), vals.csig1 * vals.csig2 + vals.ssig1 * vals.ssig2);
          somg12 = Math.max(0, comg1 * somg2 - somg1 * comg2);
          comg12 = comg1 * comg2 + somg1 * somg2;
          eta = Math.atan2(somg12 * clam120 - comg12 * slam120, comg12 * clam120 + somg12 * slam120);
          k2 = m.sq(calp0) * this._ep2;
          vals.eps = k2 / (2 * (1 + Math.sqrt(1 + k2)) + k2);
          this.C3f(vals.eps, C3a);
          B312 = g.SinCosSeries(true, vals.ssig2, vals.csig2, C3a) - g.SinCosSeries(true, vals.ssig1, vals.csig1, C3a);
          vals.domg12 = -this.f * this.A3f(vals.eps) * salp0 * (vals.sig12 + B312);
          vals.lam12 = eta + vals.domg12;
          if (diffp) {
            if (vals.calp2 === 0)
              vals.dlam12 = -2 * this._f1 * dn1 / sbet1;
            else {
              nvals = this.Lengths(vals.eps, vals.sig12, vals.ssig1, vals.csig1, dn1, vals.ssig2, vals.csig2, dn2, cbet1, cbet2, g.REDUCEDLENGTH, C1a, C2a);
              vals.dlam12 = nvals.m12b;
              vals.dlam12 *= this._f1 / (vals.calp2 * cbet2);
            }
          }
          return vals;
        };
        g.Geodesic.prototype.Inverse = function(lat1, lon1, lat2, lon2, outmask) {
          var r, vals;
          if (!outmask) outmask = g.STANDARD;
          if (outmask === g.LONG_UNROLL) outmask |= g.STANDARD;
          outmask &= g.OUT_MASK;
          r = this.InverseInt(lat1, lon1, lat2, lon2, outmask);
          vals = r.vals;
          if (outmask & g.AZIMUTH) {
            vals.azi1 = m.atan2d(r.salp1, r.calp1);
            vals.azi2 = m.atan2d(r.salp2, r.calp2);
          }
          return vals;
        };
        g.Geodesic.prototype.InverseInt = function(lat1, lon1, lat2, lon2, outmask) {
          var vals = {}, lon12, lon12s, lonsign, t, swapp, latsign, sbet1, cbet1, sbet2, cbet2, s12x, m12x, dn1, dn2, lam12, slam12, clam12, sig12, calp1, salp1, calp2, salp2, C1a, C2a, C3a, meridian, nvals, ssig1, csig1, ssig2, csig2, eps, omg12, dnm, numit, salp1a, calp1a, salp1b, calp1b, tripn, tripb, v, dv, dalp1, sdalp1, cdalp1, nsalp1, lengthmask, salp0, calp0, alp12, k2, A42, C4a, B41, B42, somg12, comg12, domg12, dbet1, dbet2, salp12, calp12, sdomg12, cdomg12;
          vals.lat1 = lat1 = m.LatFix(lat1);
          vals.lat2 = lat2 = m.LatFix(lat2);
          lat1 = m.AngRound(lat1);
          lat2 = m.AngRound(lat2);
          lon12 = m.AngDiff(lon1, lon2);
          lon12s = lon12.e;
          lon12 = lon12.d;
          if (outmask & g.LONG_UNROLL) {
            vals.lon1 = lon1;
            vals.lon2 = lon1 + lon12 + lon12s;
          } else {
            vals.lon1 = m.AngNormalize(lon1);
            vals.lon2 = m.AngNormalize(lon2);
          }
          lonsign = m.copysign(1, lon12);
          lon12 *= lonsign;
          lon12s *= lonsign;
          lam12 = lon12 * m.degree;
          t = m.sincosde(lon12, lon12s);
          slam12 = t.s;
          clam12 = t.c;
          lon12s = 180 - lon12 - lon12s;
          swapp = Math.abs(lat1) < Math.abs(lat2) || isNaN(lat2) ? -1 : 1;
          if (swapp < 0) {
            lonsign *= -1;
            [lat2, lat1] = [lat1, lat2];
          }
          latsign = m.copysign(1, -lat1);
          lat1 *= latsign;
          lat2 *= latsign;
          t = m.sincosd(lat1);
          sbet1 = this._f1 * t.s;
          cbet1 = t.c;
          t = m.hypot(sbet1, cbet1);
          sbet1 /= t;
          cbet1 /= t;
          cbet1 = Math.max(g.tiny_, cbet1);
          t = m.sincosd(lat2);
          sbet2 = this._f1 * t.s;
          cbet2 = t.c;
          t = m.hypot(sbet2, cbet2);
          sbet2 /= t;
          cbet2 /= t;
          cbet2 = Math.max(g.tiny_, cbet2);
          if (cbet1 < -sbet1) {
            if (cbet2 === cbet1)
              sbet2 = m.copysign(sbet1, sbet2);
          } else {
            if (Math.abs(sbet2) === -sbet1)
              cbet2 = cbet1;
          }
          dn1 = Math.sqrt(1 + this._ep2 * m.sq(sbet1));
          dn2 = Math.sqrt(1 + this._ep2 * m.sq(sbet2));
          C1a = new Array(g.nC1_ + 1);
          C2a = new Array(g.nC2_ + 1);
          C3a = new Array(g.nC3_);
          meridian = lat1 === -90 || slam12 === 0;
          if (meridian) {
            calp1 = clam12;
            salp1 = slam12;
            calp2 = 1;
            salp2 = 0;
            ssig1 = sbet1;
            csig1 = calp1 * cbet1;
            ssig2 = sbet2;
            csig2 = calp2 * cbet2;
            sig12 = Math.atan2(Math.max(0, csig1 * ssig2 - ssig1 * csig2), csig1 * csig2 + ssig1 * ssig2);
            nvals = this.Lengths(this._n, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, outmask | g.DISTANCE | g.REDUCEDLENGTH, C1a, C2a);
            s12x = nvals.s12b;
            m12x = nvals.m12b;
            if (outmask & g.GEODESICSCALE) {
              vals.M12 = nvals.M12;
              vals.M21 = nvals.M21;
            }
            if (sig12 < tol2_ || m12x >= 0) {
              if (sig12 < 3 * g.tiny_ || sig12 < tol0_ && (s12x < 0 || m12x < 0))
                sig12 = m12x = s12x = 0;
              m12x *= this._b;
              s12x *= this._b;
              vals.a12 = sig12 / m.degree;
            } else
              meridian = false;
          }
          somg12 = 2;
          if (!meridian && sbet1 === 0 && (this.f <= 0 || lon12s >= this.f * 180)) {
            calp1 = calp2 = 0;
            salp1 = salp2 = 1;
            s12x = this.a * lam12;
            sig12 = omg12 = lam12 / this._f1;
            m12x = this._b * Math.sin(sig12);
            if (outmask & g.GEODESICSCALE)
              vals.M12 = vals.M21 = Math.cos(sig12);
            vals.a12 = lon12 / this._f1;
          } else if (!meridian) {
            nvals = this.InverseStart(sbet1, cbet1, dn1, sbet2, cbet2, dn2, lam12, slam12, clam12, C1a, C2a);
            sig12 = nvals.sig12;
            salp1 = nvals.salp1;
            calp1 = nvals.calp1;
            if (sig12 >= 0) {
              salp2 = nvals.salp2;
              calp2 = nvals.calp2;
              dnm = nvals.dnm;
              s12x = sig12 * this._b * dnm;
              m12x = m.sq(dnm) * this._b * Math.sin(sig12 / dnm);
              if (outmask & g.GEODESICSCALE)
                vals.M12 = vals.M21 = Math.cos(sig12 / dnm);
              vals.a12 = sig12 / m.degree;
              omg12 = lam12 / (this._f1 * dnm);
            } else {
              numit = 0;
              salp1a = g.tiny_;
              calp1a = 1;
              salp1b = g.tiny_;
              calp1b = -1;
              for (tripn = false, tripb = false; ; ++numit) {
                nvals = this.Lambda12(sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1, slam12, clam12, numit < maxit1_, C1a, C2a, C3a);
                v = nvals.lam12;
                salp2 = nvals.salp2;
                calp2 = nvals.calp2;
                sig12 = nvals.sig12;
                ssig1 = nvals.ssig1;
                csig1 = nvals.csig1;
                ssig2 = nvals.ssig2;
                csig2 = nvals.csig2;
                eps = nvals.eps;
                domg12 = nvals.domg12;
                dv = nvals.dlam12;
                if (tripb || !(Math.abs(v) >= (tripn ? 8 : 1) * tol0_) || numit == maxit2_)
                  break;
                if (v > 0 && (numit < maxit1_ || calp1 / salp1 > calp1b / salp1b)) {
                  salp1b = salp1;
                  calp1b = calp1;
                } else if (v < 0 && (numit < maxit1_ || calp1 / salp1 < calp1a / salp1a)) {
                  salp1a = salp1;
                  calp1a = calp1;
                }
                if (numit < maxit1_ && dv > 0) {
                  dalp1 = -v / dv;
                  if (Math.abs(dalp1) < Math.PI) {
                    sdalp1 = Math.sin(dalp1);
                    cdalp1 = Math.cos(dalp1);
                    nsalp1 = salp1 * cdalp1 + calp1 * sdalp1;
                    if (nsalp1 > 0) {
                      calp1 = calp1 * cdalp1 - salp1 * sdalp1;
                      salp1 = nsalp1;
                      t = m.hypot(salp1, calp1);
                      salp1 /= t;
                      calp1 /= t;
                      tripn = Math.abs(v) <= 16 * tol0_;
                      continue;
                    }
                  }
                }
                salp1 = (salp1a + salp1b) / 2;
                calp1 = (calp1a + calp1b) / 2;
                t = m.hypot(salp1, calp1);
                salp1 /= t;
                calp1 /= t;
                tripn = false;
                tripb = Math.abs(salp1a - salp1) + (calp1a - calp1) < tolb_ || Math.abs(salp1 - salp1b) + (calp1 - calp1b) < tolb_;
              }
              lengthmask = outmask | (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE) ? g.DISTANCE : g.NONE);
              nvals = this.Lengths(eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, lengthmask, C1a, C2a);
              s12x = nvals.s12b;
              m12x = nvals.m12b;
              if (outmask & g.GEODESICSCALE) {
                vals.M12 = nvals.M12;
                vals.M21 = nvals.M21;
              }
              m12x *= this._b;
              s12x *= this._b;
              vals.a12 = sig12 / m.degree;
              if (outmask & g.AREA) {
                sdomg12 = Math.sin(domg12);
                cdomg12 = Math.cos(domg12);
                somg12 = slam12 * cdomg12 - clam12 * sdomg12;
                comg12 = clam12 * cdomg12 + slam12 * sdomg12;
              }
            }
          }
          if (outmask & g.DISTANCE)
            vals.s12 = 0 + s12x;
          if (outmask & g.REDUCEDLENGTH)
            vals.m12 = 0 + m12x;
          if (outmask & g.AREA) {
            salp0 = salp1 * cbet1;
            calp0 = m.hypot(calp1, salp1 * sbet1);
            if (calp0 !== 0 && salp0 !== 0) {
              ssig1 = sbet1;
              csig1 = calp1 * cbet1;
              ssig2 = sbet2;
              csig2 = calp2 * cbet2;
              k2 = m.sq(calp0) * this._ep2;
              eps = k2 / (2 * (1 + Math.sqrt(1 + k2)) + k2);
              A42 = m.sq(this.a) * calp0 * salp0 * this._e2;
              t = m.hypot(ssig1, csig1);
              ssig1 /= t;
              csig1 /= t;
              t = m.hypot(ssig2, csig2);
              ssig2 /= t;
              csig2 /= t;
              C4a = new Array(g.nC4_);
              this.C4f(eps, C4a);
              B41 = g.SinCosSeries(false, ssig1, csig1, C4a);
              B42 = g.SinCosSeries(false, ssig2, csig2, C4a);
              vals.S12 = A42 * (B42 - B41);
            } else
              vals.S12 = 0;
            if (!meridian && somg12 == 2) {
              somg12 = Math.sin(omg12);
              comg12 = Math.cos(omg12);
            }
            if (!meridian && comg12 > -0.7071 && sbet2 - sbet1 < 1.75) {
              domg12 = 1 + comg12;
              dbet1 = 1 + cbet1;
              dbet2 = 1 + cbet2;
              alp12 = 2 * Math.atan2(somg12 * (sbet1 * dbet2 + sbet2 * dbet1), domg12 * (sbet1 * sbet2 + dbet1 * dbet2));
            } else {
              salp12 = salp2 * calp1 - calp2 * salp1;
              calp12 = calp2 * calp1 + salp2 * salp1;
              if (salp12 === 0 && calp12 < 0) {
                salp12 = g.tiny_ * calp1;
                calp12 = -1;
              }
              alp12 = Math.atan2(salp12, calp12);
            }
            vals.S12 += this._c2 * alp12;
            vals.S12 *= swapp * lonsign * latsign;
            vals.S12 += 0;
          }
          if (swapp < 0) {
            [salp2, salp1] = [salp1, salp2];
            [calp2, calp1] = [calp1, calp2];
            if (outmask & g.GEODESICSCALE) {
              [vals.M21, vals.M12] = [vals.M12, vals.M21];
            }
          }
          salp1 *= swapp * lonsign;
          calp1 *= swapp * latsign;
          salp2 *= swapp * lonsign;
          calp2 *= swapp * latsign;
          return { vals, salp1, calp1, salp2, calp2 };
        };
        g.Geodesic.prototype.GenDirect = function(lat1, lon1, azi1, arcmode, s12_a12, outmask) {
          var line2;
          if (!outmask) outmask = g.STANDARD;
          else if (outmask === g.LONG_UNROLL) outmask |= g.STANDARD;
          if (!arcmode) outmask |= g.DISTANCE_IN;
          line2 = new l.GeodesicLine(this, lat1, lon1, azi1, outmask);
          return line2.GenPosition(arcmode, s12_a12, outmask);
        };
        g.Geodesic.prototype.Direct = function(lat1, lon1, azi1, s12, outmask) {
          return this.GenDirect(lat1, lon1, azi1, false, s12, outmask);
        };
        g.Geodesic.prototype.ArcDirect = function(lat1, lon1, azi1, a12, outmask) {
          return this.GenDirect(lat1, lon1, azi1, true, a12, outmask);
        };
        g.Geodesic.prototype.Line = function(lat1, lon1, azi1, caps) {
          return new l.GeodesicLine(this, lat1, lon1, azi1, caps);
        };
        g.Geodesic.prototype.DirectLine = function(lat1, lon1, azi1, s12, caps) {
          return this.GenDirectLine(lat1, lon1, azi1, false, s12, caps);
        };
        g.Geodesic.prototype.ArcDirectLine = function(lat1, lon1, azi1, a12, caps) {
          return this.GenDirectLine(lat1, lon1, azi1, true, a12, caps);
        };
        g.Geodesic.prototype.GenDirectLine = function(lat1, lon1, azi1, arcmode, s12_a12, caps) {
          var t;
          if (!caps) caps = g.STANDARD | g.DISTANCE_IN;
          if (!arcmode) caps |= g.DISTANCE_IN;
          t = new l.GeodesicLine(this, lat1, lon1, azi1, caps);
          t.GenSetDistance(arcmode, s12_a12);
          return t;
        };
        g.Geodesic.prototype.InverseLine = function(lat1, lon1, lat2, lon2, caps) {
          var r, t, azi1;
          if (!caps) caps = g.STANDARD | g.DISTANCE_IN;
          r = this.InverseInt(lat1, lon1, lat2, lon2, g.ARC);
          azi1 = m.atan2d(r.salp1, r.calp1);
          if (caps & (g.OUT_MASK & g.DISTANCE_IN)) caps |= g.DISTANCE;
          t = new l.GeodesicLine(this, lat1, lon1, azi1, caps, r.salp1, r.calp1);
          t.SetArc(r.vals.a12);
          return t;
        };
        g.Geodesic.prototype.Polygon = function(polyline) {
          return new p.PolygonArea(this, polyline);
        };
        g.WGS84 = new g.Geodesic(c.WGS84.a, c.WGS84.f);
      })(geodesic.Geodesic, geodesic.GeodesicLine, geodesic.PolygonArea, geodesic.Math, geodesic.Constants);
      (function(g, l, m) {
        l.GeodesicLine = function(geod, lat1, lon1, azi1, caps, salp1, calp1) {
          var t, cbet1, sbet1, eps, s, c;
          if (!caps) caps = g.STANDARD | g.DISTANCE_IN;
          this.a = geod.a;
          this.f = geod.f;
          this._b = geod._b;
          this._c2 = geod._c2;
          this._f1 = geod._f1;
          this.caps = caps | g.LATITUDE | g.AZIMUTH | g.LONG_UNROLL;
          this.lat1 = m.LatFix(lat1);
          this.lon1 = lon1;
          if (typeof salp1 === "undefined" || typeof calp1 === "undefined") {
            this.azi1 = m.AngNormalize(azi1);
            t = m.sincosd(m.AngRound(this.azi1));
            this.salp1 = t.s;
            this.calp1 = t.c;
          } else {
            this.azi1 = azi1;
            this.salp1 = salp1;
            this.calp1 = calp1;
          }
          t = m.sincosd(m.AngRound(this.lat1));
          sbet1 = this._f1 * t.s;
          cbet1 = t.c;
          t = m.hypot(sbet1, cbet1);
          sbet1 /= t;
          cbet1 /= t;
          cbet1 = Math.max(g.tiny_, cbet1);
          this._dn1 = Math.sqrt(1 + geod._ep2 * m.sq(sbet1));
          this._salp0 = this.salp1 * cbet1;
          this._calp0 = m.hypot(this.calp1, this.salp1 * sbet1);
          this._ssig1 = sbet1;
          this._somg1 = this._salp0 * sbet1;
          this._csig1 = this._comg1 = sbet1 !== 0 || this.calp1 !== 0 ? cbet1 * this.calp1 : 1;
          t = m.hypot(this._ssig1, this._csig1);
          this._ssig1 /= t;
          this._csig1 /= t;
          this._k2 = m.sq(this._calp0) * geod._ep2;
          eps = this._k2 / (2 * (1 + Math.sqrt(1 + this._k2)) + this._k2);
          if (this.caps & g.CAP_C1) {
            this._A1m1 = g.A1m1f(eps);
            this._C1a = new Array(g.nC1_ + 1);
            g.C1f(eps, this._C1a);
            this._B11 = g.SinCosSeries(true, this._ssig1, this._csig1, this._C1a);
            s = Math.sin(this._B11);
            c = Math.cos(this._B11);
            this._stau1 = this._ssig1 * c + this._csig1 * s;
            this._ctau1 = this._csig1 * c - this._ssig1 * s;
          }
          if (this.caps & g.CAP_C1p) {
            this._C1pa = new Array(g.nC1p_ + 1);
            g.C1pf(eps, this._C1pa);
          }
          if (this.caps & g.CAP_C2) {
            this._A2m1 = g.A2m1f(eps);
            this._C2a = new Array(g.nC2_ + 1);
            g.C2f(eps, this._C2a);
            this._B21 = g.SinCosSeries(true, this._ssig1, this._csig1, this._C2a);
          }
          if (this.caps & g.CAP_C3) {
            this._C3a = new Array(g.nC3_);
            geod.C3f(eps, this._C3a);
            this._A3c = -this.f * this._salp0 * geod.A3f(eps);
            this._B31 = g.SinCosSeries(true, this._ssig1, this._csig1, this._C3a);
          }
          if (this.caps & g.CAP_C4) {
            this._C4a = new Array(g.nC4_);
            geod.C4f(eps, this._C4a);
            this._A4 = m.sq(this.a) * this._calp0 * this._salp0 * geod._e2;
            this._B41 = g.SinCosSeries(false, this._ssig1, this._csig1, this._C4a);
          }
          this.a13 = this.s13 = NaN;
        };
        l.GeodesicLine.prototype.GenPosition = function(arcmode, s12_a12, outmask) {
          var vals = {}, sig12, ssig12, csig12, B12, AB1, ssig2, csig2, tau12, s, c, serr, omg12, lam12, lon12, E4, sbet2, cbet2, somg2, comg2, salp2, calp2, dn2, B22, AB2, J12, t, B42, salp12, calp12;
          if (!outmask) outmask = g.STANDARD;
          else if (outmask === g.LONG_UNROLL) outmask |= g.STANDARD;
          outmask &= this.caps & g.OUT_MASK;
          vals.lat1 = this.lat1;
          vals.azi1 = this.azi1;
          vals.lon1 = outmask & g.LONG_UNROLL ? this.lon1 : m.AngNormalize(this.lon1);
          if (arcmode)
            vals.a12 = s12_a12;
          else
            vals.s12 = s12_a12;
          if (!(arcmode || this.caps & g.DISTANCE_IN & g.OUT_MASK)) {
            vals.a12 = NaN;
            return vals;
          }
          B12 = 0;
          AB1 = 0;
          if (arcmode) {
            sig12 = s12_a12 * m.degree;
            t = m.sincosd(s12_a12);
            ssig12 = t.s;
            csig12 = t.c;
          } else {
            tau12 = s12_a12 / (this._b * (1 + this._A1m1));
            s = Math.sin(tau12);
            c = Math.cos(tau12);
            B12 = -g.SinCosSeries(true, this._stau1 * c + this._ctau1 * s, this._ctau1 * c - this._stau1 * s, this._C1pa);
            sig12 = tau12 - (B12 - this._B11);
            ssig12 = Math.sin(sig12);
            csig12 = Math.cos(sig12);
            if (Math.abs(this.f) > 0.01) {
              ssig2 = this._ssig1 * csig12 + this._csig1 * ssig12;
              csig2 = this._csig1 * csig12 - this._ssig1 * ssig12;
              B12 = g.SinCosSeries(true, ssig2, csig2, this._C1a);
              serr = (1 + this._A1m1) * (sig12 + (B12 - this._B11)) - s12_a12 / this._b;
              sig12 = sig12 - serr / Math.sqrt(1 + this._k2 * m.sq(ssig2));
              ssig12 = Math.sin(sig12);
              csig12 = Math.cos(sig12);
            }
          }
          ssig2 = this._ssig1 * csig12 + this._csig1 * ssig12;
          csig2 = this._csig1 * csig12 - this._ssig1 * ssig12;
          dn2 = Math.sqrt(1 + this._k2 * m.sq(ssig2));
          if (outmask & (g.DISTANCE | g.REDUCEDLENGTH | g.GEODESICSCALE)) {
            if (arcmode || Math.abs(this.f) > 0.01)
              B12 = g.SinCosSeries(true, ssig2, csig2, this._C1a);
            AB1 = (1 + this._A1m1) * (B12 - this._B11);
          }
          sbet2 = this._calp0 * ssig2;
          cbet2 = m.hypot(this._salp0, this._calp0 * csig2);
          if (cbet2 === 0)
            cbet2 = csig2 = g.tiny_;
          salp2 = this._salp0;
          calp2 = this._calp0 * csig2;
          if (arcmode && outmask & g.DISTANCE)
            vals.s12 = this._b * ((1 + this._A1m1) * sig12 + AB1);
          if (outmask & g.LONGITUDE) {
            somg2 = this._salp0 * ssig2;
            comg2 = csig2;
            E4 = m.copysign(1, this._salp0);
            omg12 = outmask & g.LONG_UNROLL ? E4 * (sig12 - (Math.atan2(ssig2, csig2) - Math.atan2(this._ssig1, this._csig1)) + (Math.atan2(E4 * somg2, comg2) - Math.atan2(E4 * this._somg1, this._comg1))) : Math.atan2(somg2 * this._comg1 - comg2 * this._somg1, comg2 * this._comg1 + somg2 * this._somg1);
            lam12 = omg12 + this._A3c * (sig12 + (g.SinCosSeries(true, ssig2, csig2, this._C3a) - this._B31));
            lon12 = lam12 / m.degree;
            vals.lon2 = outmask & g.LONG_UNROLL ? this.lon1 + lon12 : m.AngNormalize(m.AngNormalize(this.lon1) + m.AngNormalize(lon12));
          }
          if (outmask & g.LATITUDE)
            vals.lat2 = m.atan2d(sbet2, this._f1 * cbet2);
          if (outmask & g.AZIMUTH)
            vals.azi2 = m.atan2d(salp2, calp2);
          if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
            B22 = g.SinCosSeries(true, ssig2, csig2, this._C2a);
            AB2 = (1 + this._A2m1) * (B22 - this._B21);
            J12 = (this._A1m1 - this._A2m1) * sig12 + (AB1 - AB2);
            if (outmask & g.REDUCEDLENGTH)
              vals.m12 = this._b * (dn2 * (this._csig1 * ssig2) - this._dn1 * (this._ssig1 * csig2) - this._csig1 * csig2 * J12);
            if (outmask & g.GEODESICSCALE) {
              t = this._k2 * (ssig2 - this._ssig1) * (ssig2 + this._ssig1) / (this._dn1 + dn2);
              vals.M12 = csig12 + (t * ssig2 - csig2 * J12) * this._ssig1 / this._dn1;
              vals.M21 = csig12 - (t * this._ssig1 - this._csig1 * J12) * ssig2 / dn2;
            }
          }
          if (outmask & g.AREA) {
            B42 = g.SinCosSeries(false, ssig2, csig2, this._C4a);
            if (this._calp0 === 0 || this._salp0 === 0) {
              salp12 = salp2 * this.calp1 - calp2 * this.salp1;
              calp12 = calp2 * this.calp1 + salp2 * this.salp1;
            } else {
              salp12 = this._calp0 * this._salp0 * (csig12 <= 0 ? this._csig1 * (1 - csig12) + ssig12 * this._ssig1 : ssig12 * (this._csig1 * ssig12 / (1 + csig12) + this._ssig1));
              calp12 = m.sq(this._salp0) + m.sq(this._calp0) * this._csig1 * csig2;
            }
            vals.S12 = this._c2 * Math.atan2(salp12, calp12) + this._A4 * (B42 - this._B41);
          }
          if (!arcmode)
            vals.a12 = sig12 / m.degree;
          return vals;
        };
        l.GeodesicLine.prototype.Position = function(s12, outmask) {
          return this.GenPosition(false, s12, outmask);
        };
        l.GeodesicLine.prototype.ArcPosition = function(a12, outmask) {
          return this.GenPosition(true, a12, outmask);
        };
        l.GeodesicLine.prototype.GenSetDistance = function(arcmode, s13_a13) {
          if (arcmode)
            this.SetArc(s13_a13);
          else
            this.SetDistance(s13_a13);
        };
        l.GeodesicLine.prototype.SetDistance = function(s13) {
          var r;
          this.s13 = s13;
          r = this.GenPosition(false, this.s13, g.ARC);
          this.a13 = 0 + r.a12;
        };
        l.GeodesicLine.prototype.SetArc = function(a13) {
          var r;
          this.a13 = a13;
          r = this.GenPosition(true, this.a13, g.DISTANCE);
          this.s13 = 0 + r.s12;
        };
      })(geodesic.Geodesic, geodesic.GeodesicLine, geodesic.Math);
      (function(p, g, m, a) {
        var transit, transitdirect, AreaReduceA, AreaReduceB;
        transit = function(lon1, lon2) {
          var lon12 = m.AngDiff(lon1, lon2).d;
          lon1 = m.AngNormalize(lon1);
          lon2 = m.AngNormalize(lon2);
          return lon12 > 0 && (lon1 < 0 && lon2 >= 0 || lon1 > 0 && lon2 === 0) ? 1 : lon12 < 0 && lon1 >= 0 && lon2 < 0 ? -1 : 0;
        };
        transitdirect = function(lon1, lon2) {
          lon1 = lon1 % 720;
          lon2 = lon2 % 720;
          return (0 <= lon2 && lon2 < 360 || lon2 < -360 ? 0 : 1) - (0 <= lon1 && lon1 < 360 || lon1 < -360 ? 0 : 1);
        };
        AreaReduceA = function(area, area0, crossings, reverse, sign2) {
          area.Remainder(area0);
          if (crossings & 1)
            area.Add((area.Sum() < 0 ? 1 : -1) * area0 / 2);
          if (!reverse)
            area.Negate();
          if (sign2) {
            if (area.Sum() > area0 / 2)
              area.Add(-area0);
            else if (area.Sum() <= -area0 / 2)
              area.Add(+area0);
          } else {
            if (area.Sum() >= area0)
              area.Add(-area0);
            else if (area.Sum() < 0)
              area.Add(+area0);
          }
          return 0 + area.Sum();
        };
        AreaReduceB = function(area, area0, crossings, reverse, sign2) {
          area = m.remainder(area, area0);
          if (crossings & 1)
            area += (area < 0 ? 1 : -1) * area0 / 2;
          if (!reverse)
            area *= -1;
          if (sign2) {
            if (area > area0 / 2)
              area -= area0;
            else if (area <= -area0 / 2)
              area += area0;
          } else {
            if (area >= area0)
              area -= area0;
            else if (area < 0)
              area += area0;
          }
          return 0 + area;
        };
        p.PolygonArea = function(geod, polyline) {
          this._geod = geod;
          this.a = this._geod.a;
          this.f = this._geod.f;
          this._area0 = 4 * Math.PI * geod._c2;
          this.polyline = !polyline ? false : polyline;
          this._mask = g.LATITUDE | g.LONGITUDE | g.DISTANCE | (this.polyline ? g.NONE : g.AREA | g.LONG_UNROLL);
          if (!this.polyline)
            this._areasum = new a.Accumulator(0);
          this._perimetersum = new a.Accumulator(0);
          this.Clear();
        };
        p.PolygonArea.prototype.Clear = function() {
          this.num = 0;
          this._crossings = 0;
          if (!this.polyline)
            this._areasum.Set(0);
          this._perimetersum.Set(0);
          this._lat0 = this._lon0 = this.lat = this.lon = NaN;
        };
        p.PolygonArea.prototype.AddPoint = function(lat, lon) {
          var t;
          if (this.num === 0) {
            this._lat0 = this.lat = lat;
            this._lon0 = this.lon = lon;
          } else {
            t = this._geod.Inverse(this.lat, this.lon, lat, lon, this._mask);
            this._perimetersum.Add(t.s12);
            if (!this.polyline) {
              this._areasum.Add(t.S12);
              this._crossings += transit(this.lon, lon);
            }
            this.lat = lat;
            this.lon = lon;
          }
          ++this.num;
        };
        p.PolygonArea.prototype.AddEdge = function(azi, s) {
          var t;
          if (this.num) {
            t = this._geod.Direct(this.lat, this.lon, azi, s, this._mask);
            this._perimetersum.Add(s);
            if (!this.polyline) {
              this._areasum.Add(t.S12);
              this._crossings += transitdirect(this.lon, t.lon2);
            }
            this.lat = t.lat2;
            this.lon = t.lon2;
          }
          ++this.num;
        };
        p.PolygonArea.prototype.Compute = function(reverse, sign2) {
          var vals = { number: this.num }, t, tempsum;
          if (this.num < 2) {
            vals.perimeter = 0;
            if (!this.polyline)
              vals.area = 0;
            return vals;
          }
          if (this.polyline) {
            vals.perimeter = this._perimetersum.Sum();
            return vals;
          }
          t = this._geod.Inverse(this.lat, this.lon, this._lat0, this._lon0, this._mask);
          vals.perimeter = this._perimetersum.Sum(t.s12);
          tempsum = new a.Accumulator(this._areasum);
          tempsum.Add(t.S12);
          vals.area = AreaReduceA(tempsum, this._area0, this._crossings + transit(this.lon, this._lon0), reverse, sign2);
          return vals;
        };
        p.PolygonArea.prototype.TestPoint = function(lat, lon, reverse, sign2) {
          var vals = { number: this.num + 1 }, t, tempsum, crossings, i;
          if (this.num === 0) {
            vals.perimeter = 0;
            if (!this.polyline)
              vals.area = 0;
            return vals;
          }
          vals.perimeter = this._perimetersum.Sum();
          tempsum = this.polyline ? 0 : this._areasum.Sum();
          crossings = this._crossings;
          for (i = 0; i < (this.polyline ? 1 : 2); ++i) {
            t = this._geod.Inverse(i === 0 ? this.lat : lat, i === 0 ? this.lon : lon, i !== 0 ? this._lat0 : lat, i !== 0 ? this._lon0 : lon, this._mask);
            vals.perimeter += t.s12;
            if (!this.polyline) {
              tempsum += t.S12;
              crossings += transit(i === 0 ? this.lon : lon, i !== 0 ? this._lon0 : lon);
            }
          }
          if (this.polyline)
            return vals;
          vals.area = AreaReduceB(tempsum, this._area0, crossings, reverse, sign2);
          return vals;
        };
        p.PolygonArea.prototype.TestEdge = function(azi, s, reverse, sign2) {
          var vals = { number: this.num ? this.num + 1 : 0 }, t, tempsum, crossings;
          if (this.num === 0)
            return vals;
          vals.perimeter = this._perimetersum.Sum() + s;
          if (this.polyline)
            return vals;
          tempsum = this._areasum.Sum();
          crossings = this._crossings;
          t = this._geod.Direct(this.lat, this.lon, azi, s, this._mask);
          tempsum += t.S12;
          crossings += transitdirect(this.lon, t.lon2);
          crossings += transit(t.lon2, this._lon0);
          t = this._geod.Inverse(t.lat2, t.lon2, this._lat0, this._lon0, this._mask);
          vals.perimeter += t.s12;
          tempsum += t.S12;
          vals.area = AreaReduceB(tempsum, this._area0, crossings, reverse, sign2);
          return vals;
        };
      })(geodesic.PolygonArea, geodesic.Geodesic, geodesic.Math, geodesic.Accumulator);
      cb(geodesic);
    })(function(geo) {
      if (module.exports) {
        module.exports = geo;
      } else {
        window.geodesic = geo;
      }
    });
  })(geographiclibGeodesic_min);
  return geographiclibGeodesic_min.exports;
}
var geographiclibGeodesic_minExports = requireGeographiclibGeodesic_min();
function init$9() {
  this.sin_p12 = Math.sin(this.lat0);
  this.cos_p12 = Math.cos(this.lat0);
  this.g = new geographiclibGeodesic_minExports.Geodesic.Geodesic(this.a, this.es / (1 + Math.sqrt(1 - this.es)));
}
function forward$7(p) {
  var lon = p.x;
  var lat = p.y;
  var sinphi = Math.sin(p.y);
  var cosphi = Math.cos(p.y);
  var dlon = adjust_lon(lon - this.long0);
  var e0, e1, e2, e3, Mlp, Ml, c, kp, cos_c, lat1, lon1, lat2, lon2, vars, azi1;
  if (this.sphere) {
    if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
      p.x = this.x0 + this.a * (HALF_PI - lat) * Math.sin(dlon);
      p.y = this.y0 - this.a * (HALF_PI - lat) * Math.cos(dlon);
      return p;
    } else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
      p.x = this.x0 + this.a * (HALF_PI + lat) * Math.sin(dlon);
      p.y = this.y0 + this.a * (HALF_PI + lat) * Math.cos(dlon);
      return p;
    } else {
      cos_c = this.sin_p12 * sinphi + this.cos_p12 * cosphi * Math.cos(dlon);
      c = Math.acos(cos_c);
      kp = c ? c / Math.sin(c) : 1;
      p.x = this.x0 + this.a * kp * cosphi * Math.sin(dlon);
      p.y = this.y0 + this.a * kp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * Math.cos(dlon));
      return p;
    }
  } else {
    e0 = e0fn(this.es);
    e1 = e1fn(this.es);
    e2 = e2fn(this.es);
    e3 = e3fn(this.es);
    if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
      Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
      Ml = this.a * mlfn(e0, e1, e2, e3, lat);
      p.x = this.x0 + (Mlp - Ml) * Math.sin(dlon);
      p.y = this.y0 - (Mlp - Ml) * Math.cos(dlon);
      return p;
    } else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
      Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
      Ml = this.a * mlfn(e0, e1, e2, e3, lat);
      p.x = this.x0 + (Mlp + Ml) * Math.sin(dlon);
      p.y = this.y0 + (Mlp + Ml) * Math.cos(dlon);
      return p;
    } else {
      if (Math.abs(lon) < EPSLN && Math.abs(lat - this.lat0) < EPSLN) {
        p.x = p.y = 0;
        return p;
      }
      lat1 = this.lat0 / D2R$1;
      lon1 = this.long0 / D2R$1;
      lat2 = lat / D2R$1;
      lon2 = lon / D2R$1;
      vars = this.g.Inverse(lat1, lon1, lat2, lon2, this.g.AZIMUTH);
      azi1 = vars.azi1 * D2R$1;
      p.x = vars.s12 * Math.sin(azi1);
      p.y = vars.s12 * Math.cos(azi1);
      return p;
    }
  }
}
function inverse$7(p) {
  p.x -= this.x0;
  p.y -= this.y0;
  var rh, z, sinz, cosz, lon, lat, con, e0, e1, e2, e3, Mlp, M5, lat1, lon1, azi1, s12, vars;
  if (this.sphere) {
    rh = Math.sqrt(p.x * p.x + p.y * p.y);
    if (rh > 2 * HALF_PI * this.a) {
      return;
    }
    z = rh / this.a;
    sinz = Math.sin(z);
    cosz = Math.cos(z);
    lon = this.long0;
    if (Math.abs(rh) <= EPSLN) {
      lat = this.lat0;
    } else {
      lat = asinz(cosz * this.sin_p12 + p.y * sinz * this.cos_p12 / rh);
      con = Math.abs(this.lat0) - HALF_PI;
      if (Math.abs(con) <= EPSLN) {
        if (this.lat0 >= 0) {
          lon = adjust_lon(this.long0 + Math.atan2(p.x, -p.y));
        } else {
          lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
        }
      } else {
        lon = adjust_lon(this.long0 + Math.atan2(p.x * sinz, rh * this.cos_p12 * cosz - p.y * this.sin_p12 * sinz));
      }
    }
    p.x = lon;
    p.y = lat;
    return p;
  } else {
    e0 = e0fn(this.es);
    e1 = e1fn(this.es);
    e2 = e2fn(this.es);
    e3 = e3fn(this.es);
    if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
      Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
      rh = Math.sqrt(p.x * p.x + p.y * p.y);
      M5 = Mlp - rh;
      lat = imlfn(M5 / this.a, e0, e1, e2, e3);
      lon = adjust_lon(this.long0 + Math.atan2(p.x, -1 * p.y));
      p.x = lon;
      p.y = lat;
      return p;
    } else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
      Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
      rh = Math.sqrt(p.x * p.x + p.y * p.y);
      M5 = rh - Mlp;
      lat = imlfn(M5 / this.a, e0, e1, e2, e3);
      lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
      p.x = lon;
      p.y = lat;
      return p;
    } else {
      lat1 = this.lat0 / D2R$1;
      lon1 = this.long0 / D2R$1;
      azi1 = Math.atan2(p.x, p.y) / D2R$1;
      s12 = Math.sqrt(p.x * p.x + p.y * p.y);
      vars = this.g.Direct(lat1, lon1, azi1, s12, this.g.STANDARD);
      p.x = vars.lon2 * D2R$1;
      p.y = vars.lat2 * D2R$1;
      return p;
    }
  }
}
var names$8 = ["Azimuthal_Equidistant", "aeqd"];
const aeqd = {
  init: init$9,
  forward: forward$7,
  inverse: inverse$7,
  names: names$8
};
function init$8() {
  this.sin_p14 = Math.sin(this.lat0);
  this.cos_p14 = Math.cos(this.lat0);
}
function forward$6(p) {
  var sinphi, cosphi;
  var dlon;
  var coslon;
  var ksp;
  var g, x, y;
  var lon = p.x;
  var lat = p.y;
  dlon = adjust_lon(lon - this.long0);
  sinphi = Math.sin(lat);
  cosphi = Math.cos(lat);
  coslon = Math.cos(dlon);
  g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
  ksp = 1;
  if (g > 0 || Math.abs(g) <= EPSLN) {
    x = this.a * ksp * cosphi * Math.sin(dlon);
    y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
  }
  p.x = x;
  p.y = y;
  return p;
}
function inverse$6(p) {
  var rh;
  var z;
  var sinz, cosz;
  var con;
  var lon, lat;
  p.x -= this.x0;
  p.y -= this.y0;
  rh = Math.sqrt(p.x * p.x + p.y * p.y);
  z = asinz(rh / this.a);
  sinz = Math.sin(z);
  cosz = Math.cos(z);
  lon = this.long0;
  if (Math.abs(rh) <= EPSLN) {
    lat = this.lat0;
    p.x = lon;
    p.y = lat;
    return p;
  }
  lat = asinz(cosz * this.sin_p14 + p.y * sinz * this.cos_p14 / rh);
  con = Math.abs(this.lat0) - HALF_PI;
  if (Math.abs(con) <= EPSLN) {
    if (this.lat0 >= 0) {
      lon = adjust_lon(this.long0 + Math.atan2(p.x, -p.y));
    } else {
      lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
    }
    p.x = lon;
    p.y = lat;
    return p;
  }
  lon = adjust_lon(this.long0 + Math.atan2(p.x * sinz, rh * this.cos_p14 * cosz - p.y * this.sin_p14 * sinz));
  p.x = lon;
  p.y = lat;
  return p;
}
var names$7 = ["ortho"];
const ortho = {
  init: init$8,
  forward: forward$6,
  inverse: inverse$6,
  names: names$7
};
var FACE_ENUM = {
  FRONT: 1,
  RIGHT: 2,
  BACK: 3,
  LEFT: 4,
  TOP: 5,
  BOTTOM: 6
};
var AREA_ENUM = {
  AREA_0: 1,
  AREA_1: 2,
  AREA_2: 3,
  AREA_3: 4
};
function init$7() {
  this.x0 = this.x0 || 0;
  this.y0 = this.y0 || 0;
  this.lat0 = this.lat0 || 0;
  this.long0 = this.long0 || 0;
  this.lat_ts = this.lat_ts || 0;
  this.title = this.title || "Quadrilateralized Spherical Cube";
  if (this.lat0 >= HALF_PI - FORTPI / 2) {
    this.face = FACE_ENUM.TOP;
  } else if (this.lat0 <= -(HALF_PI - FORTPI / 2)) {
    this.face = FACE_ENUM.BOTTOM;
  } else if (Math.abs(this.long0) <= FORTPI) {
    this.face = FACE_ENUM.FRONT;
  } else if (Math.abs(this.long0) <= HALF_PI + FORTPI) {
    this.face = this.long0 > 0 ? FACE_ENUM.RIGHT : FACE_ENUM.LEFT;
  } else {
    this.face = FACE_ENUM.BACK;
  }
  if (this.es !== 0) {
    this.one_minus_f = 1 - (this.a - this.b) / this.a;
    this.one_minus_f_squared = this.one_minus_f * this.one_minus_f;
  }
}
function forward$5(p) {
  var xy = { x: 0, y: 0 };
  var lat, lon;
  var theta, phi;
  var t, mu;
  var area = { value: 0 };
  p.x -= this.long0;
  if (this.es !== 0) {
    lat = Math.atan(this.one_minus_f_squared * Math.tan(p.y));
  } else {
    lat = p.y;
  }
  lon = p.x;
  if (this.face === FACE_ENUM.TOP) {
    phi = HALF_PI - lat;
    if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
      area.value = AREA_ENUM.AREA_0;
      theta = lon - HALF_PI;
    } else if (lon > HALF_PI + FORTPI || lon <= -(HALF_PI + FORTPI)) {
      area.value = AREA_ENUM.AREA_1;
      theta = lon > 0 ? lon - SPI : lon + SPI;
    } else if (lon > -(HALF_PI + FORTPI) && lon <= -FORTPI) {
      area.value = AREA_ENUM.AREA_2;
      theta = lon + HALF_PI;
    } else {
      area.value = AREA_ENUM.AREA_3;
      theta = lon;
    }
  } else if (this.face === FACE_ENUM.BOTTOM) {
    phi = HALF_PI + lat;
    if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
      area.value = AREA_ENUM.AREA_0;
      theta = -lon + HALF_PI;
    } else if (lon < FORTPI && lon >= -FORTPI) {
      area.value = AREA_ENUM.AREA_1;
      theta = -lon;
    } else if (lon < -FORTPI && lon >= -(HALF_PI + FORTPI)) {
      area.value = AREA_ENUM.AREA_2;
      theta = -lon - HALF_PI;
    } else {
      area.value = AREA_ENUM.AREA_3;
      theta = lon > 0 ? -lon + SPI : -lon - SPI;
    }
  } else {
    var q, r, s;
    var sinlat, coslat;
    var sinlon, coslon;
    if (this.face === FACE_ENUM.RIGHT) {
      lon = qsc_shift_lon_origin(lon, +HALF_PI);
    } else if (this.face === FACE_ENUM.BACK) {
      lon = qsc_shift_lon_origin(lon, +SPI);
    } else if (this.face === FACE_ENUM.LEFT) {
      lon = qsc_shift_lon_origin(lon, -HALF_PI);
    }
    sinlat = Math.sin(lat);
    coslat = Math.cos(lat);
    sinlon = Math.sin(lon);
    coslon = Math.cos(lon);
    q = coslat * coslon;
    r = coslat * sinlon;
    s = sinlat;
    if (this.face === FACE_ENUM.FRONT) {
      phi = Math.acos(q);
      theta = qsc_fwd_equat_face_theta(phi, s, r, area);
    } else if (this.face === FACE_ENUM.RIGHT) {
      phi = Math.acos(r);
      theta = qsc_fwd_equat_face_theta(phi, s, -q, area);
    } else if (this.face === FACE_ENUM.BACK) {
      phi = Math.acos(-q);
      theta = qsc_fwd_equat_face_theta(phi, s, -r, area);
    } else if (this.face === FACE_ENUM.LEFT) {
      phi = Math.acos(-r);
      theta = qsc_fwd_equat_face_theta(phi, s, q, area);
    } else {
      phi = theta = 0;
      area.value = AREA_ENUM.AREA_0;
    }
  }
  mu = Math.atan(12 / SPI * (theta + Math.acos(Math.sin(theta) * Math.cos(FORTPI)) - HALF_PI));
  t = Math.sqrt((1 - Math.cos(phi)) / (Math.cos(mu) * Math.cos(mu)) / (1 - Math.cos(Math.atan(1 / Math.cos(theta)))));
  if (area.value === AREA_ENUM.AREA_1) {
    mu += HALF_PI;
  } else if (area.value === AREA_ENUM.AREA_2) {
    mu += SPI;
  } else if (area.value === AREA_ENUM.AREA_3) {
    mu += 1.5 * SPI;
  }
  xy.x = t * Math.cos(mu);
  xy.y = t * Math.sin(mu);
  xy.x = xy.x * this.a + this.x0;
  xy.y = xy.y * this.a + this.y0;
  p.x = xy.x;
  p.y = xy.y;
  return p;
}
function inverse$5(p) {
  var lp = { lam: 0, phi: 0 };
  var mu, nu, cosmu, tannu;
  var tantheta, theta, cosphi, phi;
  var t;
  var area = { value: 0 };
  p.x = (p.x - this.x0) / this.a;
  p.y = (p.y - this.y0) / this.a;
  nu = Math.atan(Math.sqrt(p.x * p.x + p.y * p.y));
  mu = Math.atan2(p.y, p.x);
  if (p.x >= 0 && p.x >= Math.abs(p.y)) {
    area.value = AREA_ENUM.AREA_0;
  } else if (p.y >= 0 && p.y >= Math.abs(p.x)) {
    area.value = AREA_ENUM.AREA_1;
    mu -= HALF_PI;
  } else if (p.x < 0 && -p.x >= Math.abs(p.y)) {
    area.value = AREA_ENUM.AREA_2;
    mu = mu < 0 ? mu + SPI : mu - SPI;
  } else {
    area.value = AREA_ENUM.AREA_3;
    mu += HALF_PI;
  }
  t = SPI / 12 * Math.tan(mu);
  tantheta = Math.sin(t) / (Math.cos(t) - 1 / Math.sqrt(2));
  theta = Math.atan(tantheta);
  cosmu = Math.cos(mu);
  tannu = Math.tan(nu);
  cosphi = 1 - cosmu * cosmu * tannu * tannu * (1 - Math.cos(Math.atan(1 / Math.cos(theta))));
  if (cosphi < -1) {
    cosphi = -1;
  } else if (cosphi > 1) {
    cosphi = 1;
  }
  if (this.face === FACE_ENUM.TOP) {
    phi = Math.acos(cosphi);
    lp.phi = HALF_PI - phi;
    if (area.value === AREA_ENUM.AREA_0) {
      lp.lam = theta + HALF_PI;
    } else if (area.value === AREA_ENUM.AREA_1) {
      lp.lam = theta < 0 ? theta + SPI : theta - SPI;
    } else if (area.value === AREA_ENUM.AREA_2) {
      lp.lam = theta - HALF_PI;
    } else {
      lp.lam = theta;
    }
  } else if (this.face === FACE_ENUM.BOTTOM) {
    phi = Math.acos(cosphi);
    lp.phi = phi - HALF_PI;
    if (area.value === AREA_ENUM.AREA_0) {
      lp.lam = -theta + HALF_PI;
    } else if (area.value === AREA_ENUM.AREA_1) {
      lp.lam = -theta;
    } else if (area.value === AREA_ENUM.AREA_2) {
      lp.lam = -theta - HALF_PI;
    } else {
      lp.lam = theta < 0 ? -theta - SPI : -theta + SPI;
    }
  } else {
    var q, r, s;
    q = cosphi;
    t = q * q;
    if (t >= 1) {
      s = 0;
    } else {
      s = Math.sqrt(1 - t) * Math.sin(theta);
    }
    t += s * s;
    if (t >= 1) {
      r = 0;
    } else {
      r = Math.sqrt(1 - t);
    }
    if (area.value === AREA_ENUM.AREA_1) {
      t = r;
      r = -s;
      s = t;
    } else if (area.value === AREA_ENUM.AREA_2) {
      r = -r;
      s = -s;
    } else if (area.value === AREA_ENUM.AREA_3) {
      t = r;
      r = s;
      s = -t;
    }
    if (this.face === FACE_ENUM.RIGHT) {
      t = q;
      q = -r;
      r = t;
    } else if (this.face === FACE_ENUM.BACK) {
      q = -q;
      r = -r;
    } else if (this.face === FACE_ENUM.LEFT) {
      t = q;
      q = r;
      r = -t;
    }
    lp.phi = Math.acos(-s) - HALF_PI;
    lp.lam = Math.atan2(r, q);
    if (this.face === FACE_ENUM.RIGHT) {
      lp.lam = qsc_shift_lon_origin(lp.lam, -HALF_PI);
    } else if (this.face === FACE_ENUM.BACK) {
      lp.lam = qsc_shift_lon_origin(lp.lam, -SPI);
    } else if (this.face === FACE_ENUM.LEFT) {
      lp.lam = qsc_shift_lon_origin(lp.lam, +HALF_PI);
    }
  }
  if (this.es !== 0) {
    var invert_sign;
    var tanphi, xa;
    invert_sign = lp.phi < 0 ? 1 : 0;
    tanphi = Math.tan(lp.phi);
    xa = this.b / Math.sqrt(tanphi * tanphi + this.one_minus_f_squared);
    lp.phi = Math.atan(Math.sqrt(this.a * this.a - xa * xa) / (this.one_minus_f * xa));
    if (invert_sign) {
      lp.phi = -lp.phi;
    }
  }
  lp.lam += this.long0;
  p.x = lp.lam;
  p.y = lp.phi;
  return p;
}
function qsc_fwd_equat_face_theta(phi, y, x, area) {
  var theta;
  if (phi < EPSLN) {
    area.value = AREA_ENUM.AREA_0;
    theta = 0;
  } else {
    theta = Math.atan2(y, x);
    if (Math.abs(theta) <= FORTPI) {
      area.value = AREA_ENUM.AREA_0;
    } else if (theta > FORTPI && theta <= HALF_PI + FORTPI) {
      area.value = AREA_ENUM.AREA_1;
      theta -= HALF_PI;
    } else if (theta > HALF_PI + FORTPI || theta <= -(HALF_PI + FORTPI)) {
      area.value = AREA_ENUM.AREA_2;
      theta = theta >= 0 ? theta - SPI : theta + SPI;
    } else {
      area.value = AREA_ENUM.AREA_3;
      theta += HALF_PI;
    }
  }
  return theta;
}
function qsc_shift_lon_origin(lon, offset2) {
  var slon = lon + offset2;
  if (slon < -SPI) {
    slon += TWO_PI;
  } else if (slon > +SPI) {
    slon -= TWO_PI;
  }
  return slon;
}
var names$6 = ["Quadrilateralized Spherical Cube", "Quadrilateralized_Spherical_Cube", "qsc"];
const qsc = {
  init: init$7,
  forward: forward$5,
  inverse: inverse$5,
  names: names$6
};
var COEFS_X = [
  [1, 22199e-21, -715515e-10, 31103e-10],
  [0.9986, -482243e-9, -24897e-9, -13309e-10],
  [0.9954, -83103e-8, -448605e-10, -986701e-12],
  [0.99, -135364e-8, -59661e-9, 36777e-10],
  [0.9822, -167442e-8, -449547e-11, -572411e-11],
  [0.973, -214868e-8, -903571e-10, 18736e-12],
  [0.96, -305085e-8, -900761e-10, 164917e-11],
  [0.9427, -382792e-8, -653386e-10, -26154e-10],
  [0.9216, -467746e-8, -10457e-8, 481243e-11],
  [0.8962, -536223e-8, -323831e-10, -543432e-11],
  [0.8679, -609363e-8, -113898e-9, 332484e-11],
  [0.835, -698325e-8, -640253e-10, 934959e-12],
  [0.7986, -755338e-8, -500009e-10, 935324e-12],
  [0.7597, -798324e-8, -35971e-9, -227626e-11],
  [0.7186, -851367e-8, -701149e-10, -86303e-10],
  [0.6732, -986209e-8, -199569e-9, 191974e-10],
  [0.6213, -0.010418, 883923e-10, 624051e-11],
  [0.5722, -906601e-8, 182e-6, 624051e-11],
  [0.5322, -677797e-8, 275608e-9, 624051e-11]
];
var COEFS_Y = [
  [-520417e-23, 0.0124, 121431e-23, -845284e-16],
  [0.062, 0.0124, -126793e-14, 422642e-15],
  [0.124, 0.0124, 507171e-14, -160604e-14],
  [0.186, 0.0123999, -190189e-13, 600152e-14],
  [0.248, 0.0124002, 710039e-13, -224e-10],
  [0.31, 0.0123992, -264997e-12, 835986e-13],
  [0.372, 0.0124029, 988983e-12, -311994e-12],
  [0.434, 0.0123893, -369093e-11, -435621e-12],
  [0.4958, 0.0123198, -102252e-10, -345523e-12],
  [0.5571, 0.0121916, -154081e-10, -582288e-12],
  [0.6176, 0.0119938, -241424e-10, -525327e-12],
  [0.6769, 0.011713, -320223e-10, -516405e-12],
  [0.7346, 0.0113541, -397684e-10, -609052e-12],
  [0.7903, 0.0109107, -489042e-10, -104739e-11],
  [0.8435, 0.0103431, -64615e-9, -140374e-14],
  [0.8936, 969686e-8, -64636e-9, -8547e-9],
  [0.9394, 840947e-8, -192841e-9, -42106e-10],
  [0.9761, 616527e-8, -256e-6, -42106e-10],
  [1, 328947e-8, -319159e-9, -42106e-10]
];
var FXC = 0.8487;
var FYC = 1.3523;
var C1 = R2D / 5;
var RC1 = 1 / C1;
var NODES = 18;
var poly3_val = function(coefs, x) {
  return coefs[0] + x * (coefs[1] + x * (coefs[2] + x * coefs[3]));
};
var poly3_der = function(coefs, x) {
  return coefs[1] + x * (2 * coefs[2] + x * 3 * coefs[3]);
};
function newton_rapshon(f_df, start2, max_err, iters) {
  var x = start2;
  for (; iters; --iters) {
    var upd = f_df(x);
    x -= upd;
    if (Math.abs(upd) < max_err) {
      break;
    }
  }
  return x;
}
function init$6() {
  this.x0 = this.x0 || 0;
  this.y0 = this.y0 || 0;
  this.long0 = this.long0 || 0;
  this.es = 0;
  this.title = this.title || "Robinson";
}
function forward$4(ll) {
  var lon = adjust_lon(ll.x - this.long0);
  var dphi = Math.abs(ll.y);
  var i = Math.floor(dphi * C1);
  if (i < 0) {
    i = 0;
  } else if (i >= NODES) {
    i = NODES - 1;
  }
  dphi = R2D * (dphi - RC1 * i);
  var xy = {
    x: poly3_val(COEFS_X[i], dphi) * lon,
    y: poly3_val(COEFS_Y[i], dphi)
  };
  if (ll.y < 0) {
    xy.y = -xy.y;
  }
  xy.x = xy.x * this.a * FXC + this.x0;
  xy.y = xy.y * this.a * FYC + this.y0;
  return xy;
}
function inverse$4(xy) {
  var ll = {
    x: (xy.x - this.x0) / (this.a * FXC),
    y: Math.abs(xy.y - this.y0) / (this.a * FYC)
  };
  if (ll.y >= 1) {
    ll.x /= COEFS_X[NODES][0];
    ll.y = xy.y < 0 ? -HALF_PI : HALF_PI;
  } else {
    var i = Math.floor(ll.y * NODES);
    if (i < 0) {
      i = 0;
    } else if (i >= NODES) {
      i = NODES - 1;
    }
    for (; ; ) {
      if (COEFS_Y[i][0] > ll.y) {
        --i;
      } else if (COEFS_Y[i + 1][0] <= ll.y) {
        ++i;
      } else {
        break;
      }
    }
    var coefs = COEFS_Y[i];
    var t = 5 * (ll.y - coefs[0]) / (COEFS_Y[i + 1][0] - coefs[0]);
    t = newton_rapshon(function(x) {
      return (poly3_val(coefs, x) - ll.y) / poly3_der(coefs, x);
    }, t, EPSLN, 100);
    ll.x /= poly3_val(COEFS_X[i], t);
    ll.y = (5 * i + t) * D2R$1;
    if (xy.y < 0) {
      ll.y = -ll.y;
    }
  }
  ll.x = adjust_lon(ll.x + this.long0);
  return ll;
}
var names$5 = ["Robinson", "robin"];
const robin = {
  init: init$6,
  forward: forward$4,
  inverse: inverse$4,
  names: names$5
};
function init$5() {
  this.name = "geocent";
}
function forward$3(p) {
  var point = geodeticToGeocentric(p, this.es, this.a);
  return point;
}
function inverse$3(p) {
  var point = geocentricToGeodetic(p, this.es, this.a, this.b);
  return point;
}
var names$4 = ["Geocentric", "geocentric", "geocent", "Geocent"];
const geocent = {
  init: init$5,
  forward: forward$3,
  inverse: inverse$3,
  names: names$4
};
var mode = {
  N_POLE: 0,
  S_POLE: 1,
  EQUIT: 2,
  OBLIQ: 3
};
var params = {
  h: { def: 1e5, num: true },
  // default is Karman line, no default in PROJ.7
  azi: { def: 0, num: true, degrees: true },
  // default is North
  tilt: { def: 0, num: true, degrees: true },
  // default is Nadir
  long0: { def: 0, num: true },
  // default is Greenwich, conversion to rad is automatic
  lat0: { def: 0, num: true }
  // default is Equator, conversion to rad is automatic
};
function init$4() {
  Object.keys(params).forEach(function(p) {
    if (typeof this[p] === "undefined") {
      this[p] = params[p].def;
    } else if (params[p].num && isNaN(this[p])) {
      throw new Error("Invalid parameter value, must be numeric " + p + " = " + this[p]);
    } else if (params[p].num) {
      this[p] = parseFloat(this[p]);
    }
    if (params[p].degrees) {
      this[p] = this[p] * D2R$1;
    }
  }.bind(this));
  if (Math.abs(Math.abs(this.lat0) - HALF_PI) < EPSLN) {
    this.mode = this.lat0 < 0 ? mode.S_POLE : mode.N_POLE;
  } else if (Math.abs(this.lat0) < EPSLN) {
    this.mode = mode.EQUIT;
  } else {
    this.mode = mode.OBLIQ;
    this.sinph0 = Math.sin(this.lat0);
    this.cosph0 = Math.cos(this.lat0);
  }
  this.pn1 = this.h / this.a;
  if (this.pn1 <= 0 || this.pn1 > 1e10) {
    throw new Error("Invalid height");
  }
  this.p = 1 + this.pn1;
  this.rp = 1 / this.p;
  this.h1 = 1 / this.pn1;
  this.pfact = (this.p + 1) * this.h1;
  this.es = 0;
  var omega = this.tilt;
  var gamma = this.azi;
  this.cg = Math.cos(gamma);
  this.sg = Math.sin(gamma);
  this.cw = Math.cos(omega);
  this.sw = Math.sin(omega);
}
function forward$2(p) {
  p.x -= this.long0;
  var sinphi = Math.sin(p.y);
  var cosphi = Math.cos(p.y);
  var coslam = Math.cos(p.x);
  var x, y;
  switch (this.mode) {
    case mode.OBLIQ:
      y = this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
      break;
    case mode.EQUIT:
      y = cosphi * coslam;
      break;
    case mode.S_POLE:
      y = -sinphi;
      break;
    case mode.N_POLE:
      y = sinphi;
      break;
  }
  y = this.pn1 / (this.p - y);
  x = y * cosphi * Math.sin(p.x);
  switch (this.mode) {
    case mode.OBLIQ:
      y *= this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
      break;
    case mode.EQUIT:
      y *= sinphi;
      break;
    case mode.N_POLE:
      y *= -(cosphi * coslam);
      break;
    case mode.S_POLE:
      y *= cosphi * coslam;
      break;
  }
  var yt, ba;
  yt = y * this.cg + x * this.sg;
  ba = 1 / (yt * this.sw * this.h1 + this.cw);
  x = (x * this.cg - y * this.sg) * this.cw * ba;
  y = yt * ba;
  p.x = x * this.a;
  p.y = y * this.a;
  return p;
}
function inverse$2(p) {
  p.x /= this.a;
  p.y /= this.a;
  var r = { x: p.x, y: p.y };
  var bm, bq, yt;
  yt = 1 / (this.pn1 - p.y * this.sw);
  bm = this.pn1 * p.x * yt;
  bq = this.pn1 * p.y * this.cw * yt;
  p.x = bm * this.cg + bq * this.sg;
  p.y = bq * this.cg - bm * this.sg;
  var rh = hypot(p.x, p.y);
  if (Math.abs(rh) < EPSLN) {
    r.x = 0;
    r.y = p.y;
  } else {
    var cosz, sinz;
    sinz = 1 - rh * rh * this.pfact;
    sinz = (this.p - Math.sqrt(sinz)) / (this.pn1 / rh + rh / this.pn1);
    cosz = Math.sqrt(1 - sinz * sinz);
    switch (this.mode) {
      case mode.OBLIQ:
        r.y = Math.asin(cosz * this.sinph0 + p.y * sinz * this.cosph0 / rh);
        p.y = (cosz - this.sinph0 * Math.sin(r.y)) * rh;
        p.x *= sinz * this.cosph0;
        break;
      case mode.EQUIT:
        r.y = Math.asin(p.y * sinz / rh);
        p.y = cosz * rh;
        p.x *= sinz;
        break;
      case mode.N_POLE:
        r.y = Math.asin(cosz);
        p.y = -p.y;
        break;
      case mode.S_POLE:
        r.y = -Math.asin(cosz);
        break;
    }
    r.x = Math.atan2(p.x, p.y);
  }
  p.x = r.x + this.long0;
  p.y = r.y;
  return p;
}
var names$3 = ["Tilted_Perspective", "tpers"];
const tpers = {
  init: init$4,
  forward: forward$2,
  inverse: inverse$2,
  names: names$3
};
function init$3() {
  this.flip_axis = this.sweep === "x" ? 1 : 0;
  this.h = Number(this.h);
  this.radius_g_1 = this.h / this.a;
  if (this.radius_g_1 <= 0 || this.radius_g_1 > 1e10) {
    throw new Error();
  }
  this.radius_g = 1 + this.radius_g_1;
  this.C = this.radius_g * this.radius_g - 1;
  if (this.es !== 0) {
    var one_es = 1 - this.es;
    var rone_es = 1 / one_es;
    this.radius_p = Math.sqrt(one_es);
    this.radius_p2 = one_es;
    this.radius_p_inv2 = rone_es;
    this.shape = "ellipse";
  } else {
    this.radius_p = 1;
    this.radius_p2 = 1;
    this.radius_p_inv2 = 1;
    this.shape = "sphere";
  }
  if (!this.title) {
    this.title = "Geostationary Satellite View";
  }
}
function forward$1(p) {
  var lon = p.x;
  var lat = p.y;
  var tmp, v_x, v_y, v_z;
  lon = lon - this.long0;
  if (this.shape === "ellipse") {
    lat = Math.atan(this.radius_p2 * Math.tan(lat));
    var r = this.radius_p / hypot(this.radius_p * Math.cos(lat), Math.sin(lat));
    v_x = r * Math.cos(lon) * Math.cos(lat);
    v_y = r * Math.sin(lon) * Math.cos(lat);
    v_z = r * Math.sin(lat);
    if ((this.radius_g - v_x) * v_x - v_y * v_y - v_z * v_z * this.radius_p_inv2 < 0) {
      p.x = Number.NaN;
      p.y = Number.NaN;
      return p;
    }
    tmp = this.radius_g - v_x;
    if (this.flip_axis) {
      p.x = this.radius_g_1 * Math.atan(v_y / hypot(v_z, tmp));
      p.y = this.radius_g_1 * Math.atan(v_z / tmp);
    } else {
      p.x = this.radius_g_1 * Math.atan(v_y / tmp);
      p.y = this.radius_g_1 * Math.atan(v_z / hypot(v_y, tmp));
    }
  } else if (this.shape === "sphere") {
    tmp = Math.cos(lat);
    v_x = Math.cos(lon) * tmp;
    v_y = Math.sin(lon) * tmp;
    v_z = Math.sin(lat);
    tmp = this.radius_g - v_x;
    if (this.flip_axis) {
      p.x = this.radius_g_1 * Math.atan(v_y / hypot(v_z, tmp));
      p.y = this.radius_g_1 * Math.atan(v_z / tmp);
    } else {
      p.x = this.radius_g_1 * Math.atan(v_y / tmp);
      p.y = this.radius_g_1 * Math.atan(v_z / hypot(v_y, tmp));
    }
  }
  p.x = p.x * this.a;
  p.y = p.y * this.a;
  return p;
}
function inverse$1(p) {
  var v_x = -1;
  var v_y = 0;
  var v_z = 0;
  var a, b, det, k;
  p.x = p.x / this.a;
  p.y = p.y / this.a;
  if (this.shape === "ellipse") {
    if (this.flip_axis) {
      v_z = Math.tan(p.y / this.radius_g_1);
      v_y = Math.tan(p.x / this.radius_g_1) * hypot(1, v_z);
    } else {
      v_y = Math.tan(p.x / this.radius_g_1);
      v_z = Math.tan(p.y / this.radius_g_1) * hypot(1, v_y);
    }
    var v_zp = v_z / this.radius_p;
    a = v_y * v_y + v_zp * v_zp + v_x * v_x;
    b = 2 * this.radius_g * v_x;
    det = b * b - 4 * a * this.C;
    if (det < 0) {
      p.x = Number.NaN;
      p.y = Number.NaN;
      return p;
    }
    k = (-b - Math.sqrt(det)) / (2 * a);
    v_x = this.radius_g + k * v_x;
    v_y *= k;
    v_z *= k;
    p.x = Math.atan2(v_y, v_x);
    p.y = Math.atan(v_z * Math.cos(p.x) / v_x);
    p.y = Math.atan(this.radius_p_inv2 * Math.tan(p.y));
  } else if (this.shape === "sphere") {
    if (this.flip_axis) {
      v_z = Math.tan(p.y / this.radius_g_1);
      v_y = Math.tan(p.x / this.radius_g_1) * Math.sqrt(1 + v_z * v_z);
    } else {
      v_y = Math.tan(p.x / this.radius_g_1);
      v_z = Math.tan(p.y / this.radius_g_1) * Math.sqrt(1 + v_y * v_y);
    }
    a = v_y * v_y + v_z * v_z + v_x * v_x;
    b = 2 * this.radius_g * v_x;
    det = b * b - 4 * a * this.C;
    if (det < 0) {
      p.x = Number.NaN;
      p.y = Number.NaN;
      return p;
    }
    k = (-b - Math.sqrt(det)) / (2 * a);
    v_x = this.radius_g + k * v_x;
    v_y *= k;
    v_z *= k;
    p.x = Math.atan2(v_y, v_x);
    p.y = Math.atan(v_z * Math.cos(p.x) / v_x);
  }
  p.x = p.x + this.long0;
  return p;
}
var names$2 = ["Geostationary Satellite View", "Geostationary_Satellite", "geos"];
const geos = {
  init: init$3,
  forward: forward$1,
  inverse: inverse$1,
  names: names$2
};
var A1 = 1.340264, A2 = -0.081106, A3 = 893e-6, A4 = 3796e-6, M = Math.sqrt(3) / 2;
function init$2() {
  this.es = 0;
  this.long0 = this.long0 !== void 0 ? this.long0 : 0;
}
function forward(p) {
  var lam = adjust_lon(p.x - this.long0);
  var phi = p.y;
  var paramLat = Math.asin(M * Math.sin(phi)), paramLatSq = paramLat * paramLat, paramLatPow6 = paramLatSq * paramLatSq * paramLatSq;
  p.x = lam * Math.cos(paramLat) / (M * (A1 + 3 * A2 * paramLatSq + paramLatPow6 * (7 * A3 + 9 * A4 * paramLatSq)));
  p.y = paramLat * (A1 + A2 * paramLatSq + paramLatPow6 * (A3 + A4 * paramLatSq));
  p.x = this.a * p.x + this.x0;
  p.y = this.a * p.y + this.y0;
  return p;
}
function inverse(p) {
  p.x = (p.x - this.x0) / this.a;
  p.y = (p.y - this.y0) / this.a;
  var EPS = 1e-9, NITER = 12, paramLat = p.y, paramLatSq, paramLatPow6, fy, fpy, dlat, i;
  for (i = 0; i < NITER; ++i) {
    paramLatSq = paramLat * paramLat;
    paramLatPow6 = paramLatSq * paramLatSq * paramLatSq;
    fy = paramLat * (A1 + A2 * paramLatSq + paramLatPow6 * (A3 + A4 * paramLatSq)) - p.y;
    fpy = A1 + 3 * A2 * paramLatSq + paramLatPow6 * (7 * A3 + 9 * A4 * paramLatSq);
    paramLat -= dlat = fy / fpy;
    if (Math.abs(dlat) < EPS) {
      break;
    }
  }
  paramLatSq = paramLat * paramLat;
  paramLatPow6 = paramLatSq * paramLatSq * paramLatSq;
  p.x = M * p.x * (A1 + 3 * A2 * paramLatSq + paramLatPow6 * (7 * A3 + 9 * A4 * paramLatSq)) / Math.cos(paramLat);
  p.y = Math.asin(Math.sin(paramLat) / M);
  p.x = adjust_lon(p.x + this.long0);
  return p;
}
var names$1 = ["eqearth", "Equal Earth", "Equal_Earth"];
const eqearth = {
  init: init$2,
  forward,
  inverse,
  names: names$1
};
var EPS10 = 1e-10;
function init$1() {
  var c;
  this.phi1 = this.lat1;
  if (Math.abs(this.phi1) < EPS10) {
    throw new Error();
  }
  if (this.es) {
    this.en = pj_enfn(this.es);
    this.m1 = pj_mlfn(
      this.phi1,
      this.am1 = Math.sin(this.phi1),
      c = Math.cos(this.phi1),
      this.en
    );
    this.am1 = c / (Math.sqrt(1 - this.es * this.am1 * this.am1) * this.am1);
    this.inverse = e_inv;
    this.forward = e_fwd;
  } else {
    if (Math.abs(this.phi1) + EPS10 >= HALF_PI) {
      this.cphi1 = 0;
    } else {
      this.cphi1 = 1 / Math.tan(this.phi1);
    }
    this.inverse = s_inv;
    this.forward = s_fwd;
  }
}
function e_fwd(p) {
  var lam = adjust_lon(p.x - (this.long0 || 0));
  var phi = p.y;
  var rh, E4, c;
  rh = this.am1 + this.m1 - pj_mlfn(phi, E4 = Math.sin(phi), c = Math.cos(phi), this.en);
  E4 = c * lam / (rh * Math.sqrt(1 - this.es * E4 * E4));
  p.x = rh * Math.sin(E4);
  p.y = this.am1 - rh * Math.cos(E4);
  p.x = this.a * p.x + (this.x0 || 0);
  p.y = this.a * p.y + (this.y0 || 0);
  return p;
}
function e_inv(p) {
  p.x = (p.x - (this.x0 || 0)) / this.a;
  p.y = (p.y - (this.y0 || 0)) / this.a;
  var s, rh, lam, phi;
  rh = hypot(p.x, p.y = this.am1 - p.y);
  phi = pj_inv_mlfn(this.am1 + this.m1 - rh, this.es, this.en);
  if ((s = Math.abs(phi)) < HALF_PI) {
    s = Math.sin(phi);
    lam = rh * Math.atan2(p.x, p.y) * Math.sqrt(1 - this.es * s * s) / Math.cos(phi);
  } else if (Math.abs(s - HALF_PI) <= EPS10) {
    lam = 0;
  } else {
    throw new Error();
  }
  p.x = adjust_lon(lam + (this.long0 || 0));
  p.y = adjust_lat(phi);
  return p;
}
function s_fwd(p) {
  var lam = adjust_lon(p.x - (this.long0 || 0));
  var phi = p.y;
  var E4, rh;
  rh = this.cphi1 + this.phi1 - phi;
  if (Math.abs(rh) > EPS10) {
    p.x = rh * Math.sin(E4 = lam * Math.cos(phi) / rh);
    p.y = this.cphi1 - rh * Math.cos(E4);
  } else {
    p.x = p.y = 0;
  }
  p.x = this.a * p.x + (this.x0 || 0);
  p.y = this.a * p.y + (this.y0 || 0);
  return p;
}
function s_inv(p) {
  p.x = (p.x - (this.x0 || 0)) / this.a;
  p.y = (p.y - (this.y0 || 0)) / this.a;
  var lam, phi;
  var rh = hypot(p.x, p.y = this.cphi1 - p.y);
  phi = this.cphi1 + this.phi1 - rh;
  if (Math.abs(phi) > HALF_PI) {
    throw new Error();
  }
  if (Math.abs(Math.abs(phi) - HALF_PI) <= EPS10) {
    lam = 0;
  } else {
    lam = rh * Math.atan2(p.x, p.y) / Math.cos(phi);
  }
  p.x = adjust_lon(lam + (this.long0 || 0));
  p.y = adjust_lat(phi);
  return p;
}
var names = ["bonne", "Bonne (Werner lat_1=90)"];
const bonne = {
  init: init$1,
  names
};
function includedProjections(proj42) {
  proj42.Proj.projections.add(tmerc);
  proj42.Proj.projections.add(etmerc);
  proj42.Proj.projections.add(utm);
  proj42.Proj.projections.add(sterea);
  proj42.Proj.projections.add(stere);
  proj42.Proj.projections.add(somerc);
  proj42.Proj.projections.add(omerc);
  proj42.Proj.projections.add(lcc);
  proj42.Proj.projections.add(krovak);
  proj42.Proj.projections.add(cass);
  proj42.Proj.projections.add(laea);
  proj42.Proj.projections.add(aea);
  proj42.Proj.projections.add(gnom);
  proj42.Proj.projections.add(cea);
  proj42.Proj.projections.add(eqc);
  proj42.Proj.projections.add(poly);
  proj42.Proj.projections.add(nzmg);
  proj42.Proj.projections.add(mill);
  proj42.Proj.projections.add(sinu);
  proj42.Proj.projections.add(moll);
  proj42.Proj.projections.add(eqdc);
  proj42.Proj.projections.add(vandg);
  proj42.Proj.projections.add(aeqd);
  proj42.Proj.projections.add(ortho);
  proj42.Proj.projections.add(qsc);
  proj42.Proj.projections.add(robin);
  proj42.Proj.projections.add(geocent);
  proj42.Proj.projections.add(tpers);
  proj42.Proj.projections.add(geos);
  proj42.Proj.projections.add(eqearth);
  proj42.Proj.projections.add(bonne);
}
proj4.defaultDatum = "WGS84";
proj4.Proj = Projection;
proj4.WGS84 = new proj4.Proj("WGS84");
proj4.Point = Point;
proj4.toPoint = common;
proj4.defs = defs;
proj4.nadgrid = nadgrid;
proj4.transform = transform;
proj4.mgrs = mgrs;
proj4.version = "__VERSION__";
includedProjections(proj4);
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
function convertToCoordinateArray(coordinate) {
  return [coordinate.x, coordinate.y];
}
function convertToGeoJSONCoordinateArray(coordinates2) {
  return coordinates2.map((linearRing2) => linearRing2.map((coordinate) => convertToCoordinateArray(coordinate)));
}
function convertToSizeArray(size) {
  return [size.width, size.height];
}
function convertEnumValue(enumValue) {
  return enumValue.toLowerCase().replace(/_/, "-");
}
function synchronizeCollection(collection, updatedIds, options2) {
  const hasChanges = updatedIds.length !== collection.getLength() || collection.getArray().some((existingItem, index) => existingItem !== options2.lookup.get(updatedIds[index]));
  if (!hasChanges) return;
  const updatedItems = updatedIds.map((id) => options2.lookup.get(id)).filter((item) => !!item);
  collection.clear();
  updatedItems.forEach((item) => collection.push(item));
}
function createOptions(configurationObject) {
  const options2 = { ...configurationObject };
  Object.keys(configurationObject).forEach((key2) => {
    const value = configurationObject[key2];
    if (value === null) {
      delete options2[key2];
    }
  });
  return options2;
}
function synchronizeAttribution(target, source) {
  if (!target) {
    target = new Attribution(createOptions(source));
  }
  return target;
}
function synchronizeScaleLine(target, source) {
  const options2 = createOptions({
    minWidth: source.minWidth,
    maxWidth: source.maxWidth,
    units: convertEnumValue(source.units),
    bar: source.displayMode === "BAR",
    steps: source.scaleBarSteps,
    text: source.scaleBarRatioVisible
  });
  return new ScaleLine(options2);
}
function synchronizeZoom(target, source) {
  if (!target) {
    target = new Zoom(createOptions(source));
  }
  return target;
}
class CanvasImageLayerRenderer extends CanvasLayerRenderer {
  /**
   * @param {import("../../layer/Image.js").default} imageLayer Image layer.
   */
  constructor(imageLayer) {
    super(imageLayer);
    this.image = null;
  }
  /**
   * @return {import('../../DataTile.js').ImageLike} Image.
   */
  getImage() {
    return !this.image ? null : this.image.getImage();
  }
  /**
   * Determine whether render should be called.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @return {boolean} Layer is ready to be rendered.
   * @override
   */
  prepareFrame(frameState) {
    const layerState = frameState.layerStatesArray[frameState.layerIndex];
    const pixelRatio = frameState.pixelRatio;
    const viewState = frameState.viewState;
    const viewResolution = viewState.resolution;
    const imageSource = this.getLayer().getSource();
    const hints = frameState.viewHints;
    let renderedExtent = frameState.extent;
    if (layerState.extent !== void 0) {
      renderedExtent = getIntersection(
        renderedExtent,
        fromUserExtent(layerState.extent, viewState.projection)
      );
    }
    if (!hints[ViewHint.ANIMATING] && !hints[ViewHint.INTERACTING] && !isEmpty(renderedExtent)) {
      if (imageSource) {
        const projection = viewState.projection;
        const image = imageSource.getImage(
          renderedExtent,
          viewResolution,
          pixelRatio,
          projection
        );
        if (image) {
          if (this.loadImage(image)) {
            this.image = image;
          } else if (image.getState() === ImageState.EMPTY) {
            this.image = null;
          }
        }
      } else {
        this.image = null;
      }
    }
    return !!this.image;
  }
  /**
   * @param {import("../../pixel.js").Pixel} pixel Pixel.
   * @return {Uint8ClampedArray} Data at the pixel location.
   * @override
   */
  getData(pixel) {
    const frameState = this.frameState;
    if (!frameState) {
      return null;
    }
    const layer = this.getLayer();
    const coordinate = apply(
      frameState.pixelToCoordinateTransform,
      pixel.slice()
    );
    const layerExtent = layer.getExtent();
    if (layerExtent) {
      if (!containsCoordinate(layerExtent, coordinate)) {
        return null;
      }
    }
    const imageExtent = this.image.getExtent();
    const img = this.image.getImage();
    const imageMapWidth = getWidth(imageExtent);
    const col = Math.floor(
      img.width * ((coordinate[0] - imageExtent[0]) / imageMapWidth)
    );
    if (col < 0 || col >= img.width) {
      return null;
    }
    const imageMapHeight = getHeight(imageExtent);
    const row = Math.floor(
      img.height * ((imageExtent[3] - coordinate[1]) / imageMapHeight)
    );
    if (row < 0 || row >= img.height) {
      return null;
    }
    return this.getImageData(img, col, row);
  }
  /**
   * Render the layer.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {HTMLElement} target Target that may be used to render content to.
   * @return {HTMLElement} The rendered element.
   * @override
   */
  renderFrame(frameState, target) {
    const image = this.image;
    const imageExtent = image.getExtent();
    const imageResolution = image.getResolution();
    const [imageResolutionX, imageResolutionY] = Array.isArray(imageResolution) ? imageResolution : [imageResolution, imageResolution];
    const imagePixelRatio = image.getPixelRatio();
    const layerState = frameState.layerStatesArray[frameState.layerIndex];
    const pixelRatio = frameState.pixelRatio;
    const viewState = frameState.viewState;
    const viewCenter = viewState.center;
    const viewResolution = viewState.resolution;
    const scaleX = pixelRatio * imageResolutionX / (viewResolution * imagePixelRatio);
    const scaleY = pixelRatio * imageResolutionY / (viewResolution * imagePixelRatio);
    this.prepareContainer(frameState, target);
    const width = this.context.canvas.width;
    const height = this.context.canvas.height;
    const context = this.getRenderContext(frameState);
    let clipped = false;
    let render2 = true;
    if (layerState.extent) {
      const layerExtent = fromUserExtent(
        layerState.extent,
        viewState.projection
      );
      render2 = intersects$1(layerExtent, frameState.extent);
      clipped = render2 && !containsExtent(layerExtent, frameState.extent);
      if (clipped) {
        this.clipUnrotated(context, frameState, layerExtent);
      }
    }
    const img = image.getImage();
    const transform2 = compose(
      this.tempTransform,
      width / 2,
      height / 2,
      scaleX,
      scaleY,
      0,
      imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolutionX,
      imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolutionY
    );
    this.renderedResolution = imageResolutionY * pixelRatio / imagePixelRatio;
    const dw = img.width * transform2[0];
    const dh = img.height * transform2[3];
    if (!this.getLayer().getSource().getInterpolate()) {
      context.imageSmoothingEnabled = false;
    }
    this.preRender(context, frameState);
    if (render2 && dw >= 0.5 && dh >= 0.5) {
      const dx = transform2[4];
      const dy = transform2[5];
      const opacity = layerState.opacity;
      if (opacity !== 1) {
        context.save();
        context.globalAlpha = opacity;
      }
      context.drawImage(img, 0, 0, +img.width, +img.height, dx, dy, dw, dh);
      if (opacity !== 1) {
        context.restore();
      }
    }
    this.postRender(this.context, frameState);
    if (clipped) {
      context.restore();
    }
    context.imageSmoothingEnabled = true;
    return this.container;
  }
}
class BaseImageLayer extends Layer {
  /**
   * @param {Options<ImageSourceType>} [options] Layer options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super(options2);
  }
}
class ImageLayer extends BaseImageLayer {
  /**
   * @param {import("./BaseImage.js").Options<ImageSourceType>} [options] Layer options.
   */
  constructor(options2) {
    super(options2);
  }
  /**
   * @override
   */
  createRenderer() {
    return new CanvasImageLayerRenderer(this);
  }
  /**
   * Get data for a pixel location.  A four element RGBA array will be returned.  For requests outside the
   * layer extent, `null` will be returned.  Data for an image can only be retrieved if the
   * source's `crossOrigin` property is set.
   *
   * ```js
   * // display layer data on every pointer move
   * map.on('pointermove', (event) => {
   *   console.log(layer.getData(event.pixel));
   * });
   * ```
   * @param {import("../pixel").Pixel} pixel Pixel.
   * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data.
   * @api
   * @override
   */
  getData(pixel) {
    return super.getData(pixel);
  }
}
class Tile extends Target {
  /**
   * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("./TileState.js").default} state State.
   * @param {Options} [options] Tile options.
   */
  constructor(tileCoord, state, options2) {
    super();
    options2 = options2 ? options2 : {};
    this.tileCoord = tileCoord;
    this.state = state;
    this.key = "";
    this.transition_ = options2.transition === void 0 ? 250 : options2.transition;
    this.transitionStarts_ = {};
    this.interpolate = !!options2.interpolate;
  }
  /**
   * @protected
   */
  changed() {
    this.dispatchEvent(EventType.CHANGE);
  }
  /**
   * Called by the tile cache when the tile is removed from the cache due to expiry
   */
  release() {
    this.setState(TileState.EMPTY);
  }
  /**
   * @return {string} Key.
   */
  getKey() {
    return this.key + "/" + this.tileCoord;
  }
  /**
   * Get the tile coordinate for this tile.
   * @return {import("./tilecoord.js").TileCoord} The tile coordinate.
   * @api
   */
  getTileCoord() {
    return this.tileCoord;
  }
  /**
   * @return {import("./TileState.js").default} State.
   */
  getState() {
    return this.state;
  }
  /**
   * Sets the state of this tile. If you write your own {@link module:ol/Tile~LoadFunction tileLoadFunction} ,
   * it is important to set the state correctly to {@link module:ol/TileState~ERROR}
   * when the tile cannot be loaded. Otherwise the tile cannot be removed from
   * the tile queue and will block other requests.
   * @param {import("./TileState.js").default} state State.
   * @api
   */
  setState(state) {
    if (this.state === TileState.EMPTY) {
      return;
    }
    if (this.state !== TileState.ERROR && this.state > state) {
      throw new Error("Tile load sequence violation");
    }
    this.state = state;
    this.changed();
  }
  /**
   * Load the image or retry if loading previously failed.
   * Loading is taken care of by the tile queue, and calling this method is
   * only needed for preloading or for reloading in case of an error.
   * @abstract
   * @api
   */
  load() {
    abstract();
  }
  /**
   * Get the alpha value for rendering.
   * @param {string} id An id for the renderer.
   * @param {number} time The render frame time.
   * @return {number} A number between 0 and 1.
   */
  getAlpha(id, time) {
    if (!this.transition_) {
      return 1;
    }
    let start2 = this.transitionStarts_[id];
    if (!start2) {
      start2 = time;
      this.transitionStarts_[id] = start2;
    } else if (start2 === -1) {
      return 1;
    }
    const delta = time - start2 + 1e3 / 60;
    if (delta >= this.transition_) {
      return 1;
    }
    return easeIn(delta / this.transition_);
  }
  /**
   * Determine if a tile is in an alpha transition.  A tile is considered in
   * transition if tile.getAlpha() has not yet been called or has been called
   * and returned 1.
   * @param {string} id An id for the renderer.
   * @return {boolean} The tile is in transition.
   */
  inTransition(id) {
    if (!this.transition_) {
      return false;
    }
    return this.transitionStarts_[id] !== -1;
  }
  /**
   * Mark a transition as complete.
   * @param {string} id An id for the renderer.
   */
  endTransition(id) {
    if (this.transition_) {
      this.transitionStarts_[id] = -1;
    }
  }
  /**
   * @override
   */
  disposeInternal() {
    this.release();
    super.disposeInternal();
  }
}
function asImageLike(data) {
  return data instanceof Image || data instanceof HTMLCanvasElement || data instanceof HTMLVideoElement || data instanceof ImageBitmap ? data : null;
}
const disposedError = new Error("disposed");
const defaultSize = [256, 256];
class DataTile extends Tile {
  /**
   * @param {Options} options Tile options.
   */
  constructor(options2) {
    const state = TileState.IDLE;
    super(options2.tileCoord, state, {
      transition: options2.transition,
      interpolate: options2.interpolate
    });
    this.loader_ = options2.loader;
    this.data_ = null;
    this.error_ = null;
    this.size_ = options2.size || null;
    this.controller_ = options2.controller || null;
  }
  /**
   * Get the tile size.
   * @return {import('./size.js').Size} Tile size.
   */
  getSize() {
    if (this.size_) {
      return this.size_;
    }
    const imageData = asImageLike(this.data_);
    if (imageData) {
      return [imageData.width, imageData.height];
    }
    return defaultSize;
  }
  /**
   * Get the data for the tile.
   * @return {Data} Tile data.
   * @api
   */
  getData() {
    return this.data_;
  }
  /**
   * Get any loading error.
   * @return {Error} Loading error.
   * @api
   */
  getError() {
    return this.error_;
  }
  /**
   * Load the tile data.
   * @api
   * @override
   */
  load() {
    if (this.state !== TileState.IDLE && this.state !== TileState.ERROR) {
      return;
    }
    this.state = TileState.LOADING;
    this.changed();
    const self2 = this;
    this.loader_().then(function(data) {
      self2.data_ = data;
      self2.state = TileState.LOADED;
      self2.changed();
    }).catch(function(error2) {
      self2.error_ = error2;
      self2.state = TileState.ERROR;
      self2.changed();
    });
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    if (this.controller_) {
      this.controller_.abort(disposedError);
      this.controller_ = null;
    }
    super.disposeInternal();
  }
}
class ImageTile extends Tile {
  /**
   * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("./TileState.js").default} state State.
   * @param {string} src Image source URI.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("./Tile.js").LoadFunction} tileLoadFunction Tile load function.
   * @param {import("./Tile.js").Options} [options] Tile options.
   */
  constructor(tileCoord, state, src, crossOrigin, tileLoadFunction, options2) {
    super(tileCoord, state, options2);
    this.crossOrigin_ = crossOrigin;
    this.src_ = src;
    this.key = src;
    this.image_ = new Image();
    if (crossOrigin !== null) {
      this.image_.crossOrigin = crossOrigin;
    }
    this.unlisten_ = null;
    this.tileLoadFunction_ = tileLoadFunction;
  }
  /**
   * Get the HTML image element for this tile (may be a Canvas, Image, or Video).
   * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
   * @api
   */
  getImage() {
    return this.image_;
  }
  /**
   * Sets an HTML image element for this tile (may be a Canvas or preloaded Image).
   * @param {HTMLCanvasElement|HTMLImageElement} element Element.
   */
  setImage(element) {
    this.image_ = element;
    this.state = TileState.LOADED;
    this.unlistenImage_();
    this.changed();
  }
  /**
   * Tracks loading or read errors.
   *
   * @private
   */
  handleImageError_() {
    this.state = TileState.ERROR;
    this.unlistenImage_();
    this.image_ = getBlankImage();
    this.changed();
  }
  /**
   * Tracks successful image load.
   *
   * @private
   */
  handleImageLoad_() {
    const image = (
      /** @type {HTMLImageElement} */
      this.image_
    );
    if (image.naturalWidth && image.naturalHeight) {
      this.state = TileState.LOADED;
    } else {
      this.state = TileState.EMPTY;
    }
    this.unlistenImage_();
    this.changed();
  }
  /**
   * Load the image or retry if loading previously failed.
   * Loading is taken care of by the tile queue, and calling this method is
   * only needed for preloading or for reloading in case of an error.
   *
   * To retry loading tiles on failed requests, use a custom `tileLoadFunction`
   * that checks for error status codes and reloads only when the status code is
   * 408, 429, 500, 502, 503 and 504, and only when not too many retries have been
   * made already:
   *
   * ```js
   * const retryCodes = [408, 429, 500, 502, 503, 504];
   * const retries = {};
   * source.setTileLoadFunction((tile, src) => {
   *   const image = tile.getImage();
   *   fetch(src)
   *     .then((response) => {
   *       if (retryCodes.includes(response.status)) {
   *         retries[src] = (retries[src] || 0) + 1;
   *         if (retries[src] <= 3) {
   *           setTimeout(() => tile.load(), retries[src] * 1000);
   *         }
   *         return Promise.reject();
   *       }
   *       return response.blob();
   *     })
   *     .then((blob) => {
   *       const imageUrl = URL.createObjectURL(blob);
   *       image.src = imageUrl;
   *       setTimeout(() => URL.revokeObjectURL(imageUrl), 5000);
   *     })
   *     .catch(() => tile.setState(3)); // error
   * });
   * ```
   * @api
   * @override
   */
  load() {
    if (this.state == TileState.ERROR) {
      this.state = TileState.IDLE;
      this.image_ = new Image();
      if (this.crossOrigin_ !== null) {
        this.image_.crossOrigin = this.crossOrigin_;
      }
    }
    if (this.state == TileState.IDLE) {
      this.state = TileState.LOADING;
      this.changed();
      this.tileLoadFunction_(this, this.src_);
      this.unlisten_ = listenImage(
        this.image_,
        this.handleImageLoad_.bind(this),
        this.handleImageError_.bind(this)
      );
    }
  }
  /**
   * Discards event handlers which listen for load completion or errors.
   *
   * @private
   */
  unlistenImage_() {
    if (this.unlisten_) {
      this.unlisten_();
      this.unlisten_ = null;
    }
  }
  /**
   * @override
   */
  disposeInternal() {
    this.unlistenImage_();
    this.image_ = null;
    super.disposeInternal();
  }
}
function getBlankImage() {
  const ctx = createCanvasContext2D(1, 1);
  ctx.fillStyle = "rgba(0,0,0,0)";
  ctx.fillRect(0, 0, 1, 1);
  return ctx.canvas;
}
class TileRange {
  /**
   * @param {number} minX Minimum X.
   * @param {number} maxX Maximum X.
   * @param {number} minY Minimum Y.
   * @param {number} maxY Maximum Y.
   */
  constructor(minX, maxX, minY, maxY) {
    this.minX = minX;
    this.maxX = maxX;
    this.minY = minY;
    this.maxY = maxY;
  }
  /**
   * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @return {boolean} Contains tile coordinate.
   */
  contains(tileCoord) {
    return this.containsXY(tileCoord[1], tileCoord[2]);
  }
  /**
   * @param {TileRange} tileRange Tile range.
   * @return {boolean} Contains.
   */
  containsTileRange(tileRange) {
    return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX && this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;
  }
  /**
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @return {boolean} Contains coordinate.
   */
  containsXY(x, y) {
    return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;
  }
  /**
   * @param {TileRange} tileRange Tile range.
   * @return {boolean} Equals.
   */
  equals(tileRange) {
    return this.minX == tileRange.minX && this.minY == tileRange.minY && this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;
  }
  /**
   * @param {TileRange} tileRange Tile range.
   */
  extend(tileRange) {
    if (tileRange.minX < this.minX) {
      this.minX = tileRange.minX;
    }
    if (tileRange.maxX > this.maxX) {
      this.maxX = tileRange.maxX;
    }
    if (tileRange.minY < this.minY) {
      this.minY = tileRange.minY;
    }
    if (tileRange.maxY > this.maxY) {
      this.maxY = tileRange.maxY;
    }
  }
  /**
   * @return {number} Height.
   */
  getHeight() {
    return this.maxY - this.minY + 1;
  }
  /**
   * @return {import("./size.js").Size} Size.
   */
  getSize() {
    return [this.getWidth(), this.getHeight()];
  }
  /**
   * @return {number} Width.
   */
  getWidth() {
    return this.maxX - this.minX + 1;
  }
  /**
   * @param {TileRange} tileRange Tile range.
   * @return {boolean} Intersects.
   */
  intersects(tileRange) {
    return this.minX <= tileRange.maxX && this.maxX >= tileRange.minX && this.minY <= tileRange.maxY && this.maxY >= tileRange.minY;
  }
}
function createOrUpdate$1(minX, maxX, minY, maxY, tileRange) {
  if (tileRange !== void 0) {
    tileRange.minX = minX;
    tileRange.maxX = maxX;
    tileRange.minY = minY;
    tileRange.maxY = maxY;
    return tileRange;
  }
  return new TileRange(minX, maxX, minY, maxY);
}
let brokenDiagonalRendering_;
const canvasPool = [];
function drawTestTriangle(ctx, u1, v1, u2, v2) {
  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.lineTo(u1, v1);
  ctx.lineTo(u2, v2);
  ctx.closePath();
  ctx.save();
  ctx.clip();
  ctx.fillRect(0, 0, Math.max(u1, u2) + 1, Math.max(v1, v2));
  ctx.restore();
}
function verifyBrokenDiagonalRendering(data, offset2) {
  return Math.abs(data[offset2 * 4] - 210) > 2 || Math.abs(data[offset2 * 4 + 3] - 0.75 * 255) > 2;
}
function isBrokenDiagonalRendering() {
  if (brokenDiagonalRendering_ === void 0) {
    const ctx = createCanvasContext2D(6, 6, canvasPool);
    ctx.globalCompositeOperation = "lighter";
    ctx.fillStyle = "rgba(210, 0, 0, 0.75)";
    drawTestTriangle(ctx, 4, 5, 4, 0);
    drawTestTriangle(ctx, 4, 5, 0, 5);
    const data = ctx.getImageData(0, 0, 3, 3).data;
    brokenDiagonalRendering_ = verifyBrokenDiagonalRendering(data, 0) || verifyBrokenDiagonalRendering(data, 4) || verifyBrokenDiagonalRendering(data, 8);
    releaseCanvas(ctx);
    canvasPool.push(ctx.canvas);
  }
  return brokenDiagonalRendering_;
}
function calculateSourceResolution(sourceProj, targetProj, targetCenter, targetResolution) {
  const sourceCenter = transform$1(targetCenter, targetProj, sourceProj);
  let sourceResolution = getPointResolution(
    targetProj,
    targetResolution,
    targetCenter
  );
  const targetMetersPerUnit = targetProj.getMetersPerUnit();
  if (targetMetersPerUnit !== void 0) {
    sourceResolution *= targetMetersPerUnit;
  }
  const sourceMetersPerUnit = sourceProj.getMetersPerUnit();
  if (sourceMetersPerUnit !== void 0) {
    sourceResolution /= sourceMetersPerUnit;
  }
  const sourceExtent = sourceProj.getExtent();
  if (!sourceExtent || containsCoordinate(sourceExtent, sourceCenter)) {
    const compensationFactor = getPointResolution(sourceProj, sourceResolution, sourceCenter) / sourceResolution;
    if (isFinite(compensationFactor) && compensationFactor > 0) {
      sourceResolution /= compensationFactor;
    }
  }
  return sourceResolution;
}
function calculateSourceExtentResolution(sourceProj, targetProj, targetExtent, targetResolution) {
  const targetCenter = getCenter(targetExtent);
  let sourceResolution = calculateSourceResolution(
    sourceProj,
    targetProj,
    targetCenter,
    targetResolution
  );
  if (!isFinite(sourceResolution) || sourceResolution <= 0) {
    forEachCorner(targetExtent, function(corner) {
      sourceResolution = calculateSourceResolution(
        sourceProj,
        targetProj,
        corner,
        targetResolution
      );
      return isFinite(sourceResolution) && sourceResolution > 0;
    });
  }
  return sourceResolution;
}
function render(width, height, pixelRatio, sourceResolution, sourceExtent, targetResolution, targetExtent, triangulation, sources, gutter, renderEdges, interpolate, drawSingle, clipExtent) {
  const context = createCanvasContext2D(
    Math.round(pixelRatio * width),
    Math.round(pixelRatio * height),
    canvasPool
  );
  if (!interpolate) {
    context.imageSmoothingEnabled = false;
  }
  if (sources.length === 0) {
    return context.canvas;
  }
  context.scale(pixelRatio, pixelRatio);
  function pixelRound(value) {
    return Math.round(value * pixelRatio) / pixelRatio;
  }
  context.globalCompositeOperation = "lighter";
  const sourceDataExtent = createEmpty();
  sources.forEach(function(src, i, arr) {
    extend$2(sourceDataExtent, src.extent);
  });
  let stitchContext;
  const stitchScale = pixelRatio / sourceResolution;
  const inverseScale = (interpolate ? 1 : 1 + Math.pow(2, -24)) / stitchScale;
  if (!drawSingle || sources.length !== 1 || gutter !== 0) {
    stitchContext = createCanvasContext2D(
      Math.round(getWidth(sourceDataExtent) * stitchScale),
      Math.round(getHeight(sourceDataExtent) * stitchScale),
      canvasPool
    );
    if (!interpolate) {
      stitchContext.imageSmoothingEnabled = false;
    }
    sources.forEach(function(src, i, arr) {
      if (src.image.width > 0 && src.image.height > 0) {
        if (src.clipExtent) {
          stitchContext.save();
          const xPos2 = (src.clipExtent[0] - sourceDataExtent[0]) * stitchScale;
          const yPos2 = -(src.clipExtent[3] - sourceDataExtent[3]) * stitchScale;
          const width2 = getWidth(src.clipExtent) * stitchScale;
          const height2 = getHeight(src.clipExtent) * stitchScale;
          stitchContext.rect(
            interpolate ? xPos2 : Math.round(xPos2),
            interpolate ? yPos2 : Math.round(yPos2),
            interpolate ? width2 : Math.round(xPos2 + width2) - Math.round(xPos2),
            interpolate ? height2 : Math.round(yPos2 + height2) - Math.round(yPos2)
          );
          stitchContext.clip();
        }
        const xPos = (src.extent[0] - sourceDataExtent[0]) * stitchScale;
        const yPos = -(src.extent[3] - sourceDataExtent[3]) * stitchScale;
        const srcWidth = getWidth(src.extent) * stitchScale;
        const srcHeight = getHeight(src.extent) * stitchScale;
        stitchContext.drawImage(
          src.image,
          gutter,
          gutter,
          src.image.width - 2 * gutter,
          src.image.height - 2 * gutter,
          interpolate ? xPos : Math.round(xPos),
          interpolate ? yPos : Math.round(yPos),
          interpolate ? srcWidth : Math.round(xPos + srcWidth) - Math.round(xPos),
          interpolate ? srcHeight : Math.round(yPos + srcHeight) - Math.round(yPos)
        );
        if (src.clipExtent) {
          stitchContext.restore();
        }
      }
    });
  }
  const targetTopLeft = getTopLeft(targetExtent);
  triangulation.getTriangles().forEach(function(triangle2, i, arr) {
    const source = triangle2.source;
    const target = triangle2.target;
    let x0 = source[0][0], y0 = source[0][1];
    let x1 = source[1][0], y1 = source[1][1];
    let x2 = source[2][0], y2 = source[2][1];
    const u0 = pixelRound((target[0][0] - targetTopLeft[0]) / targetResolution);
    const v0 = pixelRound(
      -(target[0][1] - targetTopLeft[1]) / targetResolution
    );
    const u1 = pixelRound((target[1][0] - targetTopLeft[0]) / targetResolution);
    const v1 = pixelRound(
      -(target[1][1] - targetTopLeft[1]) / targetResolution
    );
    const u2 = pixelRound((target[2][0] - targetTopLeft[0]) / targetResolution);
    const v2 = pixelRound(
      -(target[2][1] - targetTopLeft[1]) / targetResolution
    );
    const sourceNumericalShiftX = x0;
    const sourceNumericalShiftY = y0;
    x0 = 0;
    y0 = 0;
    x1 -= sourceNumericalShiftX;
    y1 -= sourceNumericalShiftY;
    x2 -= sourceNumericalShiftX;
    y2 -= sourceNumericalShiftY;
    const augmentedMatrix = [
      [x1, y1, 0, 0, u1 - u0],
      [x2, y2, 0, 0, u2 - u0],
      [0, 0, x1, y1, v1 - v0],
      [0, 0, x2, y2, v2 - v0]
    ];
    const affineCoefs = solveLinearSystem(augmentedMatrix);
    if (!affineCoefs) {
      return;
    }
    context.save();
    context.beginPath();
    if (isBrokenDiagonalRendering() || !interpolate) {
      context.moveTo(u1, v1);
      const steps = 4;
      const ud = u0 - u1;
      const vd = v0 - v1;
      for (let step = 0; step < steps; step++) {
        context.lineTo(
          u1 + pixelRound((step + 1) * ud / steps),
          v1 + pixelRound(step * vd / (steps - 1))
        );
        if (step != steps - 1) {
          context.lineTo(
            u1 + pixelRound((step + 1) * ud / steps),
            v1 + pixelRound((step + 1) * vd / (steps - 1))
          );
        }
      }
      context.lineTo(u2, v2);
    } else {
      context.moveTo(u1, v1);
      context.lineTo(u0, v0);
      context.lineTo(u2, v2);
    }
    context.clip();
    context.transform(
      affineCoefs[0],
      affineCoefs[2],
      affineCoefs[1],
      affineCoefs[3],
      u0,
      v0
    );
    context.translate(
      sourceDataExtent[0] - sourceNumericalShiftX,
      sourceDataExtent[3] - sourceNumericalShiftY
    );
    let image;
    if (stitchContext) {
      image = stitchContext.canvas;
      context.scale(inverseScale, -inverseScale);
    } else {
      const source2 = sources[0];
      const extent = source2.extent;
      image = source2.image;
      context.scale(
        getWidth(extent) / image.width,
        -getHeight(extent) / image.height
      );
    }
    context.drawImage(image, 0, 0);
    context.restore();
  });
  if (stitchContext) {
    releaseCanvas(stitchContext);
    canvasPool.push(stitchContext.canvas);
  }
  if (renderEdges) {
    context.save();
    context.globalCompositeOperation = "source-over";
    context.strokeStyle = "black";
    context.lineWidth = 1;
    triangulation.getTriangles().forEach(function(triangle2, i, arr) {
      const target = triangle2.target;
      const u0 = (target[0][0] - targetTopLeft[0]) / targetResolution;
      const v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;
      const u1 = (target[1][0] - targetTopLeft[0]) / targetResolution;
      const v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;
      const u2 = (target[2][0] - targetTopLeft[0]) / targetResolution;
      const v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;
      context.beginPath();
      context.moveTo(u1, v1);
      context.lineTo(u0, v0);
      context.lineTo(u2, v2);
      context.closePath();
      context.stroke();
    });
    context.restore();
  }
  return context.canvas;
}
const MAX_SUBDIVISION = 10;
const MAX_TRIANGLE_WIDTH = 0.25;
class Triangulation {
  /**
   * @param {import("../proj/Projection.js").default} sourceProj Source projection.
   * @param {import("../proj/Projection.js").default} targetProj Target projection.
   * @param {import("../extent.js").Extent} targetExtent Target extent to triangulate.
   * @param {import("../extent.js").Extent} maxSourceExtent Maximal source extent that can be used.
   * @param {number} errorThreshold Acceptable error (in source units).
   * @param {?number} destinationResolution The (optional) resolution of the destination.
   * @param {import("../transform.js").Transform} [sourceMatrix] Source transform matrix.
   */
  constructor(sourceProj, targetProj, targetExtent, maxSourceExtent, errorThreshold, destinationResolution, sourceMatrix) {
    this.sourceProj_ = sourceProj;
    this.targetProj_ = targetProj;
    let transformInvCache = {};
    const transformInv = sourceMatrix ? createTransformFromCoordinateTransform(
      (input) => apply(
        sourceMatrix,
        transform$1(input, this.targetProj_, this.sourceProj_)
      )
    ) : getTransform(this.targetProj_, this.sourceProj_);
    this.transformInv_ = function(c) {
      const key2 = c[0] + "/" + c[1];
      if (!transformInvCache[key2]) {
        transformInvCache[key2] = transformInv(c);
      }
      return transformInvCache[key2];
    };
    this.maxSourceExtent_ = maxSourceExtent;
    this.errorThresholdSquared_ = errorThreshold * errorThreshold;
    this.triangles_ = [];
    this.wrapsXInSource_ = false;
    this.canWrapXInSource_ = this.sourceProj_.canWrapX() && !!maxSourceExtent && !!this.sourceProj_.getExtent() && getWidth(maxSourceExtent) >= getWidth(this.sourceProj_.getExtent());
    this.sourceWorldWidth_ = this.sourceProj_.getExtent() ? getWidth(this.sourceProj_.getExtent()) : null;
    this.targetWorldWidth_ = this.targetProj_.getExtent() ? getWidth(this.targetProj_.getExtent()) : null;
    const destinationTopLeft = getTopLeft(targetExtent);
    const destinationTopRight = getTopRight(targetExtent);
    const destinationBottomRight = getBottomRight(targetExtent);
    const destinationBottomLeft = getBottomLeft(targetExtent);
    const sourceTopLeft = this.transformInv_(destinationTopLeft);
    const sourceTopRight = this.transformInv_(destinationTopRight);
    const sourceBottomRight = this.transformInv_(destinationBottomRight);
    const sourceBottomLeft = this.transformInv_(destinationBottomLeft);
    const maxSubdivision = MAX_SUBDIVISION + (destinationResolution ? Math.max(
      0,
      Math.ceil(
        Math.log2(
          getArea(targetExtent) / (destinationResolution * destinationResolution * 256 * 256)
        )
      )
    ) : 0);
    this.addQuad_(
      destinationTopLeft,
      destinationTopRight,
      destinationBottomRight,
      destinationBottomLeft,
      sourceTopLeft,
      sourceTopRight,
      sourceBottomRight,
      sourceBottomLeft,
      maxSubdivision
    );
    if (this.wrapsXInSource_) {
      let leftBound = Infinity;
      this.triangles_.forEach(function(triangle2, i, arr) {
        leftBound = Math.min(
          leftBound,
          triangle2.source[0][0],
          triangle2.source[1][0],
          triangle2.source[2][0]
        );
      });
      this.triangles_.forEach((triangle2) => {
        if (Math.max(
          triangle2.source[0][0],
          triangle2.source[1][0],
          triangle2.source[2][0]
        ) - leftBound > this.sourceWorldWidth_ / 2) {
          const newTriangle = [
            [triangle2.source[0][0], triangle2.source[0][1]],
            [triangle2.source[1][0], triangle2.source[1][1]],
            [triangle2.source[2][0], triangle2.source[2][1]]
          ];
          if (newTriangle[0][0] - leftBound > this.sourceWorldWidth_ / 2) {
            newTriangle[0][0] -= this.sourceWorldWidth_;
          }
          if (newTriangle[1][0] - leftBound > this.sourceWorldWidth_ / 2) {
            newTriangle[1][0] -= this.sourceWorldWidth_;
          }
          if (newTriangle[2][0] - leftBound > this.sourceWorldWidth_ / 2) {
            newTriangle[2][0] -= this.sourceWorldWidth_;
          }
          const minX = Math.min(
            newTriangle[0][0],
            newTriangle[1][0],
            newTriangle[2][0]
          );
          const maxX = Math.max(
            newTriangle[0][0],
            newTriangle[1][0],
            newTriangle[2][0]
          );
          if (maxX - minX < this.sourceWorldWidth_ / 2) {
            triangle2.source = newTriangle;
          }
        }
      });
    }
    transformInvCache = {};
  }
  /**
   * Adds triangle to the triangulation.
   * @param {import("../coordinate.js").Coordinate} a The target a coordinate.
   * @param {import("../coordinate.js").Coordinate} b The target b coordinate.
   * @param {import("../coordinate.js").Coordinate} c The target c coordinate.
   * @param {import("../coordinate.js").Coordinate} aSrc The source a coordinate.
   * @param {import("../coordinate.js").Coordinate} bSrc The source b coordinate.
   * @param {import("../coordinate.js").Coordinate} cSrc The source c coordinate.
   * @private
   */
  addTriangle_(a, b, c, aSrc, bSrc, cSrc) {
    this.triangles_.push({
      source: [aSrc, bSrc, cSrc],
      target: [a, b, c]
    });
  }
  /**
   * Adds quad (points in clock-wise order) to the triangulation
   * (and reprojects the vertices) if valid.
   * Performs quad subdivision if needed to increase precision.
   *
   * @param {import("../coordinate.js").Coordinate} a The target a coordinate.
   * @param {import("../coordinate.js").Coordinate} b The target b coordinate.
   * @param {import("../coordinate.js").Coordinate} c The target c coordinate.
   * @param {import("../coordinate.js").Coordinate} d The target d coordinate.
   * @param {import("../coordinate.js").Coordinate} aSrc The source a coordinate.
   * @param {import("../coordinate.js").Coordinate} bSrc The source b coordinate.
   * @param {import("../coordinate.js").Coordinate} cSrc The source c coordinate.
   * @param {import("../coordinate.js").Coordinate} dSrc The source d coordinate.
   * @param {number} maxSubdivision Maximal allowed subdivision of the quad.
   * @private
   */
  addQuad_(a, b, c, d, aSrc, bSrc, cSrc, dSrc, maxSubdivision) {
    const sourceQuadExtent = boundingExtent([aSrc, bSrc, cSrc, dSrc]);
    const sourceCoverageX = this.sourceWorldWidth_ ? getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null;
    const sourceWorldWidth = (
      /** @type {number} */
      this.sourceWorldWidth_
    );
    const wrapsX = this.sourceProj_.canWrapX() && sourceCoverageX > 0.5 && sourceCoverageX < 1;
    let needsSubdivision = false;
    if (maxSubdivision > 0) {
      if (this.targetProj_.isGlobal() && this.targetWorldWidth_) {
        const targetQuadExtent = boundingExtent([a, b, c, d]);
        const targetCoverageX = getWidth(targetQuadExtent) / this.targetWorldWidth_;
        needsSubdivision = targetCoverageX > MAX_TRIANGLE_WIDTH || needsSubdivision;
      }
      if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) {
        needsSubdivision = sourceCoverageX > MAX_TRIANGLE_WIDTH || needsSubdivision;
      }
    }
    if (!needsSubdivision && this.maxSourceExtent_) {
      if (isFinite(sourceQuadExtent[0]) && isFinite(sourceQuadExtent[1]) && isFinite(sourceQuadExtent[2]) && isFinite(sourceQuadExtent[3])) {
        if (!intersects$1(sourceQuadExtent, this.maxSourceExtent_)) {
          return;
        }
      }
    }
    let isNotFinite = 0;
    if (!needsSubdivision) {
      if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) || !isFinite(bSrc[0]) || !isFinite(bSrc[1]) || !isFinite(cSrc[0]) || !isFinite(cSrc[1]) || !isFinite(dSrc[0]) || !isFinite(dSrc[1])) {
        if (maxSubdivision > 0) {
          needsSubdivision = true;
        } else {
          isNotFinite = (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) ? 8 : 0) + (!isFinite(bSrc[0]) || !isFinite(bSrc[1]) ? 4 : 0) + (!isFinite(cSrc[0]) || !isFinite(cSrc[1]) ? 2 : 0) + (!isFinite(dSrc[0]) || !isFinite(dSrc[1]) ? 1 : 0);
          if (isNotFinite != 1 && isNotFinite != 2 && isNotFinite != 4 && isNotFinite != 8) {
            return;
          }
        }
      }
    }
    if (maxSubdivision > 0) {
      if (!needsSubdivision) {
        const center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2];
        const centerSrc = this.transformInv_(center);
        let dx;
        if (wrapsX) {
          const centerSrcEstimX = (modulo(aSrc[0], sourceWorldWidth) + modulo(cSrc[0], sourceWorldWidth)) / 2;
          dx = centerSrcEstimX - modulo(centerSrc[0], sourceWorldWidth);
        } else {
          dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0];
        }
        const dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1];
        const centerSrcErrorSquared = dx * dx + dy * dy;
        needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_;
      }
      if (needsSubdivision) {
        if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) {
          const bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2];
          const bcSrc = this.transformInv_(bc);
          const da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2];
          const daSrc = this.transformInv_(da);
          this.addQuad_(
            a,
            b,
            bc,
            da,
            aSrc,
            bSrc,
            bcSrc,
            daSrc,
            maxSubdivision - 1
          );
          this.addQuad_(
            da,
            bc,
            c,
            d,
            daSrc,
            bcSrc,
            cSrc,
            dSrc,
            maxSubdivision - 1
          );
        } else {
          const ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
          const abSrc = this.transformInv_(ab);
          const cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2];
          const cdSrc = this.transformInv_(cd);
          this.addQuad_(
            a,
            ab,
            cd,
            d,
            aSrc,
            abSrc,
            cdSrc,
            dSrc,
            maxSubdivision - 1
          );
          this.addQuad_(
            ab,
            b,
            c,
            cd,
            abSrc,
            bSrc,
            cSrc,
            cdSrc,
            maxSubdivision - 1
          );
        }
        return;
      }
    }
    if (wrapsX) {
      if (!this.canWrapXInSource_) {
        return;
      }
      this.wrapsXInSource_ = true;
    }
    if ((isNotFinite & 11) == 0) {
      this.addTriangle_(a, c, d, aSrc, cSrc, dSrc);
    }
    if ((isNotFinite & 14) == 0) {
      this.addTriangle_(a, c, b, aSrc, cSrc, bSrc);
    }
    if (isNotFinite) {
      if ((isNotFinite & 13) == 0) {
        this.addTriangle_(b, d, a, bSrc, dSrc, aSrc);
      }
      if ((isNotFinite & 7) == 0) {
        this.addTriangle_(b, d, c, bSrc, dSrc, cSrc);
      }
    }
  }
  /**
   * Calculates extent of the `source` coordinates from all the triangles.
   *
   * @return {import("../extent.js").Extent} Calculated extent.
   */
  calculateSourceExtent() {
    const extent = createEmpty();
    this.triangles_.forEach(function(triangle2, i, arr) {
      const src = triangle2.source;
      extendCoordinate(extent, src[0]);
      extendCoordinate(extent, src[1]);
      extendCoordinate(extent, src[2]);
    });
    return extent;
  }
  /**
   * @return {Array<Triangle>} Array of the calculated triangles.
   */
  getTriangles() {
    return this.triangles_;
  }
}
const ERROR_THRESHOLD = 0.5;
class ReprojTile extends Tile {
  /**
   * @param {import("../proj/Projection.js").default} sourceProj Source projection.
   * @param {import("../tilegrid/TileGrid.js").default} sourceTileGrid Source tile grid.
   * @param {import("../proj/Projection.js").default} targetProj Target projection.
   * @param {import("../tilegrid/TileGrid.js").default} targetTileGrid Target tile grid.
   * @param {import("../tilecoord.js").TileCoord} tileCoord Coordinate of the tile.
   * @param {import("../tilecoord.js").TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X.
   * @param {number} pixelRatio Pixel ratio.
   * @param {number} gutter Gutter of the source tiles.
   * @param {FunctionType} getTileFunction
   *     Function returning source tiles (z, x, y, pixelRatio).
   * @param {number} [errorThreshold] Acceptable reprojection error (in px).
   * @param {boolean} [renderEdges] Render reprojection edges.
   * @param {import("../Tile.js").Options} [options] Tile options.
   */
  constructor(sourceProj, sourceTileGrid, targetProj, targetTileGrid, tileCoord, wrappedTileCoord, pixelRatio, gutter, getTileFunction, errorThreshold, renderEdges, options2) {
    super(tileCoord, TileState.IDLE, options2);
    this.renderEdges_ = renderEdges !== void 0 ? renderEdges : false;
    this.pixelRatio_ = pixelRatio;
    this.gutter_ = gutter;
    this.canvas_ = null;
    this.sourceTileGrid_ = sourceTileGrid;
    this.targetTileGrid_ = targetTileGrid;
    this.wrappedTileCoord_ = wrappedTileCoord ? wrappedTileCoord : tileCoord;
    this.sourceTiles_ = [];
    this.sourcesListenerKeys_ = null;
    this.sourceZ_ = 0;
    this.clipExtent_ = sourceProj.canWrapX() ? sourceProj.getExtent() : void 0;
    const targetExtent = targetTileGrid.getTileCoordExtent(
      this.wrappedTileCoord_
    );
    const maxTargetExtent = this.targetTileGrid_.getExtent();
    let maxSourceExtent = this.sourceTileGrid_.getExtent();
    const limitedTargetExtent = maxTargetExtent ? getIntersection(targetExtent, maxTargetExtent) : targetExtent;
    if (getArea(limitedTargetExtent) === 0) {
      this.state = TileState.EMPTY;
      return;
    }
    const sourceProjExtent = sourceProj.getExtent();
    if (sourceProjExtent) {
      if (!maxSourceExtent) {
        maxSourceExtent = sourceProjExtent;
      } else {
        maxSourceExtent = getIntersection(maxSourceExtent, sourceProjExtent);
      }
    }
    const targetResolution = targetTileGrid.getResolution(
      this.wrappedTileCoord_[0]
    );
    const sourceResolution = calculateSourceExtentResolution(
      sourceProj,
      targetProj,
      limitedTargetExtent,
      targetResolution
    );
    if (!isFinite(sourceResolution) || sourceResolution <= 0) {
      this.state = TileState.EMPTY;
      return;
    }
    const errorThresholdInPixels = errorThreshold !== void 0 ? errorThreshold : ERROR_THRESHOLD;
    this.triangulation_ = new Triangulation(
      sourceProj,
      targetProj,
      limitedTargetExtent,
      maxSourceExtent,
      sourceResolution * errorThresholdInPixels,
      targetResolution
    );
    if (this.triangulation_.getTriangles().length === 0) {
      this.state = TileState.EMPTY;
      return;
    }
    this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution);
    let sourceExtent = this.triangulation_.calculateSourceExtent();
    if (maxSourceExtent) {
      if (sourceProj.canWrapX()) {
        sourceExtent[1] = clamp(
          sourceExtent[1],
          maxSourceExtent[1],
          maxSourceExtent[3]
        );
        sourceExtent[3] = clamp(
          sourceExtent[3],
          maxSourceExtent[1],
          maxSourceExtent[3]
        );
      } else {
        sourceExtent = getIntersection(sourceExtent, maxSourceExtent);
      }
    }
    if (!getArea(sourceExtent)) {
      this.state = TileState.EMPTY;
    } else {
      let worldWidth = 0;
      let worldsAway = 0;
      if (sourceProj.canWrapX()) {
        worldWidth = getWidth(sourceProjExtent);
        worldsAway = Math.floor(
          (sourceExtent[0] - sourceProjExtent[0]) / worldWidth
        );
      }
      const sourceExtents = wrapAndSliceX(
        sourceExtent.slice(),
        sourceProj,
        true
      );
      sourceExtents.forEach((extent) => {
        const sourceRange = sourceTileGrid.getTileRangeForExtentAndZ(
          extent,
          this.sourceZ_
        );
        for (let srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) {
          for (let srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) {
            const tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio);
            if (tile) {
              const offset2 = worldsAway * worldWidth;
              this.sourceTiles_.push({ tile, offset: offset2 });
            }
          }
        }
        ++worldsAway;
      });
      if (this.sourceTiles_.length === 0) {
        this.state = TileState.EMPTY;
      }
    }
  }
  /**
   * Get the HTML Canvas element for this tile.
   * @return {HTMLCanvasElement} Canvas.
   */
  getImage() {
    return this.canvas_;
  }
  /**
   * @private
   */
  reproject_() {
    const sources = [];
    this.sourceTiles_.forEach((source) => {
      const tile = source.tile;
      if (tile && tile.getState() == TileState.LOADED) {
        const extent = this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord);
        extent[0] += source.offset;
        extent[2] += source.offset;
        const clipExtent = this.clipExtent_?.slice();
        if (clipExtent) {
          clipExtent[0] += source.offset;
          clipExtent[2] += source.offset;
        }
        sources.push({
          extent,
          clipExtent,
          image: tile.getImage()
        });
      }
    });
    this.sourceTiles_.length = 0;
    if (sources.length === 0) {
      this.state = TileState.ERROR;
    } else {
      const z = this.wrappedTileCoord_[0];
      const size = this.targetTileGrid_.getTileSize(z);
      const width = typeof size === "number" ? size : size[0];
      const height = typeof size === "number" ? size : size[1];
      const targetResolution = this.targetTileGrid_.getResolution(z);
      const sourceResolution = this.sourceTileGrid_.getResolution(
        this.sourceZ_
      );
      const targetExtent = this.targetTileGrid_.getTileCoordExtent(
        this.wrappedTileCoord_
      );
      this.canvas_ = render(
        width,
        height,
        this.pixelRatio_,
        sourceResolution,
        this.sourceTileGrid_.getExtent(),
        targetResolution,
        targetExtent,
        this.triangulation_,
        sources,
        this.gutter_,
        this.renderEdges_,
        this.interpolate
      );
      this.state = TileState.LOADED;
    }
    this.changed();
  }
  /**
   * Load not yet loaded URI.
   * @override
   */
  load() {
    if (this.state == TileState.IDLE) {
      this.state = TileState.LOADING;
      this.changed();
      let leftToLoad = 0;
      this.sourcesListenerKeys_ = [];
      this.sourceTiles_.forEach(({ tile }) => {
        const state = tile.getState();
        if (state == TileState.IDLE || state == TileState.LOADING) {
          leftToLoad++;
          const sourceListenKey = listen(tile, EventType.CHANGE, (e) => {
            const state2 = tile.getState();
            if (state2 == TileState.LOADED || state2 == TileState.ERROR || state2 == TileState.EMPTY) {
              unlistenByKey(sourceListenKey);
              leftToLoad--;
              if (leftToLoad === 0) {
                this.unlistenSources_();
                this.reproject_();
              }
            }
          });
          this.sourcesListenerKeys_.push(sourceListenKey);
        }
      });
      if (leftToLoad === 0) {
        setTimeout(this.reproject_.bind(this), 0);
      } else {
        this.sourceTiles_.forEach(function({ tile }, i, arr) {
          const state = tile.getState();
          if (state == TileState.IDLE) {
            tile.load();
          }
        });
      }
    }
  }
  /**
   * @private
   */
  unlistenSources_() {
    this.sourcesListenerKeys_.forEach(unlistenByKey);
    this.sourcesListenerKeys_ = null;
  }
  /**
   * Remove from the cache due to expiry
   * @override
   */
  release() {
    if (this.canvas_) {
      releaseCanvas(this.canvas_.getContext("2d"));
      canvasPool.push(this.canvas_);
      this.canvas_ = null;
    }
    super.release();
  }
}
class LRUCache {
  /**
   * @param {number} [highWaterMark] High water mark.
   */
  constructor(highWaterMark) {
    this.highWaterMark = highWaterMark !== void 0 ? highWaterMark : 2048;
    this.count_ = 0;
    this.entries_ = {};
    this.oldest_ = null;
    this.newest_ = null;
  }
  deleteOldest() {
    const entry = this.pop();
    if (entry instanceof Disposable) {
      entry.dispose();
    }
  }
  /**
   * @return {boolean} Can expire cache.
   */
  canExpireCache() {
    return this.highWaterMark > 0 && this.getCount() > this.highWaterMark;
  }
  /**
   * Expire the cache. When the cache entry is a {@link module:ol/Disposable~Disposable},
   * the entry will be disposed.
   * @param {!Object<string, boolean>} [keep] Keys to keep. To be implemented by subclasses.
   */
  expireCache(keep) {
    while (this.canExpireCache()) {
      this.deleteOldest();
    }
  }
  /**
   * FIXME empty description for jsdoc
   */
  clear() {
    while (this.oldest_) {
      this.deleteOldest();
    }
  }
  /**
   * @param {string} key Key.
   * @return {boolean} Contains key.
   */
  containsKey(key2) {
    return this.entries_.hasOwnProperty(key2);
  }
  /**
   * @param {function(T, string, LRUCache<T>): ?} f The function
   *     to call for every entry from the oldest to the newer. This function takes
   *     3 arguments (the entry value, the entry key and the LRUCache object).
   *     The return value is ignored.
   */
  forEach(f) {
    let entry = this.oldest_;
    while (entry) {
      f(entry.value_, entry.key_, this);
      entry = entry.newer;
    }
  }
  /**
   * @param {string} key Key.
   * @param {*} [options] Options (reserved for subclasses).
   * @return {T} Value.
   */
  get(key2, options2) {
    const entry = this.entries_[key2];
    assert(
      entry !== void 0,
      "Tried to get a value for a key that does not exist in the cache"
    );
    if (entry === this.newest_) {
      return entry.value_;
    }
    if (entry === this.oldest_) {
      this.oldest_ = /** @type {Entry} */
      this.oldest_.newer;
      this.oldest_.older = null;
    } else {
      entry.newer.older = entry.older;
      entry.older.newer = entry.newer;
    }
    entry.newer = null;
    entry.older = this.newest_;
    this.newest_.newer = entry;
    this.newest_ = entry;
    return entry.value_;
  }
  /**
   * Remove an entry from the cache.
   * @param {string} key The entry key.
   * @return {T} The removed entry.
   */
  remove(key2) {
    const entry = this.entries_[key2];
    assert(
      entry !== void 0,
      "Tried to get a value for a key that does not exist in the cache"
    );
    if (entry === this.newest_) {
      this.newest_ = /** @type {Entry} */
      entry.older;
      if (this.newest_) {
        this.newest_.newer = null;
      }
    } else if (entry === this.oldest_) {
      this.oldest_ = /** @type {Entry} */
      entry.newer;
      if (this.oldest_) {
        this.oldest_.older = null;
      }
    } else {
      entry.newer.older = entry.older;
      entry.older.newer = entry.newer;
    }
    delete this.entries_[key2];
    --this.count_;
    return entry.value_;
  }
  /**
   * @return {number} Count.
   */
  getCount() {
    return this.count_;
  }
  /**
   * @return {Array<string>} Keys.
   */
  getKeys() {
    const keys = new Array(this.count_);
    let i = 0;
    let entry;
    for (entry = this.newest_; entry; entry = entry.older) {
      keys[i++] = entry.key_;
    }
    return keys;
  }
  /**
   * @return {Array<T>} Values.
   */
  getValues() {
    const values = new Array(this.count_);
    let i = 0;
    let entry;
    for (entry = this.newest_; entry; entry = entry.older) {
      values[i++] = entry.value_;
    }
    return values;
  }
  /**
   * @return {T} Last value.
   */
  peekLast() {
    return this.oldest_.value_;
  }
  /**
   * @return {string} Last key.
   */
  peekLastKey() {
    return this.oldest_.key_;
  }
  /**
   * Get the key of the newest item in the cache.  Throws if the cache is empty.
   * @return {string} The newest key.
   */
  peekFirstKey() {
    return this.newest_.key_;
  }
  /**
   * Return an entry without updating least recently used time.
   * @param {string} key Key.
   * @return {T|undefined} Value.
   */
  peek(key2) {
    return this.entries_[key2]?.value_;
  }
  /**
   * @return {T} value Value.
   */
  pop() {
    const entry = this.oldest_;
    delete this.entries_[entry.key_];
    if (entry.newer) {
      entry.newer.older = null;
    }
    this.oldest_ = /** @type {Entry} */
    entry.newer;
    if (!this.oldest_) {
      this.newest_ = null;
    }
    --this.count_;
    return entry.value_;
  }
  /**
   * @param {string} key Key.
   * @param {T} value Value.
   */
  replace(key2, value) {
    this.get(key2);
    this.entries_[key2].value_ = value;
  }
  /**
   * @param {string} key Key.
   * @param {T} value Value.
   */
  set(key2, value) {
    assert(
      !(key2 in this.entries_),
      "Tried to set a value for a key that is used already"
    );
    const entry = {
      key_: key2,
      newer: null,
      older: this.newest_,
      value_: value
    };
    if (!this.newest_) {
      this.oldest_ = entry;
    } else {
      this.newest_.newer = entry;
    }
    this.newest_ = entry;
    this.entries_[key2] = entry;
    ++this.count_;
  }
  /**
   * Set a maximum number of entries for the cache.
   * @param {number} size Cache size.
   * @api
   */
  setSize(size) {
    this.highWaterMark = size;
  }
}
function createOrUpdate(z, x, y, tileCoord) {
  if (tileCoord !== void 0) {
    tileCoord[0] = z;
    tileCoord[1] = x;
    tileCoord[2] = y;
    return tileCoord;
  }
  return [z, x, y];
}
function getKeyZXY(z, x, y) {
  return z + "/" + x + "/" + y;
}
function hash(tileCoord) {
  return hashZXY(tileCoord[0], tileCoord[1], tileCoord[2]);
}
function hashZXY(z, x, y) {
  return (x << z) + y;
}
function withinExtentAndZ(tileCoord, tileGrid) {
  const z = tileCoord[0];
  const x = tileCoord[1];
  const y = tileCoord[2];
  if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) {
    return false;
  }
  const tileRange = tileGrid.getFullTileRange(z);
  if (!tileRange) {
    return true;
  }
  return tileRange.containsXY(x, y);
}
function getCacheKey(source, sourceKey, z, x, y) {
  return `${getUid(source)},${sourceKey},${getKeyZXY(z, x, y)}`;
}
function addTileToLookup(tilesByZ, tile, z) {
  if (!(z in tilesByZ)) {
    tilesByZ[z] = /* @__PURE__ */ new Set([tile]);
    return true;
  }
  const set2 = tilesByZ[z];
  const existing = set2.has(tile);
  if (!existing) {
    set2.add(tile);
  }
  return !existing;
}
function removeTileFromLookup(tilesByZ, tile, z) {
  const set2 = tilesByZ[z];
  if (set2) {
    return set2.delete(tile);
  }
  return false;
}
function getRenderExtent(frameState, extent) {
  const layerState = frameState.layerStatesArray[frameState.layerIndex];
  if (layerState.extent) {
    extent = getIntersection(
      extent,
      fromUserExtent(layerState.extent, frameState.viewState.projection)
    );
  }
  const source = (
    /** @type {import("../../source/Tile.js").default} */
    layerState.layer.getRenderSource()
  );
  if (!source.getWrapX()) {
    const gridExtent = source.getTileGridForProjection(frameState.viewState.projection).getExtent();
    if (gridExtent) {
      extent = getIntersection(extent, gridExtent);
    }
  }
  return extent;
}
class CanvasTileLayerRenderer extends CanvasLayerRenderer {
  /**
   * @param {LayerType} tileLayer Tile layer.
   * @param {Options} [options] Options.
   */
  constructor(tileLayer, options2) {
    super(tileLayer);
    options2 = options2 || {};
    this.extentChanged = true;
    this.renderComplete = false;
    this.renderedExtent_ = null;
    this.renderedPixelRatio;
    this.renderedProjection = null;
    this.renderedTiles = [];
    this.renderedSourceKey_;
    this.renderedSourceRevision_;
    this.tempExtent = createEmpty();
    this.tempTileRange_ = new TileRange(0, 0, 0, 0);
    this.tempTileCoord_ = createOrUpdate(0, 0, 0);
    const cacheSize2 = options2.cacheSize !== void 0 ? options2.cacheSize : 512;
    this.tileCache_ = new LRUCache(cacheSize2);
    this.maxStaleKeys = cacheSize2 * 0.5;
  }
  /**
   * @return {LRUCache} Tile cache.
   */
  getTileCache() {
    return this.tileCache_;
  }
  /**
   * Get a tile from the cache or create one if needed.
   *
   * @param {number} z Tile coordinate z.
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @return {import("../../Tile.js").default|null} Tile (or null if outside source extent).
   * @protected
   */
  getOrCreateTile(z, x, y, frameState) {
    const tileCache = this.tileCache_;
    const tileLayer = this.getLayer();
    const tileSource = tileLayer.getSource();
    const cacheKey = getCacheKey(tileSource, tileSource.getKey(), z, x, y);
    let tile;
    if (tileCache.containsKey(cacheKey)) {
      tile = tileCache.get(cacheKey);
    } else {
      tile = tileSource.getTile(
        z,
        x,
        y,
        frameState.pixelRatio,
        frameState.viewState.projection
      );
      if (!tile) {
        return null;
      }
      tileCache.set(cacheKey, tile);
    }
    return tile;
  }
  /**
   * @param {number} z Tile coordinate z.
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @return {import("../../Tile.js").default|null} Tile (or null if outside source extent).
   * @protected
   */
  getTile(z, x, y, frameState) {
    const tile = this.getOrCreateTile(z, x, y, frameState);
    if (!tile) {
      return null;
    }
    return tile;
  }
  /**
   * @param {import("../../pixel.js").Pixel} pixel Pixel.
   * @return {Uint8ClampedArray} Data at the pixel location.
   * @override
   */
  getData(pixel) {
    const frameState = this.frameState;
    if (!frameState) {
      return null;
    }
    const layer = this.getLayer();
    const coordinate = apply(
      frameState.pixelToCoordinateTransform,
      pixel.slice()
    );
    const layerExtent = layer.getExtent();
    if (layerExtent) {
      if (!containsCoordinate(layerExtent, coordinate)) {
        return null;
      }
    }
    const viewState = frameState.viewState;
    const source = layer.getRenderSource();
    const tileGrid = source.getTileGridForProjection(viewState.projection);
    const tilePixelRatio = source.getTilePixelRatio(frameState.pixelRatio);
    for (let z = tileGrid.getZForResolution(viewState.resolution); z >= tileGrid.getMinZoom(); --z) {
      const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z);
      const tile = this.getTile(z, tileCoord[1], tileCoord[2], frameState);
      if (!tile || tile.getState() !== TileState.LOADED) {
        continue;
      }
      const tileOrigin = tileGrid.getOrigin(z);
      const tileSize = toSize(tileGrid.getTileSize(z));
      const tileResolution = tileGrid.getResolution(z);
      let image;
      if (tile instanceof ImageTile || tile instanceof ReprojTile) {
        image = tile.getImage();
      } else if (tile instanceof DataTile) {
        image = asImageLike(tile.getData());
        if (!image) {
          continue;
        }
      } else {
        continue;
      }
      const col = Math.floor(
        tilePixelRatio * ((coordinate[0] - tileOrigin[0]) / tileResolution - tileCoord[1] * tileSize[0])
      );
      const row = Math.floor(
        tilePixelRatio * ((tileOrigin[1] - coordinate[1]) / tileResolution - tileCoord[2] * tileSize[1])
      );
      const gutter = Math.round(
        tilePixelRatio * source.getGutterForProjection(viewState.projection)
      );
      return this.getImageData(image, col + gutter, row + gutter);
    }
    return null;
  }
  /**
   * Determine whether render should be called.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @return {boolean} Layer is ready to be rendered.
   * @override
   */
  prepareFrame(frameState) {
    if (!this.renderedProjection) {
      this.renderedProjection = frameState.viewState.projection;
    } else if (frameState.viewState.projection !== this.renderedProjection) {
      this.tileCache_.clear();
      this.renderedProjection = frameState.viewState.projection;
    }
    const source = this.getLayer().getSource();
    if (!source) {
      return false;
    }
    const sourceRevision = source.getRevision();
    if (!this.renderedSourceRevision_) {
      this.renderedSourceRevision_ = sourceRevision;
    } else if (this.renderedSourceRevision_ !== sourceRevision) {
      this.renderedSourceRevision_ = sourceRevision;
      if (this.renderedSourceKey_ === source.getKey()) {
        this.tileCache_.clear();
      }
    }
    return true;
  }
  /**
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {import("../../extent.js").Extent} extent The extent to be rendered.
   * @param {number} initialZ The zoom level.
   * @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
   * @param {number} preload Number of additional levels to load.
   */
  enqueueTiles(frameState, extent, initialZ, tilesByZ, preload) {
    const viewState = frameState.viewState;
    const tileLayer = this.getLayer();
    const tileSource = tileLayer.getRenderSource();
    const tileGrid = tileSource.getTileGridForProjection(viewState.projection);
    const tileSourceKey = getUid(tileSource);
    if (!(tileSourceKey in frameState.wantedTiles)) {
      frameState.wantedTiles[tileSourceKey] = {};
    }
    const wantedTiles = frameState.wantedTiles[tileSourceKey];
    const map = tileLayer.getMapInternal();
    const minZ = Math.max(
      initialZ - preload,
      tileGrid.getMinZoom(),
      tileGrid.getZForResolution(
        Math.min(
          tileLayer.getMaxResolution(),
          map ? map.getView().getResolutionForZoom(Math.max(tileLayer.getMinZoom(), 0)) : tileGrid.getResolution(0)
        ),
        tileSource.zDirection
      )
    );
    const rotation = viewState.rotation;
    const viewport = rotation ? getRotatedViewport(
      viewState.center,
      viewState.resolution,
      rotation,
      frameState.size
    ) : void 0;
    for (let z = initialZ; z >= minZ; --z) {
      const tileRange = tileGrid.getTileRangeForExtentAndZ(
        extent,
        z,
        this.tempTileRange_
      );
      const tileResolution = tileGrid.getResolution(z);
      for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
        for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
          if (rotation && !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport)) {
            continue;
          }
          const tile = this.getTile(z, x, y, frameState);
          if (!tile) {
            continue;
          }
          const added = addTileToLookup(tilesByZ, tile, z);
          if (!added) {
            continue;
          }
          const tileQueueKey = tile.getKey();
          wantedTiles[tileQueueKey] = true;
          if (tile.getState() === TileState.IDLE) {
            if (!frameState.tileQueue.isKeyQueued(tileQueueKey)) {
              const tileCoord = createOrUpdate(z, x, y, this.tempTileCoord_);
              frameState.tileQueue.enqueue([
                tile,
                tileSourceKey,
                tileGrid.getTileCoordCenter(tileCoord),
                tileResolution
              ]);
            }
          }
        }
      }
    }
  }
  /**
   * Look for tiles covering the provided tile coordinate at an alternate
   * zoom level.  Loaded tiles will be added to the provided tile texture lookup.
   * @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate.
   * @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
   * @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level.
   * @private
   */
  findStaleTile_(tileCoord, tilesByZ) {
    const tileCache = this.tileCache_;
    const z = tileCoord[0];
    const x = tileCoord[1];
    const y = tileCoord[2];
    const staleKeys = this.getStaleKeys();
    for (let i = 0; i < staleKeys.length; ++i) {
      const cacheKey = getCacheKey(
        this.getLayer().getSource(),
        staleKeys[i],
        z,
        x,
        y
      );
      if (tileCache.containsKey(cacheKey)) {
        const tile = tileCache.peek(cacheKey);
        if (tile.getState() === TileState.LOADED) {
          tile.endTransition(getUid(this));
          addTileToLookup(tilesByZ, tile, z);
          return true;
        }
      }
    }
    return false;
  }
  /**
   * Look for tiles covering the provided tile coordinate at an alternate
   * zoom level.  Loaded tiles will be added to the provided tile texture lookup.
   * @param {import("../../tilegrid/TileGrid.js").default} tileGrid The tile grid.
   * @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate.
   * @param {number} altZ The alternate zoom level.
   * @param {TileLookup} tilesByZ Lookup of tiles by zoom level.
   * @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level.
   * @private
   */
  findAltTiles_(tileGrid, tileCoord, altZ, tilesByZ) {
    const tileRange = tileGrid.getTileRangeForTileCoordAndZ(
      tileCoord,
      altZ,
      this.tempTileRange_
    );
    if (!tileRange) {
      return false;
    }
    let covered = true;
    const tileCache = this.tileCache_;
    const source = this.getLayer().getRenderSource();
    const sourceKey = source.getKey();
    for (let x = tileRange.minX; x <= tileRange.maxX; ++x) {
      for (let y = tileRange.minY; y <= tileRange.maxY; ++y) {
        const cacheKey = getCacheKey(source, sourceKey, altZ, x, y);
        let loaded = false;
        if (tileCache.containsKey(cacheKey)) {
          const tile = tileCache.peek(cacheKey);
          if (tile.getState() === TileState.LOADED) {
            addTileToLookup(tilesByZ, tile, altZ);
            loaded = true;
          }
        }
        if (!loaded) {
          covered = false;
        }
      }
    }
    return covered;
  }
  /**
   * Render the layer.
   *
   * The frame rendering logic has three parts:
   *
   *  1. Enqueue tiles
   *  2. Find alt tiles for those that are not yet loaded
   *  3. Render loaded tiles
   *
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {HTMLElement} target Target that may be used to render content to.
   * @return {HTMLElement} The rendered element.
   * @override
   */
  renderFrame(frameState, target) {
    this.renderComplete = true;
    const layerState = frameState.layerStatesArray[frameState.layerIndex];
    const viewState = frameState.viewState;
    const projection = viewState.projection;
    const viewResolution = viewState.resolution;
    const viewCenter = viewState.center;
    const pixelRatio = frameState.pixelRatio;
    const tileLayer = this.getLayer();
    const tileSource = tileLayer.getSource();
    const tileGrid = tileSource.getTileGridForProjection(projection);
    const z = tileGrid.getZForResolution(viewResolution, tileSource.zDirection);
    const tileResolution = tileGrid.getResolution(z);
    const sourceKey = tileSource.getKey();
    if (!this.renderedSourceKey_) {
      this.renderedSourceKey_ = sourceKey;
    } else if (this.renderedSourceKey_ !== sourceKey) {
      this.prependStaleKey(this.renderedSourceKey_);
      this.renderedSourceKey_ = sourceKey;
    }
    let frameExtent = frameState.extent;
    const tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio);
    this.prepareContainer(frameState, target);
    const width = this.context.canvas.width;
    const height = this.context.canvas.height;
    const layerExtent = layerState.extent && fromUserExtent(layerState.extent, projection);
    if (layerExtent) {
      frameExtent = getIntersection(
        frameExtent,
        fromUserExtent(layerState.extent, projection)
      );
    }
    const dx = tileResolution * width / 2 / tilePixelRatio;
    const dy = tileResolution * height / 2 / tilePixelRatio;
    const canvasExtent = [
      viewCenter[0] - dx,
      viewCenter[1] - dy,
      viewCenter[0] + dx,
      viewCenter[1] + dy
    ];
    const tilesByZ = {};
    this.renderedTiles.length = 0;
    const preload = tileLayer.getPreload();
    if (frameState.nextExtent) {
      const targetZ = tileGrid.getZForResolution(
        viewState.nextResolution,
        tileSource.zDirection
      );
      const nextExtent = getRenderExtent(frameState, frameState.nextExtent);
      this.enqueueTiles(frameState, nextExtent, targetZ, tilesByZ, preload);
    }
    const renderExtent = getRenderExtent(frameState, frameExtent);
    this.enqueueTiles(frameState, renderExtent, z, tilesByZ, 0);
    if (preload > 0) {
      setTimeout(() => {
        this.enqueueTiles(
          frameState,
          renderExtent,
          z - 1,
          tilesByZ,
          preload - 1
        );
      }, 0);
    }
    if (!(z in tilesByZ)) {
      return this.container;
    }
    const uid = getUid(this);
    const time = frameState.time;
    for (const tile of tilesByZ[z]) {
      const tileState = tile.getState();
      if (tileState === TileState.EMPTY) {
        continue;
      }
      const tileCoord = tile.tileCoord;
      if (tileState === TileState.LOADED) {
        const alpha = tile.getAlpha(uid, time);
        if (alpha === 1) {
          tile.endTransition(uid);
          continue;
        }
      }
      if (tileState !== TileState.ERROR) {
        this.renderComplete = false;
      }
      const hasStaleTile = this.findStaleTile_(tileCoord, tilesByZ);
      if (hasStaleTile) {
        removeTileFromLookup(tilesByZ, tile, z);
        frameState.animate = true;
        continue;
      }
      const coveredByChildren = this.findAltTiles_(
        tileGrid,
        tileCoord,
        z + 1,
        tilesByZ
      );
      if (coveredByChildren) {
        continue;
      }
      const minZoom = tileGrid.getMinZoom();
      for (let parentZ = z - 1; parentZ >= minZoom; --parentZ) {
        const coveredByParent = this.findAltTiles_(
          tileGrid,
          tileCoord,
          parentZ,
          tilesByZ
        );
        if (coveredByParent) {
          break;
        }
      }
    }
    const canvasScale = tileResolution / viewResolution * pixelRatio / tilePixelRatio;
    const context = this.getRenderContext(frameState);
    compose(
      this.tempTransform,
      width / 2,
      height / 2,
      canvasScale,
      canvasScale,
      0,
      -width / 2,
      -height / 2
    );
    if (layerState.extent) {
      this.clipUnrotated(context, frameState, layerExtent);
    }
    if (!tileSource.getInterpolate()) {
      context.imageSmoothingEnabled = false;
    }
    this.preRender(context, frameState);
    const zs = Object.keys(tilesByZ).map(Number);
    zs.sort(ascending);
    let currentClip;
    const clips = [];
    const clipZs = [];
    for (let i = zs.length - 1; i >= 0; --i) {
      const currentZ = zs[i];
      const currentTilePixelSize = tileSource.getTilePixelSize(
        currentZ,
        pixelRatio,
        projection
      );
      const currentResolution = tileGrid.getResolution(currentZ);
      const currentScale = currentResolution / tileResolution;
      const dx2 = currentTilePixelSize[0] * currentScale * canvasScale;
      const dy2 = currentTilePixelSize[1] * currentScale * canvasScale;
      const originTileCoord = tileGrid.getTileCoordForCoordAndZ(
        getTopLeft(canvasExtent),
        currentZ
      );
      const originTileExtent = tileGrid.getTileCoordExtent(originTileCoord);
      const origin = apply(this.tempTransform, [
        tilePixelRatio * (originTileExtent[0] - canvasExtent[0]) / tileResolution,
        tilePixelRatio * (canvasExtent[3] - originTileExtent[3]) / tileResolution
      ]);
      const tileGutter = tilePixelRatio * tileSource.getGutterForProjection(projection);
      for (const tile of tilesByZ[currentZ]) {
        if (tile.getState() !== TileState.LOADED) {
          continue;
        }
        const tileCoord = tile.tileCoord;
        const xIndex = originTileCoord[1] - tileCoord[1];
        const nextX = Math.round(origin[0] - (xIndex - 1) * dx2);
        const yIndex = originTileCoord[2] - tileCoord[2];
        const nextY = Math.round(origin[1] - (yIndex - 1) * dy2);
        const x = Math.round(origin[0] - xIndex * dx2);
        const y = Math.round(origin[1] - yIndex * dy2);
        const w = nextX - x;
        const h = nextY - y;
        const transition = zs.length === 1;
        let contextSaved = false;
        currentClip = [x, y, x + w, y, x + w, y + h, x, y + h];
        for (let i2 = 0, ii = clips.length; i2 < ii; ++i2) {
          if (!transition && currentZ < clipZs[i2]) {
            const clip = clips[i2];
            if (intersects$1(
              [x, y, x + w, y + h],
              [clip[0], clip[3], clip[4], clip[7]]
            )) {
              if (!contextSaved) {
                context.save();
                contextSaved = true;
              }
              context.beginPath();
              context.moveTo(currentClip[0], currentClip[1]);
              context.lineTo(currentClip[2], currentClip[3]);
              context.lineTo(currentClip[4], currentClip[5]);
              context.lineTo(currentClip[6], currentClip[7]);
              context.moveTo(clip[6], clip[7]);
              context.lineTo(clip[4], clip[5]);
              context.lineTo(clip[2], clip[3]);
              context.lineTo(clip[0], clip[1]);
              context.clip();
            }
          }
        }
        clips.push(currentClip);
        clipZs.push(currentZ);
        this.drawTile(tile, frameState, x, y, w, h, tileGutter, transition);
        if (contextSaved) {
          context.restore();
        }
        this.renderedTiles.unshift(tile);
        this.updateUsedTiles(frameState.usedTiles, tileSource, tile);
      }
    }
    this.renderedResolution = tileResolution;
    this.extentChanged = !this.renderedExtent_ || !equals$1(this.renderedExtent_, canvasExtent);
    this.renderedExtent_ = canvasExtent;
    this.renderedPixelRatio = pixelRatio;
    this.postRender(this.context, frameState);
    if (layerState.extent) {
      context.restore();
    }
    context.imageSmoothingEnabled = true;
    if (this.renderComplete) {
      const postRenderFunction = (map, frameState2) => {
        const tileSourceKey = getUid(tileSource);
        const wantedTiles = frameState2.wantedTiles[tileSourceKey];
        const tilesCount = wantedTiles ? Object.keys(wantedTiles).length : 0;
        this.updateCacheSize(tilesCount);
        this.tileCache_.expireCache();
      };
      frameState.postRenderFunctions.push(postRenderFunction);
    }
    return this.container;
  }
  /**
   * Increases the cache size if needed
   * @param {number} tileCount Minimum number of tiles needed.
   */
  updateCacheSize(tileCount) {
    this.tileCache_.highWaterMark = Math.max(
      this.tileCache_.highWaterMark,
      tileCount * 2
    );
  }
  /**
   * @param {import("../../Tile.js").default} tile Tile.
   * @param {import("../../Map.js").FrameState} frameState Frame state.
   * @param {number} x Left of the tile.
   * @param {number} y Top of the tile.
   * @param {number} w Width of the tile.
   * @param {number} h Height of the tile.
   * @param {number} gutter Tile gutter.
   * @param {boolean} transition Apply an alpha transition.
   * @protected
   */
  drawTile(tile, frameState, x, y, w, h, gutter, transition) {
    let image;
    if (tile instanceof DataTile) {
      image = asImageLike(tile.getData());
      if (!image) {
        throw new Error("Rendering array data is not yet supported");
      }
    } else {
      image = this.getTileImage(
        /** @type {import("../../ImageTile.js").default} */
        tile
      );
    }
    if (!image) {
      return;
    }
    const context = this.getRenderContext(frameState);
    const uid = getUid(this);
    const layerState = frameState.layerStatesArray[frameState.layerIndex];
    const alpha = layerState.opacity * (transition ? tile.getAlpha(uid, frameState.time) : 1);
    const alphaChanged = alpha !== context.globalAlpha;
    if (alphaChanged) {
      context.save();
      context.globalAlpha = alpha;
    }
    context.drawImage(
      image,
      gutter,
      gutter,
      image.width - 2 * gutter,
      image.height - 2 * gutter,
      x,
      y,
      w,
      h
    );
    if (alphaChanged) {
      context.restore();
    }
    if (alpha !== layerState.opacity) {
      frameState.animate = true;
    } else if (transition) {
      tile.endTransition(uid);
    }
  }
  /**
   * @return {HTMLCanvasElement} Image
   */
  getImage() {
    const context = this.context;
    return context ? context.canvas : null;
  }
  /**
   * Get the image from a tile.
   * @param {import("../../ImageTile.js").default} tile Tile.
   * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
   * @protected
   */
  getTileImage(tile) {
    return tile.getImage();
  }
  /**
   * @param {!Object<string, !Object<string, boolean>>} usedTiles Used tiles.
   * @param {import("../../source/Tile.js").default} tileSource Tile source.
   * @param {import('../../Tile.js').default} tile Tile.
   * @protected
   */
  updateUsedTiles(usedTiles, tileSource, tile) {
    const tileSourceKey = getUid(tileSource);
    if (!(tileSourceKey in usedTiles)) {
      usedTiles[tileSourceKey] = {};
    }
    usedTiles[tileSourceKey][tile.getKey()] = true;
  }
}
const TileProperty = {
  PRELOAD: "preload",
  USE_INTERIM_TILES_ON_ERROR: "useInterimTilesOnError"
};
class BaseTileLayer extends Layer {
  /**
   * @param {Options<TileSourceType>} [options] Tile layer options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    const baseOptions = Object.assign({}, options2);
    const cacheSize2 = options2.cacheSize;
    delete options2.cacheSize;
    delete baseOptions.preload;
    delete baseOptions.useInterimTilesOnError;
    super(baseOptions);
    this.on;
    this.once;
    this.un;
    this.cacheSize_ = cacheSize2;
    this.setPreload(options2.preload !== void 0 ? options2.preload : 0);
    this.setUseInterimTilesOnError(
      options2.useInterimTilesOnError !== void 0 ? options2.useInterimTilesOnError : true
    );
  }
  /**
   * @return {number|undefined} The suggested cache size
   * @protected
   */
  getCacheSize() {
    return this.cacheSize_;
  }
  /**
   * Return the level as number to which we will preload tiles up to.
   * @return {number} The level to preload tiles up to.
   * @observable
   * @api
   */
  getPreload() {
    return (
      /** @type {number} */
      this.get(TileProperty.PRELOAD)
    );
  }
  /**
   * Set the level as number to which we will preload tiles up to.
   * @param {number} preload The level to preload tiles up to.
   * @observable
   * @api
   */
  setPreload(preload) {
    this.set(TileProperty.PRELOAD, preload);
  }
  /**
   * Deprecated.  Whether we use interim tiles on error.
   * @return {boolean} Use interim tiles on error.
   * @observable
   * @api
   */
  getUseInterimTilesOnError() {
    return (
      /** @type {boolean} */
      this.get(TileProperty.USE_INTERIM_TILES_ON_ERROR)
    );
  }
  /**
   * Deprecated.  Set whether we use interim tiles on error.
   * @param {boolean} useInterimTilesOnError Use interim tiles on error.
   * @observable
   * @api
   */
  setUseInterimTilesOnError(useInterimTilesOnError) {
    this.set(TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
  }
  /**
   * Get data for a pixel location.  The return type depends on the source data.  For image tiles,
   * a four element RGBA array will be returned.  For data tiles, the array length will match the
   * number of bands in the dataset.  For requests outside the layer extent, `null` will be returned.
   * Data for a image tiles can only be retrieved if the source's `crossOrigin` property is set.
   *
   * ```js
   * // display layer data on every pointer move
   * map.on('pointermove', (event) => {
   *   console.log(layer.getData(event.pixel));
   * });
   * ```
   * @param {import("../pixel").Pixel} pixel Pixel.
   * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data.
   * @api
   * @override
   */
  getData(pixel) {
    return super.getData(pixel);
  }
}
class TileLayer extends BaseTileLayer {
  /**
   * @param {import("./BaseTile.js").Options<TileSourceType>} [options] Tile layer options.
   */
  constructor(options2) {
    super(options2);
  }
  /**
   * @override
   */
  createRenderer() {
    return new CanvasTileLayerRenderer(this, {
      cacheSize: this.getCacheSize()
    });
  }
}
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
function synchronizeLayer(target, source, _context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/layer/Layer");
  }
  target.setOpacity(source.opacity);
  target.setVisible(source.visible);
  target.setZIndex(source.zIndex || void 0);
  target.setMinZoom(source.minZoom || -Infinity);
  target.setMaxZoom(source.maxZoom || Infinity);
  target.setBackground(source.background || void 0);
  return target;
}
function synchronizeTileLayer(target, source, context) {
  if (!target) {
    target = new TileLayer(
      createOptions({
        ...source,
        source: context.lookup.get(source.source)
      })
    );
  }
  synchronizeLayer(target, source);
  target.setSource(context.lookup.get(source.source));
  return target;
}
function synchronizeVectorLayer(target, source, context) {
  if (!target) {
    target = new VectorLayer(
      createOptions({
        ...source,
        source: context.lookup.get(source.source),
        style: void 0
      })
    );
  }
  synchronizeLayer(target, source);
  target.setSource(context.lookup.get(source.source));
  return target;
}
function synchronizeFeatureLayer(target, source, context) {
  target = synchronizeVectorLayer(target, source, context);
  const clusterStyle = context.lookup.get(source.clusterStyle);
  target.setStyle((feature) => {
    const size = feature.get("features").length;
    if (size === 1) {
      const originalFeature = feature.get("features")[0];
      let originalStyle = originalFeature.getStyle();
      if (typeof originalStyle === "function") {
        originalStyle = originalStyle(originalFeature);
      }
      if (originalStyle) {
        return originalStyle;
      }
    }
    const textStyle = clusterStyle ? clusterStyle.getText() : null;
    if (textStyle) {
      textStyle.setText(size.toString());
    }
    return clusterStyle;
  });
  return target;
}
function synchronizeImageLayer(target, source, context) {
  if (!target) {
    target = new ImageLayer(
      createOptions({
        ...source,
        source: context.lookup.get(source.source)
      })
    );
  }
  synchronizeLayer(target, source);
  target.setSource(context.lookup.get(source.source));
  return target;
}
class Cluster extends VectorSource {
  /**
   * @param {Options<FeatureType>} [options] Cluster options.
   */
  constructor(options2) {
    options2 = options2 || {};
    super({
      attributions: options2.attributions,
      wrapX: options2.wrapX
    });
    this.resolution = void 0;
    this.distance = options2.distance !== void 0 ? options2.distance : 20;
    this.minDistance = options2.minDistance || 0;
    this.interpolationRatio = 0;
    this.features = [];
    this.geometryFunction = options2.geometryFunction || function(feature) {
      const geometry = (
        /** @type {Point} */
        feature.getGeometry()
      );
      assert(
        !geometry || geometry.getType() === "Point",
        "The default `geometryFunction` can only handle `Point` or null geometries"
      );
      return geometry;
    };
    this.createCustomCluster_ = options2.createCluster;
    this.source = null;
    this.boundRefresh_ = this.refresh.bind(this);
    this.updateDistance(this.distance, this.minDistance);
    this.setSource(options2.source || null);
  }
  /**
   * Remove all features from the source.
   * @param {boolean} [fast] Skip dispatching of {@link module:ol/source/VectorEventType~VectorEventType#removefeature} events.
   * @api
   * @override
   */
  clear(fast) {
    this.features.length = 0;
    super.clear(fast);
  }
  /**
   * Get the distance in pixels between clusters.
   * @return {number} Distance.
   * @api
   */
  getDistance() {
    return this.distance;
  }
  /**
   * Get a reference to the wrapped source.
   * @return {VectorSource<FeatureType>|null} Source.
   * @api
   */
  getSource() {
    return this.source;
  }
  /**
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} resolution Resolution.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @override
   */
  loadFeatures(extent, resolution, projection) {
    this.source?.loadFeatures(extent, resolution, projection);
    if (resolution !== this.resolution) {
      this.resolution = resolution;
      this.refresh();
    }
  }
  /**
   * Set the distance within which features will be clusterd together.
   * @param {number} distance The distance in pixels.
   * @api
   */
  setDistance(distance) {
    this.updateDistance(distance, this.minDistance);
  }
  /**
   * Set the minimum distance between clusters. Will be capped at the
   * configured distance.
   * @param {number} minDistance The minimum distance in pixels.
   * @api
   */
  setMinDistance(minDistance) {
    this.updateDistance(this.distance, minDistance);
  }
  /**
   * The configured minimum distance between clusters.
   * @return {number} The minimum distance in pixels.
   * @api
   */
  getMinDistance() {
    return this.minDistance;
  }
  /**
   * Replace the wrapped source.
   * @param {VectorSource<FeatureType>|null} source The new source for this instance.
   * @api
   */
  setSource(source) {
    if (this.source) {
      this.source.removeEventListener(EventType.CHANGE, this.boundRefresh_);
    }
    this.source = source;
    if (source) {
      source.addEventListener(EventType.CHANGE, this.boundRefresh_);
    }
    this.refresh();
  }
  /**
   * Handle the source changing.
   * @override
   */
  refresh() {
    this.clear();
    this.cluster();
    this.addFeatures(this.features);
  }
  /**
   * Update the distances and refresh the source if necessary.
   * @param {number} distance The new distance.
   * @param {number} minDistance The new minimum distance.
   */
  updateDistance(distance, minDistance) {
    const ratio = distance === 0 ? 0 : Math.min(minDistance, distance) / distance;
    const changed = distance !== this.distance || this.interpolationRatio !== ratio;
    this.distance = distance;
    this.minDistance = minDistance;
    this.interpolationRatio = ratio;
    if (changed) {
      this.refresh();
    }
  }
  /**
   * @protected
   */
  cluster() {
    if (this.resolution === void 0 || !this.source) {
      return;
    }
    const extent = createEmpty();
    const mapDistance = this.distance * this.resolution;
    const features = this.source.getFeatures();
    const clustered = {};
    for (let i = 0, ii = features.length; i < ii; i++) {
      const feature = features[i];
      if (!(getUid(feature) in clustered)) {
        const geometry = this.geometryFunction(feature);
        if (geometry) {
          const coordinates2 = geometry.getCoordinates();
          createOrUpdateFromCoordinate(coordinates2, extent);
          buffer(extent, mapDistance, extent);
          const neighbors = this.source.getFeaturesInExtent(extent).filter(function(neighbor) {
            const uid = getUid(neighbor);
            if (uid in clustered) {
              return false;
            }
            clustered[uid] = true;
            return true;
          });
          this.features.push(this.createCluster(neighbors, extent));
        }
      }
    }
  }
  /**
   * @param {Array<FeatureType>} features Features
   * @param {import("../extent.js").Extent} extent The searched extent for these features.
   * @return {Feature} The cluster feature.
   * @protected
   */
  createCluster(features, extent) {
    const centroid2 = [0, 0];
    for (let i = features.length - 1; i >= 0; --i) {
      const geometry2 = this.geometryFunction(features[i]);
      if (geometry2) {
        add$3(centroid2, geometry2.getCoordinates());
      } else {
        features.splice(i, 1);
      }
    }
    scale$2(centroid2, 1 / features.length);
    const searchCenter = getCenter(extent);
    const ratio = this.interpolationRatio;
    const geometry = new Point$1([
      centroid2[0] * (1 - ratio) + searchCenter[0] * ratio,
      centroid2[1] * (1 - ratio) + searchCenter[1] * ratio
    ]);
    if (this.createCustomCluster_) {
      return this.createCustomCluster_(geometry, features);
    }
    return new Feature({
      geometry,
      features
    });
  }
}
function fromResolutionLike(resolution) {
  if (Array.isArray(resolution)) {
    return Math.min(...resolution);
  }
  return resolution;
}
class ReprojImage extends ImageWrapper {
  /**
   * @param {import("../proj/Projection.js").default} sourceProj Source projection (of the data).
   * @param {import("../proj/Projection.js").default} targetProj Target projection.
   * @param {import("../extent.js").Extent} targetExtent Target extent.
   * @param {number} targetResolution Target resolution.
   * @param {number} pixelRatio Pixel ratio.
   * @param {FunctionType} getImageFunction
   *     Function returning source images (extent, resolution, pixelRatio).
   * @param {boolean} interpolate Use linear interpolation when resampling.
   */
  constructor(sourceProj, targetProj, targetExtent, targetResolution, pixelRatio, getImageFunction, interpolate) {
    let maxSourceExtent = sourceProj.getExtent();
    if (maxSourceExtent && sourceProj.canWrapX()) {
      maxSourceExtent = maxSourceExtent.slice();
      maxSourceExtent[0] = -Infinity;
      maxSourceExtent[2] = Infinity;
    }
    let maxTargetExtent = targetProj.getExtent();
    if (maxTargetExtent && targetProj.canWrapX()) {
      maxTargetExtent = maxTargetExtent.slice();
      maxTargetExtent[0] = -Infinity;
      maxTargetExtent[2] = Infinity;
    }
    const limitedTargetExtent = maxTargetExtent ? getIntersection(targetExtent, maxTargetExtent) : targetExtent;
    const targetCenter = getCenter(limitedTargetExtent);
    const sourceResolution = calculateSourceResolution(
      sourceProj,
      targetProj,
      targetCenter,
      targetResolution
    );
    const errorThresholdInPixels = ERROR_THRESHOLD;
    const triangulation = new Triangulation(
      sourceProj,
      targetProj,
      limitedTargetExtent,
      maxSourceExtent,
      sourceResolution * errorThresholdInPixels,
      targetResolution
    );
    const sourceExtent = triangulation.calculateSourceExtent();
    const sourceImage = isEmpty(sourceExtent) ? null : getImageFunction(sourceExtent, sourceResolution, pixelRatio);
    const state = sourceImage ? ImageState.IDLE : ImageState.EMPTY;
    const sourcePixelRatio = sourceImage ? sourceImage.getPixelRatio() : 1;
    super(targetExtent, targetResolution, sourcePixelRatio, state);
    this.targetProj_ = targetProj;
    this.maxSourceExtent_ = maxSourceExtent;
    this.triangulation_ = triangulation;
    this.targetResolution_ = targetResolution;
    this.targetExtent_ = targetExtent;
    this.sourceImage_ = sourceImage;
    this.sourcePixelRatio_ = sourcePixelRatio;
    this.interpolate_ = interpolate;
    this.canvas_ = null;
    this.sourceListenerKey_ = null;
  }
  /**
   * Clean up.
   * @override
   */
  disposeInternal() {
    if (this.state == ImageState.LOADING) {
      this.unlistenSource_();
    }
    super.disposeInternal();
  }
  /**
   * @return {HTMLCanvasElement} Image.
   * @override
   */
  getImage() {
    return this.canvas_;
  }
  /**
   * @return {import("../proj/Projection.js").default} Projection.
   */
  getProjection() {
    return this.targetProj_;
  }
  /**
   * @private
   */
  reproject_() {
    const sourceState = this.sourceImage_.getState();
    if (sourceState == ImageState.LOADED) {
      const width = getWidth(this.targetExtent_) / this.targetResolution_;
      const height = getHeight(this.targetExtent_) / this.targetResolution_;
      this.canvas_ = render(
        width,
        height,
        this.sourcePixelRatio_,
        fromResolutionLike(this.sourceImage_.getResolution()),
        this.maxSourceExtent_,
        this.targetResolution_,
        this.targetExtent_,
        this.triangulation_,
        [
          {
            extent: this.sourceImage_.getExtent(),
            image: this.sourceImage_.getImage()
          }
        ],
        0,
        void 0,
        this.interpolate_,
        true
      );
    }
    this.state = sourceState;
    this.changed();
  }
  /**
   * Load not yet loaded URI.
   * @override
   */
  load() {
    if (this.state == ImageState.IDLE) {
      this.state = ImageState.LOADING;
      this.changed();
      const sourceState = this.sourceImage_.getState();
      if (sourceState == ImageState.LOADED || sourceState == ImageState.ERROR) {
        this.reproject_();
      } else {
        this.sourceListenerKey_ = listen(
          this.sourceImage_,
          EventType.CHANGE,
          (e) => {
            const sourceState2 = this.sourceImage_.getState();
            if (sourceState2 == ImageState.LOADED || sourceState2 == ImageState.ERROR) {
              this.unlistenSource_();
              this.reproject_();
            }
          }
        );
        this.sourceImage_.load();
      }
    }
  }
  /**
   * @private
   */
  unlistenSource_() {
    unlistenByKey(
      /** @type {!import("../events.js").EventsKey} */
      this.sourceListenerKey_
    );
    this.sourceListenerKey_ = null;
  }
}
const DECIMALS$1 = 4;
const ImageSourceEventType = {
  /**
   * Triggered when an image starts loading.
   * @event module:ol/source/Image.ImageSourceEvent#imageloadstart
   * @api
   */
  IMAGELOADSTART: "imageloadstart",
  /**
   * Triggered when an image finishes loading.
   * @event module:ol/source/Image.ImageSourceEvent#imageloadend
   * @api
   */
  IMAGELOADEND: "imageloadend",
  /**
   * Triggered if image loading results in an error.
   * @event module:ol/source/Image.ImageSourceEvent#imageloaderror
   * @api
   */
  IMAGELOADERROR: "imageloaderror"
};
class ImageSourceEvent extends BaseEvent {
  /**
   * @param {string} type Type.
   * @param {import("../Image.js").default} image The image.
   */
  constructor(type, image) {
    super(type);
    this.image = image;
  }
}
class ImageSource extends Source {
  /**
   * @param {Options} options Single image source options.
   */
  constructor(options2) {
    super({
      attributions: options2.attributions,
      projection: options2.projection,
      state: options2.state,
      interpolate: options2.interpolate !== void 0 ? options2.interpolate : true
    });
    this.on;
    this.once;
    this.un;
    this.loader = options2.loader || null;
    this.resolutions_ = options2.resolutions !== void 0 ? options2.resolutions : null;
    this.reprojectedImage_ = null;
    this.reprojectedRevision_ = 0;
    this.image = null;
    this.wantedExtent_;
    this.wantedResolution_;
    this.static_ = options2.loader ? options2.loader.length === 0 : false;
    this.wantedProjection_ = null;
  }
  /**
   * @return {Array<number>|null} Resolutions.
   * @override
   */
  getResolutions() {
    return this.resolutions_;
  }
  /**
   * @param {Array<number>|null} resolutions Resolutions.
   */
  setResolutions(resolutions) {
    this.resolutions_ = resolutions;
  }
  /**
   * @protected
   * @param {number} resolution Resolution.
   * @return {number} Resolution.
   */
  findNearestResolution(resolution) {
    const resolutions = this.getResolutions();
    if (resolutions) {
      const idx = linearFindNearest(resolutions, resolution, 0);
      resolution = resolutions[idx];
    }
    return resolution;
  }
  /**
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {import("../Image.js").default} Single image.
   */
  getImage(extent, resolution, pixelRatio, projection) {
    const sourceProjection = this.getProjection();
    if (!sourceProjection || !projection || equivalent$1(sourceProjection, projection)) {
      if (sourceProjection) {
        projection = sourceProjection;
      }
      return this.getImageInternal(extent, resolution, pixelRatio, projection);
    }
    if (this.reprojectedImage_) {
      if (this.reprojectedRevision_ == this.getRevision() && equivalent$1(this.reprojectedImage_.getProjection(), projection) && this.reprojectedImage_.getResolution() == resolution && equals$1(this.reprojectedImage_.getExtent(), extent)) {
        return this.reprojectedImage_;
      }
      this.reprojectedImage_.dispose();
      this.reprojectedImage_ = null;
    }
    this.reprojectedImage_ = new ReprojImage(
      sourceProjection,
      projection,
      extent,
      resolution,
      pixelRatio,
      (extent2, resolution2, pixelRatio2) => this.getImageInternal(extent2, resolution2, pixelRatio2, sourceProjection),
      this.getInterpolate()
    );
    this.reprojectedRevision_ = this.getRevision();
    return this.reprojectedImage_;
  }
  /**
   * @abstract
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {import("../Image.js").default} Single image.
   * @protected
   */
  getImageInternal(extent, resolution, pixelRatio, projection) {
    if (this.loader) {
      const requestExtent = getRequestExtent(extent, resolution, pixelRatio, 1);
      const requestResolution = this.findNearestResolution(resolution);
      if (this.image && (this.static_ || this.wantedProjection_ === projection && (this.wantedExtent_ && containsExtent(this.wantedExtent_, requestExtent) || containsExtent(this.image.getExtent(), requestExtent)) && (this.wantedResolution_ && fromResolutionLike(this.wantedResolution_) === requestResolution || fromResolutionLike(this.image.getResolution()) === requestResolution))) {
        return this.image;
      }
      this.wantedProjection_ = projection;
      this.wantedExtent_ = requestExtent;
      this.wantedResolution_ = requestResolution;
      this.image = new ImageWrapper(
        requestExtent,
        requestResolution,
        pixelRatio,
        this.loader
      );
      this.image.addEventListener(
        EventType.CHANGE,
        this.handleImageChange.bind(this)
      );
    }
    return this.image;
  }
  /**
   * Handle image change events.
   * @param {import("../events/Event.js").default} event Event.
   * @protected
   */
  handleImageChange(event) {
    const image = (
      /** @type {import("../Image.js").default} */
      event.target
    );
    let type;
    switch (image.getState()) {
      case ImageState.LOADING:
        this.loading = true;
        type = ImageSourceEventType.IMAGELOADSTART;
        break;
      case ImageState.LOADED:
        this.loading = false;
        type = ImageSourceEventType.IMAGELOADEND;
        break;
      case ImageState.ERROR:
        this.loading = false;
        type = ImageSourceEventType.IMAGELOADERROR;
        break;
      default:
        return;
    }
    if (this.hasListener(type)) {
      this.dispatchEvent(new ImageSourceEvent(type, image));
    }
  }
}
function defaultImageLoadFunction(image, src) {
  image.getImage().src = src;
}
function getRequestExtent(extent, resolution, pixelRatio, ratio) {
  const imageResolution = resolution / pixelRatio;
  const center = getCenter(extent);
  const viewWidth = ceil(getWidth(extent) / imageResolution, DECIMALS$1);
  const viewHeight = ceil(getHeight(extent) / imageResolution, DECIMALS$1);
  const marginWidth = ceil((ratio - 1) * viewWidth / 2, DECIMALS$1);
  const requestWidth = viewWidth + 2 * marginWidth;
  const marginHeight = ceil((ratio - 1) * viewHeight / 2, DECIMALS$1);
  const requestHeight = viewHeight + 2 * marginHeight;
  return getForViewAndSize(center, imageResolution, 0, [
    requestWidth,
    requestHeight
  ]);
}
function appendParams(uri, params2) {
  const keyParams = [];
  Object.keys(params2).forEach(function(k) {
    if (params2[k] !== null && params2[k] !== void 0) {
      keyParams.push(k + "=" + encodeURIComponent(params2[k]));
    }
  });
  const qs = keyParams.join("&");
  uri = uri.replace(/[?&]$/, "");
  uri += uri.includes("?") ? "&" : "?";
  return uri + qs;
}
const zRegEx = /\{z\}/g;
const xRegEx = /\{x\}/g;
const yRegEx = /\{y\}/g;
const dashYRegEx = /\{-y\}/g;
function renderXYZTemplate(template2, z, x, y, maxY) {
  return template2.replace(zRegEx, z.toString()).replace(xRegEx, x.toString()).replace(yRegEx, y.toString()).replace(dashYRegEx, function() {
    if (maxY === void 0) {
      throw new Error(
        "If the URL template has a {-y} placeholder, the grid extent must be known"
      );
    }
    return (maxY - y).toString();
  });
}
function expandUrl(url) {
  const urls = [];
  let match2 = /\{([a-z])-([a-z])\}/.exec(url);
  if (match2) {
    const startCharCode = match2[1].charCodeAt(0);
    const stopCharCode = match2[2].charCodeAt(0);
    let charCode;
    for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
      urls.push(url.replace(match2[0], String.fromCharCode(charCode)));
    }
    return urls;
  }
  match2 = /\{(\d+)-(\d+)\}/.exec(url);
  if (match2) {
    const stop2 = parseInt(match2[2], 10);
    for (let i = parseInt(match2[1], 10); i <= stop2; i++) {
      urls.push(url.replace(match2[0], i.toString()));
    }
    return urls;
  }
  urls.push(url);
  return urls;
}
const DEFAULT_VERSION = "1.3.0";
const GETFEATUREINFO_IMAGE_SIZE = [101, 101];
function getRequestUrl(baseUrl, extent, size, projection, params2) {
  params2["WIDTH"] = size[0];
  params2["HEIGHT"] = size[1];
  const axisOrientation = projection.getAxisOrientation();
  const v13 = compareVersions(params2["VERSION"], "1.3") >= 0;
  params2[v13 ? "CRS" : "SRS"] = projection.getCode();
  const bbox = v13 && axisOrientation.startsWith("ne") ? [extent[1], extent[0], extent[3], extent[2]] : extent;
  params2["BBOX"] = bbox.join(",");
  return appendParams(baseUrl, params2);
}
function getImageSrc(extent, resolution, pixelRatio, projection, url, params2, serverType) {
  params2 = Object.assign({ REQUEST: "GetMap" }, params2);
  const imageResolution = resolution / pixelRatio;
  const imageSize = [
    round(getWidth(extent) / imageResolution, DECIMALS$1),
    round(getHeight(extent) / imageResolution, DECIMALS$1)
  ];
  if (pixelRatio != 1) {
    switch (serverType) {
      case "geoserver":
        const dpi = 90 * pixelRatio + 0.5 | 0;
        if ("FORMAT_OPTIONS" in params2) {
          params2["FORMAT_OPTIONS"] += ";dpi:" + dpi;
        } else {
          params2["FORMAT_OPTIONS"] = "dpi:" + dpi;
        }
        break;
      case "mapserver":
        params2["MAP_RESOLUTION"] = 90 * pixelRatio;
        break;
      case "carmentaserver":
      case "qgis":
        params2["DPI"] = 90 * pixelRatio;
        break;
      default:
        throw new Error("Unknown `serverType` configured");
    }
  }
  const src = getRequestUrl(url, extent, imageSize, projection, params2);
  return src;
}
function getRequestParams(params2, request) {
  return Object.assign(
    {
      "REQUEST": request,
      "SERVICE": "WMS",
      "VERSION": DEFAULT_VERSION,
      "FORMAT": "image/png",
      "STYLES": "",
      "TRANSPARENT": "TRUE"
    },
    params2
  );
}
function createLoader(options2) {
  const hidpi = options2.hidpi === void 0 ? true : options2.hidpi;
  const projection = get$2(options2.projection || "EPSG:3857");
  const ratio = options2.ratio || 1.5;
  const load2 = options2.load || decode$1;
  const crossOrigin = options2.crossOrigin ?? null;
  return (extent, resolution, pixelRatio) => {
    extent = getRequestExtent(extent, resolution, pixelRatio, ratio);
    if (pixelRatio != 1 && (!hidpi || options2.serverType === void 0)) {
      pixelRatio = 1;
    }
    const src = getImageSrc(
      extent,
      resolution,
      pixelRatio,
      projection,
      options2.url,
      getRequestParams(options2.params, "GetMap"),
      options2.serverType
    );
    const image = new Image();
    image.crossOrigin = crossOrigin;
    return load2(image, src).then((image2) => ({ image: image2, extent, pixelRatio }));
  };
}
function getFeatureInfoUrl(options2, coordinate, resolution) {
  if (options2.url === void 0) {
    return void 0;
  }
  const projectionObj = get$2(options2.projection || "EPSG:3857");
  const extent = getForViewAndSize(
    coordinate,
    resolution,
    0,
    GETFEATUREINFO_IMAGE_SIZE
  );
  const baseParams = {
    "QUERY_LAYERS": options2.params["LAYERS"],
    "INFO_FORMAT": "application/json"
  };
  Object.assign(
    baseParams,
    getRequestParams(options2.params, "GetFeatureInfo"),
    options2.params
  );
  const x = floor((coordinate[0] - extent[0]) / resolution, DECIMALS$1);
  const y = floor((extent[3] - coordinate[1]) / resolution, DECIMALS$1);
  const v13 = compareVersions(baseParams["VERSION"], "1.3") >= 0;
  baseParams[v13 ? "I" : "X"] = x;
  baseParams[v13 ? "J" : "Y"] = y;
  return getRequestUrl(
    options2.url,
    extent,
    GETFEATUREINFO_IMAGE_SIZE,
    projectionObj,
    baseParams
  );
}
function getLegendUrl(options2, resolution) {
  if (options2.url === void 0) {
    return void 0;
  }
  const baseParams = {
    "SERVICE": "WMS",
    "VERSION": DEFAULT_VERSION,
    "REQUEST": "GetLegendGraphic",
    "FORMAT": "image/png"
  };
  if (resolution !== void 0) {
    const mpu = get$2(options2.projection || "EPSG:3857").getMetersPerUnit() || 1;
    const pixelSize = 28e-5;
    baseParams["SCALE"] = resolution * mpu / pixelSize;
  }
  Object.assign(baseParams, options2.params);
  if (options2.params !== void 0 && baseParams["LAYER"] === void 0) {
    const layers = baseParams["LAYERS"];
    const isSingleLayer = !Array.isArray(layers) || layers.length !== 1;
    if (!isSingleLayer) {
      return void 0;
    }
    baseParams["LAYER"] = layers;
  }
  return appendParams(options2.url, baseParams);
}
class ImageWMS extends ImageSource {
  /**
   * @param {Options} [options] ImageWMS options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : {};
    super({
      attributions: options2.attributions,
      interpolate: options2.interpolate,
      projection: options2.projection,
      resolutions: options2.resolutions
    });
    this.crossOrigin_ = options2.crossOrigin !== void 0 ? options2.crossOrigin : null;
    this.url_ = options2.url;
    this.imageLoadFunction_ = options2.imageLoadFunction !== void 0 ? options2.imageLoadFunction : defaultImageLoadFunction;
    this.params_ = Object.assign({}, options2.params);
    this.serverType_ = options2.serverType;
    this.hidpi_ = options2.hidpi !== void 0 ? options2.hidpi : true;
    this.renderedRevision_ = 0;
    this.ratio_ = options2.ratio !== void 0 ? options2.ratio : 1.5;
    this.loaderProjection_ = null;
  }
  /**
   * Return the GetFeatureInfo URL for the passed coordinate, resolution, and
   * projection. Return `undefined` if the GetFeatureInfo URL cannot be
   * constructed.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {number} resolution Resolution.
   * @param {import("../proj.js").ProjectionLike} projection Projection.
   * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
   *     be provided. If `QUERY_LAYERS` is not provided then the layers specified
   *     in the `LAYERS` parameter will be used. `VERSION` should not be
   *     specified here.
   * @return {string|undefined} GetFeatureInfo URL.
   * @api
   */
  getFeatureInfoUrl(coordinate, resolution, projection, params2) {
    const projectionObj = get$2(projection);
    const sourceProjectionObj = this.getProjection();
    if (sourceProjectionObj && sourceProjectionObj !== projectionObj) {
      resolution = calculateSourceResolution(
        sourceProjectionObj,
        projectionObj,
        coordinate,
        resolution
      );
      coordinate = transform$1(coordinate, projectionObj, sourceProjectionObj);
    }
    const options2 = {
      url: this.url_,
      params: {
        ...this.params_,
        ...params2
      },
      projection: sourceProjectionObj || projectionObj
    };
    return getFeatureInfoUrl(options2, coordinate, resolution);
  }
  /**
   * Return the GetLegendGraphic URL, optionally optimized for the passed
   * resolution and possibly including any passed specific parameters. Returns
   * `undefined` if the GetLegendGraphic URL cannot be constructed.
   *
   * @param {number} [resolution] Resolution. If set to undefined, `SCALE`
   *     will not be calculated and included in URL.
   * @param {Object} [params] GetLegendGraphic params. If `LAYER` is set, the
   *     request is generated for this wms layer, else it will try to use the
   *     configured wms layer. Default `FORMAT` is `image/png`.
   *     `VERSION` should not be specified here.
   * @return {string|undefined} GetLegendGraphic URL.
   * @api
   */
  getLegendUrl(resolution, params2) {
    return getLegendUrl(
      {
        url: this.url_,
        params: {
          ...this.params_,
          ...params2
        }
      },
      resolution
    );
  }
  /**
   * Get the user-provided params, i.e. those passed to the constructor through
   * the "params" option, and possibly updated using the updateParams method.
   * @return {Object} Params.
   * @api
   */
  getParams() {
    return this.params_;
  }
  /**
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} resolution Resolution.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {import("../Image.js").default} Single image.
   * @override
   */
  getImageInternal(extent, resolution, pixelRatio, projection) {
    if (this.url_ === void 0) {
      return null;
    }
    if (!this.loader || this.loaderProjection_ !== projection) {
      this.loaderProjection_ = projection;
      this.loader = createLoader({
        crossOrigin: this.crossOrigin_,
        params: this.params_,
        projection,
        serverType: this.serverType_,
        hidpi: this.hidpi_,
        url: this.url_,
        ratio: this.ratio_,
        load: (image, src) => {
          this.image.setImage(image);
          this.imageLoadFunction_(this.image, src);
          return decode$1(image);
        }
      });
    }
    return super.getImageInternal(extent, resolution, pixelRatio, projection);
  }
  /**
   * Return the image load function of the source.
   * @return {import("../Image.js").LoadFunction} The image load function.
   * @api
   */
  getImageLoadFunction() {
    return this.imageLoadFunction_;
  }
  /**
   * Return the URL used for this WMS source.
   * @return {string|undefined} URL.
   * @api
   */
  getUrl() {
    return this.url_;
  }
  /**
   * Set the image load function of the source.
   * @param {import("../Image.js").LoadFunction} imageLoadFunction Image load function.
   * @api
   */
  setImageLoadFunction(imageLoadFunction) {
    this.imageLoadFunction_ = imageLoadFunction;
    this.changed();
  }
  /**
   * Set the URL to use for requests.
   * @param {string|undefined} url URL.
   * @api
   */
  setUrl(url) {
    if (url != this.url_) {
      this.url_ = url;
      this.loader = null;
      this.changed();
    }
  }
  /**
   * Set the user-provided params.
   * @param {Object} params Params.
   * @api
   */
  setParams(params2) {
    this.params_ = Object.assign({}, params2);
    this.changed();
  }
  /**
   * Update the user-provided params.
   * @param {Object} params Params.
   * @api
   */
  updateParams(params2) {
    Object.assign(this.params_, params2);
    this.changed();
  }
  /**
   * @override
   */
  changed() {
    this.image = null;
    super.changed();
  }
}
const tmpTileCoord = [0, 0, 0];
const DECIMALS = 5;
class TileGrid {
  /**
   * @param {Options} options Tile grid options.
   */
  constructor(options2) {
    this.minZoom = options2.minZoom !== void 0 ? options2.minZoom : 0;
    this.resolutions_ = options2.resolutions;
    assert(
      isSorted(
        this.resolutions_,
        /**
         * @param {number} a First resolution
         * @param {number} b Second resolution
         * @return {number} Comparison result
         */
        (a, b) => b - a
      ),
      "`resolutions` must be sorted in descending order"
    );
    let zoomFactor;
    if (!options2.origins) {
      for (let i = 0, ii = this.resolutions_.length - 1; i < ii; ++i) {
        if (!zoomFactor) {
          zoomFactor = this.resolutions_[i] / this.resolutions_[i + 1];
        } else {
          if (this.resolutions_[i] / this.resolutions_[i + 1] !== zoomFactor) {
            zoomFactor = void 0;
            break;
          }
        }
      }
    }
    this.zoomFactor_ = zoomFactor;
    this.maxZoom = this.resolutions_.length - 1;
    this.origin_ = options2.origin !== void 0 ? options2.origin : null;
    this.origins_ = null;
    if (options2.origins !== void 0) {
      this.origins_ = options2.origins;
      assert(
        this.origins_.length == this.resolutions_.length,
        "Number of `origins` and `resolutions` must be equal"
      );
    }
    const extent = options2.extent;
    if (extent !== void 0 && !this.origin_ && !this.origins_) {
      this.origin_ = getTopLeft(extent);
    }
    assert(
      !this.origin_ && this.origins_ || this.origin_ && !this.origins_,
      "Either `origin` or `origins` must be configured, never both"
    );
    this.tileSizes_ = null;
    if (options2.tileSizes !== void 0) {
      this.tileSizes_ = options2.tileSizes;
      assert(
        this.tileSizes_.length == this.resolutions_.length,
        "Number of `tileSizes` and `resolutions` must be equal"
      );
    }
    this.tileSize_ = options2.tileSize !== void 0 ? options2.tileSize : !this.tileSizes_ ? DEFAULT_TILE_SIZE : null;
    assert(
      !this.tileSize_ && this.tileSizes_ || this.tileSize_ && !this.tileSizes_,
      "Either `tileSize` or `tileSizes` must be configured, never both"
    );
    this.extent_ = extent !== void 0 ? extent : null;
    this.fullTileRanges_ = null;
    this.tmpSize_ = [0, 0];
    this.tmpExtent_ = [0, 0, 0, 0];
    if (options2.sizes !== void 0) {
      this.fullTileRanges_ = options2.sizes.map((size, z) => {
        const tileRange = new TileRange(
          Math.min(0, size[0]),
          Math.max(size[0] - 1, -1),
          Math.min(0, size[1]),
          Math.max(size[1] - 1, -1)
        );
        if (extent) {
          const restrictedTileRange = this.getTileRangeForExtentAndZ(extent, z);
          tileRange.minX = Math.max(restrictedTileRange.minX, tileRange.minX);
          tileRange.maxX = Math.min(restrictedTileRange.maxX, tileRange.maxX);
          tileRange.minY = Math.max(restrictedTileRange.minY, tileRange.minY);
          tileRange.maxY = Math.min(restrictedTileRange.maxY, tileRange.maxY);
        }
        return tileRange;
      });
    } else if (extent) {
      this.calculateTileRanges_(extent);
    }
  }
  /**
   * Call a function with each tile coordinate for a given extent and zoom level.
   *
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} zoom Integer zoom level.
   * @param {function(import("../tilecoord.js").TileCoord): void} callback Function called with each tile coordinate.
   * @api
   */
  forEachTileCoord(extent, zoom, callback) {
    const tileRange = this.getTileRangeForExtentAndZ(extent, zoom);
    for (let i = tileRange.minX, ii = tileRange.maxX; i <= ii; ++i) {
      for (let j = tileRange.minY, jj = tileRange.maxY; j <= jj; ++j) {
        callback([zoom, i, j]);
      }
    }
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {function(number, import("../TileRange.js").default): boolean} callback Callback.
   * @param {import("../TileRange.js").default} [tempTileRange] Temporary import("../TileRange.js").default object.
   * @param {import("../extent.js").Extent} [tempExtent] Temporary import("../extent.js").Extent object.
   * @return {boolean} Callback succeeded.
   */
  forEachTileCoordParentTileRange(tileCoord, callback, tempTileRange, tempExtent) {
    let tileRange, x, y;
    let tileCoordExtent = null;
    let z = tileCoord[0] - 1;
    if (this.zoomFactor_ === 2) {
      x = tileCoord[1];
      y = tileCoord[2];
    } else {
      tileCoordExtent = this.getTileCoordExtent(tileCoord, tempExtent);
    }
    while (z >= this.minZoom) {
      if (x !== void 0 && y !== void 0) {
        x = Math.floor(x / 2);
        y = Math.floor(y / 2);
        tileRange = createOrUpdate$1(x, x, y, y, tempTileRange);
      } else {
        tileRange = this.getTileRangeForExtentAndZ(
          tileCoordExtent,
          z,
          tempTileRange
        );
      }
      if (callback(z, tileRange)) {
        return true;
      }
      --z;
    }
    return false;
  }
  /**
   * Get the extent for this tile grid, if it was configured.
   * @return {import("../extent.js").Extent} Extent.
   * @api
   */
  getExtent() {
    return this.extent_;
  }
  /**
   * Get the maximum zoom level for the grid.
   * @return {number} Max zoom.
   * @api
   */
  getMaxZoom() {
    return this.maxZoom;
  }
  /**
   * Get the minimum zoom level for the grid.
   * @return {number} Min zoom.
   * @api
   */
  getMinZoom() {
    return this.minZoom;
  }
  /**
   * Get the origin for the grid at the given zoom level.
   * @param {number} z Integer zoom level.
   * @return {import("../coordinate.js").Coordinate} Origin.
   * @api
   */
  getOrigin(z) {
    if (this.origin_) {
      return this.origin_;
    }
    return this.origins_[z];
  }
  /**
   * Get the resolution for the given zoom level.
   * @param {number} z Integer zoom level.
   * @return {number} Resolution.
   * @api
   */
  getResolution(z) {
    return this.resolutions_[z];
  }
  /**
   * Get the list of resolutions for the tile grid.
   * @return {Array<number>} Resolutions.
   * @api
   */
  getResolutions() {
    return this.resolutions_;
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("../TileRange.js").default} [tempTileRange] Temporary import("../TileRange.js").default object.
   * @param {import("../extent.js").Extent} [tempExtent] Temporary import("../extent.js").Extent object.
   * @return {import("../TileRange.js").default|null} Tile range.
   */
  getTileCoordChildTileRange(tileCoord, tempTileRange, tempExtent) {
    if (tileCoord[0] < this.maxZoom) {
      if (this.zoomFactor_ === 2) {
        const minX = tileCoord[1] * 2;
        const minY = tileCoord[2] * 2;
        return createOrUpdate$1(
          minX,
          minX + 1,
          minY,
          minY + 1,
          tempTileRange
        );
      }
      const tileCoordExtent = this.getTileCoordExtent(
        tileCoord,
        tempExtent || this.tmpExtent_
      );
      return this.getTileRangeForExtentAndZ(
        tileCoordExtent,
        tileCoord[0] + 1,
        tempTileRange
      );
    }
    return null;
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {number} z Integer zoom level.
   * @param {import("../TileRange.js").default} [tempTileRange] Temporary import("../TileRange.js").default object.
   * @return {import("../TileRange.js").default|null} Tile range.
   */
  getTileRangeForTileCoordAndZ(tileCoord, z, tempTileRange) {
    if (z > this.maxZoom || z < this.minZoom) {
      return null;
    }
    const tileCoordZ = tileCoord[0];
    const tileCoordX = tileCoord[1];
    const tileCoordY = tileCoord[2];
    if (z === tileCoordZ) {
      return createOrUpdate$1(
        tileCoordX,
        tileCoordY,
        tileCoordX,
        tileCoordY,
        tempTileRange
      );
    }
    if (this.zoomFactor_) {
      const factor = Math.pow(this.zoomFactor_, z - tileCoordZ);
      const minX = Math.floor(tileCoordX * factor);
      const minY = Math.floor(tileCoordY * factor);
      if (z < tileCoordZ) {
        return createOrUpdate$1(minX, minX, minY, minY, tempTileRange);
      }
      const maxX = Math.floor(factor * (tileCoordX + 1)) - 1;
      const maxY = Math.floor(factor * (tileCoordY + 1)) - 1;
      return createOrUpdate$1(minX, maxX, minY, maxY, tempTileRange);
    }
    const tileCoordExtent = this.getTileCoordExtent(tileCoord, this.tmpExtent_);
    return this.getTileRangeForExtentAndZ(tileCoordExtent, z, tempTileRange);
  }
  /**
   * Get a tile range for the given extent and integer zoom level.
   * @param {import("../extent.js").Extent} extent Extent.
   * @param {number} z Integer zoom level.
   * @param {import("../TileRange.js").default} [tempTileRange] Temporary tile range object.
   * @return {import("../TileRange.js").default} Tile range.
   */
  getTileRangeForExtentAndZ(extent, z, tempTileRange) {
    this.getTileCoordForXYAndZ_(extent[0], extent[3], z, false, tmpTileCoord);
    const minX = tmpTileCoord[1];
    const minY = tmpTileCoord[2];
    this.getTileCoordForXYAndZ_(extent[2], extent[1], z, true, tmpTileCoord);
    const maxX = tmpTileCoord[1];
    const maxY = tmpTileCoord[2];
    return createOrUpdate$1(minX, maxX, minY, maxY, tempTileRange);
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @return {import("../coordinate.js").Coordinate} Tile center.
   */
  getTileCoordCenter(tileCoord) {
    const origin = this.getOrigin(tileCoord[0]);
    const resolution = this.getResolution(tileCoord[0]);
    const tileSize = toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);
    return [
      origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution,
      origin[1] - (tileCoord[2] + 0.5) * tileSize[1] * resolution
    ];
  }
  /**
   * Get the extent of a tile coordinate.
   *
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("../extent.js").Extent} [tempExtent] Temporary extent object.
   * @return {import("../extent.js").Extent} Extent.
   * @api
   */
  getTileCoordExtent(tileCoord, tempExtent) {
    const origin = this.getOrigin(tileCoord[0]);
    const resolution = this.getResolution(tileCoord[0]);
    const tileSize = toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);
    const minX = origin[0] + tileCoord[1] * tileSize[0] * resolution;
    const minY = origin[1] - (tileCoord[2] + 1) * tileSize[1] * resolution;
    const maxX = minX + tileSize[0] * resolution;
    const maxY = minY + tileSize[1] * resolution;
    return createOrUpdate$2(minX, minY, maxX, maxY, tempExtent);
  }
  /**
   * Get the tile coordinate for the given map coordinate and resolution.  This
   * method considers that coordinates that intersect tile boundaries should be
   * assigned the higher tile coordinate.
   *
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {number} resolution Resolution.
   * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Destination import("../tilecoord.js").TileCoord object.
   * @return {import("../tilecoord.js").TileCoord} Tile coordinate.
   * @api
   */
  getTileCoordForCoordAndResolution(coordinate, resolution, opt_tileCoord) {
    return this.getTileCoordForXYAndResolution_(
      coordinate[0],
      coordinate[1],
      resolution,
      false,
      opt_tileCoord
    );
  }
  /**
   * Note that this method should not be called for resolutions that correspond
   * to an integer zoom level.  Instead call the `getTileCoordForXYAndZ_` method.
   * @param {number} x X.
   * @param {number} y Y.
   * @param {number} resolution Resolution (for a non-integer zoom level).
   * @param {boolean} reverseIntersectionPolicy Instead of letting edge
   *     intersections go to the higher tile coordinate, let edge intersections
   *     go to the lower tile coordinate.
   * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Temporary import("../tilecoord.js").TileCoord object.
   * @return {import("../tilecoord.js").TileCoord} Tile coordinate.
   * @private
   */
  getTileCoordForXYAndResolution_(x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) {
    const z = this.getZForResolution(resolution);
    const scale2 = resolution / this.getResolution(z);
    const origin = this.getOrigin(z);
    const tileSize = toSize(this.getTileSize(z), this.tmpSize_);
    let tileCoordX = scale2 * (x - origin[0]) / resolution / tileSize[0];
    let tileCoordY = scale2 * (origin[1] - y) / resolution / tileSize[1];
    if (reverseIntersectionPolicy) {
      tileCoordX = ceil(tileCoordX, DECIMALS) - 1;
      tileCoordY = ceil(tileCoordY, DECIMALS) - 1;
    } else {
      tileCoordX = floor(tileCoordX, DECIMALS);
      tileCoordY = floor(tileCoordY, DECIMALS);
    }
    return createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord);
  }
  /**
   * Although there is repetition between this method and `getTileCoordForXYAndResolution_`,
   * they should have separate implementations.  This method is for integer zoom
   * levels.  The other method should only be called for resolutions corresponding
   * to non-integer zoom levels.
   * @param {number} x Map x coordinate.
   * @param {number} y Map y coordinate.
   * @param {number} z Integer zoom level.
   * @param {boolean} reverseIntersectionPolicy Instead of letting edge
   *     intersections go to the higher tile coordinate, let edge intersections
   *     go to the lower tile coordinate.
   * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Temporary import("../tilecoord.js").TileCoord object.
   * @return {import("../tilecoord.js").TileCoord} Tile coordinate.
   * @private
   */
  getTileCoordForXYAndZ_(x, y, z, reverseIntersectionPolicy, opt_tileCoord) {
    const origin = this.getOrigin(z);
    const resolution = this.getResolution(z);
    const tileSize = toSize(this.getTileSize(z), this.tmpSize_);
    let tileCoordX = (x - origin[0]) / resolution / tileSize[0];
    let tileCoordY = (origin[1] - y) / resolution / tileSize[1];
    if (reverseIntersectionPolicy) {
      tileCoordX = ceil(tileCoordX, DECIMALS) - 1;
      tileCoordY = ceil(tileCoordY, DECIMALS) - 1;
    } else {
      tileCoordX = floor(tileCoordX, DECIMALS);
      tileCoordY = floor(tileCoordY, DECIMALS);
    }
    return createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord);
  }
  /**
   * Get a tile coordinate given a map coordinate and zoom level.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {number} z Integer zoom level, e.g. the result of a `getZForResolution()` method call
   * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Destination import("../tilecoord.js").TileCoord object.
   * @return {import("../tilecoord.js").TileCoord} Tile coordinate.
   * @api
   */
  getTileCoordForCoordAndZ(coordinate, z, opt_tileCoord) {
    return this.getTileCoordForXYAndZ_(
      coordinate[0],
      coordinate[1],
      z,
      false,
      opt_tileCoord
    );
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @return {number} Tile resolution.
   */
  getTileCoordResolution(tileCoord) {
    return this.resolutions_[tileCoord[0]];
  }
  /**
   * Get the tile size for a zoom level. The type of the return value matches the
   * `tileSize` or `tileSizes` that the tile grid was configured with. To always
   * get an {@link import("../size.js").Size}, run the result through {@link module:ol/size.toSize}.
   * @param {number} z Z.
   * @return {number|import("../size.js").Size} Tile size.
   * @api
   */
  getTileSize(z) {
    if (this.tileSize_) {
      return this.tileSize_;
    }
    return this.tileSizes_[z];
  }
  /**
   * @param {number} z Zoom level.
   * @return {import("../TileRange.js").default|null} Extent tile range for the specified zoom level.
   */
  getFullTileRange(z) {
    if (!this.fullTileRanges_) {
      return this.extent_ ? this.getTileRangeForExtentAndZ(this.extent_, z) : null;
    }
    return this.fullTileRanges_[z];
  }
  /**
   * @param {number} resolution Resolution.
   * @param {number|import("../array.js").NearestDirectionFunction} [opt_direction]
   *     If 0, the nearest resolution will be used.
   *     If 1, the nearest higher resolution (lower Z) will be used. If -1, the
   *     nearest lower resolution (higher Z) will be used. Default is 0.
   *     Use a {@link module:ol/array~NearestDirectionFunction} for more precise control.
   *
   * For example to change tile Z at the midpoint of zoom levels
   * ```js
   * function(value, high, low) {
   *   return value - low * Math.sqrt(high / low);
   * }
   * ```
   * @return {number} Z.
   * @api
   */
  getZForResolution(resolution, opt_direction) {
    const z = linearFindNearest(
      this.resolutions_,
      resolution,
      opt_direction || 0
    );
    return clamp(z, this.minZoom, this.maxZoom);
  }
  /**
   * The tile with the provided tile coordinate intersects the given viewport.
   * @param {import('../tilecoord.js').TileCoord} tileCoord Tile coordinate.
   * @param {Array<number>} viewport Viewport as returned from {@link module:ol/extent.getRotatedViewport}.
   * @return {boolean} The tile with the provided tile coordinate intersects the given viewport.
   */
  tileCoordIntersectsViewport(tileCoord, viewport) {
    return intersectsLinearRing(
      viewport,
      0,
      viewport.length,
      2,
      this.getTileCoordExtent(tileCoord)
    );
  }
  /**
   * @param {!import("../extent.js").Extent} extent Extent for this tile grid.
   * @private
   */
  calculateTileRanges_(extent) {
    const length = this.resolutions_.length;
    const fullTileRanges = new Array(length);
    for (let z = this.minZoom; z < length; ++z) {
      fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z);
    }
    this.fullTileRanges_ = fullTileRanges;
  }
}
function getForProjection(projection) {
  let tileGrid = projection.getDefaultTileGrid();
  if (!tileGrid) {
    tileGrid = createForProjection(projection);
    projection.setDefaultTileGrid(tileGrid);
  }
  return tileGrid;
}
function wrapX(tileGrid, tileCoord, projection) {
  const z = tileCoord[0];
  const center = tileGrid.getTileCoordCenter(tileCoord);
  const projectionExtent = extentFromProjection(projection);
  if (!containsCoordinate(projectionExtent, center)) {
    const worldWidth = getWidth(projectionExtent);
    const worldsAway = Math.ceil(
      (projectionExtent[0] - center[0]) / worldWidth
    );
    center[0] += worldWidth * worldsAway;
    return tileGrid.getTileCoordForCoordAndZ(center, z);
  }
  return tileCoord;
}
function createForExtent(extent, maxZoom, tileSize, corner) {
  corner = corner !== void 0 ? corner : "top-left";
  const resolutions = resolutionsFromExtent(extent, maxZoom, tileSize);
  return new TileGrid({
    extent,
    origin: getCorner(extent, corner),
    resolutions,
    tileSize
  });
}
function createXYZ(options2) {
  const xyzOptions = options2 || {};
  const extent = xyzOptions.extent || get$2("EPSG:3857").getExtent();
  const gridOptions = {
    extent,
    minZoom: xyzOptions.minZoom,
    tileSize: xyzOptions.tileSize,
    resolutions: resolutionsFromExtent(
      extent,
      xyzOptions.maxZoom,
      xyzOptions.tileSize,
      xyzOptions.maxResolution
    )
  };
  return new TileGrid(gridOptions);
}
function resolutionsFromExtent(extent, maxZoom, tileSize, maxResolution) {
  maxZoom = maxZoom !== void 0 ? maxZoom : DEFAULT_MAX_ZOOM;
  tileSize = toSize(tileSize !== void 0 ? tileSize : DEFAULT_TILE_SIZE);
  const height = getHeight(extent);
  const width = getWidth(extent);
  maxResolution = maxResolution > 0 ? maxResolution : Math.max(width / tileSize[0], height / tileSize[1]);
  const length = maxZoom + 1;
  const resolutions = new Array(length);
  for (let z = 0; z < length; ++z) {
    resolutions[z] = maxResolution / Math.pow(2, z);
  }
  return resolutions;
}
function createForProjection(projection, maxZoom, tileSize, corner) {
  const extent = extentFromProjection(projection);
  return createForExtent(extent, maxZoom, tileSize, corner);
}
function extentFromProjection(projection) {
  projection = get$2(projection);
  let extent = projection.getExtent();
  if (!extent) {
    const half = 180 * METERS_PER_UNIT$1.degrees / projection.getMetersPerUnit();
    extent = createOrUpdate$2(-half, -half, half, half);
  }
  return extent;
}
function createFromTemplate(template2, tileGrid) {
  return (
    /**
     * @param {import("./tilecoord.js").TileCoord} tileCoord Tile Coordinate.
     * @param {number} pixelRatio Pixel ratio.
     * @param {import("./proj/Projection.js").default} projection Projection.
     * @return {string|undefined} Tile URL.
     */
    (function(tileCoord, pixelRatio, projection) {
      if (!tileCoord) {
        return void 0;
      }
      let maxY;
      const z = tileCoord[0];
      if (tileGrid) {
        const range2 = tileGrid.getFullTileRange(z);
        if (range2) {
          maxY = range2.getHeight() - 1;
        }
      }
      return renderXYZTemplate(template2, z, tileCoord[1], tileCoord[2], maxY);
    })
  );
}
function createFromTemplates(templates, tileGrid) {
  const len = templates.length;
  const tileUrlFunctions = new Array(len);
  for (let i = 0; i < len; ++i) {
    tileUrlFunctions[i] = createFromTemplate(templates[i], tileGrid);
  }
  return createFromTileUrlFunctions(tileUrlFunctions);
}
function createFromTileUrlFunctions(tileUrlFunctions) {
  if (tileUrlFunctions.length === 1) {
    return tileUrlFunctions[0];
  }
  return (
    /**
     * @param {import("./tilecoord.js").TileCoord} tileCoord Tile Coordinate.
     * @param {number} pixelRatio Pixel ratio.
     * @param {import("./proj/Projection.js").default} projection Projection.
     * @return {string|undefined} Tile URL.
     */
    (function(tileCoord, pixelRatio, projection) {
      if (!tileCoord) {
        return void 0;
      }
      const h = hash(tileCoord);
      const index = modulo(h, tileUrlFunctions.length);
      return tileUrlFunctions[index](tileCoord, pixelRatio, projection);
    })
  );
}
class TileSource extends Source {
  /**
   * @param {Options} options SourceTile source options.
   */
  constructor(options2) {
    super({
      attributions: options2.attributions,
      attributionsCollapsible: options2.attributionsCollapsible,
      projection: options2.projection,
      state: options2.state,
      wrapX: options2.wrapX,
      interpolate: options2.interpolate
    });
    this.on;
    this.once;
    this.un;
    this.tilePixelRatio_ = options2.tilePixelRatio !== void 0 ? options2.tilePixelRatio : 1;
    this.tileGrid = options2.tileGrid !== void 0 ? options2.tileGrid : null;
    const tileSize = [256, 256];
    if (this.tileGrid) {
      toSize(this.tileGrid.getTileSize(this.tileGrid.getMinZoom()), tileSize);
    }
    this.tmpSize = [0, 0];
    this.key_ = options2.key || getUid(this);
    this.tileOptions = {
      transition: options2.transition,
      interpolate: options2.interpolate
    };
    this.zDirection = options2.zDirection ? options2.zDirection : 0;
  }
  /**
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {number} Gutter.
   */
  getGutterForProjection(projection) {
    return 0;
  }
  /**
   * Return the key to be used for all tiles in the source.
   * @return {string} The key for all tiles.
   */
  getKey() {
    return this.key_;
  }
  /**
   * Set the value to be used as the key for all tiles in the source.
   * @param {string} key The key for tiles.
   * @protected
   */
  setKey(key2) {
    if (this.key_ !== key2) {
      this.key_ = key2;
      this.changed();
    }
  }
  /**
   * @param {import("../proj/Projection").default} [projection] Projection.
   * @return {Array<number>|null} Resolutions.
   * @override
   */
  getResolutions(projection) {
    const tileGrid = projection ? this.getTileGridForProjection(projection) : this.tileGrid;
    if (!tileGrid) {
      return null;
    }
    return tileGrid.getResolutions();
  }
  /**
   * @abstract
   * @param {number} z Tile coordinate z.
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {TileType|null} Tile.
   */
  getTile(z, x, y, pixelRatio, projection) {
    return abstract();
  }
  /**
   * Return the tile grid of the tile source.
   * @return {import("../tilegrid/TileGrid.js").default|null} Tile grid.
   * @api
   */
  getTileGrid() {
    return this.tileGrid;
  }
  /**
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {!import("../tilegrid/TileGrid.js").default} Tile grid.
   */
  getTileGridForProjection(projection) {
    if (!this.tileGrid) {
      return getForProjection(projection);
    }
    return this.tileGrid;
  }
  /**
   * Get the tile pixel ratio for this source. Subclasses may override this
   * method, which is meant to return a supported pixel ratio that matches the
   * provided `pixelRatio` as close as possible.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} Tile pixel ratio.
   */
  getTilePixelRatio(pixelRatio) {
    return this.tilePixelRatio_;
  }
  /**
   * @param {number} z Z.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {import("../size.js").Size} Tile size.
   */
  getTilePixelSize(z, pixelRatio, projection) {
    const tileGrid = this.getTileGridForProjection(projection);
    const tilePixelRatio = this.getTilePixelRatio(pixelRatio);
    const tileSize = toSize(tileGrid.getTileSize(z), this.tmpSize);
    if (tilePixelRatio == 1) {
      return tileSize;
    }
    return scale(tileSize, tilePixelRatio, this.tmpSize);
  }
  /**
   * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate
   * is outside the resolution and extent range of the tile grid, `null` will be
   * returned.
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("../proj/Projection.js").default} [projection] Projection.
   * @return {import("../tilecoord.js").TileCoord} Tile coordinate to be passed to the tileUrlFunction or
   *     null if no tile URL should be created for the passed `tileCoord`.
   */
  getTileCoordForTileUrlFunction(tileCoord, projection) {
    const gridProjection = projection !== void 0 ? projection : this.getProjection();
    const tileGrid = projection !== void 0 ? this.getTileGridForProjection(gridProjection) : this.tileGrid || this.getTileGridForProjection(gridProjection);
    if (this.getWrapX() && gridProjection.isGlobal()) {
      tileCoord = wrapX(tileGrid, tileCoord, gridProjection);
    }
    return withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;
  }
  /**
   * Remove all cached reprojected tiles from the source. The next render cycle will create new tiles.
   * @api
   */
  clear() {
  }
  /**
   * @override
   */
  refresh() {
    this.clear();
    super.refresh();
  }
}
class TileSourceEvent extends BaseEvent {
  /**
   * @param {string} type Type.
   * @param {import("../Tile.js").default} tile The tile.
   */
  constructor(type, tile) {
    super(type);
    this.tile = tile;
  }
}
const TileEventType = {
  /**
   * Triggered when a tile starts loading.
   * @event module:ol/source/Tile.TileSourceEvent#tileloadstart
   * @api
   */
  TILELOADSTART: "tileloadstart",
  /**
   * Triggered when a tile finishes loading, either when its data is loaded,
   * or when loading was aborted because the tile is no longer needed.
   * @event module:ol/source/Tile.TileSourceEvent#tileloadend
   * @api
   */
  TILELOADEND: "tileloadend",
  /**
   * Triggered if tile loading results in an error. Note that this is not the
   * right place to re-fetch tiles. See {@link module:ol/ImageTile~ImageTile#load}
   * for details.
   * @event module:ol/source/Tile.TileSourceEvent#tileloaderror
   * @api
   */
  TILELOADERROR: "tileloaderror"
};
class UrlTile extends TileSource {
  /**
   * @param {Options} options Image tile options.
   */
  constructor(options2) {
    super({
      attributions: options2.attributions,
      cacheSize: options2.cacheSize,
      projection: options2.projection,
      state: options2.state,
      tileGrid: options2.tileGrid,
      tilePixelRatio: options2.tilePixelRatio,
      wrapX: options2.wrapX,
      transition: options2.transition,
      interpolate: options2.interpolate,
      key: options2.key,
      attributionsCollapsible: options2.attributionsCollapsible,
      zDirection: options2.zDirection
    });
    this.generateTileUrlFunction_ = this.tileUrlFunction === UrlTile.prototype.tileUrlFunction;
    this.tileLoadFunction = options2.tileLoadFunction;
    if (options2.tileUrlFunction) {
      this.tileUrlFunction = options2.tileUrlFunction;
    }
    this.urls = null;
    if (options2.urls) {
      this.setUrls(options2.urls);
    } else if (options2.url) {
      this.setUrl(options2.url);
    }
    this.tileLoadingKeys_ = {};
  }
  /**
   * Deprecated.  Use an ImageTile source instead.
   * Return the tile load function of the source.
   * @return {import("../Tile.js").LoadFunction} TileLoadFunction
   * @api
   */
  getTileLoadFunction() {
    return this.tileLoadFunction;
  }
  /**
   * Deprecated.  Use an ImageTile source instead.
   * Return the tile URL function of the source.
   * @return {import("../Tile.js").UrlFunction} TileUrlFunction
   * @api
   */
  getTileUrlFunction() {
    return Object.getPrototypeOf(this).tileUrlFunction === this.tileUrlFunction ? this.tileUrlFunction.bind(this) : this.tileUrlFunction;
  }
  /**
   * Deprecated.  Use an ImageTile source instead.
   * Return the URLs used for this source.
   * When a tileUrlFunction is used instead of url or urls,
   * null will be returned.
   * @return {!Array<string>|null} URLs.
   * @api
   */
  getUrls() {
    return this.urls;
  }
  /**
   * Handle tile change events.
   * @param {import("../events/Event.js").default} event Event.
   * @protected
   */
  handleTileChange(event) {
    const tile = (
      /** @type {import("../Tile.js").default} */
      event.target
    );
    const uid = getUid(tile);
    const tileState = tile.getState();
    let type;
    if (tileState == TileState.LOADING) {
      this.tileLoadingKeys_[uid] = true;
      type = TileEventType.TILELOADSTART;
    } else if (uid in this.tileLoadingKeys_) {
      delete this.tileLoadingKeys_[uid];
      type = tileState == TileState.ERROR ? TileEventType.TILELOADERROR : tileState == TileState.LOADED ? TileEventType.TILELOADEND : void 0;
    }
    if (type != void 0) {
      this.dispatchEvent(new TileSourceEvent(type, tile));
    }
  }
  /**
   * Deprecated.  Use an ImageTile source instead.
   * Set the tile load function of the source.
   * @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
   * @api
   */
  setTileLoadFunction(tileLoadFunction) {
    this.tileLoadFunction = tileLoadFunction;
    this.changed();
  }
  /**
   * Deprecated.  Use an ImageTile source instead.
   * Set the tile URL function of the source.
   * @param {import("../Tile.js").UrlFunction} tileUrlFunction Tile URL function.
   * @param {string} [key] Optional new tile key for the source.
   * @api
   */
  setTileUrlFunction(tileUrlFunction, key2) {
    this.tileUrlFunction = tileUrlFunction;
    if (typeof key2 !== "undefined") {
      this.setKey(key2);
    } else {
      this.changed();
    }
  }
  /**
   * Set the URL to use for requests.
   * @param {string} url URL.
   * @api
   */
  setUrl(url) {
    const urls = expandUrl(url);
    this.urls = urls;
    this.setUrls(urls);
  }
  /**
   * Deprecated.  Use an ImageTile source instead.
   * Set the URLs to use for requests.
   * @param {Array<string>} urls URLs.
   * @api
   */
  setUrls(urls) {
    this.urls = urls;
    const key2 = urls.join("\n");
    if (this.generateTileUrlFunction_) {
      this.setTileUrlFunction(createFromTemplates(urls, this.tileGrid), key2);
    } else {
      this.setKey(key2);
    }
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {string|undefined} Tile URL.
   */
  tileUrlFunction(tileCoord, pixelRatio, projection) {
    return void 0;
  }
}
class TileImage extends UrlTile {
  /**
   * @param {!Options} options Image tile options.
   */
  constructor(options2) {
    super({
      attributions: options2.attributions,
      cacheSize: options2.cacheSize,
      projection: options2.projection,
      state: options2.state,
      tileGrid: options2.tileGrid,
      tileLoadFunction: options2.tileLoadFunction ? options2.tileLoadFunction : defaultTileLoadFunction,
      tilePixelRatio: options2.tilePixelRatio,
      tileUrlFunction: options2.tileUrlFunction,
      url: options2.url,
      urls: options2.urls,
      wrapX: options2.wrapX,
      transition: options2.transition,
      interpolate: options2.interpolate !== void 0 ? options2.interpolate : true,
      key: options2.key,
      attributionsCollapsible: options2.attributionsCollapsible,
      zDirection: options2.zDirection
    });
    this.crossOrigin = options2.crossOrigin !== void 0 ? options2.crossOrigin : null;
    this.tileClass = options2.tileClass !== void 0 ? options2.tileClass : ImageTile;
    this.tileGridForProjection = {};
    this.reprojectionErrorThreshold_ = options2.reprojectionErrorThreshold;
    this.renderReprojectionEdges_ = false;
  }
  /**
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {number} Gutter.
   * @override
   */
  getGutterForProjection(projection) {
    if (this.getProjection() && projection && !equivalent$1(this.getProjection(), projection)) {
      return 0;
    }
    return this.getGutter();
  }
  /**
   * @return {number} Gutter.
   */
  getGutter() {
    return 0;
  }
  /**
   * Return the key to be used for all tiles in the source.
   * @return {string} The key for all tiles.
   * @override
   */
  getKey() {
    let key2 = super.getKey();
    if (!this.getInterpolate()) {
      key2 += ":disable-interpolation";
    }
    return key2;
  }
  /**
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {!import("../tilegrid/TileGrid.js").default} Tile grid.
   * @override
   */
  getTileGridForProjection(projection) {
    const thisProj = this.getProjection();
    if (this.tileGrid && (!thisProj || equivalent$1(thisProj, projection))) {
      return this.tileGrid;
    }
    const projKey = getUid(projection);
    if (!(projKey in this.tileGridForProjection)) {
      this.tileGridForProjection[projKey] = getForProjection(projection);
    }
    return this.tileGridForProjection[projKey];
  }
  /**
   * @param {number} z Tile coordinate z.
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @param {string} key The key set on the tile.
   * @return {!ImageTile} Tile.
   * @private
   */
  createTile_(z, x, y, pixelRatio, projection, key2) {
    const tileCoord = [z, x, y];
    const urlTileCoord = this.getTileCoordForTileUrlFunction(
      tileCoord,
      projection
    );
    const tileUrl = urlTileCoord ? this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : void 0;
    const tile = new this.tileClass(
      tileCoord,
      tileUrl !== void 0 ? TileState.IDLE : TileState.EMPTY,
      tileUrl !== void 0 ? tileUrl : "",
      this.crossOrigin,
      this.tileLoadFunction,
      this.tileOptions
    );
    tile.key = key2;
    tile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this));
    return tile;
  }
  /**
   * @param {number} z Tile coordinate z.
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @return {!(ImageTile|ReprojTile)} Tile.
   * @override
   */
  getTile(z, x, y, pixelRatio, projection) {
    const sourceProjection = this.getProjection();
    if (!sourceProjection || !projection || equivalent$1(sourceProjection, projection)) {
      return this.getTileInternal(
        z,
        x,
        y,
        pixelRatio,
        sourceProjection || projection
      );
    }
    const tileCoord = [z, x, y];
    const key2 = this.getKey();
    const sourceTileGrid = this.getTileGridForProjection(sourceProjection);
    const targetTileGrid = this.getTileGridForProjection(projection);
    const wrappedTileCoord = this.getTileCoordForTileUrlFunction(
      tileCoord,
      projection
    );
    const tile = new ReprojTile(
      sourceProjection,
      sourceTileGrid,
      projection,
      targetTileGrid,
      tileCoord,
      wrappedTileCoord,
      this.getTilePixelRatio(pixelRatio),
      this.getGutter(),
      (z2, x2, y2, pixelRatio2) => this.getTileInternal(z2, x2, y2, pixelRatio2, sourceProjection),
      this.reprojectionErrorThreshold_,
      this.renderReprojectionEdges_,
      this.tileOptions
    );
    tile.key = key2;
    return tile;
  }
  /**
   * @param {number} z Tile coordinate z.
   * @param {number} x Tile coordinate x.
   * @param {number} y Tile coordinate y.
   * @param {number} pixelRatio Pixel ratio.
   * @param {!import("../proj/Projection.js").default} projection Projection.
   * @return {!ImageTile} Tile.
   * @protected
   */
  getTileInternal(z, x, y, pixelRatio, projection) {
    const key2 = this.getKey();
    return this.createTile_(z, x, y, pixelRatio, projection, key2);
  }
  /**
   * Sets whether to render reprojection edges or not (usually for debugging).
   * @param {boolean} render Render the edges.
   * @api
   */
  setRenderReprojectionEdges(render2) {
    if (this.renderReprojectionEdges_ == render2) {
      return;
    }
    this.renderReprojectionEdges_ = render2;
    this.changed();
  }
  /**
   * Sets the tile grid to use when reprojecting the tiles to the given
   * projection instead of the default tile grid for the projection.
   *
   * This can be useful when the default tile grid cannot be created
   * (e.g. projection has no extent defined) or
   * for optimization reasons (custom tile size, resolutions, ...).
   *
   * @param {import("../proj.js").ProjectionLike} projection Projection.
   * @param {import("../tilegrid/TileGrid.js").default} tilegrid Tile grid to use for the projection.
   * @api
   */
  setTileGridForProjection(projection, tilegrid) {
    const proj = get$2(projection);
    if (proj) {
      const projKey = getUid(proj);
      if (!(projKey in this.tileGridForProjection)) {
        this.tileGridForProjection[projKey] = tilegrid;
      }
    }
  }
}
function defaultTileLoadFunction(imageTile, src) {
  imageTile.getImage().src = src;
}
class XYZ extends TileImage {
  /**
   * @param {Options} [options] XYZ options.
   */
  constructor(options2) {
    options2 = options2 || {};
    const projection = options2.projection !== void 0 ? options2.projection : "EPSG:3857";
    const tileGrid = options2.tileGrid !== void 0 ? options2.tileGrid : createXYZ({
      extent: extentFromProjection(projection),
      maxResolution: options2.maxResolution,
      maxZoom: options2.maxZoom,
      minZoom: options2.minZoom,
      tileSize: options2.tileSize
    });
    super({
      attributions: options2.attributions,
      cacheSize: options2.cacheSize,
      crossOrigin: options2.crossOrigin,
      interpolate: options2.interpolate,
      projection,
      reprojectionErrorThreshold: options2.reprojectionErrorThreshold,
      tileGrid,
      tileLoadFunction: options2.tileLoadFunction,
      tilePixelRatio: options2.tilePixelRatio,
      tileUrlFunction: options2.tileUrlFunction,
      url: options2.url,
      urls: options2.urls,
      wrapX: options2.wrapX !== void 0 ? options2.wrapX : true,
      transition: options2.transition,
      attributionsCollapsible: options2.attributionsCollapsible,
      zDirection: options2.zDirection
    });
    this.gutter_ = options2.gutter !== void 0 ? options2.gutter : 0;
  }
  /**
   * @return {number} Gutter.
   * @override
   */
  getGutter() {
    return this.gutter_;
  }
}
const ATTRIBUTION = '&#169; <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors.';
class OSM extends XYZ {
  /**
   * @param {Options} [options] Open Street Map options.
   */
  constructor(options2) {
    options2 = options2 || {};
    let attributions;
    if (options2.attributions !== void 0) {
      attributions = options2.attributions;
    } else {
      attributions = [ATTRIBUTION];
    }
    const crossOrigin = options2.crossOrigin !== void 0 ? options2.crossOrigin : "anonymous";
    const url = options2.url !== void 0 ? options2.url : "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
    super({
      attributions,
      attributionsCollapsible: false,
      cacheSize: options2.cacheSize,
      crossOrigin,
      interpolate: options2.interpolate,
      maxZoom: options2.maxZoom !== void 0 ? options2.maxZoom : 19,
      reprojectionErrorThreshold: options2.reprojectionErrorThreshold,
      tileLoadFunction: options2.tileLoadFunction,
      transition: options2.transition,
      url,
      wrapX: options2.wrapX,
      zDirection: options2.zDirection
    });
  }
}
class TileWMS extends TileImage {
  /**
   * @param {Options} [options] Tile WMS options.
   */
  constructor(options2) {
    options2 = options2 ? options2 : (
      /** @type {Options} */
      {}
    );
    const params2 = Object.assign({}, options2.params);
    super({
      attributions: options2.attributions,
      attributionsCollapsible: options2.attributionsCollapsible,
      cacheSize: options2.cacheSize,
      crossOrigin: options2.crossOrigin,
      interpolate: options2.interpolate,
      projection: options2.projection,
      reprojectionErrorThreshold: options2.reprojectionErrorThreshold,
      tileClass: options2.tileClass,
      tileGrid: options2.tileGrid,
      tileLoadFunction: options2.tileLoadFunction,
      url: options2.url,
      urls: options2.urls,
      wrapX: options2.wrapX !== void 0 ? options2.wrapX : true,
      transition: options2.transition,
      zDirection: options2.zDirection
    });
    this.gutter_ = options2.gutter !== void 0 ? options2.gutter : 0;
    this.params_ = params2;
    this.v13_ = true;
    this.serverType_ = options2.serverType;
    this.hidpi_ = options2.hidpi !== void 0 ? options2.hidpi : true;
    this.tmpExtent_ = createEmpty();
    this.updateV13_();
    this.setKey(this.getKeyForParams_());
  }
  /**
   * Return the GetFeatureInfo URL for the passed coordinate, resolution, and
   * projection. Return `undefined` if the GetFeatureInfo URL cannot be
   * constructed.
   * @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
   * @param {number} resolution Resolution.
   * @param {import("../proj.js").ProjectionLike} projection Projection.
   * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
   *     be provided. If `QUERY_LAYERS` is not provided then the layers specified
   *     in the `LAYERS` parameter will be used. `VERSION` should not be
   *     specified here.
   * @return {string|undefined} GetFeatureInfo URL.
   * @api
   */
  getFeatureInfoUrl(coordinate, resolution, projection, params2) {
    const projectionObj = get$2(projection);
    const sourceProjectionObj = this.getProjection() || projectionObj;
    let tileGrid = this.getTileGrid();
    if (!tileGrid) {
      tileGrid = this.getTileGridForProjection(sourceProjectionObj);
    }
    const sourceProjCoord = transform$1(
      coordinate,
      projectionObj,
      sourceProjectionObj
    );
    const sourceResolution = calculateSourceResolution(
      sourceProjectionObj,
      projectionObj,
      coordinate,
      resolution
    );
    const z = tileGrid.getZForResolution(sourceResolution, this.zDirection);
    const tileResolution = tileGrid.getResolution(z);
    const tileCoord = tileGrid.getTileCoordForCoordAndZ(sourceProjCoord, z);
    if (tileGrid.getResolutions().length <= tileCoord[0]) {
      return void 0;
    }
    let tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
    const gutter = this.gutter_;
    if (gutter !== 0) {
      tileExtent = buffer(tileExtent, tileResolution * gutter, tileExtent);
    }
    const baseParams = {
      "QUERY_LAYERS": this.params_["LAYERS"]
    };
    Object.assign(
      baseParams,
      getRequestParams(this.params_, "GetFeatureInfo"),
      params2
    );
    const x = Math.floor((sourceProjCoord[0] - tileExtent[0]) / tileResolution);
    const y = Math.floor((tileExtent[3] - sourceProjCoord[1]) / tileResolution);
    baseParams[this.v13_ ? "I" : "X"] = x;
    baseParams[this.v13_ ? "J" : "Y"] = y;
    return this.getRequestUrl_(
      tileCoord,
      tileExtent,
      1,
      sourceProjectionObj || projectionObj,
      baseParams
    );
  }
  /**
   * Return the GetLegendGraphic URL, optionally optimized for the passed
   * resolution and possibly including any passed specific parameters. Returns
   * `undefined` if the GetLegendGraphic URL cannot be constructed.
   *
   * @param {number} [resolution] Resolution. If set to undefined, `SCALE`
   *     will not be calculated and included in URL.
   * @param {Object} [params] GetLegendGraphic params. If `LAYER` is set, the
   *     request is generated for this wms layer, else it will try to use the
   *     configured wms layer. Default `FORMAT` is `image/png`.
   *     `VERSION` should not be specified here.
   * @return {string|undefined} GetLegendGraphic URL.
   * @api
   */
  getLegendUrl(resolution, params2) {
    if (this.urls[0] === void 0) {
      return void 0;
    }
    const baseParams = {
      "SERVICE": "WMS",
      "VERSION": DEFAULT_VERSION,
      "REQUEST": "GetLegendGraphic",
      "FORMAT": "image/png"
    };
    if (params2 === void 0 || params2["LAYER"] === void 0) {
      const layers = this.params_.LAYERS;
      const isSingleLayer = !Array.isArray(layers) || layers.length === 1;
      if (!isSingleLayer) {
        return void 0;
      }
      baseParams["LAYER"] = layers;
    }
    if (resolution !== void 0) {
      const mpu = this.getProjection() ? this.getProjection().getMetersPerUnit() : 1;
      const pixelSize = 28e-5;
      baseParams["SCALE"] = resolution * mpu / pixelSize;
    }
    Object.assign(baseParams, params2);
    return appendParams(
      /** @type {string} */
      this.urls[0],
      baseParams
    );
  }
  /**
   * @return {number} Gutter.
   * @override
   */
  getGutter() {
    return this.gutter_;
  }
  /**
   * Get the user-provided params, i.e. those passed to the constructor through
   * the "params" option, and possibly updated using the updateParams method.
   * @return {Object} Params.
   * @api
   */
  getParams() {
    return this.params_;
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
   * @param {import("../extent.js").Extent} tileExtent Tile extent.
   * @param {number} pixelRatio Pixel ratio.
   * @param {import("../proj/Projection.js").default} projection Projection.
   * @param {Object} params Params.
   * @return {string|undefined} Request URL.
   * @private
   */
  getRequestUrl_(tileCoord, tileExtent, pixelRatio, projection, params2) {
    const urls = this.urls;
    if (!urls) {
      return void 0;
    }
    let url;
    if (urls.length == 1) {
      url = urls[0];
    } else {
      const index = modulo(hash(tileCoord), urls.length);
      url = urls[index];
    }
    return getImageSrc(
      tileExtent,
      (this.tileGrid || this.getTileGridForProjection(projection)).getResolution(tileCoord[0]),
      pixelRatio,
      projection,
      url,
      params2,
      this.serverType_
    );
  }
  /**
   * Get the tile pixel ratio for this source.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} Tile pixel ratio.
   * @override
   */
  getTilePixelRatio(pixelRatio) {
    return !this.hidpi_ || this.serverType_ === void 0 ? 1 : pixelRatio;
  }
  /**
   * @private
   * @return {string} The key for the current params.
   */
  getKeyForParams_() {
    let i = 0;
    const res = [];
    for (const key2 in this.params_) {
      res[i++] = key2 + "-" + this.params_[key2];
    }
    return res.join("/");
  }
  /**
   * @param {Object} params New URL paremeters.
   * @private
   */
  setParams_(params2) {
    this.params_ = params2;
    this.updateV13_();
    this.setKey(this.getKeyForParams_());
  }
  /**
   * Set the URL parameters passed to the WMS source.
   * @param {Object} params New URL paremeters.
   * @api
   */
  setParams(params2) {
    this.setParams_(Object.assign({}, params2));
  }
  /**
   * Update the URL parameters. This method can be used to update a subset of the WMS
   * parameters. Call `setParams` to set all of the parameters.
   * @param {Object} params Updated URL parameters.
   * @api
   */
  updateParams(params2) {
    this.setParams_(Object.assign(this.params_, params2));
  }
  /**
   * @private
   */
  updateV13_() {
    const version = this.params_["VERSION"] || DEFAULT_VERSION;
    this.v13_ = compareVersions(version, "1.3") >= 0;
  }
  /**
   * @param {import("../tilecoord.js").TileCoord} tileCoord The tile coordinate
   * @param {number} pixelRatio The pixel ratio
   * @param {import("../proj/Projection.js").default} projection The projection
   * @return {string|undefined} The tile URL
   * @override
   */
  tileUrlFunction(tileCoord, pixelRatio, projection) {
    let tileGrid = this.getTileGrid();
    if (!tileGrid) {
      tileGrid = this.getTileGridForProjection(projection);
    }
    if (tileGrid.getResolutions().length <= tileCoord[0]) {
      return void 0;
    }
    if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === void 0)) {
      pixelRatio = 1;
    }
    const tileResolution = tileGrid.getResolution(tileCoord[0]);
    let tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
    const gutter = this.gutter_;
    if (gutter !== 0) {
      tileExtent = buffer(tileExtent, tileResolution * gutter, tileExtent);
    }
    const baseParams = Object.assign(
      {},
      getRequestParams(this.params_, "GetMap")
    );
    return this.getRequestUrl_(
      tileCoord,
      tileExtent,
      pixelRatio,
      projection,
      baseParams
    );
  }
}
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
function synchronizeSource(target, source, _context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/source/Source");
  }
  target.setAttributions(source.attributions);
  return target;
}
function synchronizeTileSource(target, source, context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/source/Tile");
  }
  synchronizeSource(target, source);
  return target;
}
function synchronizeUrlTileSource(target, source, context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/source/UrlTile");
  }
  synchronizeTileSource(target, source);
  if (source.url) {
    target.setUrl(source.url);
  }
  return target;
}
function synchronizeTileImageSource(target, source, context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/source/TileImage");
  }
  synchronizeUrlTileSource(target, source);
  return target;
}
function synchronizeTileWMSSource(target, source, context) {
  if (!target) {
    target = new TileWMS(createOptions(source));
  }
  synchronizeTileImageSource(target, source);
  return target;
}
function synchronizeXYZSource(target, source, context) {
  if (!target) {
    target = new XYZ(createOptions(source));
  }
  synchronizeTileImageSource(target, source);
  return target;
}
function synchronizeOSMSource(target, source, context) {
  if (!target) {
    target = new OSM(createOptions(source));
  }
  if (!source.attributions) {
    source.attributions = ATTRIBUTION;
  }
  synchronizeXYZSource(target, source);
  return target;
}
function synchronizeImageSource(target, source, context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/source/Image");
  }
  synchronizeSource(target, source);
  return target;
}
function synchronizeImageWMSSource(target, source, context) {
  if (!target) {
    target = new ImageWMS(createOptions(source));
  }
  synchronizeImageSource(target, source);
  if (source.url) {
    target.setUrl(source.url);
  }
  return target;
}
function synchronizeVectorSource(target, source, context) {
  if (!target) {
    target = new VectorSource(
      createOptions({
        ...source,
        features: new Collection()
      })
    );
  }
  synchronizeSource(target, source);
  synchronizeCollection(target.getFeaturesCollection(), source.features, context);
  return target;
}
function synchronizeCluster(target, source, context) {
  if (!target) {
    target = new Cluster(
      createOptions({
        ...source,
        source: new VectorSource({ features: new Collection() })
      })
    );
  }
  target.setDistance(source.distance);
  target.setMinDistance(source.minDistance);
  synchronizeCollection(target.getSource().getFeaturesCollection(), source.features, context);
  return target;
}
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
function synchronizeFill(target, source, context) {
  if (!target) {
    target = new Fill();
  }
  target.setColor(source.color);
  context.connector.forceRender();
  return target;
}
function synchronizeStroke(target, source, context) {
  if (!target) {
    target = new Stroke();
  }
  target.setColor(source.color);
  target.setWidth(source.width);
  context.connector.forceRender();
  return target;
}
function synchronizeImageStyle(target, source, _context) {
  if (!target) {
    throw new Error("Can not instantiate base class: ol/style/Image");
  }
  target.setOpacity(source.opacity);
  target.setRotateWithView(source.rotateWithView);
  target.setRotation(source.rotation);
  target.setScale(source.scale);
  return target;
}
function synchronizeIcon(target, source, context) {
  if (!target) {
    const src = source.img || source.src;
    target = new Icon(
      createOptions({
        ...source,
        img: void 0,
        src,
        imgSize: source.imgSize ? convertToSizeArray(source.imgSize) : void 0,
        anchor: source.anchor ? convertToCoordinateArray(source.anchor) : void 0,
        anchorOrigin: source.anchorOrigin ? convertEnumValue(source.anchorOrigin) : void 0
      })
    );
  }
  synchronizeImageStyle(target, source);
  context.connector.forceRender();
  return target;
}
function synchronizeText(target, source, context) {
  if (!target) {
    target = new Text$1();
  }
  target.setFont(source.font);
  target.setOffsetX(source.offset && source.offset.x || 0);
  target.setOffsetY(source.offset && source.offset.y || 0);
  target.setScale(source.scale);
  target.setRotation(source.rotation);
  target.setRotateWithView(source.rotateWithView);
  target.setTextAlign(source.textAlign ? convertEnumValue(source.textAlign) : void 0);
  target.setTextBaseline(source.textBaseline ? convertEnumValue(source.textBaseline) : void 0);
  target.setFill(source.fill ? context.lookup.get(source.fill) : void 0);
  target.setStroke(source.stroke ? context.lookup.get(source.stroke) : void 0);
  target.setBackgroundFill(source.backgroundFill ? context.lookup.get(source.backgroundFill) : void 0);
  target.setBackgroundStroke(source.backgroundStroke ? context.lookup.get(source.backgroundStroke) : void 0);
  target.setPadding([source.padding, source.padding, source.padding, source.padding]);
  context.connector.forceRender();
  return target;
}
function synchronizeStyle(target, source, context) {
  if (!target) {
    target = new Style();
  }
  target.setImage(source.image ? context.lookup.get(source.image) : void 0);
  target.setFill(source.fill ? context.lookup.get(source.fill) : void 0);
  target.setStroke(source.stroke ? context.lookup.get(source.stroke) : void 0);
  target.setText(source.text ? context.lookup.get(source.text) : void 0);
  context.connector.forceRender();
  return target;
}
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
const fallbackTextStyle = new Text$1({
  font: "13px sans-serif",
  offsetY: 10,
  fill: new Fill({ color: "#333" }),
  stroke: new Stroke({ color: "#fff", width: 3 })
});
function synchronizeMap(target, source, context) {
  if (!target) {
    throw new Error("Existing map instance must be provided");
  }
  synchronizeCollection(target.getLayers(), source.layers, context);
  synchronizeCollection(target.getControls(), source.visibleControls, context);
  target.setView(context.lookup.get(source.view));
  return target;
}
function synchronizeView(target, source, _context) {
  if (!target) {
    target = new View({
      projection: source.projection
    });
  }
  target.setCenter(source.center ? convertToCoordinateArray(source.center) : [0, 0]);
  target.setRotation(source.rotation || 0);
  target.setZoom(source.zoom || 0);
  return target;
}
function synchronizeLineString(target, source, _context) {
  if (!target) {
    target = new LineString(source.coordinates.map((coord) => convertToCoordinateArray(coord)));
  }
  target.setCoordinates(source.coordinates.map((coord) => convertToCoordinateArray(coord)));
  return target;
}
function synchronizePoint(target, source, _context) {
  if (!target) {
    target = new Point$1(convertToCoordinateArray(source.coordinates));
  }
  target.setCoordinates(convertToCoordinateArray(source.coordinates));
  return target;
}
function synchronizePolygon(target, source, _context) {
  if (!target) {
    target = new Polygon(convertToGeoJSONCoordinateArray(source.coordinates));
  }
  target.setCoordinates(convertToGeoJSONCoordinateArray(source.coordinates));
  return target;
}
function synchronizeFeature(target, source, context) {
  if (!target) {
    target = new Feature();
  }
  target.setGeometry(context.lookup.get(source.geometry));
  const style = context.lookup.get(source.style);
  target.setStyle(() => {
    if (!style) {
      return void 0;
    }
    if (source.text && !style.getText()) {
      style.setText(fallbackTextStyle);
    }
    if (style.getText()) {
      style.getText().setText(source.text);
    }
    return style;
  });
  target.draggable = source.draggable;
  return target;
}
const synchronizerLookup = {
  "ol/Feature": synchronizeFeature,
  "ol/Map": synchronizeMap,
  "ol/View": synchronizeView,
  // Layers
  "ol/layer/Feature": synchronizeFeatureLayer,
  "ol/layer/Image": synchronizeImageLayer,
  "ol/layer/Tile": synchronizeTileLayer,
  "ol/layer/Vector": synchronizeVectorLayer,
  // Sources
  "ol/source/Cluster": synchronizeCluster,
  "ol/source/ImageWMS": synchronizeImageWMSSource,
  "ol/source/OSM": synchronizeOSMSource,
  "ol/source/TileWMS": synchronizeTileWMSSource,
  "ol/source/Vector": synchronizeVectorSource,
  "ol/source/XYZ": synchronizeXYZSource,
  // Geometry
  "ol/geom/LineString": synchronizeLineString,
  "ol/geom/Point": synchronizePoint,
  "ol/geom/Polygon": synchronizePolygon,
  // Styles
  "ol/style/Icon": synchronizeIcon,
  "ol/style/Fill": synchronizeFill,
  "ol/style/Stroke": synchronizeStroke,
  "ol/style/Style": synchronizeStyle,
  "ol/style/Text": synchronizeText,
  // Controls
  "ol/control/Attribution": synchronizeAttribution,
  "ol/control/ScaleLine": synchronizeScaleLine,
  "ol/control/Zoom": synchronizeZoom
};
function synchronize(updatedObject, context) {
  const type = updatedObject.type;
  if (!type) {
    throw new Error("Configuration object must have a type");
  }
  if (!updatedObject.id) {
    throw new Error("Configuration object must have an ID");
  }
  let instance = context.lookup.get(updatedObject.id);
  const synchronizer = synchronizerLookup[type];
  if (!synchronizer) {
    throw new Error(`Unsupported configuration object type: ${type}`);
  }
  instance = synchronizer(instance, updatedObject, context);
  context.lookup.put(updatedObject.id, instance);
  instance.id = updatedObject.id;
  instance.typeName = type;
  return instance;
}
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
class SimpleLookup {
  constructor() {
    this.map = /* @__PURE__ */ new Map();
  }
  get(id) {
    return this.map.get(id);
  }
  put(id, instance) {
    this.map.set(id, instance);
  }
}
class WeakReferenceLookup {
  constructor() {
    this.map = /* @__PURE__ */ new Map();
    this.registry = new FinalizationRegistry((id) => {
      this.map.delete(id);
    });
  }
  get(id) {
    const weakRef = this.map.get(id);
    return weakRef ? weakRef.deref() : void 0;
  }
  put(id, instance) {
    const existingRef = this.map.get(id);
    if (existingRef) {
      this.registry.unregister(existingRef);
    }
    const ref = new WeakRef(instance);
    this.map.set(id, ref);
    this.registry.register(instance, id, ref);
  }
}
const supportsWeakReferenceLookup = window.WeakRef && window.FinalizationRegistry;
function createLookup() {
  return supportsWeakReferenceLookup ? new WeakReferenceLookup() : new SimpleLookup();
}
function getFeatureInfo(map, feature) {
  const layer = map.getLayers().getArray().find((layer2) => {
    const source2 = layer2.getSource && layer2.getSource();
    const isVectorSource = source2 && source2 instanceof VectorSource;
    return isVectorSource && source2.getFeatures().includes(feature);
  });
  const source = layer && layer.getSource();
  const clusterFeatures = feature.get("features");
  if (Array.isArray(clusterFeatures) && clusterFeatures.length === 1) {
    feature = clusterFeatures[0];
  }
  const isCluster = Array.isArray(clusterFeatures) && clusterFeatures.length > 1;
  return {
    feature,
    layer,
    source,
    isCluster
  };
}
/**
 * @license
 * Copyright 2000-2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See <https://vaadin.com/commercial-license-and-service-terms> for the full
 * license.
 */
setUserProjection$1("EPSG:4326");
function init(mapElement) {
  mapElement.configuration.getControls().clear();
  mapElement.$connector = {
    /**
     * Lookup for storing and retrieving every OL instance used in the map's configuration
     * by its unique ID
     */
    lookup: createLookup(),
    /**
     * Synchronizes an array of Javascript objects into OL instances.
     * It is expected that objects that are lower in the configuration hierarchy occur
     * earlier in the array than objects that are higher in the hierarchy. That ensures
     * that lower-level objects are synchronized first, before higher-level objects that
     * reference them.
     * @param changedObjects array of Javascript objects to be synchronized into OL instances
     */
    synchronize(changedObjects) {
      const context = { synchronize, lookup: this.lookup, mapElement, connector: mapElement.$connector };
      changedObjects.forEach((change) => {
        if (change.type === "ol/Map") {
          this.lookup.put(change.id, mapElement.configuration);
        }
        synchronize(change, context);
      });
    },
    /**
     * Forces a render of the OpenLayers map. Some objects in OpenLayers are not observable
     * and do not trigger change events, for example Style objects or any of their children.
     * In these cases this method can be called from the synchronization functions of these
     * objects.
     * This method will trigger a debounced render of the map by firing a change event from
     * each layer. We simply render all layers as a sync. function does not know which layer
     * its synced object is in. Even if the change event is fired from multiple layers, this
     * only results in a single render of the map.
     */
    forceRender() {
      if (this._forceRenderTimeout) {
        return;
      }
      this._forceRenderTimeout = setTimeout(() => {
        this._forceRenderTimeout = null;
        mapElement.configuration.getLayers().getArray().forEach((layer) => layer.changed());
      });
    },
    /**
     * Adjust the map view to fit the given features.
     * @param featureIds array of IDs of the features to fit in the map view
     * @param options optional options for the OL `View.fit` method
     */
    zoomToFit(featureIds, options2) {
      setTimeout(() => {
        const features = featureIds.map((id) => this.lookup.get(id)).filter(Boolean);
        if (features.length === 0) {
          return;
        }
        let extent;
        features.forEach((feature) => {
          const featureExtent = feature.getGeometry().getExtent();
          if (!extent) {
            extent = featureExtent.slice();
          } else {
            extend$2(extent, featureExtent);
          }
        });
        const padding = options2?.padding ?? 0;
        const duration = options2?.duration ?? 0;
        const bounds = mapElement.getBoundingClientRect();
        const size = [bounds.width, bounds.height];
        mapElement.configuration.getView().fit(extent, {
          padding: [padding, padding, padding, padding],
          duration,
          size
        });
      });
    }
  };
  mapElement.configuration.on("moveend", (_event) => {
    const view = mapElement.configuration.getView();
    const center = view.getCenter();
    const rotation = view.getRotation();
    const zoom = view.getZoom();
    const extent = view.calculateExtent();
    const customEvent = new CustomEvent("map-view-moveend", {
      detail: {
        center,
        rotation,
        zoom,
        extent
      }
    });
    mapElement.dispatchEvent(customEvent);
  });
  mapElement.configuration.on("singleclick", (event) => {
    const coordinate = event.coordinate;
    const pixelCoordinate = event.pixel;
    const featuresAtPixel = mapElement.configuration.getFeaturesAtPixel(pixelCoordinate);
    const featureInfos = featuresAtPixel.map((feature) => getFeatureInfo(mapElement.configuration, feature));
    const nonClusterFeatures = featureInfos.filter((info) => info && !info.isCluster);
    const mapClickEvent = new CustomEvent("map-click", {
      detail: {
        coordinate,
        features: nonClusterFeatures,
        originalEvent: event.originalEvent
      }
    });
    mapElement.dispatchEvent(mapClickEvent);
    if (nonClusterFeatures.length > 0) {
      const featureInfo = nonClusterFeatures[0];
      const featureClickEvent = new CustomEvent("map-feature-click", {
        detail: {
          feature: featureInfo.feature,
          layer: featureInfo.layer,
          originalEvent: event.originalEvent
        }
      });
      mapElement.dispatchEvent(featureClickEvent);
    }
    const clusterInfos = featureInfos.filter((info) => info && info.isCluster);
    if (clusterInfos.length > 0) {
      const clusterInfo = clusterInfos[0];
      const clusterClickEvent = new CustomEvent("map-cluster-click", {
        detail: {
          features: clusterInfo.feature.get("features"),
          layer: clusterInfo.layer,
          originalEvent: event.originalEvent
        }
      });
      mapElement.dispatchEvent(clusterClickEvent);
    }
  });
  const translate2 = new Translate({
    filter(feature) {
      return !!feature.draggable;
    }
  });
  translate2.on("translateend", (event) => {
    const feature = event.features.item(0);
    if (!feature) return;
    const featureInfo = getFeatureInfo(mapElement.configuration, feature);
    const featureDropEvent = new CustomEvent("map-feature-drop", {
      detail: {
        feature,
        layer: featureInfo.layer,
        coordinate: event.coordinate,
        startCoordinate: event.startCoordinate
      }
    });
    mapElement.dispatchEvent(featureDropEvent);
  });
  mapElement.configuration.addInteraction(translate2);
}
function setUserProjection(projection) {
  setUserProjection$1(projection);
}
function defineProjection(projection, wksDefinition) {
  proj4.defs(projection, wksDefinition);
  register(proj4);
}
window.Vaadin.Flow.mapConnector = {
  init,
  setUserProjection,
  defineProjection
};
/**
 * @license
 * Copyright (c) 2025 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const markdownSlotStyles = css$h`
  @layer vaadin.base {
    vaadin-markdown {
      line-height: 1.6;

      h1,
      h2,
      h3,
      h4,
      h5,
      h6 {
        font-weight: 600;
        line-height: 1.25;
        text-wrap: balance;
      }

      h1 {
        font-size: 1.75em;
        margin-top: 1.8em;
        margin-bottom: 0.9em;
      }

      h2 {
        font-size: 1.5em;
        margin-top: 1.6em;
        margin-bottom: 0.8em;
      }

      h3 {
        font-size: 1.25em;
        margin-top: 1.4em;
        margin-bottom: 0.7em;
      }

      h4 {
        font-size: 1.125em;
        margin-top: 1.2em;
        margin-bottom: 0.6em;
      }

      h5 {
        font-size: 1em;
        margin-top: 1em;
        margin-bottom: 0.5em;
      }

      h6 {
        font-size: 0.875em;
        margin-top: 1em;
        margin-bottom: 0.5em;
      }

      p,
      ul,
      ol,
      blockquote,
      table,
      figure {
        margin-inline: 0;
        margin-block: 1.25em;
      }

      code {
        font-family: ui-monospace, monospace;
        font-size: 0.9em;
        line-height: 1.25;
        font-weight: 500;

        &::before,
        &::after {
          content: '\`';
          color: var(--vaadin-text-color-secondary);
        }
      }

      pre {
        background-color: light-dark(var(--vaadin-text-color), var(--vaadin-background-container));
        border-radius: var(--vaadin-radius-m);
        color: light-dark(var(--vaadin-background-color), var(--vaadin-text-color));
        padding: var(--vaadin-padding-m);

        code {
          font-weight: 500;

          &::before,
          &::after {
            content: '';
          }
        }
      }

      hr {
        height: 0;
        border: 0;
        border-top: 1px solid var(--vaadin-border-color-secondary);
        margin-block: 3em;
      }

      b,
      strong {
        font-weight: 600;
      }

      blockquote {
        font-weight: 500;
        font-style: italic;
        border-left: 0.25rem solid var(--vaadin-border-color);
        quotes: '\\201C' '\\201D' '\\2018' '\\2019';
        margin-inline: 0;
        padding-inline-start: 1em;
      }

      ul {
        list-style-type: disc;
      }

      ul,
      ol {
        padding-inline-start: 1.625em;
      }

      li {
        margin-block: 0.5em;
        padding-inline-start: 0.375em;

        &::marker {
          color: var(--vaadin-text-color-disabled);
        }
      }

      ol li::marker {
        font-weight: 400;
        color: var(--vaadin-text-color-secondary);
      }

      ul:has(> li > input[type='checkbox']:first-child) {
        list-style: none;
        padding-inline-start: 0;
      }

      img,
      video,
      svg,
      canvas,
      audio,
      iframe,
      embed,
      object {
        display: block;
      }

      img,
      video {
        max-width: 100%;
        height: auto;
        border-radius: var(--vaadin-radius-m);
      }

      figcaption {
        font-size: 0.875em;
        line-height: 1.125;
        color: var(--vaadin-text-color-secondary);
        margin-top: 0.75em;
      }

      table {
        min-width: 100%;
        border-spacing: 0;
      }

      th {
        text-align: start;
        font-weight: 500;
        background: var(--vaadin-background-container);
      }

      th,
      td {
        padding: var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container);
      }

      tr:not(:last-child) {
        th,
        td {
          border-bottom: 1px solid var(--vaadin-border-color-secondary);
        }
      }
    }
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Markdown extends SlotStylesMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
  static get is() {
    return "vaadin-markdown";
  }
  static get styles() {
    return css$h`
      :host {
        display: block;
      }

      :host([hidden]) {
        display: none !important;
      }
    `;
  }
  /** @protected */
  get slotStyles() {
    return [markdownSlotStyles];
  }
  static get properties() {
    return {
      /**
       * The Markdown content.
       *
       */
      content: {
        type: String,
        sync: true
      }
    };
  }
  /** @protected */
  render() {
    return html`<slot></slot>`;
  }
  /**
   * @protected
   * @override
   */
  updated(props) {
    super.updated(props);
    if (props.has("content")) {
      renderMarkdownToElement(this, this.content);
    }
  }
}
defineCustomElement(Markdown);
const vaadinMarkdown = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  Markdown
}, Symbol.toStringTag, { value: "Module" }));
function initLazy(menubar, appId) {
  if (menubar.$connector) {
    return;
  }
  const observer = new MutationObserver((records) => {
    const hasChangedAttributes = records.some((entry) => {
      const oldValue = entry.oldValue;
      const newValue = entry.target.getAttribute(entry.attributeName);
      return oldValue !== newValue;
    });
    if (hasChangedAttributes) {
      menubar.$connector.generateItems();
    }
  });
  menubar.$connector = {
    /**
     * Generates and assigns the items to the menu bar.
     *
     * When the method is called without providing a node id,
     * the previously generated items tree will be used.
     * That can be useful if you only want to sync the disabled and hidden properties of root items.
     *
     * @param {number | undefined} nodeId
     */
    generateItems(nodeId) {
      if (!menubar.shadowRoot) {
        setTimeout(() => menubar.$connector.generateItems(nodeId));
        return;
      }
      if (!menubar._container) {
        queueMicrotask(() => menubar.$connector.generateItems(nodeId));
        return;
      }
      if (nodeId) {
        menubar.__generatedItems = window.Vaadin.Flow.contextMenuConnector.generateItemsTree(appId, nodeId);
      }
      let items = menubar.__generatedItems || [];
      items.forEach((item) => {
        item.disabled = item.component.disabled;
        item.component._rootItem = item;
      });
      items.forEach((item) => {
        observer.observe(item.component, {
          attributeFilter: ["hidden", "disabled"],
          attributeOldValue: true
        });
      });
      items = items.filter((item) => !item.component.hidden);
      menubar.items = items;
    }
  };
}
function setClassName(component) {
  const item = component._rootItem || component._item;
  if (item) {
    item.className = component.className;
  }
}
window.Vaadin.Flow.menubarConnector = { initLazy, setClassName };
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const messageInputButtonStyles = css$h`
  :host {
    flex: none;
    align-self: end;
    margin: var(
      --vaadin-input-field-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
    --vaadin-button-border-width: 0;
    --vaadin-button-background: transparent;
    --vaadin-button-text-color: var(--vaadin-text-color);
    --vaadin-button-padding: 0;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class MessageInputButton extends ButtonMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-message-input-button";
  }
  static get styles() {
    return [buttonStyles, messageInputButtonStyles];
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-button-container">
        <span part="label">
          <slot></slot>
        </span>
      </div>
    `;
  }
}
defineCustomElement(MessageInputButton);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const messageInputStyles = css$h`
  :host {
    box-sizing: border-box;
    display: flex;
    max-height: 50vh;
    flex-shrink: 0;
    border: var(--vaadin-input-field-border-width, 1px) solid
      var(--vaadin-input-field-border-color, var(--vaadin-border-color));
    border-radius: var(--vaadin-input-field-border-radius, var(--vaadin-radius-m));
    background: var(--vaadin-input-field-background, var(--vaadin-background-color));
  }

  :host([hidden]) {
    display: none !important;
  }

  :host(:focus-within) {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
    outline-offset: calc(var(--vaadin-input-field-border-width, 1px) * -1);
  }

  :host([disabled]) {
    --vaadin-input-field-value-color: var(--vaadin-input-field-disabled-text-color, var(--vaadin-text-color-disabled));
    --vaadin-input-field-background: var(
      --vaadin-input-field-disabled-background,
      var(--vaadin-background-container-strong)
    );
    --vaadin-input-field-border-color: transparent;
  }

  ::slotted([slot='textarea']) {
    flex: 1;
    --vaadin-input-field-border-width: 0 !important;
    --vaadin-focus-ring-width: 0;
    --vaadin-input-field-background: transparent !important;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N$4 = {
  send: "Send",
  message: "Message"
};
const MessageInputMixin = (superClass) => class MessageInputMixinClass extends I18nMixin(DEFAULT_I18N$4, superClass) {
  static get properties() {
    return {
      /**
       * Current content of the text input field
       */
      value: {
        type: String,
        value: "",
        sync: true
      },
      /**
       * Set to true to disable this element.
       */
      disabled: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        sync: true
      },
      /** @private */
      _button: {
        type: Object,
        sync: true
      },
      /** @private */
      _textArea: {
        type: Object,
        sync: true
      }
    };
  }
  static get observers() {
    return [
      "__buttonPropsChanged(_button, disabled, __effectiveI18n)",
      "__textAreaPropsChanged(_textArea, disabled, __effectiveI18n, value)"
    ];
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure and default values:
   * ```js
   * {
   *   // Used as the button label
   *   send: 'Send',
   *
   *   // Used as the input field's placeholder and aria-label
   *   message: 'Message'
   * }
   * ```
   * @type {!MessageInputI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @protected */
  ready() {
    super.ready();
    this._buttonController = new SlotController(this, "button", "vaadin-message-input-button", {
      initializer: (btn) => {
        btn.addEventListener("click", () => {
          this.__submit();
        });
        this._button = btn;
      }
    });
    this.addController(this._buttonController);
    this._textAreaController = new SlotController(this, "textarea", "vaadin-text-area", {
      initializer: (textarea) => {
        textarea.addEventListener("value-changed", (event) => {
          this.value = event.detail.value;
        });
        textarea.addEventListener("keydown", (event) => {
          if (event.key === "Enter" && !event.shiftKey) {
            event.preventDefault();
            event.stopImmediatePropagation();
            this.__submit();
          }
        });
        textarea.minRows = 1;
        (textarea.inputElement || textarea).setAttribute("enterkeyhint", "send");
        this._textArea = textarea;
      }
    });
    this.addController(this._textAreaController);
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
  }
  focus(options2) {
    if (this._textArea) {
      this._textArea.focus(options2);
    }
  }
  /** @private */
  __buttonPropsChanged(button, disabled, effectiveI18n) {
    if (button) {
      button.disabled = disabled;
      button.textContent = effectiveI18n.send;
    }
  }
  /** @private */
  __textAreaPropsChanged(textArea, disabled, effectiveI18n, value) {
    if (textArea) {
      textArea.disabled = disabled;
      textArea.value = value;
      const message2 = effectiveI18n.message;
      textArea.placeholder = message2;
      textArea.accessibleName = message2;
    }
  }
  /**
   * Submits the current value as an custom event named 'submit'.
   * It also clears the text input and refocuses it for sending another message.
   * In UI, can be triggered by pressing the submit button or pressing enter key when field is focused.
   * It does not submit anything if text is empty.
   */
  __submit() {
    if (this.value !== "") {
      this.dispatchEvent(new CustomEvent("submit", { detail: { value: this.value } }));
      this.value = "";
    }
    this._textArea.focus();
  }
  /**
   * Fired when a new message is submitted with `<vaadin-message-input>`, either
   * by clicking the "send" button, or pressing the Enter key.
   * @event submit
   */
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class MessageInput extends MessageInputMixin(
  ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-message-input";
  }
  static get styles() {
    return messageInputStyles;
  }
  /** @protected */
  render() {
    return html`
      <slot name="textarea"></slot>

      <slot name="button"></slot>

      <slot name="tooltip"></slot>
    `;
  }
}
defineCustomElement(MessageInput);
function createDateTimeFormatter(locale) {
  return new Intl.DateTimeFormat(locale, {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "numeric"
  });
}
function getFormatter(locale) {
  const localeParts = locale?.split("-");
  const fallbackLocales = [
    locale,
    // Full locale (e.g., "de-DE-hw")
    localeParts?.slice(0, 2).join("-"),
    // Base locale without variant (e.g., "de-DE")
    localeParts?.[0]
    // Language only (e.g., "de")
  ];
  for (const fallbackLocale of fallbackLocales) {
    try {
      return createDateTimeFormatter(fallbackLocale);
    } catch (e) {
    }
  }
  return createDateTimeFormatter(void 0);
}
function formatItems(items, locale) {
  const formatter = getFormatter(locale);
  return items.map(
    (item) => item.time ? Object.assign(item, {
      time: formatter.format(new Date(item.time))
    }) : item
  );
}
window.Vaadin.Flow.messageListConnector = {
  /**
   * Initializes the connector for the given message list element.
   * Sets up event listeners for attachment clicks.
   */
  initLazy(list) {
    if (list._flowConnectorInitialized) {
      return;
    }
    list._flowConnectorInitialized = true;
    list.addEventListener("attachment-click", (e) => {
      const { item, attachment } = e.detail;
      const itemIndex = list.items.indexOf(item);
      const attachmentIndex = item?.attachments?.indexOf(attachment) ?? -1;
      if (itemIndex < 0 || attachmentIndex < 0) {
        return;
      }
      list.dispatchEvent(
        new CustomEvent("attachment-click-flow", {
          detail: { itemIndex, attachmentIndex }
        })
      );
    });
  },
  /**
   * Fully replaces the items in the list with the given items.
   */
  setItems(list, items, locale) {
    this.initLazy(list);
    list.items = formatItems(items, locale);
  },
  /**
   * Sets the text of the item at the given index to the given text.
   */
  setItemText(list, text, index) {
    list.items[index].text = text;
    list.items = [...list.items];
  },
  /**
   * Appends the given text to the text of the item at the given index.
   */
  appendItemText(list, appendedText, index) {
    const currentText = list.items[index].text || "";
    this.setItemText(list, currentText + appendedText, index);
  },
  /**
   * Adds the given items to the end of the list.
   */
  addItems(list, newItems, locale) {
    this.initLazy(list);
    list.items = [...list.items || [], ...formatItems(newItems, locale)];
  }
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const messageStyles = css$h`
  :host {
    display: flex;
    flex-direction: row;
    padding: var(--vaadin-message-padding, var(--vaadin-padding-s) var(--vaadin-padding-m));
    gap: var(--vaadin-message-gap, var(--vaadin-gap-xs) var(--vaadin-gap-s));
    outline-offset: calc(var(--vaadin-focus-ring-width) * -1);
  }

  :host([hidden]) {
    display: none !important;
  }

  :host(:focus-visible),
  :is(:focus-visible, [focus-ring]) {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }

  [part='content'] {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    gap: inherit;
  }

  [part='header'] {
    align-items: baseline;
    display: flex;
    flex-flow: row wrap;
    gap: inherit;
    row-gap: 0;
    line-height: var(--vaadin-message-header-line-height, inherit);
  }

  [part='name'] {
    font-size: var(--vaadin-message-name-font-size, inherit);
    font-weight: var(--vaadin-message-name-font-weight, 500);
    color: var(--vaadin-message-name-color, var(--vaadin-text-color));
  }

  [part='time'] {
    font-size: var(--vaadin-message-time-font-size, max(11px, 0.75em));
    font-weight: var(--vaadin-message-time-font-weight, inherit);
    color: var(--vaadin-message-time-color, var(--vaadin-text-color-secondary));
  }

  [part='message'] {
    white-space: pre-wrap;
    font-size: var(--vaadin-message-font-size, inherit);
    font-weight: var(--vaadin-message-font-weight, inherit);
    line-height: var(--vaadin-message-line-height, inherit);
    color: var(--vaadin-message-text-color, var(--vaadin-text-color));
  }

  ::slotted([slot='avatar']) {
    flex: none;
  }

  ::slotted(vaadin-markdown) {
    white-space: normal;
  }

  [part='attachments'] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--vaadin-gap-s);
    padding-bottom: var(--vaadin-gap-xs);
  }

  [part~='attachment'] {
    display: inline-grid;
    grid-template-columns: max-content 1fr;
    gap: var(--vaadin-message-attachment-gap, var(--vaadin-gap-s));
    align-items: center;
    background: var(--vaadin-message-attachment-background, var(--vaadin-background-container));
    color: var(--vaadin-message-attachment-text-color, var(--vaadin-text-color));
    cursor: var(--vaadin-clickable-cursor);
    border: var(--vaadin-message-attachment-border-width, 0) solid
      var(--vaadin-message-attachment-border-color, var(--vaadin-border-color));
    border-radius: var(--vaadin-message-attachment-border-radius, var(--vaadin-radius-m));
    padding: 0;
    margin: 0;
    font: inherit;
    font-size: var(--vaadin-message-attachment-font-size, inherit);
    line-height: var(--vaadin-message-attachment-line-height, inherit);
    font-weight: var(--vaadin-message-attachment-font-weight, inherit);
    text-align: start;
    contain: content;
  }

  [part='attachment-icon'] {
    grid-column: 1;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--vaadin-background-container-strong);
    padding: var(--vaadin-message-attachment-padding, var(--vaadin-padding-s));
    contain: content;

    &::before {
      content: '\\2003' / '';
      display: inline-flex;
      align-items: center;
      flex: none;
      height: var(--vaadin-icon-size, 1lh);
      width: var(--vaadin-icon-size, 1lh);
      mask-image: var(--_vaadin-icon-file);
      mask-size: var(--vaadin-icon-visual-size, 100%);
      mask-position: 50%;
      mask-repeat: no-repeat;
      background: currentColor;
    }
  }

  [part='attachment-preview'] {
    grid-column: 1 / -1;
    max-width: 100px;
    max-height: 100px;
  }

  [part='attachment-name'] {
    grid-column: 2;
    padding: var(--vaadin-message-attachment-padding, var(--vaadin-padding-s));
    padding-inline-start: 0;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const MessageMixin = (superClass) => class MessageMixinClass extends FocusMixin(superClass) {
  static get properties() {
    return {
      /**
       * Time of sending the message. It is rendered as-is to the part='time' slot,
       * so the formatting is up to you.
       */
      time: {
        type: String
      },
      /**
       * The name of the user posting the message.
       * It will be placed in the name part to indicate who has sent the message.
       * It is also used as a tooltip for the avatar.
       * Example: `message.userName = "Jessica Jacobs";`
       * @attr {string} user-name
       */
      userName: {
        type: String
      },
      /**
       * The abbreviation of the user.
       * The abbreviation will be passed on to avatar of the message.
       * If the user does not have an avatar picture set with `userImg`, `userAbbr` will be shown in the avatar.
       * Example: `message.userAbbr = "JJ";`
       * @attr {string} user-abbr
       */
      userAbbr: {
        type: String
      },
      /**
       * An URL for a user image.
       * The image will be used in the avatar component to show who has sent the message.
       * Example: `message.userImg = "/static/img/avatar.jpg";`
       * @attr {string} user-img
       */
      userImg: {
        type: String
      },
      /**
       * A color index to be used to render the color of the avatar.
       *
       * @attr {number} user-color-index
       */
      userColorIndex: {
        type: Number
      },
      /**
       * An array of attachment objects to display with the message.
       * Each attachment object can have the following properties:
       * - `name`: The name of the attachment file
       * - `url`: The URL of the attachment
       * - `type`: The MIME type of the attachment (e.g., 'image/png', 'application/pdf')
       *
       * Image attachments (type starting with "image/") show a thumbnail preview,
       * while other attachments show a document icon with the file name.
       *
       * @type {Array<{name?: string, url?: string, type?: string}>}
       */
      attachments: {
        type: Array
      },
      /** @private */
      _avatar: {
        type: Object
      }
    };
  }
  static get observers() {
    return ["__avatarChanged(_avatar, userName, userAbbr, userImg, userColorIndex)"];
  }
  /** @protected */
  ready() {
    super.ready();
    this._avatarController = new SlotController(this, "avatar", "vaadin-avatar", {
      initializer: (avatar) => {
        avatar.setAttribute("aria-hidden", "true");
        this._avatar = avatar;
      }
    });
    this.addController(this._avatarController);
  }
  /** @private */
  __avatarChanged(avatar, userName, userAbbr, userImg, userColorIndex) {
    if (avatar) {
      avatar.setProperties({
        name: userName,
        abbr: userAbbr,
        img: userImg,
        colorIndex: userColorIndex
      });
    }
  }
  /**
   * Renders attachments for the message.
   * @private
   */
  __renderAttachments() {
    if (!(window.Vaadin && window.Vaadin.featureFlags && (window.Vaadin.featureFlags.messageListAttachments || window.Vaadin.featureFlags.aiComponents))) {
      return "";
    }
    const attachments = this.attachments;
    if (!attachments || attachments.length === 0) {
      return "";
    }
    return html`
        <div part="attachments">${attachments.map((attachment) => this.__renderAttachment(attachment))}</div>
      `;
  }
  /**
   * Renders a single attachment.
   * @param {Object} attachment - The attachment object with name, url, and type properties
   * @private
   */
  __renderAttachment(attachment) {
    const isImage = attachment.type && attachment.type.startsWith("image/");
    if (isImage) {
      return html`
          <button
            type="button"
            part="attachment attachment-image"
            aria-label="${attachment.name || ""}"
            @click="${() => this.__onAttachmentClick(attachment)}"
          >
            <img part="attachment-preview" src="${ifDefined(attachment.url)}" alt="" />
          </button>
        `;
    }
    return html`
        <button type="button" part="attachment attachment-file" @click="${() => this.__onAttachmentClick(attachment)}">
          <span part="attachment-icon" aria-hidden="true"></span>
          <span part="attachment-name">${attachment.name || ""}</span>
        </button>
      `;
  }
  /**
   * Dispatches an event when an attachment is clicked.
   * @param {Object} attachment - The attachment that was clicked
   * @private
   */
  __onAttachmentClick(attachment) {
    this.dispatchEvent(
      new CustomEvent("attachment-click", {
        detail: { attachment }
      })
    );
  }
  /**
   * Fired when an attachment is clicked.
   * @event attachment-click
   */
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Message extends MessageMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-message";
  }
  static get styles() {
    return messageStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <slot name="avatar"></slot>
      <div part="content">
        <div part="header">
          <span part="name">${this.userName}</span>
          <span part="time">${this.time}</span>
        </div>
        ${this.__renderAttachments()}
        <div part="message"><slot></slot></div>
      </div>
    `;
  }
}
defineCustomElement(Message);
const MessageListMixin = (superClass) => class MessageListMixinClass extends KeyboardDirectionMixin(superClass) {
  static get properties() {
    return {
      /**
       * An array of objects which will be rendered as messages.
       * The message objects can have the following properties:
       * ```js
       * Array<{
       *   text: string,
       *   time: string,
       *   userName: string,
       *   userAbbr: string,
       *   userImg: string,
       *   userColorIndex: number,
       *   className: string,
       *   theme: string,
       *   attachments: Array<{
       *     name: string,
       *     url: string,
       *     type: string
       *   }>
       * }>
       * ```
       *
       * When a message has attachments, they are rendered in the message's shadow DOM.
       * Image attachments (type starting with "image/") show a thumbnail preview,
       * while other attachments show a document icon with the file name.
       * Clicking an attachment dispatches an `attachment-click` event.
       */
      items: {
        type: Array,
        value: () => [],
        observer: "_itemsChanged",
        sync: true
      },
      /**
       * When set to `true`, the message text is parsed as Markdown.
       */
      markdown: {
        type: Boolean,
        observer: "__markdownChanged",
        reflectToAttribute: true
      },
      /**
       * When set to `true`, new messages are announced to assistive technologies using ARIA live regions.
       * @attr {boolean} announce-messages
       */
      announceMessages: {
        type: Boolean,
        value: false,
        observer: "__announceChanged",
        sync: true
      }
    };
  }
  /** @protected */
  get _messages() {
    return [...this.querySelectorAll("vaadin-message")];
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("aria-relevant", "additions");
    this.setAttribute("role", "region");
  }
  /**
   * Handles attachment-click events from child messages and dispatches
   * a new event enriched with the item.
   * @param {CustomEvent} e
   * @param {Object} item
   * @private
   */
  __onAttachmentClick(e, item) {
    this.dispatchEvent(
      new CustomEvent("attachment-click", {
        detail: {
          ...e.detail,
          item
        }
      })
    );
  }
  /**
   * Override method inherited from `KeyboardDirectionMixin`
   * to use the list of message elements as items.
   *
   * @return {Element[]}
   * @protected
   * @override
   */
  _getItems() {
    return this._messages;
  }
  /** @private */
  _itemsChanged(newVal, oldVal) {
    const items = newVal || [];
    const oldItems = oldVal || [];
    if (items.length || oldItems.length) {
      const focusedIndex = this._getIndexOfFocusableElement();
      const closeToBottom = this.scrollHeight < this.clientHeight + this.scrollTop + 50;
      this._renderMessages(items);
      this._setTabIndexesByIndex(focusedIndex);
      if (oldItems.length) {
        this.__enableScrollSnapping();
      }
      requestAnimationFrame(() => {
        if (items.length > oldItems.length && closeToBottom) {
          this._scrollToLastMessage();
        }
      });
    }
  }
  /** @private */
  __markdownChanged(markdown) {
    if (markdown && !customElements.get("vaadin-markdown")) {
      __vitePreload(() => Promise.resolve().then(() => vaadinMarkdown), true ? void 0 : void 0, import.meta.url).then(() => customElements.whenDefined("vaadin-markdown")).then(() => this._renderMessages(this.items));
    }
    this._renderMessages(this.items);
  }
  /** @private */
  _renderMessages(items) {
    const loadingMarkdown = this.markdown && !customElements.get("vaadin-markdown");
    render$1(
      html`
          ${items.map(
        (item) => html`
              <vaadin-message
                role="listitem"
                .time="${item.time}"
                .userAbbr="${item.userAbbr}"
                .userName="${item.userName}"
                .userImg="${item.userImg}"
                .userColorIndex="${item.userColorIndex}"
                .attachments="${item.attachments}"
                theme="${ifDefined(item.theme)}"
                class="${ifDefined(item.className)}"
                @focusin="${this._onMessageFocusIn}"
                @attachment-click="${(e) => this.__onAttachmentClick(e, item)}"
                style="${ifDefined(loadingMarkdown ? "visibility: hidden" : void 0)}"
                >${this.markdown ? html`<vaadin-markdown .content=${item.text}></vaadin-markdown>` : item.text}<vaadin-avatar slot="avatar"></vaadin-avatar
              ></vaadin-message>
            `
      )}
        `,
      this,
      { host: this }
    );
  }
  /** @private */
  _scrollToLastMessage() {
    if (this.items.length > 0) {
      this.scrollTop = this.scrollHeight - this.clientHeight;
    }
  }
  /** @private */
  __enableScrollSnapping() {
    this.$.list.style.setProperty("--_vaadin-message-list-scroll-snap-align", "end");
    this.__debounceScrollSnapping = Debouncer.debounce(this.__debounceScrollSnapping, timeOut.after(500), () => {
      this.$.list.style.removeProperty("--_vaadin-message-list-scroll-snap-align");
    });
  }
  /** @private */
  _onMessageFocusIn(e) {
    const target = e.composedPath().find((node) => node instanceof customElements.get("vaadin-message"));
    this._setTabIndexesByMessage(target);
  }
  /**
   * @param {number} index
   * @protected
   */
  _setTabIndexesByIndex(index) {
    const message2 = this._messages[index] || this._messages[0];
    this._setTabIndexesByMessage(message2);
  }
  /** @private */
  _setTabIndexesByMessage(message2) {
    this._messages.forEach((e) => {
      e.tabIndex = e === message2 ? 0 : -1;
    });
  }
  /** @private */
  _getIndexOfFocusableElement() {
    const index = this._messages.findIndex((e) => e.tabIndex === 0);
    return index !== -1 ? index : 0;
  }
  /** @private */
  __announceChanged(announceMessages) {
    this.ariaLive = announceMessages ? "polite" : null;
  }
  /**
   * Fired when an attachment is clicked.
   * @event attachment-click
   */
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class MessageList extends SlotStylesMixin(MessageListMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement))))) {
  static get is() {
    return "vaadin-message-list";
  }
  static get styles() {
    return css$h`
      :host {
        display: block;
        overflow: auto;
        padding: var(--vaadin-message-list-padding, var(--vaadin-padding-xs) 0);
        scroll-padding: var(--vaadin-message-list-padding, var(--vaadin-padding-xs) 0);
        scroll-snap-type: y proximity;
      }

      :host([hidden]) {
        display: none !important;
      }

      [part='list']::after {
        content: '';
        display: block;
        scroll-snap-align: var(--_vaadin-message-list-scroll-snap-align, none);
      }
    `;
  }
  /** @protected */
  render() {
    return html`
      <div part="list" role="list" id="list">
        <slot></slot>
      </div>
    `;
  }
  /** @protected */
  get slotStyles() {
    const tag = this.localName;
    return [
      `
      ${tag} :where(vaadin-markdown > :is(h1, h2, h3, h4, h5, h6, p, ul, ol):first-child) {
        margin-top: 0;
      }

      ${tag} :where(vaadin-markdown > :is(h1, h2, h3, h4, h5, h6, p, ul, ol):last-child) {
        margin-bottom: 0;
      }
      `
    ];
  }
}
defineCustomElement(MessageList);
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const notificationCardStyles = css$h`
  :host {
    display: block;
  }

  [part='overlay'] {
    pointer-events: auto;
    box-sizing: border-box;
    width: var(--vaadin-notification-width, 40ch);
    max-width: 100%;
    padding: var(--vaadin-notification-padding, var(--vaadin-padding-s));
    background: var(--vaadin-notification-background, var(--vaadin-background-container));
    border: var(--vaadin-notification-border-width, 1px) solid
      var(--vaadin-notification-border-color, var(--vaadin-border-color-secondary));
    box-shadow: var(--vaadin-notification-shadow, 0 8px 24px -4px rgba(0, 0, 0, 0.3));
    border-radius: var(--vaadin-notification-border-radius, var(--vaadin-radius-l));
    cursor: default;
  }

  @media (forced-colors: active) {
    [part='overlay'] {
      border: 3px solid !important;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const notificationContainerStyles = css$h`
  :host {
    /* How much space to reserve for overlay box shadow, to prevent clipping it with overflow:auto */
    --_paint-area: 2em;
    /* Space between notifications and the viewport */
    --_padding: var(--vaadin-notification-viewport-inset, var(--vaadin-padding-s));
    /* Space between notifications */
    --_gap: var(--vaadin-notification-container-gap, var(--vaadin-gap-s));
    display: grid;
    /* top-stretch, top and bottom regions, bottom-stretch */
    grid-template-rows: auto 1fr auto;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    overflow: hidden;
    padding: max(env(safe-area-inset-top, 0px), var(--_padding)) max(env(safe-area-inset-right, 0px), var(--_padding))
      max(env(safe-area-inset-bottom, 0px), var(--_padding)) max(env(safe-area-inset-left, 0px), var(--_padding));
    border: 0;
    background: transparent;
    pointer-events: none;
    interpolate-size: allow-keywords;
  }

  :host > * {
    grid-column: 1;
  }

  [region-group] {
    position: relative;
    grid-row: 2 / 3;
  }

  [region] {
    max-width: 100%;
    max-height: 100%;
    pointer-events: auto;
    scrollbar-width: none;
  }

  /* scrollbar-width is supported since Safari 18.2, use the following for earlier */
  [region]::-webkit-scrollbar {
    display: none;
  }

  [region='top-stretch'] {
    grid-row: 1;
    z-index: 2;
    --vaadin-notification-width: 100%;
  }

  [region='bottom-stretch'] {
    grid-row: 3;
    z-index: 2;
    --vaadin-notification-width: 100%;
  }

  [region='middle'],
  [region-group] > [region] {
    position: absolute;
  }

  [region='middle'] {
    position: fixed;
    top: 50%;
    left: 50%;
    translate: round(-50%, 1px) round(-50%, 1px);
    max-width: calc(100% - var(--_padding) * 2);
  }

  [region]:where(:hover, :focus-within) {
    z-index: 1;
    overflow: auto;
    overscroll-behavior: contain;
    padding: var(--_paint-area);
  }

  [region]:not([region='middle'], [region$='center']):where(:hover, :focus-within) {
    margin-inline: calc(var(--_paint-area) * -1);
  }

  [region]:not([region='middle']):where(:hover, :focus-within) {
    margin-block: calc(var(--_paint-area) * -1);
  }

  [region-group='top'] > [region] {
    top: 0;
  }

  [region-group='bottom'] > [region] {
    bottom: 0;
  }

  [region-group] > [region$='start'] {
    inset-inline-start: 0;
  }

  [region-group] > [region$='center'] {
    left: 50%;
    translate: -50%;
  }

  [region-group] > [region$='end'] {
    inset-inline-end: 0;
  }

  ::slotted(*) {
    margin-bottom: var(--_gap);
  }

  :is([region^='bottom'], [region='middle']) ::slotted(*) {
    margin-top: var(--_gap);
    margin-bottom: 0;
  }
`;
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const OverlayClassMixin = (superclass) => class OverlayClassMixinClass extends superclass {
  static get properties() {
    return {
      /**
       * A space-delimited list of CSS class names to set on the overlay element.
       * This property does not affect other CSS class names set manually via JS.
       *
       * Note, if the CSS class name was set with this property, clearing it will
       * remove it from the overlay, even if the same class name was also added
       * manually, e.g. by using `classList.add()` in the `renderer` function.
       *
       * @attr {string} overlay-class
       */
      overlayClass: {
        type: String
      },
      /**
       * An overlay element on which CSS class names are set.
       *
       * @protected
       */
      _overlayElement: {
        type: Object
      }
    };
  }
  static get observers() {
    return ["__updateOverlayClassNames(overlayClass, _overlayElement)"];
  }
  /** @private */
  __updateOverlayClassNames(overlayClass, overlayElement) {
    if (!overlayElement) {
      return;
    }
    if (overlayClass === void 0) {
      return;
    }
    const { classList } = overlayElement;
    if (!this.__initialClasses) {
      this.__initialClasses = new Set(classList);
    }
    if (Array.isArray(this.__previousClasses)) {
      const classesToRemove = this.__previousClasses.filter((name) => !this.__initialClasses.has(name));
      if (classesToRemove.length > 0) {
        classList.remove(...classesToRemove);
      }
    }
    const classesToAdd = typeof overlayClass === "string" ? overlayClass.split(" ").filter(Boolean) : [];
    if (classesToAdd.length > 0) {
      classList.add(...classesToAdd);
    }
    this.__previousClasses = classesToAdd;
  }
};
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const NotificationContainerMixin = (superClass) => class extends superClass {
  static get properties() {
    return {
      /**
       * True when the container is opened
       */
      opened: {
        type: Boolean,
        value: false,
        sync: true,
        observer: "_openedChanged"
      }
    };
  }
  constructor() {
    super();
    this._boundVaadinOverlayClose = this._onVaadinOverlayClose.bind(this);
    if (isIOS) {
      this._boundIosResizeListener = () => this._detectIosNavbar();
    }
  }
  /** @protected */
  firstUpdated(props) {
    super.firstUpdated(props);
    this.popover = "manual";
  }
  /**
   * Move the notification container to the top of the stack.
   */
  bringToFront() {
    if (this.matches(":popover-open")) {
      this.hidePopover();
      this.showPopover();
    }
  }
  /** @private */
  _openedChanged(opened) {
    if (opened) {
      document.body.appendChild(this);
      this.showPopover();
      document.addEventListener("vaadin-overlay-close", this._boundVaadinOverlayClose);
      if (this._boundIosResizeListener) {
        this._detectIosNavbar();
        window.addEventListener("resize", this._boundIosResizeListener);
      }
    } else {
      document.body.removeChild(this);
      this.hidePopover();
      document.removeEventListener("vaadin-overlay-close", this._boundVaadinOverlayClose);
      if (this._boundIosResizeListener) {
        window.removeEventListener("resize", this._boundIosResizeListener);
      }
    }
  }
  /** @private */
  _detectIosNavbar() {
    const innerHeight = window.innerHeight;
    const innerWidth = window.innerWidth;
    const landscape = innerWidth > innerHeight;
    const clientHeight = document.documentElement.clientHeight;
    if (landscape && clientHeight > innerHeight) {
      this.style.bottom = `${clientHeight - innerHeight}px`;
    } else {
      this.style.bottom = "0";
    }
  }
  /** @private */
  _onVaadinOverlayClose(event) {
    const sourceEvent = event.detail.sourceEvent;
    const isFromNotification = sourceEvent && sourceEvent.composedPath().indexOf(this) >= 0;
    if (isFromNotification) {
      event.preventDefault();
    }
  }
};
const NotificationMixin = (superClass) => class extends ThemePropertyMixin(OverlayClassMixin(superClass)) {
  static get properties() {
    return {
      /**
       * When true, the notification card has `aria-live` attribute set to
       * `assertive` instead of `polite`. This makes screen readers announce
       * the notification content immediately when it appears.
       */
      assertive: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * The duration in milliseconds to show the notification.
       * Set to `0` or a negative number to disable the notification auto-closing.
       */
      duration: {
        type: Number,
        value: 5e3,
        sync: true
      },
      /**
       * True if the notification is currently displayed.
       */
      opened: {
        type: Boolean,
        value: false,
        notify: true,
        sync: true,
        observer: "_openedChanged"
      },
      /**
       * Alignment of the notification in the viewport
       * Valid values are `top-stretch|top-start|top-center|top-end|middle|bottom-start|bottom-center|bottom-end|bottom-stretch`
       */
      position: {
        type: String,
        value: "bottom-start",
        observer: "_positionChanged",
        sync: true
      },
      /**
       * Custom function for rendering the content of the notification.
       * Receives two arguments:
       *
       * - `root` The `<vaadin-notification-card>` DOM element. Append
       *   your content to it.
       * - `notification` The reference to the `<vaadin-notification>` element.
       * @type {!NotificationRenderer | undefined}
       */
      renderer: {
        type: Function,
        sync: true
      }
    };
  }
  static get observers() {
    return ["_durationChanged(duration, opened)", "_rendererChanged(renderer, opened, _overlayElement)"];
  }
  /**
   * Shows a notification with the given content.
   * By default, positions the notification at `bottom-start` and uses a 5 second duration.
   * An options object can be passed to configure the notification.
   * The options object has the following structure:
   *
   * ```ts
   * {
   *   assertive?: boolean
   *   position?: string
   *   duration?: number
   *   theme?: string
   * }
   * ```
   *
   * See the individual documentation for:
   * - [`assertive`](#/elements/vaadin-notification#property-assertive)
   * - [`position`](#/elements/vaadin-notification#property-position)
   * - [`duration`](#/elements/vaadin-notification#property-duration)
   *
   * @param contents the contents to show, either as a string or a Lit template.
   * @param options optional options for customizing the notification.
   */
  static show(contents, options2) {
    const Notification2 = customElements.get("vaadin-notification");
    if (isTemplateResult(contents)) {
      return Notification2._createAndShowNotification((root) => {
        render$1(contents, root);
      }, options2);
    }
    return Notification2._createAndShowNotification((root) => {
      root.innerText = contents;
    }, options2);
  }
  /** @private */
  static _createAndShowNotification(renderer, options2) {
    const notification = document.createElement("vaadin-notification");
    if (options2 && Number.isFinite(options2.duration)) {
      notification.duration = options2.duration;
    }
    if (options2 && options2.position) {
      notification.position = options2.position;
    }
    if (options2 && options2.assertive) {
      notification.assertive = options2.assertive;
    }
    if (options2 && options2.theme) {
      notification.setAttribute("theme", options2.theme);
    }
    if (options2 && options2.className) {
      notification.overlayClass = options2.className;
    }
    notification.renderer = renderer;
    document.body.appendChild(notification);
    notification.opened = true;
    notification.addEventListener("opened-changed", (e) => {
      if (!e.detail.value) {
        notification.remove();
      }
    });
    return notification;
  }
  /** @private */
  get _container() {
    const Notification2 = customElements.get("vaadin-notification");
    if (!Notification2._container) {
      Notification2._container = document.createElement("vaadin-notification-container");
      document.body.appendChild(Notification2._container);
    }
    return Notification2._container;
  }
  /** @protected */
  get _card() {
    return this._overlayElement;
  }
  /** @protected */
  ready() {
    super.ready();
    this._overlayElement = this.shadowRoot.querySelector("vaadin-notification-card");
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    queueMicrotask(() => {
      if (!this.isConnected) {
        this.opened = false;
      }
    });
  }
  /**
   * Requests an update for the content of the notification.
   * While performing the update, it invokes the renderer passed in the `renderer` property.
   *
   * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
   */
  requestContentUpdate() {
    if (!this.renderer || !this._card) {
      return;
    }
    this.renderer(this._card, this);
  }
  /** @private */
  __computeAriaLive(assertive) {
    return assertive ? "assertive" : "polite";
  }
  /** @private */
  _rendererChanged(renderer, opened, card) {
    if (!card) {
      return;
    }
    const rendererChanged = this._oldRenderer !== renderer;
    this._oldRenderer = renderer;
    if (rendererChanged) {
      card.innerHTML = "";
      delete card._$litPart$;
    }
    if (opened) {
      if (!this._didAnimateNotificationAppend) {
        this._animatedAppendNotificationCard();
      }
      this.requestContentUpdate();
    }
  }
  /**
   * Opens the notification.
   */
  open() {
    this.opened = true;
  }
  /**
   * Closes the notification.
   */
  close() {
    this.opened = false;
  }
  /** @private */
  _openedChanged(opened) {
    if (opened) {
      this._container.opened = true;
      this._animatedAppendNotificationCard();
    } else if (this._card) {
      this._closeNotificationCard();
    }
  }
  /** @private */
  __cleanUpOpeningClosingState() {
    this._card.removeAttribute("opening");
    this._card.removeAttribute("closing");
    this._card.removeEventListener("animationend", this.__animationEndListener);
  }
  /** @private */
  _animatedAppendNotificationCard() {
    if (this._card) {
      this.__cleanUpOpeningClosingState();
      this._card.setAttribute("opening", "");
      this._appendNotificationCard();
      this.__animationEndListener = () => this.__cleanUpOpeningClosingState();
      this._card.addEventListener("animationend", this.__animationEndListener);
      this._didAnimateNotificationAppend = true;
    } else {
      this._didAnimateNotificationAppend = false;
    }
  }
  /** @private */
  _appendNotificationCard() {
    if (!this._card) {
      return;
    }
    if (!this._container.shadowRoot.querySelector(`slot[name="${this.position}"]`)) {
      console.warn(`Invalid alignment parameter provided: position=${this.position}`);
      return;
    }
    if (this._container.firstElementChild) {
      this._container.bringToFront();
    }
    this._card.slot = this.position;
    if (this._container.firstElementChild && /top/u.test(this.position)) {
      this._container.insertBefore(this._card, this._container.firstElementChild);
    } else {
      this._container.appendChild(this._card);
    }
  }
  /** @private */
  _removeNotificationCard() {
    if (!this._card) {
      return;
    }
    if (this._card.parentNode) {
      this._card.parentNode.removeChild(this._card);
    }
    this._card.removeAttribute("closing");
    this._container.opened = Boolean(this._container.firstElementChild);
    this.dispatchEvent(new CustomEvent("closed"));
  }
  /** @private */
  _closeNotificationCard() {
    if (this._durationTimeoutId) {
      clearTimeout(this._durationTimeoutId);
    }
    this._animatedRemoveNotificationCard();
  }
  /** @private */
  _animatedRemoveNotificationCard() {
    this.__cleanUpOpeningClosingState();
    this._card.setAttribute("closing", "");
    const name = getComputedStyle(this._card).getPropertyValue("animation-name");
    if (name && name !== "none") {
      this.__animationEndListener = () => {
        this._removeNotificationCard();
        this.__cleanUpOpeningClosingState();
      };
      this._card.addEventListener("animationend", this.__animationEndListener);
    } else {
      this._removeNotificationCard();
    }
  }
  /** @private */
  _positionChanged() {
    if (this.opened) {
      this._animatedAppendNotificationCard();
    }
  }
  /** @private */
  _durationChanged(duration, opened) {
    if (opened) {
      clearTimeout(this._durationTimeoutId);
      if (duration > 0) {
        this._durationTimeoutId = setTimeout(() => this.close(), duration);
      }
    }
  }
  /**
   * Fired when the notification is closed.
   *
   * @event closed
   */
};
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class NotificationContainer extends NotificationContainerMixin(
  ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-notification-container";
  }
  static get styles() {
    return notificationContainerStyles;
  }
  /** @protected */
  render() {
    return html`
      <div region="top-stretch"><slot name="top-stretch"></slot></div>
      <div region-group="top">
        <div region="top-start"><slot name="top-start"></slot></div>
        <div region="top-center"><slot name="top-center"></slot></div>
        <div region="top-end"><slot name="top-end"></slot></div>
      </div>
      <div region="middle"><slot name="middle"></slot></div>
      <div region-group="bottom">
        <div region="bottom-start"><slot name="bottom-start"></slot></div>
        <div region="bottom-center"><slot name="bottom-center"></slot></div>
        <div region="bottom-end"><slot name="bottom-end"></slot></div>
      </div>
      <div region="bottom-stretch"><slot name="bottom-stretch"></slot></div>
    `;
  }
}
class NotificationCard extends ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))) {
  static get is() {
    return "vaadin-notification-card";
  }
  static get styles() {
    return notificationCardStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="overlay">
        <div part="content">
          <slot></slot>
        </div>
      </div>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("role", "alert");
  }
}
class Notification extends NotificationMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
  static get is() {
    return "vaadin-notification";
  }
  static get styles() {
    return css$h`
      :host {
        display: none !important;
      }
    `;
  }
  /** @protected */
  render() {
    return html`
      <vaadin-notification-card
        theme="${ifDefined(this._theme)}"
        aria-live="${this.__computeAriaLive(this.assertive)}"
      ></vaadin-notification-card>
    `;
  }
  /**
   * Fired when the notification is closed.
   *
   * @event closed
   */
}
defineCustomElement(NotificationContainer);
defineCustomElement(NotificationCard);
defineCustomElement(Notification);
const _window$2 = window;
_window$2.Vaadin ||= {};
_window$2.Vaadin.Flow ||= {};
_window$2.Vaadin.Flow.popover ||= {};
Object.assign(_window$2.Vaadin.Flow.popover, {
  setDefaultHideDelay: (hideDelay) => Popover.setDefaultHideDelay(hideDelay),
  setDefaultFocusDelay: (focusDelay) => Popover.setDefaultFocusDelay(focusDelay),
  setDefaultHoverDelay: (hoverDelay) => Popover.setDefaultHoverDelay(hoverDelay)
});
const { defaultHideDelay: defaultHideDelay$1, defaultFocusDelay: defaultFocusDelay$1, defaultHoverDelay: defaultHoverDelay$1 } = _window$2.Vaadin.Flow.popover;
if (defaultHideDelay$1) {
  Popover.setDefaultHideDelay(defaultHideDelay$1);
}
if (defaultFocusDelay$1) {
  Popover.setDefaultFocusDelay(defaultFocusDelay$1);
}
if (defaultHoverDelay$1) {
  Popover.setDefaultHoverDelay(defaultHoverDelay$1);
}
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const progressBarStyles = css$h`
  :host {
    display: block;
    width: 100%; /* prevent collapsing inside non-stretching column flex */
    height: var(--vaadin-progress-bar-height, 0.5lh);
    contain: layout size;
  }

  :host([hidden]) {
    display: none !important;
  }

  [part='bar'] {
    box-sizing: border-box;
    height: 100%;
    --_padding: var(--vaadin-progress-bar-padding, 0px);
    padding: var(--_padding);
    background: var(--vaadin-progress-bar-background, var(--vaadin-background-container));
    border-radius: var(--vaadin-progress-bar-border-radius, var(--vaadin-radius-m));
    border: var(--vaadin-progress-bar-border-width, 1px) solid
      var(--vaadin-progress-bar-border-color, var(--vaadin-border-color-secondary));
  }

  [part='value'] {
    box-sizing: border-box;
    height: 100%;
    width: calc(var(--vaadin-progress-value) * 100%);
    background: var(--vaadin-progress-bar-value-background, var(--vaadin-border-color));
    border-radius: calc(
      var(--vaadin-progress-bar-border-radius, var(--vaadin-radius-m)) - var(
          --vaadin-progress-bar-border-width,
          1px
        ) - var(--_padding)
    );
    transition: width 150ms;
  }

  /* Indeterminate progress */
  :host([indeterminate]) [part='value'] {
    --_w-min: clamp(8px, 5%, 16px);
    --_w-max: clamp(16px, 20%, 128px);
    animation: indeterminate var(--vaadin-progress-bar-animation-duration, 1s) linear infinite alternate;
    width: var(--_w-min);
  }

  :host([indeterminate][aria-valuenow]) [part='value'] {
    animation-delay: 150ms;
  }

  @keyframes indeterminate {
    0% {
      animation-timing-function: ease-in;
    }

    20% {
      margin-inline-start: 0%;
      width: var(--_w-max);
    }

    50% {
      margin-inline-start: calc(50% - var(--_w-max) / 2);
    }

    80% {
      width: var(--_w-max);
      margin-inline-start: calc(100% - var(--_w-max));
      animation-timing-function: ease-out;
    }

    100% {
      width: var(--_w-min);
      margin-inline-start: calc(100% - var(--_w-min));
    }
  }

  @keyframes indeterminate-reduced {
    100% {
      opacity: 0.2;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    [part='value'] {
      transition: none;
    }

    :host([indeterminate]) [part='value'] {
      width: 25%;
      animation: indeterminate-reduced 2s linear infinite alternate;
    }
  }

  @media (forced-colors: active) {
    [part='bar'] {
      border-width: max(1px, var(--vaadin-progress-bar-border-width));
    }

    [part='value'] {
      background: CanvasText !important;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const ProgressMixin = (superClass) => class VaadinProgressMixin extends superClass {
  static get properties() {
    return {
      /**
       * Current progress value.
       */
      value: {
        type: Number,
        observer: "_valueChanged"
      },
      /**
       * Minimum bound of the progress bar.
       */
      min: {
        type: Number,
        value: 0,
        observer: "_minChanged"
      },
      /**
       * Maximum bound of the progress bar.
       */
      max: {
        type: Number,
        value: 1,
        observer: "_maxChanged"
      },
      /**
       * Indeterminate state of the progress bar.
       * This property takes precedence over other state properties (min, max, value).
       */
      indeterminate: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      }
    };
  }
  static get observers() {
    return ["_normalizedValueChanged(value, min, max)"];
  }
  /** @protected */
  ready() {
    super.ready();
    this.setAttribute("role", "progressbar");
  }
  /** @private */
  _normalizedValueChanged(value, min2, max2) {
    const newNormalizedValue = this._normalizeValue(value, min2, max2);
    this.style.setProperty("--vaadin-progress-value", newNormalizedValue);
  }
  /** @private */
  _valueChanged(newV) {
    this.setAttribute("aria-valuenow", newV);
  }
  /** @private */
  _minChanged(newV) {
    this.setAttribute("aria-valuemin", newV);
  }
  /** @private */
  _maxChanged(newV) {
    this.setAttribute("aria-valuemax", newV);
  }
  /**
   * Percent of current progress relative to whole progress bar (max - min)
   * @private
   */
  _normalizeValue(value, min2, max2) {
    let nV;
    if (!value && value !== 0) {
      nV = 0;
    } else if (min2 >= max2) {
      nV = 1;
    } else {
      nV = (value - min2) / (max2 - min2);
      nV = Math.min(Math.max(nV, 0), 1);
    }
    return nV;
  }
};
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class ProgressBar extends ProgressMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-progress-bar";
  }
  static get styles() {
    return progressBarStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="bar">
        <div part="value"></div>
      </div>
    `;
  }
}
defineCustomElement(ProgressBar);
function stateReducer(state, action) {
  switch (action.type) {
    case "stateKeyChanged":
      const { value } = action;
      return {
        ...state,
        key: value
      };
    default:
      return state;
  }
}
const emptyAction = () => {
};
class ReactAdapterElement extends HTMLElement {
  #root = void 0;
  #rootRendered = false;
  #rendering = void 0;
  #state = /* @__PURE__ */ Object.create(null);
  #stateSetters = /* @__PURE__ */ new Map();
  #customEvents = /* @__PURE__ */ new Map();
  #dispatchFlowState = emptyAction;
  #readyCallback = /* @__PURE__ */ new Map();
  #renderHooks;
  #Wrapper;
  #unmounting;
  constructor() {
    super();
    this.#renderHooks = {
      useState: this.useState.bind(this),
      useCustomEvent: this.useCustomEvent.bind(this),
      useContent: this.useContent.bind(this)
    };
    this.#Wrapper = this.#renderWrapper.bind(this);
    this.#markAsUsed();
  }
  async connectedCallback() {
    this.#rendering = /* @__PURE__ */ reactExports.createElement(this.#Wrapper);
    const createNewRoot = this.dispatchEvent(
      new CustomEvent("flow-portal-add", {
        bubbles: true,
        cancelable: true,
        composed: true,
        detail: {
          children: this.#rendering,
          domNode: this
        }
      })
    );
    if (!createNewRoot || this.#root) {
      return;
    }
    await this.#unmounting;
    this.#root = clientExports.createRoot(this);
    this.#maybeRenderRoot();
    this.#root.render(this.#rendering);
  }
  /**
   * Add a callback for specified element identifier to be called when
   * react element is ready.
   * <p>
   * For internal use only. May be renamed or removed in a future release.
   *
   * @param id element identifier that callback is for
   * @param readyCallback callback method to be informed on element ready state
   * @internal
   */
  addReadyCallback(id, readyCallback) {
    this.#readyCallback.set(id, readyCallback);
  }
  async disconnectedCallback() {
    if (!this.#root) {
      this.dispatchEvent(
        new CustomEvent("flow-portal-remove", {
          bubbles: true,
          cancelable: true,
          composed: true,
          detail: {
            children: this.#rendering,
            domNode: this
          }
        })
      );
    } else {
      this.#unmounting = Promise.resolve();
      await this.#unmounting;
      this.#root.unmount();
      this.#root = void 0;
    }
    this.#rootRendered = false;
    this.#rendering = void 0;
  }
  /**
   * A hook API for using stateful JS properties of the Web Component from
   * the React `render()`.
   *
   * @typeParam T - Type of the state value
   *
   * @param key - Web Component property name, which is used for two-way
   * value propagation from the server and back.
   * @param initialValue - Fallback initial value (optional). Only applies if
   * the Java component constructor does not invoke `setState`.
   * @returns A tuple with two values:
   * 1. The current state.
   * 2. The `set` function for changing the state and triggering render
   * @protected
   */
  useState(key2, initialValue) {
    if (this.#stateSetters.has(key2)) {
      return [this.#state[key2], this.#stateSetters.get(key2)];
    }
    const value = this[key2] ?? initialValue;
    this.#state[key2] = value;
    Object.defineProperty(this, key2, {
      enumerable: true,
      get() {
        return this.#state[key2];
      },
      set(nextValue) {
        this.#state[key2] = nextValue;
        this.#dispatchFlowState({ type: "stateKeyChanged", key: key2, value });
      }
    });
    const dispatchChangedEvent = this.useCustomEvent(`${key2}-changed`, { detail: { value } });
    const setValue = (value2) => {
      this.#state[key2] = value2;
      dispatchChangedEvent({ value: value2 });
      this.#dispatchFlowState({ type: "stateKeyChanged", key: key2, value: value2 });
    };
    this.#stateSetters.set(key2, setValue);
    return [value, setValue];
  }
  /**
   * A hook helper to simplify dispatching a `CustomEvent` on the Web
   * Component from React.
   *
   * @typeParam T - The type for `event.detail` value (optional).
   *
   * @param type - The `CustomEvent` type string.
   * @param options - The settings for the `CustomEvent`.
   * @returns The `dispatch` function. The function parameters change
   * depending on the `T` generic type:
   * - For `undefined` type (default), has no parameters.
   * - For other types, has one parameter for the `event.detail` value of that type.
   * @protected
   */
  useCustomEvent(type, options2 = {}) {
    if (!this.#customEvents.has(type)) {
      const dispatch = ((detail) => {
        const eventInitDict = detail === void 0 ? options2 : {
          ...options2,
          detail
        };
        const event = new CustomEvent(type, eventInitDict);
        return this.dispatchEvent(event);
      });
      this.#customEvents.set(type, dispatch);
      return dispatch;
    }
    return this.#customEvents.get(type);
  }
  /**
   * Prepare content container for Flow to bind server Element to.
   *
   * @param name container name attribute matching server name attribute
   * @protected
   */
  useContent(name) {
    reactExports.useEffect(() => {
      this.#readyCallback.get(name)?.();
    }, []);
    return /* @__PURE__ */ reactExports.createElement("flow-content-container", { name, style: { display: "contents" } });
  }
  #maybeRenderRoot() {
    if (this.#rootRendered || !this.#root) {
      return;
    }
    this.#root.render(/* @__PURE__ */ reactExports.createElement(this.#Wrapper));
    this.#rootRendered = true;
  }
  #renderWrapper() {
    const [state, dispatchFlowState] = reactExports.useReducer(stateReducer, this.#state);
    this.#state = state;
    this.#dispatchFlowState = dispatchFlowState;
    return this.render(this.#renderHooks);
  }
  #markAsUsed() {
    let vaadinObject = window.Vaadin || {};
    if (vaadinObject.developmentMode) {
      vaadinObject.registrations = vaadinObject.registrations || [];
      vaadinObject.registrations.push({
        is: "ReactAdapterElement",
        version: "25.1.1"
      });
    }
  }
}
var _jsxFileName = "/home/thomas/Dropbox/data/Schule_Organisation/Beurteilung/2025_WS/Code_2025/griesypizza2/src/main/frontend/generated/jar-resources/ReactRouterOutletElement.tsx";
class ReactRouterOutletElement extends ReactAdapterElement {
  async connectedCallback() {
    await super.connectedCallback();
    this.style.display = "contents";
  }
  render() {
    return jsxDEV(Outlet, {}, void 0, false, { fileName: _jsxFileName, lineNumber: 12, columnNumber: 12 }, this);
  }
}
customElements.define("react-router-outlet", ReactRouterOutletElement);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const richTextEditorPopupOverlay = css$h`
  [part='overlay'] {
    padding: var(
      --vaadin-rich-text-editor-overlay-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
  }

  [part='content'] {
    display: grid;
    gap: var(--vaadin-rich-text-editor-overlay-gap, var(--vaadin-gap-s));
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }

  [part='content'] ::slotted(button) {
    background-color: var(--_btn-background);
    border: var(--vaadin-rich-text-editor-overlay-color-option-border-width, 1px) solid
      var(--vaadin-rich-text-editor-overlay-color-option-border-color, transparent);
    border-radius: var(--vaadin-rich-text-editor-overlay-color-option-border-radius, 9999px);
    cursor: var(--vaadin-clickable-cursor);
    font: inherit;
    height: var(--vaadin-rich-text-editor-overlay-color-option-height, 1lh);
    padding: 0;
    width: var(--vaadin-rich-text-editor-overlay-color-option-width, 1lh);
  }

  [part='content'] ::slotted(button:first-of-type) {
    background-color: transparent;
    border-color: var(--vaadin-border-color-secondary);
    background-image: repeating-linear-gradient(
      135deg,
      transparent 0%,
      transparent 47%,
      red 50%,
      transparent 53%,
      transparent 100%
    );
  }

  [part='content'] ::slotted(button:focus-visible) {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
    outline-offset: 1px;
  }
`;
const richTextEditorPopupOverlayStyles = [overlayStyles, richTextEditorPopupOverlay];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class RichTextEditorPopup extends PolylitMixin(LitElement) {
  static get is() {
    return "vaadin-rich-text-editor-popup";
  }
  static get styles() {
    return css$h`
      :host([opened]),
      :host([opening]),
      :host([closing]) {
        display: block !important;
        position: fixed;
      }

      :host,
      :host([hidden]) {
        display: none !important;
      }
    `;
  }
  static get properties() {
    return {
      target: {
        type: Object
      },
      opened: {
        type: Boolean,
        reflectToAttribute: true,
        notify: true
      },
      colors: {
        type: Array
      }
    };
  }
  static get observers() {
    return ["__openedOrTargetChanged(opened, target)", "__colorsChanged(colors)"];
  }
  /** @protected */
  render() {
    return html`
      <vaadin-rich-text-editor-popup-overlay
        id="overlay"
        .owner="${this}"
        .opened="${this.opened}"
        .positionTarget="${this.target}"
        no-vertical-overlap
        horizontal-align="start"
        vertical-align="top"
        focus-trap
        exportparts="overlay, content"
        @opened-changed="${this._onOpenedChanged}"
        @vaadin-overlay-escape-press="${this._onOverlayEscapePress}"
      >
        <slot></slot>
      </vaadin-rich-text-editor-popup-overlay>
    `;
  }
  /** @private */
  _onOpenedChanged(event) {
    this.opened = event.detail.value;
  }
  /** @private */
  _onOverlayEscapePress() {
    this.target.focus();
  }
  /** @private */
  _onColorClick(e) {
    const { color: color2 } = e.target.dataset;
    this.dispatchEvent(new CustomEvent("color-selected", { detail: { color: color2 } }));
  }
  /** @private */
  __colorsChanged(colors) {
    render$1(
      html`
        ${colors.map(
        (color2) => html`
            <button data-color="${color2}" style="--_btn-background: ${color2}" @click="${this._onColorClick}"></button>
          `
      )}
      `,
      this,
      { host: this }
    );
  }
  /** @private */
  __openedOrTargetChanged(opened, target) {
    if (target) {
      target.setAttribute("aria-expanded", opened ? "true" : "false");
    }
  }
}
defineCustomElement(RichTextEditorPopup);
class RichTextEditorPopupOverlay extends PositionMixin(
  OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-rich-text-editor-popup-overlay";
  }
  static get styles() {
    return richTextEditorPopupOverlayStyles;
  }
  /** @protected */
  render() {
    return html`
      <div part="overlay" id="overlay">
        <div part="content" id="content">
          <slot></slot>
        </div>
      </div>
    `;
  }
  /**
   * Override method from OverlayFocusMixin to use owner as content root
   * @protected
   * @override
   */
  get _contentRoot() {
    return this.owner;
  }
  /**
   * Override method from OverlayFocusMixin to use owner as focus trap root
   * @protected
   * @override
   */
  get _focusTrapRoot() {
    return this.owner;
  }
}
defineCustomElement(RichTextEditorPopupOverlay);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const icons = css$h`
  :host {
    --_vaadin-icon-align-center: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 5H3"/><path d="M17 12H7"/><path d="M19 19H5"/></svg>');
    --_vaadin-icon-align-left: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 5H3"/><path d="M15 12H3"/><path d="M17 19H3"/></svg>');
    --_vaadin-icon-align-right: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 5H3"/><path d="M21 12H9"/><path d="M21 19H7"/></svg>');
    --_vaadin-icon-background: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.6 12L12 9.4L8 13.4L10.575 16L14.6 12ZM13.425 8L16 10.575L20 6.6L17.4 4L13.425 8ZM11.325 7.275L16.725 12.675L12 17.425C11.6 17.825 11.1292 18.025 10.5875 18.025C10.0458 18.025 9.575 17.825 9.175 17.425L8.5 18H3.5L6.65 14.875C6.25 14.475 6.04167 13.9958 6.025 13.4375C6.00833 12.8792 6.2 12.4 6.6 12L11.325 7.275ZM11.325 7.275L16 2.6C16.4 2.2 16.8708 2 17.4125 2C17.9542 2 18.425 2.2 18.825 2.6L21.425 5.175C21.825 5.575 22.025 6.04583 22.025 6.5875C22.025 7.12917 21.825 7.6 21.425 8L16.725 12.675L11.325 7.275Z" fill="currentColor"/></svg>');
    --_vaadin-icon-bold: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linejoin="round" d="M6.75 3.744h-.753v8.25h7.125a4.125 4.125 0 0 0 0-8.25H6.75Zm0 0v.38m0 16.122h6.747a4.5 4.5 0 0 0 0-9.001h-7.5v9h.753Zm0 0v-.37m0-15.751h6a3.75 3.75 0 1 1 0 7.5h-6m0-7.5v7.5m0 0v8.25m0-8.25h6.375a4.125 4.125 0 0 1 0 8.25H6.75m.747-15.38h4.875a3.375 3.375 0 0 1 0 6.75H7.497v-6.75Zm0 7.5h5.25a3.75 3.75 0 0 1 0 7.5h-5.25v-7.5Z" /></svg>');
    --_vaadin-icon-clear: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="m528-546-93-93-121-121h486v120H568l-40 94ZM792-56 460-388l-80 188H249l119-280L56-792l56-56 736 736-56 56Z"/></svg>');
    --_vaadin-icon-code: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/></svg>');
    --_vaadin-icon-color: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.5 17L10.75 3H13.25L18.5 17H16.1L14.85 13.4H9.2L7.9 17H5.5ZM9.9 11.4H14.1L12.05 5.6H11.95L9.9 11.4Z" fill="currentColor"/></svg>');
    --_vaadin-icon-color-underline: url('data:image/svg+xml,<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 24V20H22V24H2Z" fill="currentColor"/></svg>');
    --_vaadin-icon-h1: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="m17 12 3-2v8"/></svg>');
    --_vaadin-icon-h2: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1"/></svg>');
    --_vaadin-icon-h3: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2"/><path d="M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2"/></svg>');
    --_vaadin-icon-indent: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 5H11"/><path d="M21 12H11"/><path d="M21 19H11"/><path d="m3 8 4 4-4 4"/></svg>');
    --_vaadin-icon-italic: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" x2="10" y1="4" y2="4"/><line x1="14" x2="5" y1="20" y2="20"/><line x1="15" x2="9" y1="4" y2="20"/></svg>');
    --_vaadin-icon-list-number: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 5h10"/><path d="M11 12h10"/><path d="M11 19h10"/><path d="M4 4h1v5"/><path d="M4 9h2"/><path d="M6.5 20H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02"/></svg>');
    --_vaadin-icon-list-bullet: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 5h.01"/><path d="M3 12h.01"/><path d="M3 19h.01"/><path d="M8 5h13"/><path d="M8 12h13"/><path d="M8 19h13"/></svg>');
    --_vaadin-icon-outdent: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 5H11"/><path d="M21 12H11"/><path d="M21 19H11"/><path d="m7 8-4 4 4 4"/></svg>');
    --_vaadin-icon-quote: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 5H3"/><path d="M21 12H8"/><path d="M21 19H8"/><path d="M3 12v7"/></svg>');
    --_vaadin-icon-strikethrough: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4H9a3 3 0 0 0-2.83 4"/><path d="M14 12a4 4 0 0 1 0 8H6"/><line x1="4" x2="20" y1="12" y2="12"/></svg>');
    --_vaadin-icon-subscript: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m4 5 8 8"/><path d="m12 5-8 8"/><path d="M20 19h-4c0-1.5.44-2 1.5-2.5S20 15.33 20 14c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07"/></svg>');
    --_vaadin-icon-superscript: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m4 19 8-8"/><path d="m12 19-8-8"/><path d="M20 12h-4c0-1.5.442-2 1.5-2.5S20 8.334 20 7.002c0-.472-.17-.93-.484-1.29a2.105 2.105 0 0 0-2.617-.436c-.42.239-.738.614-.899 1.06"/></svg>');
    --_vaadin-icon-underline: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" x2="20" y1="20" y2="20"/></svg>');
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const base = css$h`
  :host {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
  }

  :host([hidden]) {
    display: none !important;
  }

  .announcer {
    clip: rect(0, 0, 0, 0);
    position: fixed;
  }

  input[type='file'] {
    display: none;
  }

  .vaadin-rich-text-editor-container {
    display: flex;
    flex: auto;
    flex-direction: column;
    max-height: inherit;
    min-height: inherit;
    background: var(--vaadin-rich-text-editor-background, var(--vaadin-background-color));
    border: var(--vaadin-input-field-border-width, 1px) solid
      var(--vaadin-input-field-border-color, var(--vaadin-border-color));
    border-radius: var(--vaadin-input-field-border-radius, var(--vaadin-radius-m));
    outline-offset: calc(var(--vaadin-input-field-border-width, 1px) * -1);
    contain: paint;
  }

  .vaadin-rich-text-editor-container:has([part='content']:focus-within),
  .vaadin-rich-text-editor-container:has([part~='toolbar-button']:active) {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }
`;
const content = css$h`
  :host {
    --_item-indent: var(--vaadin-padding-s);
    --_marker-indent: var(--vaadin-gap-s);
    --_list-indent: var(--_item-indent);
  }

  [part='content'] {
    box-sizing: border-box;
    display: flex;
    flex: auto;
    flex-direction: column;
    overflow: hidden;
    position: relative;
    cursor: text;
  }

  /*
    Quill core styles.
    CSS selectors removed: margin & padding reset, check list, indentation, video, colors, ordered & unordered list, h1-6, anchor
  */
  .ql-clipboard {
    height: 1px;
    left: -100000px;
    overflow-y: hidden;
    position: absolute;
    top: 50%;
  }

  .ql-clipboard p {
    margin: 0;
    padding: 0;
  }

  .ql-editor {
    box-sizing: border-box;
    color: var(--vaadin-rich-text-editor-content-color, var(--vaadin-text-color));
    flex: 1;
    font-size: var(--vaadin-rich-text-editor-content-font-size, var(--vaadin-input-field-value-font-size, inherit));
    height: 100%;
    line-height: var(--vaadin-rich-text-editor-content-line-height, inherit);
    outline: none;
    overflow-y: auto;
    padding: var(
      --vaadin-rich-text-editor-content-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
    tab-size: calc(var(--_item-indent) * 2);
    text-align: left;
    white-space: pre-wrap;
    word-wrap: break-word;
  }

  .ql-editor > * {
    cursor: text;
  }

  .ql-align-left {
    text-align: left;
  }

  .ql-direction-rtl {
    direction: rtl;
    text-align: inherit;
  }

  .ql-align-center {
    text-align: center;
  }

  .ql-align-justify {
    text-align: justify;
  }

  .ql-align-right {
    text-align: right;
  }

  .ql-code-block-container {
    font-family: monospace;
    background-color: var(--vaadin-background-container);
    border-radius: var(--vaadin-radius-s);
    white-space: pre-wrap;
    margin-block: var(--vaadin-padding-s);
    padding: var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container);
  }

  /* lists */
  .ql-editor ol {
    padding-inline-start: var(--_list-indent);
  }

  .ql-editor li {
    list-style-type: none;
    position: relative;
    padding-inline-start: var(--_item-indent);
  }

  .ql-editor li > .ql-ui::before {
    display: inline-block;
    width: var(--_item-indent);
    margin-inline: calc(var(--_item-indent) * -1) var(--_marker-indent);
    text-align: end;
    white-space: nowrap;
  }

  .ql-editor li[data-list='bullet'] > .ql-ui::before {
    content: '\\2022';
    font-size: 1.5rem;
    line-height: 1rem;
    align-self: baseline;
    vertical-align: text-top;
  }

  .ql-editor p,
  .ql-editor h1,
  .ql-editor h2,
  .ql-editor h3,
  .ql-editor h4,
  .ql-editor h5,
  .ql-editor h6 {
    counter-set: list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  }

  /* 0 */
  .ql-editor li[data-list='ordered'] {
    counter-increment: list-0;
  }

  .ql-editor li[data-list='ordered'] > .ql-ui::before {
    content: counter(list-0, decimal) '. ';
  }

  /* 1 */
  .ql-editor li[data-list='ordered'].ql-indent-1 {
    counter-increment: list-1;
  }

  .ql-editor li[data-list='ordered'].ql-indent-1 > .ql-ui::before {
    content: counter(list-1, lower-alpha) '. ';
  }

  .ql-editor li[data-list].ql-indent-1 {
    counter-set: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  }

  /* 2 */
  .ql-editor li[data-list='ordered'].ql-indent-2 {
    counter-increment: list-2;
  }

  .ql-editor li[data-list='ordered'].ql-indent-2 > .ql-ui::before {
    content: counter(list-2, lower-roman) '. ';
  }

  .ql-editor li[data-list].ql-indent-2 {
    counter-set: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  }

  /* 3 */
  .ql-editor li[data-list='ordered'].ql-indent-3 {
    counter-increment: list-3;
  }

  .ql-editor li[data-list='ordered'].ql-indent-3 > .ql-ui::before {
    content: counter(list-3, decimal) '. ';
  }

  .ql-editor li[data-list].ql-indent-3 {
    counter-set: list-4 list-5 list-6 list-7 list-8 list-9;
  }

  /* 4 */
  .ql-editor li[data-list='ordered'].ql-indent-4 {
    counter-increment: list-4;
  }

  .ql-editor li[data-list='ordered'].ql-indent-4 > .ql-ui::before {
    content: counter(list-4, lower-alpha) '. ';
  }

  .ql-editor li[data-list].ql-indent-4 {
    counter-set: list-5 list-6 list-7 list-8 list-9;
  }

  /* 5 */
  .ql-editor li[data-list='ordered'].ql-indent-5 {
    counter-increment: list-5;
  }

  .ql-editor li[data-list='ordered'].ql-indent-5 > .ql-ui::before {
    content: counter(list-5, lower-roman) '. ';
  }

  .ql-editor li[data-list].ql-indent-5 {
    counter-set: list-6 list-7 list-8 list-9;
  }

  /* 6 */
  .ql-editor li[data-list='ordered'].ql-indent-6 {
    counter-increment: list-6;
  }

  .ql-editor li[data-list='ordered'].ql-indent-6 > .ql-ui::before {
    content: counter(list-6, decimal) '. ';
  }

  .ql-editor li[data-list].ql-indent-6 {
    counter-set: list-7 list-8 list-9;
  }

  /* 7 */
  .ql-editor li[data-list='ordered'].ql-indent-7 {
    counter-increment: list-7;
  }

  .ql-editor li[data-list='ordered'].ql-indent-7 > .ql-ui::before {
    content: counter(list-7, lower-alpha) '. ';
  }

  .ql-editor li[data-list].ql-indent-7 {
    counter-set: list-8 list-9;
  }

  /* 8 */
  .ql-editor li[data-list='ordered'].ql-indent-8 {
    counter-increment: list-8;
  }

  .ql-editor li[data-list='ordered'].ql-indent-8 > .ql-ui::before {
    content: counter(list-8, lower-roman) '. ';
  }

  .ql-editor li[data-list].ql-indent-8 {
    counter-set: list-9;
  }

  /* indent 1 */
  .ql-editor .ql-indent-1 {
    padding-inline-start: calc(var(--_item-indent) * 2);
  }

  .ql-editor li.ql-indent-1 {
    padding-inline-start: calc(var(--_list-indent) + var(--_item-indent) * 2);
  }

  /* indent 2 */
  .ql-editor .ql-indent-2 {
    padding-inline-start: calc(var(--_item-indent) * 4);
  }

  .ql-editor li.ql-indent-2 {
    padding-inline-start: calc(var(--_list-indent) * 2 + var(--_item-indent) * 3);
  }

  /* indent 3 */
  .ql-editor .ql-indent-3 {
    padding-inline-start: calc(var(--_item-indent) * 6);
  }

  .ql-editor li.ql-indent-3 {
    padding-inline-start: calc(var(--_list-indent) * 3 + var(--_item-indent) * 4);
  }

  /* indent 4 */
  .ql-editor .ql-indent-4 {
    padding-inline-start: calc(var(--_item-indent) * 8);
  }

  .ql-editor li.ql-indent-4 {
    padding-inline-start: calc(var(--_list-indent) * 4 + var(--_item-indent) * 5);
  }

  /* indent 5 */
  .ql-editor .ql-indent-5 {
    padding-inline-start: calc(var(--_item-indent) * 10);
  }

  .ql-editor li.ql-indent-5 {
    padding-inline-start: calc(var(--_list-indent) * 5 + var(--_item-indent) * 6);
  }

  /* indent 6 */
  .ql-editor .ql-indent-6 {
    padding-inline-start: calc(var(--_item-indent) * 12);
  }

  .ql-editor li.ql-indent-6 {
    padding-inline-start: calc(var(--_list-indent) * 6 + var(--_item-indent) * 7);
  }

  /* indent 7 */
  .ql-editor .ql-indent-7 {
    padding-inline-start: calc(var(--_item-indent) * 14);
  }

  .ql-editor li.ql-indent-7 {
    padding-inline-start: calc(var(--_list-indent) * 7 + var(--_item-indent) * 8);
  }

  /* indent 8 */
  .ql-editor .ql-indent-8 {
    padding-inline-start: calc(var(--_item-indent) * 16);
  }

  .ql-editor li.ql-indent-8 {
    padding-inline-start: calc(var(--_list-indent) * 8 + var(--_item-indent) * 9);
  }
  /* quill core end */

  blockquote {
    border-inline-start: 4px solid var(--vaadin-border-color-secondary);
    margin: var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container);
    padding-inline-start: var(--vaadin-padding-s);
  }

  code {
    background-color: var(--vaadin-background-container);
    border-radius: var(--vaadin-radius-s);
    padding: 0.125rem 0.25rem;
  }

  img {
    max-width: 100%;
  }

  .ql-editor > :is(p, ol, ul, blockquote, .ql-code-block-container):first-child {
    margin-top: 0;
  }

  .ql-editor > :is(p, ol, ul, blockquote, .ql-code-block-container):last-child {
    margin-bottom: 0;
  }

  /* RTL specific styles */
  :host([dir='rtl']) .ql-editor {
    direction: rtl;
    text-align: right;
  }
`;
const toolbar = css$h`
  [part='toolbar'] {
    background-color: var(--vaadin-rich-text-editor-toolbar-background, var(--vaadin-background-container));
    display: flex;
    flex-shrink: 0;
    flex-wrap: wrap;
    gap: var(--vaadin-rich-text-editor-toolbar-gap, var(--vaadin-gap-s));
    padding: var(--vaadin-rich-text-editor-toolbar-padding, var(--vaadin-padding-s));
  }

  [part~='toolbar-group'] {
    display: flex;
  }

  [part~='toolbar-button'] {
    background: var(--vaadin-rich-text-editor-toolbar-button-background, var(--vaadin-background-container));
    border: var(--vaadin-rich-text-editor-toolbar-button-border-width, 1px) solid
      var(--vaadin-rich-text-editor-toolbar-button-border-color, transparent);
    border-radius: var(--vaadin-rich-text-editor-toolbar-button-border-radius, var(--vaadin-radius-m));
    color: var(--vaadin-rich-text-editor-toolbar-button-text-color, var(--vaadin-text-color));
    cursor: var(--vaadin-clickable-cursor);
    flex-shrink: 0;
    font: inherit;
    padding: var(
      --vaadin-rich-text-editor-toolbar-button-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
    position: relative;
  }

  [part~='toolbar-button']::before {
    background: currentColor;
    content: '';
    display: block;
    height: var(--vaadin-icon-size, 1lh);
    width: var(--vaadin-icon-size, 1lh);
    mask-size: var(--vaadin-icon-visual-size, 100%);
    mask-repeat: no-repeat;
    mask-position: 50%;
  }

  [part~='toolbar-button']:focus-visible {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
    outline-offset: 1px;
    z-index: 1;
  }

  [part~='toolbar-button-pressed'],
  [part~='toolbar-button'][aria-expanded='true'] {
    --vaadin-rich-text-editor-toolbar-button-background: var(--vaadin-background-container-strong);
  }

  [part~='toolbar-button-undo']::before {
    mask-image: var(--_vaadin-icon-undo);
  }

  [part~='toolbar-button-redo']::before {
    mask-image: var(--_vaadin-icon-redo);
  }

  [part~='toolbar-button-bold']::before {
    mask-image: var(--_vaadin-icon-bold);
  }

  [part~='toolbar-button-italic']::before {
    mask-image: var(--_vaadin-icon-italic);
  }

  [part~='toolbar-button-underline']::before {
    mask-image: var(--_vaadin-icon-underline);
  }

  [part~='toolbar-button-strike']::before {
    mask-image: var(--_vaadin-icon-strikethrough);
  }

  [part~='toolbar-button-color']::before {
    mask-image: var(--_vaadin-icon-color);
  }

  [part~='toolbar-button-color']::after {
    background-color: var(--_color-value, currentColor);
  }

  [part~='toolbar-button-background']::before {
    mask-image: var(--_vaadin-icon-background);
  }

  [part~='toolbar-button-background']::after {
    background-color: var(--_background-value, currentColor);
  }

  [part~='toolbar-button-color']::after,
  [part~='toolbar-button-background']::after {
    bottom: 50%;
    content: '';
    display: block;
    height: var(--vaadin-icon-size, 1lh);
    mask-image: var(--_vaadin-icon-color-underline);
    position: absolute;
    transform: translateY(50%);
    width: var(--vaadin-icon-size, 1lh);
  }

  [part~='toolbar-button-h1']::before {
    mask-image: var(--_vaadin-icon-h1);
  }

  [part~='toolbar-button-h2']::before {
    mask-image: var(--_vaadin-icon-h2);
  }

  [part~='toolbar-button-h3']::before {
    mask-image: var(--_vaadin-icon-h3);
  }

  [part~='toolbar-button-subscript']::before {
    mask-image: var(--_vaadin-icon-subscript);
  }

  [part~='toolbar-button-superscript']::before {
    mask-image: var(--_vaadin-icon-superscript);
  }

  [part~='toolbar-button-list-ordered']::before {
    mask-image: var(--_vaadin-icon-list-number);
  }

  [part~='toolbar-button-list-bullet']::before {
    mask-image: var(--_vaadin-icon-list-bullet);
  }

  [part~='toolbar-button-outdent']::before {
    mask-image: var(--_vaadin-icon-outdent);
  }

  [part~='toolbar-button-indent']::before {
    mask-image: var(--_vaadin-icon-indent);
  }

  [part~='toolbar-button-align-left']::before {
    mask-image: var(--_vaadin-icon-align-left);
  }

  [part~='toolbar-button-align-center']::before {
    mask-image: var(--_vaadin-icon-align-center);
  }

  [part~='toolbar-button-align-right']::before {
    mask-image: var(--_vaadin-icon-align-right);
  }

  [part~='toolbar-button-image']::before {
    mask-image: var(--_vaadin-icon-image);
  }

  [part~='toolbar-button-link']::before {
    mask-image: var(--_vaadin-icon-link);
  }

  [part~='toolbar-button-blockquote']::before {
    mask-image: var(--_vaadin-icon-quote);
  }

  [part~='toolbar-button-code-block']::before {
    mask-image: var(--_vaadin-icon-code);
  }

  [part~='toolbar-button-clean']::before {
    mask-image: var(--_vaadin-icon-clear);
  }

  @media (forced-colors: active) {
    [part~='toolbar-button']::before {
      background: CanvasText;
    }

    [part~='toolbar-button-pressed'] {
      background: Highlight;
    }

    [part~='toolbar-button-pressed']::before {
      background: HighlightText;
    }
  }
`;
const states = css$h`
  :host([readonly]) [part='toolbar'] {
    display: none;
  }

  :host([disabled]) {
    pointer-events: none;
    opacity: 0.5;
    -webkit-user-select: none;
    user-select: none;
  }
`;
const richTextEditorStyles = [icons, base, content, toolbar, states];
var vaadinQuill = { exports: {} };
/*!
 * Quill Editor v2.0.3
 * https://quilljs.com
 * Copyright (c) 2017-2026, Slab
 * Copyright (c) 2014, Jason Chen
 * Copyright (c) 2013, salesforce.com
 */
var hasRequiredVaadinQuill;
function requireVaadinQuill() {
  if (hasRequiredVaadinQuill) return vaadinQuill.exports;
  hasRequiredVaadinQuill = 1;
  (function(module) {
    !(function(t, e) {
      t.Quill = e();
    })(window, (function() {
      return (function() {
        var t = { 698: function(t2, e2, n2) {
          n2.d(e2, { Ay: function() {
            return a;
          }, Ji: function() {
            return h;
          }, zo: function() {
            return c;
          } });
          var s2 = n2(3), i = n2(398), r = n2(36), o = n2(850), l = n2(508);
          class a extends s2.BlockBlot {
            cache = {};
            delta() {
              return null == this.cache.delta && (this.cache.delta = (function(t3) {
                let e3 = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1];
                return t3.descendants(s2.LeafBlot).reduce(((t4, n3) => 0 === n3.length() ? t4 : t4.insert(n3.value(), h(n3, {}, e3))), new i.Ay()).insert("\n", h(t3));
              })(this)), this.cache.delta;
            }
            deleteAt(t3, e3) {
              super.deleteAt(t3, e3), this.cache = {};
            }
            formatAt(t3, e3, n3, i2) {
              e3 <= 0 || (this.scroll.query(n3, s2.Scope.BLOCK) ? t3 + e3 === this.length() && this.format(n3, i2) : super.formatAt(t3, Math.min(e3, this.length() - t3 - 1), n3, i2), this.cache = {});
            }
            insertAt(t3, e3, n3) {
              if (null != n3) return super.insertAt(t3, e3, n3), void (this.cache = {});
              if (0 === e3.length) return;
              const s3 = e3.split("\n"), i2 = s3.shift();
              i2.length > 0 && (t3 < this.length() - 1 || null == this.children.tail ? super.insertAt(Math.min(t3, this.length() - 1), i2) : this.children.tail.insertAt(this.children.tail.length(), i2), this.cache = {});
              let r2 = this;
              s3.reduce(((t4, e4) => (r2 = r2.split(t4, true), r2.insertAt(0, e4), e4.length)), t3 + i2.length);
            }
            insertBefore(t3, e3) {
              const { head: n3 } = this.children;
              super.insertBefore(t3, e3), n3 instanceof r.A && n3.remove(), this.cache = {};
            }
            length() {
              return null == this.cache.length && (this.cache.length = super.length() + 1), this.cache.length;
            }
            moveChildren(t3, e3) {
              super.moveChildren(t3, e3), this.cache = {};
            }
            optimize(t3) {
              super.optimize(t3), this.cache = {};
            }
            path(t3) {
              return super.path(t3, true);
            }
            removeChild(t3) {
              super.removeChild(t3), this.cache = {};
            }
            split(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
              if (e3 && (0 === t3 || t3 >= this.length() - 1)) {
                const e4 = this.clone();
                return 0 === t3 ? (this.parent.insertBefore(e4, this), this) : (this.parent.insertBefore(e4, this.next), e4);
              }
              const n3 = super.split(t3, e3);
              return this.cache = {}, n3;
            }
          }
          a.blotName = "block", a.tagName = "P", a.defaultChild = r.A, a.allowedChildren = [r.A, o.A, s2.EmbedBlot, l.A];
          class c extends s2.EmbedBlot {
            attach() {
              super.attach(), this.attributes = new s2.AttributorStore(this.domNode);
            }
            delta() {
              return new i.Ay().insert(this.value(), { ...this.formats(), ...this.attributes.values() });
            }
            format(t3, e3) {
              const n3 = this.scroll.query(t3, s2.Scope.BLOCK_ATTRIBUTE);
              null != n3 && this.attributes.attribute(n3, e3);
            }
            formatAt(t3, e3, n3, s3) {
              this.format(n3, s3);
            }
            insertAt(t3, e3, n3) {
              if (null != n3) return void super.insertAt(t3, e3, n3);
              const s3 = e3.split("\n"), i2 = s3.pop(), r2 = s3.map(((t4) => {
                const e4 = this.scroll.create(a.blotName);
                return e4.insertAt(0, t4), e4;
              })), o2 = this.split(t3);
              r2.forEach(((t4) => {
                this.parent.insertBefore(t4, o2);
              })), i2 && this.parent.insertBefore(this.scroll.create("text", i2), o2);
            }
          }
          function h(t3) {
            let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n3 = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2];
            return null == t3 ? e3 : ("formats" in t3 && "function" == typeof t3.formats && (e3 = { ...e3, ...t3.formats() }, n3 && delete e3["code-token"]), null == t3.parent || "scroll" === t3.parent.statics.blotName || t3.parent.statics.scope !== t3.statics.scope ? e3 : h(t3.parent, e3, n3));
          }
          c.scope = s2.Scope.BLOCK_BLOT;
        }, 36: function(t2, e2, n2) {
          var s2 = n2(3);
          class i extends s2.EmbedBlot {
            static value() {
            }
            optimize() {
              (this.prev || this.next) && this.remove();
            }
            length() {
              return 0;
            }
            value() {
              return "";
            }
          }
          i.blotName = "break", i.tagName = "BR", e2.A = i;
        }, 580: function(t2, e2, n2) {
          var s2 = n2(3);
          class i extends s2.ContainerBlot {
          }
          e2.A = i;
        }, 541: function(t2, e2, n2) {
          var s2 = n2(3), i = n2(508);
          class r extends s2.EmbedBlot {
            static blotName = "cursor";
            static className = "ql-cursor";
            static tagName = "span";
            static CONTENTS = "\uFEFF";
            static value() {
            }
            constructor(t3, e3, n3) {
              super(t3, e3), this.selection = n3, this.textNode = document.createTextNode(r.CONTENTS), this.domNode.appendChild(this.textNode), this.savedLength = 0;
            }
            detach() {
              null != this.parent && this.parent.removeChild(this);
            }
            format(t3, e3) {
              if (0 !== this.savedLength) return void super.format(t3, e3);
              let n3 = this, i2 = 0;
              for (; null != n3 && n3.statics.scope !== s2.Scope.BLOCK_BLOT; ) i2 += n3.offset(n3.parent), n3 = n3.parent;
              null != n3 && (this.savedLength = r.CONTENTS.length, n3.optimize(), n3.formatAt(i2, r.CONTENTS.length, t3, e3), this.savedLength = 0);
            }
            index(t3, e3) {
              return t3 === this.textNode ? 0 : super.index(t3, e3);
            }
            length() {
              return this.savedLength;
            }
            position() {
              return [this.textNode, this.textNode.data.length];
            }
            remove() {
              super.remove(), this.parent = null;
            }
            restore() {
              if (this.selection.composing || null == this.parent) return null;
              const t3 = this.selection.getNativeRange();
              for (; null != this.domNode.lastChild && this.domNode.lastChild !== this.textNode; ) this.domNode.parentNode.insertBefore(this.domNode.lastChild, this.domNode);
              const e3 = this.prev instanceof i.A ? this.prev : null, n3 = e3 ? e3.length() : 0, s3 = this.next instanceof i.A ? this.next : null, o = s3 ? s3.text : "", { textNode: l } = this, a = l.data.split(r.CONTENTS).join("");
              let c;
              if (l.data = r.CONTENTS, e3) c = e3, (a || s3) && (e3.insertAt(e3.length(), a + o), s3 && s3.remove());
              else if (s3) c = s3, s3.insertAt(0, a);
              else {
                const t4 = document.createTextNode(a);
                c = this.scroll.create(t4), this.parent.insertBefore(c, this);
              }
              if (this.remove(), t3) {
                const i2 = (t4, i3) => e3 && t4 === e3.domNode ? i3 : t4 === l ? n3 + i3 - 1 : s3 && t4 === s3.domNode ? n3 + a.length + i3 : null, r2 = i2(t3.start.node, t3.start.offset), o2 = i2(t3.end.node, t3.end.offset);
                if (null !== r2 && null !== o2) return { startNode: c.domNode, startOffset: r2, endNode: c.domNode, endOffset: o2 };
              }
              return null;
            }
            update(t3, e3) {
              if (t3.some(((t4) => "characterData" === t4.type && t4.target === this.textNode))) {
                const t4 = this.restore();
                t4 && (e3.range = t4);
              }
            }
            optimize(t3) {
              super.optimize(t3);
              let { parent: e3 } = this;
              for (; e3; ) {
                if ("A" === e3.domNode.tagName) {
                  this.savedLength = r.CONTENTS.length, e3.isolate(this.offset(e3), this.length()).unwrap(), this.savedLength = 0;
                  break;
                }
                e3 = e3.parent;
              }
            }
            value() {
              return "";
            }
          }
          e2.A = r;
        }, 746: function(t2, e2, n2) {
          var s2 = n2(3), i = n2(508);
          const r = "\uFEFF";
          class o extends s2.EmbedBlot {
            constructor(t3, e3) {
              super(t3, e3), this.contentNode = document.createElement("span"), this.contentNode.setAttribute("contenteditable", "false"), Array.from(this.domNode.childNodes).forEach(((t4) => {
                this.contentNode.appendChild(t4);
              })), this.leftGuard = document.createTextNode(r), this.rightGuard = document.createTextNode(r), this.domNode.appendChild(this.leftGuard), this.domNode.appendChild(this.contentNode), this.domNode.appendChild(this.rightGuard);
            }
            index(t3, e3) {
              return t3 === this.leftGuard ? 0 : t3 === this.rightGuard ? 1 : super.index(t3, e3);
            }
            restore(t3) {
              let e3, n3 = null;
              const s3 = t3.data.split(r).join("");
              if (t3 === this.leftGuard) if (this.prev instanceof i.A) {
                const t4 = this.prev.length();
                this.prev.insertAt(t4, s3), n3 = { startNode: this.prev.domNode, startOffset: t4 + s3.length };
              } else e3 = document.createTextNode(s3), this.parent.insertBefore(this.scroll.create(e3), this), n3 = { startNode: e3, startOffset: s3.length };
              else t3 === this.rightGuard && (this.next instanceof i.A ? (this.next.insertAt(0, s3), n3 = { startNode: this.next.domNode, startOffset: s3.length }) : (e3 = document.createTextNode(s3), this.parent.insertBefore(this.scroll.create(e3), this.next), n3 = { startNode: e3, startOffset: s3.length }));
              return t3.data = r, n3;
            }
            update(t3, e3) {
              t3.forEach(((t4) => {
                if ("characterData" === t4.type && (t4.target === this.leftGuard || t4.target === this.rightGuard)) {
                  const n3 = this.restore(t4.target);
                  n3 && (e3.range = n3);
                }
              }));
            }
          }
          e2.A = o;
        }, 850: function(t2, e2, n2) {
          var s2 = n2(3), i = n2(36), r = n2(508);
          class o extends s2.InlineBlot {
            static allowedChildren = [o, i.A, s2.EmbedBlot, r.A];
            static order = ["cursor", "inline", "link", "underline", "strike", "italic", "bold", "script", "code"];
            static compare(t3, e3) {
              const n3 = o.order.indexOf(t3), s3 = o.order.indexOf(e3);
              return n3 >= 0 || s3 >= 0 ? n3 - s3 : t3 === e3 ? 0 : t3 < e3 ? -1 : 1;
            }
            formatAt(t3, e3, n3, i2) {
              if (o.compare(this.statics.blotName, n3) < 0 && this.scroll.query(n3, s2.Scope.BLOT)) {
                const s3 = this.isolate(t3, e3);
                i2 && s3.wrap(n3, i2);
              } else super.formatAt(t3, e3, n3, i2);
            }
            optimize(t3) {
              if (super.optimize(t3), this.parent instanceof o && o.compare(this.statics.blotName, this.parent.statics.blotName) > 0) {
                const t4 = this.parent.isolate(this.offset(), this.length());
                this.moveChildren(t4), t4.wrap(this);
              }
            }
          }
          e2.A = o;
        }, 508: function(t2, e2, n2) {
          n2.d(e2, { A: function() {
            return i;
          }, X: function() {
            return o;
          } });
          var s2 = n2(3);
          class i extends s2.TextBlot {
          }
          const r = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
          function o(t3) {
            return t3.replace(/[&<>"']/g, ((t4) => r[t4]));
          }
        }, 729: function(t2, e2, n2) {
          n2.d(e2, { default: function() {
            return B;
          } });
          var s2 = n2(543), i = n2(698), r = n2(36), o = n2(580), l = n2(541), a = n2(746), c = n2(850), h = n2(3), u = n2(398), d = n2(200);
          function f(t3) {
            return t3 instanceof i.Ay || t3 instanceof i.zo;
          }
          function p(t3) {
            return "function" == typeof t3.updateContent;
          }
          class m extends h.ScrollBlot {
            static blotName = "scroll";
            static className = "ql-editor";
            static tagName = "DIV";
            static defaultChild = i.Ay;
            static allowedChildren = [i.Ay, i.zo, o.A];
            constructor(t3, e3, n3) {
              let { emitter: s3 } = n3;
              super(t3, e3), this.emitter = s3, this.batch = false, this.optimize(), this.enable(), this.domNode.addEventListener("dragstart", ((t4) => this.handleDragStart(t4)));
            }
            batchStart() {
              Array.isArray(this.batch) || (this.batch = []);
            }
            batchEnd() {
              if (!this.batch) return;
              const t3 = this.batch;
              this.batch = false, this.update(t3);
            }
            emitMount(t3) {
              this.emitter.emit(d.A.events.SCROLL_BLOT_MOUNT, t3);
            }
            emitUnmount(t3) {
              this.emitter.emit(d.A.events.SCROLL_BLOT_UNMOUNT, t3);
            }
            emitEmbedUpdate(t3, e3) {
              this.emitter.emit(d.A.events.SCROLL_EMBED_UPDATE, t3, e3);
            }
            deleteAt(t3, e3) {
              const [n3, s3] = this.line(t3), [o2] = this.line(t3 + e3);
              if (super.deleteAt(t3, e3), null != o2 && n3 !== o2 && s3 > 0) {
                if (n3 instanceof i.zo || o2 instanceof i.zo) return void this.optimize();
                const t4 = o2.children.head instanceof r.A ? null : o2.children.head;
                n3.moveChildren(o2, t4), n3.remove();
              }
              this.optimize();
            }
            enable() {
              let t3 = !(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0];
              this.domNode.setAttribute("contenteditable", t3 ? "true" : "false");
            }
            formatAt(t3, e3, n3, s3) {
              super.formatAt(t3, e3, n3, s3), this.optimize();
            }
            insertAt(t3, e3, n3) {
              if (t3 >= this.length()) if (null == n3 || null == this.scroll.query(e3, h.Scope.BLOCK)) {
                const t4 = this.scroll.create(this.statics.defaultChild.blotName);
                this.appendChild(t4), null == n3 && e3.endsWith("\n") ? t4.insertAt(0, e3.slice(0, -1), n3) : t4.insertAt(0, e3, n3);
              } else {
                const t4 = this.scroll.create(e3, n3);
                this.appendChild(t4);
              }
              else super.insertAt(t3, e3, n3);
              this.optimize();
            }
            insertBefore(t3, e3) {
              if (t3.statics.scope === h.Scope.INLINE_BLOT) {
                const n3 = this.scroll.create(this.statics.defaultChild.blotName);
                n3.appendChild(t3), super.insertBefore(n3, e3);
              } else super.insertBefore(t3, e3);
            }
            insertContents(t3, e3) {
              const n3 = this.deltaToRenderBlocks(e3.concat(new u.Ay().insert("\n"))), s3 = n3.pop();
              if (null == s3) return;
              this.batchStart();
              const r2 = n3.shift();
              if (r2) {
                const e4 = "block" === r2.type && (0 === r2.delta.length() || !this.descendant(i.zo, t3)[0] && t3 < this.length()), n4 = "block" === r2.type ? r2.delta : new u.Ay().insert({ [r2.key]: r2.value });
                g(this, t3, n4);
                const s4 = "block" === r2.type ? 1 : 0, o3 = t3 + n4.length() + s4;
                e4 && this.insertAt(o3 - 1, "\n");
                const l3 = (0, i.Ji)(this.line(t3)[0]), a3 = u.xb.diff(l3, r2.attributes) || {};
                Object.keys(a3).forEach(((t4) => {
                  this.formatAt(o3 - 1, 1, t4, a3[t4]);
                })), t3 = o3;
              }
              let [o2, l2] = this.children.find(t3);
              n3.length && (o2 && (o2 = o2.split(l2), l2 = 0), n3.forEach(((t4) => {
                if ("block" === t4.type) g(this.createBlock(t4.attributes, o2 || void 0), 0, t4.delta);
                else {
                  const e4 = this.create(t4.key, t4.value);
                  this.insertBefore(e4, o2 || void 0), Object.keys(t4.attributes).forEach(((n4) => {
                    e4.format(n4, t4.attributes[n4]);
                  }));
                }
              }))), "block" === s3.type && s3.delta.length() && g(this, o2 ? o2.offset(o2.scroll) + l2 : this.length(), s3.delta), this.batchEnd(), this.optimize();
            }
            isEnabled() {
              return "true" === this.domNode.getAttribute("contenteditable");
            }
            leaf(t3) {
              const e3 = this.path(t3).pop();
              if (!e3) return [null, -1];
              const [n3, s3] = e3;
              return n3 instanceof h.LeafBlot ? [n3, s3] : [null, -1];
            }
            line(t3) {
              return t3 === this.length() ? this.line(t3 - 1) : this.descendant(f, t3);
            }
            lines() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : Number.MAX_VALUE;
              const n3 = (t4, e4, s3) => {
                let i2 = [], r2 = s3;
                return t4.children.forEachAt(e4, s3, ((t5, e5, s4) => {
                  f(t5) ? i2.push(t5) : t5 instanceof h.ContainerBlot && (i2 = i2.concat(n3(t5, e5, r2))), r2 -= s4;
                })), i2;
              };
              return n3(this, t3, e3);
            }
            optimize() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
              this.batch || (super.optimize(t3, e3), t3.length > 0 && this.emitter.emit(d.A.events.SCROLL_OPTIMIZE, t3, e3));
            }
            path(t3) {
              return super.path(t3).slice(1);
            }
            remove() {
            }
            update(t3) {
              if (this.batch) return void (Array.isArray(t3) && (this.batch = this.batch.concat(t3)));
              let e3 = d.A.sources.USER;
              "string" == typeof t3 && (e3 = t3), Array.isArray(t3) || (t3 = this.observer.takeRecords()), (t3 = t3.filter(((t4) => {
                let { target: e4 } = t4;
                const n3 = this.find(e4, true);
                return n3 && !p(n3);
              }))).length > 0 && this.emitter.emit(d.A.events.SCROLL_BEFORE_UPDATE, e3, t3), super.update(t3.concat([])), t3.length > 0 && this.emitter.emit(d.A.events.SCROLL_UPDATE, e3, t3);
            }
            updateEmbedAt(t3, e3, n3) {
              const [s3] = this.descendant(((t4) => t4 instanceof i.zo), t3);
              s3 && s3.statics.blotName === e3 && p(s3) && s3.updateContent(n3);
            }
            handleDragStart(t3) {
              t3.preventDefault();
            }
            deltaToRenderBlocks(t3) {
              const e3 = [];
              let n3 = new u.Ay();
              return t3.forEach(((t4) => {
                const s3 = t4?.insert;
                if (s3) if ("string" == typeof s3) {
                  const i2 = s3.split("\n");
                  i2.slice(0, -1).forEach(((s4) => {
                    n3.insert(s4, t4.attributes), e3.push({ type: "block", delta: n3, attributes: t4.attributes ?? {} }), n3 = new u.Ay();
                  }));
                  const r2 = i2[i2.length - 1];
                  r2 && n3.insert(r2, t4.attributes);
                } else {
                  const i2 = Object.keys(s3)[0];
                  if (!i2) return;
                  this.query(i2, h.Scope.INLINE) ? n3.push(t4) : (n3.length() && e3.push({ type: "block", delta: n3, attributes: {} }), n3 = new u.Ay(), e3.push({ type: "blockEmbed", key: i2, value: s3[i2], attributes: t4.attributes ?? {} }));
                }
              })), n3.length() && e3.push({ type: "block", delta: n3, attributes: {} }), e3;
            }
            createBlock(t3, e3) {
              let n3;
              const s3 = {};
              Object.entries(t3).forEach(((t4) => {
                let [e4, i3] = t4;
                null != this.query(e4, h.Scope.BLOCK & h.Scope.BLOT) ? n3 = e4 : s3[e4] = i3;
              }));
              const i2 = this.create(n3 || this.statics.defaultChild.blotName, n3 ? t3[n3] : void 0);
              this.insertBefore(i2, e3 || void 0);
              const r2 = i2.length();
              return Object.entries(s3).forEach(((t4) => {
                let [e4, n4] = t4;
                i2.formatAt(0, r2, e4, n4);
              })), i2;
            }
          }
          function g(t3, e3, n3) {
            n3.reduce(((e4, n4) => {
              const s3 = u.Op.length(n4);
              let r2 = n4.attributes || {};
              if (null != n4.insert) {
                if ("string" == typeof n4.insert) {
                  const s4 = n4.insert;
                  t3.insertAt(e4, s4);
                  const [o2] = t3.descendant(h.LeafBlot, e4), l2 = (0, i.Ji)(o2);
                  r2 = u.xb.diff(l2, r2) || {};
                } else if ("object" == typeof n4.insert) {
                  const s4 = Object.keys(n4.insert)[0];
                  if (null == s4) return e4;
                  if (t3.insertAt(e4, s4, n4.insert[s4]), null != t3.scroll.query(s4, h.Scope.INLINE)) {
                    const [n5] = t3.descendant(h.LeafBlot, e4), s5 = (0, i.Ji)(n5);
                    r2 = u.xb.diff(s5, r2) || {};
                  }
                }
              }
              return Object.keys(r2).forEach(((n5) => {
                t3.formatAt(e4, s3, n5, r2[n5]);
              })), e4 + s3;
            }), e3);
          }
          var b = m, y = n2(508), A5 = n2(584), N = n2(266);
          class v extends N.A {
            static DEFAULTS = { delay: 1e3, maxStack: 100, userOnly: false };
            lastRecorded = 0;
            ignoreChange = false;
            stack = { undo: [], redo: [] };
            currentRange = null;
            constructor(t3, e3) {
              super(t3, e3), this.quill.on(s2.Ay.events.EDITOR_CHANGE, ((t4, e4, n3, i2) => {
                t4 === s2.Ay.events.SELECTION_CHANGE ? e4 && i2 !== s2.Ay.sources.SILENT && (this.currentRange = e4) : t4 === s2.Ay.events.TEXT_CHANGE && (this.ignoreChange || (this.options.userOnly && i2 !== s2.Ay.sources.USER ? this.transform(e4) : this.record(e4, n3)), this.currentRange = x(this.currentRange, e4));
              })), this.quill.keyboard.addBinding({ key: "z", shortKey: true }, this.undo.bind(this)), this.quill.keyboard.addBinding({ key: ["z", "Z"], shortKey: true, shiftKey: true }, this.redo.bind(this)), /Win/i.test(navigator.platform) && this.quill.keyboard.addBinding({ key: "y", shortKey: true }, this.redo.bind(this)), this.quill.root.addEventListener("beforeinput", ((t4) => {
                "historyUndo" === t4.inputType ? (this.undo(), t4.preventDefault()) : "historyRedo" === t4.inputType && (this.redo(), t4.preventDefault());
              }));
            }
            change(t3, e3) {
              if (0 === this.stack[t3].length) return;
              const n3 = this.stack[t3].pop();
              if (!n3) return;
              const i2 = this.quill.getContents(), r2 = n3.delta.invert(i2);
              this.stack[e3].push({ delta: r2, range: x(n3.range, r2) }), this.lastRecorded = 0, this.ignoreChange = true, this.quill.updateContents(n3.delta, s2.Ay.sources.USER), this.ignoreChange = false, this.restoreSelection(n3);
            }
            clear() {
              this.stack = { undo: [], redo: [] };
            }
            cutoff() {
              this.lastRecorded = 0;
            }
            record(t3, e3) {
              if (0 === t3.ops.length) return;
              this.stack.redo = [];
              let n3 = t3.invert(e3), s3 = this.currentRange;
              const i2 = Date.now();
              if (this.lastRecorded + this.options.delay > i2 && this.stack.undo.length > 0) {
                const t4 = this.stack.undo.pop();
                t4 && (n3 = n3.compose(t4.delta), s3 = t4.range);
              } else this.lastRecorded = i2;
              0 !== n3.length() && (this.stack.undo.push({ delta: n3, range: s3 }), this.stack.undo.length > this.options.maxStack && this.stack.undo.shift());
            }
            redo() {
              this.change("redo", "undo");
            }
            transform(t3) {
              E4(this.stack.undo, t3), E4(this.stack.redo, t3);
            }
            undo() {
              this.change("undo", "redo");
            }
            restoreSelection(t3) {
              if (t3.range) this.quill.setSelection(t3.range, s2.Ay.sources.USER);
              else {
                const e3 = (function(t4, e4) {
                  const n3 = e4.reduce(((t5, e5) => t5 + (e5.delete || 0)), 0);
                  let s3 = e4.length() - n3;
                  return (function(t5, e5) {
                    const n4 = e5.ops[e5.ops.length - 1];
                    return null != n4 && (null != n4.insert ? "string" == typeof n4.insert && n4.insert.endsWith("\n") : null != n4.attributes && Object.keys(n4.attributes).some(((e6) => null != t5.query(e6, h.Scope.BLOCK))));
                  })(t4, e4) && (s3 -= 1), s3;
                })(this.quill.scroll, t3.delta);
                this.quill.setSelection(e3, s2.Ay.sources.USER);
              }
            }
          }
          function E4(t3, e3) {
            let n3 = e3;
            for (let e4 = t3.length - 1; e4 >= 0; e4 -= 1) {
              const s3 = t3[e4];
              t3[e4] = { delta: n3.transform(s3.delta, true), range: s3.range && x(s3.range, n3) }, n3 = s3.delta.transform(n3), 0 === t3[e4].delta.length() && t3.splice(e4, 1);
            }
          }
          function x(t3, e3) {
            if (!t3) return t3;
            const n3 = e3.transformPosition(t3.index);
            return { index: n3, length: e3.transformPosition(t3.index + t3.length) - n3 };
          }
          var L = n2(123);
          class S extends N.A {
            constructor(t3, e3) {
              super(t3, e3), t3.root.addEventListener("drop", ((e4) => {
                e4.preventDefault();
                let n3 = null;
                if (document.caretRangeFromPoint) n3 = document.caretRangeFromPoint(e4.clientX, e4.clientY);
                else if (document.caretPositionFromPoint) {
                  const t4 = document.caretPositionFromPoint(e4.clientX, e4.clientY);
                  n3 = document.createRange(), n3.setStart(t4.offsetNode, t4.offset), n3.setEnd(t4.offsetNode, t4.offset);
                }
                const s3 = n3 && t3.selection.normalizeNative(n3);
                if (s3) {
                  const n4 = t3.selection.normalizedToRange(s3);
                  e4.dataTransfer?.files && this.upload(n4, e4.dataTransfer.files);
                }
              }));
            }
            upload(t3, e3) {
              const n3 = [];
              Array.from(e3).forEach(((t4) => {
                t4 && this.options.mimetypes?.includes(t4.type) && n3.push(t4);
              })), n3.length > 0 && this.options.handler.call(this, t3, n3);
            }
          }
          S.DEFAULTS = { mimetypes: ["image/png", "image/jpeg"], handler(t3, e3) {
            if (!this.quill.scroll.query("image")) return;
            const n3 = e3.map(((t4) => new Promise(((e4) => {
              const n4 = new FileReader();
              n4.onload = () => {
                e4(n4.result);
              }, n4.readAsDataURL(t4);
            }))));
            Promise.all(n3).then(((e4) => {
              const n4 = e4.reduce(((t4, e5) => t4.insert({ image: e5 })), new u.Ay().retain(t3.index).delete(t3.length));
              this.quill.updateContents(n4, d.A.sources.USER), this.quill.setSelection(t3.index + e4.length, d.A.sources.SILENT);
            }));
          } };
          var T = S;
          const k = ["insertText", "insertReplacementText"];
          class O2 extends N.A {
            constructor(t3, e3) {
              super(t3, e3), t3.root.addEventListener("beforeinput", ((t4) => {
                this.handleBeforeInput(t4);
              })), /Android/i.test(navigator.userAgent) || t3.on(s2.Ay.events.COMPOSITION_BEFORE_START, (() => {
                this.handleCompositionStart();
              }));
            }
            deleteRange(t3) {
              (0, L.Xo)({ range: t3, quill: this.quill });
            }
            replaceText(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "";
              if (0 === t3.length) return false;
              if (e3) {
                const n3 = this.quill.getFormat(t3.index, 1);
                this.deleteRange(t3), this.quill.updateContents(new u.Ay().retain(t3.index).insert(e3, n3), s2.Ay.sources.USER);
              } else this.deleteRange(t3);
              return this.quill.setSelection(t3.index + e3.length, 0, s2.Ay.sources.SILENT), true;
            }
            handleBeforeInput(t3) {
              if (this.quill.composition.isComposing || t3.defaultPrevented || !k.includes(t3.inputType)) return;
              const e3 = t3.getTargetRanges ? t3.getTargetRanges()[0] : null;
              if (!e3 || true === e3.collapsed) return;
              const n3 = (function(t4) {
                return "string" == typeof t4.data ? t4.data : t4.dataTransfer?.types.includes("text/plain") ? t4.dataTransfer.getData("text/plain") : null;
              })(t3);
              if (null == n3) return;
              const s3 = this.quill.selection.normalizeNative(e3), i2 = s3 ? this.quill.selection.normalizedToRange(s3) : null;
              i2 && this.replaceText(i2, n3) && t3.preventDefault();
            }
            handleCompositionStart() {
              const t3 = this.quill.getSelection();
              t3 && this.replaceText(t3);
            }
          }
          var w = O2;
          const C = /Mac/i.test(navigator.platform);
          class q extends N.A {
            isListening = false;
            selectionChangeDeadline = 0;
            constructor(t3, e3) {
              super(t3, e3), this.handleArrowKeys(), this.handleNavigationShortcuts();
            }
            handleArrowKeys() {
              this.quill.keyboard.addBinding({ key: ["ArrowLeft", "ArrowRight"], offset: 0, shiftKey: null, handler(t3, e3) {
                let { line: n3, event: i2 } = e3;
                if (!(n3 instanceof h.ParentBlot && n3.uiNode)) return true;
                const r2 = "rtl" === getComputedStyle(n3.domNode).direction;
                return !!(r2 && "ArrowRight" !== i2.key || !r2 && "ArrowLeft" !== i2.key) || (this.quill.setSelection(t3.index - 1, t3.length + (i2.shiftKey ? 1 : 0), s2.Ay.sources.USER), false);
              } });
            }
            handleNavigationShortcuts() {
              this.quill.root.addEventListener("keydown", ((t3) => {
                !t3.defaultPrevented && ((t4) => "ArrowLeft" === t4.key || "ArrowRight" === t4.key || "ArrowUp" === t4.key || "ArrowDown" === t4.key || "Home" === t4.key || !(!C || "a" !== t4.key || true !== t4.ctrlKey))(t3) && this.ensureListeningToSelectionChange();
              }));
            }
            ensureListeningToSelectionChange() {
              this.selectionChangeDeadline = Date.now() + 100, this.isListening || (this.isListening = true, document.addEventListener("selectionchange", (() => {
                this.isListening = false, Date.now() <= this.selectionChangeDeadline && this.handleSelectionChange();
              }), { once: true }));
            }
            handleSelectionChange() {
              const t3 = document.getSelection();
              if (!t3) return;
              const e3 = t3.getRangeAt(0);
              if (true !== e3.collapsed || 0 !== e3.startOffset) return;
              const n3 = this.quill.scroll.find(e3.startContainer);
              if (!(n3 instanceof h.ParentBlot && n3.uiNode)) return;
              const s3 = document.createRange();
              s3.setStartAfter(n3.uiNode), s3.setEndAfter(n3.uiNode), t3.removeAllRanges(), t3.addRange(s3);
            }
          }
          var R2 = q;
          s2.Ay.register({ "blots/block": i.Ay, "blots/block/embed": i.zo, "blots/break": r.A, "blots/container": o.A, "blots/cursor": l.A, "blots/embed": a.A, "blots/inline": c.A, "blots/scroll": b, "blots/text": y.A, "modules/clipboard": A5.Ay, "modules/history": v, "modules/keyboard": L.Ay, "modules/uploader": T, "modules/input": w, "modules/uiNode": R2 });
          var B = s2.Ay;
        }, 200: function(t2, e2, n2) {
          n2.d(e2, { A: function() {
            return l;
          } });
          class s2 {
            listener;
            context;
            once;
            constructor(t3, e3, n3 = false) {
              this.listener = t3, this.context = e3, this.once = n3;
            }
          }
          class i {
            static prefixed = false;
            _events = /* @__PURE__ */ Object.create(null);
            _eventsCount = 0;
            #t(t3, e3, n3, i2) {
              if ("function" != typeof e3) throw new TypeError("The listener must be a function");
              const r2 = new s2(e3, n3 || this, i2), o2 = this._events[t3];
              return Array.isArray(o2) ? o2.push(r2) : o2 ? this._events[t3] = [o2, r2] : (this._events[t3] = r2, this._eventsCount++), this;
            }
            clearEvent(t3) {
              0 == --this._eventsCount ? this._events = /* @__PURE__ */ Object.create(null) : delete this._events[t3];
            }
            eventNames() {
              return 0 === this._eventsCount ? [] : Reflect.ownKeys(this._events);
            }
            listeners(t3) {
              const e3 = this._events[t3];
              return e3 ? Array.isArray(e3) ? e3.map(((t4) => t4.listener)) : [e3.listener] : [];
            }
            listenerCount(t3) {
              const e3 = this._events[t3];
              return e3 ? Array.isArray(e3) ? e3.length : 1 : 0;
            }
            emit(t3, ...e3) {
              const n3 = this._events[t3];
              return !!n3 && (Array.isArray(n3) ? n3.slice(0).forEach(((n4) => {
                n4.once && this.removeListener(t3, n4.listener, void 0, true), n4.listener.call(n4.context, ...e3);
              })) : (n3.once && this.removeListener(t3, n3.listener, void 0, true), n3.listener.call(n3.context, ...e3)), true);
            }
            on(t3, e3, n3) {
              return this.#t(t3, e3, n3, false);
            }
            once(t3, e3, n3) {
              return this.#t(t3, e3, n3, true);
            }
            removeListener(t3, e3, n3, s3) {
              const i2 = this._events[t3];
              if (!i2) return this;
              if (!e3) return this.clearEvent(t3), this;
              if (Array.isArray(i2)) {
                const r2 = [];
                i2.forEach(((t4) => {
                  (t4.listener !== e3 || s3 && !t4.once || n3 && t4.context !== n3) && r2.push(t4);
                })), r2.length ? this._events[t3] = 1 === r2.length ? r2[0] : r2 : this.clearEvent(t3);
              } else i2.listener !== e3 || s3 && !i2.once || n3 && i2.context !== n3 || this.clearEvent(t3);
              return this;
            }
            removeAllListeners(t3) {
              return t3 ? this._events[t3] && this.clearEvent(t3) : (this._events = /* @__PURE__ */ Object.create(null), this._eventsCount = 0), this;
            }
            off(t3, e3, n3, s3) {
              return this.removeListener(t3, e3, n3, s3);
            }
            addListener(t3, e3, n3) {
              return this.on(t3, e3, n3);
            }
          }
          const r = (0, n2(78).A)("quill:events"), o = [];
          ["selectionchange", "mousedown", "mouseup", "click"].forEach(((t3) => {
            document.addEventListener(t3, (function() {
              for (var t4 = arguments.length, e3 = new Array(t4), n3 = 0; n3 < t4; n3++) e3[n3] = arguments[n3];
              o.forEach(((t5) => {
                t5.handleDOM(...e3);
              }));
            }));
          }));
          var l = class extends i {
            static events = { EDITOR_CHANGE: "editor-change", SCROLL_BEFORE_UPDATE: "scroll-before-update", SCROLL_BLOT_MOUNT: "scroll-blot-mount", SCROLL_BLOT_UNMOUNT: "scroll-blot-unmount", SCROLL_OPTIMIZE: "scroll-optimize", SCROLL_UPDATE: "scroll-update", SCROLL_EMBED_UPDATE: "scroll-embed-update", SELECTION_CHANGE: "selection-change", TEXT_CHANGE: "text-change", COMPOSITION_BEFORE_START: "composition-before-start", COMPOSITION_START: "composition-start", COMPOSITION_BEFORE_END: "composition-before-end", COMPOSITION_END: "composition-end" };
            static sources = { API: "api", SILENT: "silent", USER: "user" };
            constructor() {
              super(), this.domListeners = {}, this.on("error", r.error);
            }
            connect() {
              o.push(this);
            }
            disconnect() {
              o.splice(o.indexOf(this), 1);
            }
            emit() {
              for (var t3 = arguments.length, e3 = new Array(t3), n3 = 0; n3 < t3; n3++) e3[n3] = arguments[n3];
              return r.log.call(r, ...e3), super.emit(...e3);
            }
            handleDOM(t3) {
              for (var e3 = arguments.length, n3 = new Array(e3 > 1 ? e3 - 1 : 0), s3 = 1; s3 < e3; s3++) n3[s3 - 1] = arguments[s3];
              const i2 = t3.composedPath()[0];
              (this.domListeners[t3.type] || []).forEach(((e4) => {
                let { node: s4, handler: r2 } = e4;
                (i2 === s4 || ((t4, e5) => {
                  if (e5.getRootNode() === document) return t4.contains(e5);
                  for (; !t4.contains(e5); ) {
                    const t5 = e5.getRootNode();
                    if (!t5) return false;
                    const n4 = t5.host;
                    if (!n4) return false;
                    e5 = n4;
                  }
                  return true;
                })(s4, i2)) && r2(t3, ...n3);
              }));
            }
            listenDOM(t3, e3, n3) {
              this.domListeners[t3] || (this.domListeners[t3] = []), this.domListeners[t3].push({ node: e3, handler: n3 });
            }
          };
        }, 78: function(t2, e2) {
          const n2 = ["error", "warn", "log", "info"];
          let s2 = "warn";
          function i(t3) {
            if (s2 && n2.indexOf(t3) <= n2.indexOf(s2)) {
              for (var e3 = arguments.length, i2 = new Array(e3 > 1 ? e3 - 1 : 0), r2 = 1; r2 < e3; r2++) i2[r2 - 1] = arguments[r2];
              console[t3](...i2);
            }
          }
          function r(t3) {
            return n2.reduce(((e3, n3) => (e3[n3] = i.bind(console, n3, t3), e3)), {});
          }
          r.level = (t3) => {
            s2 = t3;
          }, i.level = r.level, e2.A = r;
        }, 266: function(t2, e2) {
          e2.A = class {
            static DEFAULTS = {};
            constructor(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
              this.quill = t3, this.options = e3;
            }
          };
        }, 543: function(t2, e2, n2) {
          n2.d(e2, { Ay: function() {
            return B;
          } });
          var s2 = n2(3), i = n2(398), r = n2(698), o = n2(36), l = n2(541), a = n2(508), c = n2(298), h = n2(857), u = n2(697);
          const d = /^[ -~]*$/;
          function f(t3, e3, n3) {
            if (0 === t3.length) {
              const [t4] = g(n3.pop());
              return e3 <= 0 ? `</li></${t4}>` : `</li></${t4}>${f([], e3 - 1, n3)}`;
            }
            const [{ child: s3, offset: i2, length: r2, indent: o2, type: l2 }, ...a3] = t3, [c2, h2] = g(l2);
            if (o2 > e3) return n3.push(l2), o2 === e3 + 1 ? `<${c2}><li${h2}>${p(s3, i2, r2)}${f(a3, o2, n3)}` : `<${c2}><li>${f(t3, e3 + 1, n3)}`;
            const u2 = n3[n3.length - 1];
            if (o2 === e3 && l2 === u2) return `</li><li${h2}>${p(s3, i2, r2)}${f(a3, o2, n3)}`;
            const [d2] = g(n3.pop());
            return `</li></${d2}>${f(t3, e3 - 1, n3)}`;
          }
          function p(t3, e3, n3) {
            let i2 = arguments.length > 3 && void 0 !== arguments[3] && arguments[3];
            if ("html" in t3 && "function" == typeof t3.html) return t3.html(e3, n3);
            if (t3 instanceof a.A) return (0, a.X)(t3.value().slice(e3, e3 + n3)).replaceAll(/  +/g, ((t4) => "&nbsp;".repeat(t4.length - 1) + " "));
            if (t3 instanceof s2.ParentBlot) {
              if ("list-container" === t3.statics.blotName) {
                const s4 = [];
                return t3.children.forEachAt(e3, n3, ((t4, e4, n4) => {
                  const i3 = "formats" in t4 && "function" == typeof t4.formats ? t4.formats() : {};
                  s4.push({ child: t4, offset: e4, length: n4, indent: i3.indent || 0, type: i3.list });
                })), f(s4, -1, []);
              }
              const s3 = [];
              if (t3.children.forEachAt(e3, n3, ((t4, e4, n4) => {
                s3.push(p(t4, e4, n4));
              })), i2 || "list" === t3.statics.blotName) return s3.join("");
              const { outerHTML: r2, innerHTML: o2 } = t3.domNode, [l2, a3] = r2.split(`>${o2}<`);
              return "<table" === l2 ? `<table style="border: 1px solid #000;">${s3.join("")}<${a3}` : `${l2}>${s3.join("")}<${a3}`;
            }
            return t3.domNode instanceof Element ? t3.domNode.outerHTML : "";
          }
          function m(t3, e3) {
            return Object.keys(e3).reduce(((n3, s3) => {
              if (null == t3[s3]) return n3;
              const i2 = e3[s3];
              return i2 === t3[s3] ? n3[s3] = i2 : Array.isArray(i2) ? i2.indexOf(t3[s3]) < 0 ? n3[s3] = i2.concat([t3[s3]]) : n3[s3] = i2 : n3[s3] = [i2, t3[s3]], n3;
            }), {});
          }
          function g(t3) {
            const e3 = "ordered" === t3 ? "ol" : "ul";
            switch (t3) {
              case "checked":
                return [e3, ' data-list="checked"'];
              case "unchecked":
                return [e3, ' data-list="unchecked"'];
              default:
                return [e3, ""];
            }
          }
          function b(t3) {
            return t3.reduce(((t4, e3) => {
              if ("string" == typeof e3.insert) {
                const n3 = e3.insert.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
                return t4.insert(n3, e3.attributes);
              }
              return t4.push(e3);
            }), new i.Ay());
          }
          function y(t3, e3) {
            let { index: n3, length: s3 } = t3;
            return new c.Q(n3 + e3, s3);
          }
          var A5 = class {
            constructor(t3) {
              this.scroll = t3, this.delta = this.getDelta();
            }
            applyDelta(t3) {
              this.scroll.update();
              let e3 = this.scroll.length();
              this.scroll.batchStart();
              const n3 = b(t3), o2 = new i.Ay();
              return (function(t4) {
                const e4 = [];
                return t4.forEach(((t5) => {
                  "string" == typeof t5.insert ? t5.insert.split("\n").forEach(((n4, s3) => {
                    s3 && e4.push({ insert: "\n", attributes: t5.attributes }), n4 && e4.push({ insert: n4, attributes: t5.attributes });
                  })) : e4.push(t5);
                })), e4;
              })(n3.ops.slice()).reduce(((t4, n4) => {
                const l2 = i.Op.length(n4);
                let c2 = n4.attributes || {}, h2 = false, u2 = false;
                if (null != n4.insert) {
                  if (o2.retain(l2), "string" == typeof n4.insert) {
                    const o3 = n4.insert;
                    u2 = !o3.endsWith("\n") && (e3 <= t4 || !!this.scroll.descendant(r.zo, t4)[0]), this.scroll.insertAt(t4, o3);
                    const [l3, a3] = this.scroll.line(t4);
                    let h3 = Object.assign({}, (0, r.Ji)(l3));
                    if (l3 instanceof r.Ay) {
                      const [t5] = l3.descendant(s2.LeafBlot, a3);
                      t5 && (h3 = Object.assign(h3, (0, r.Ji)(t5)));
                    }
                    c2 = i.xb.diff(h3, c2) || {};
                  } else if ("object" == typeof n4.insert) {
                    const o3 = Object.keys(n4.insert)[0];
                    if (null == o3) return t4;
                    const l3 = null != this.scroll.query(o3, s2.Scope.INLINE);
                    if (l3) (e3 <= t4 || this.scroll.descendant(r.zo, t4)[0]) && (u2 = true);
                    else if (t4 > 0) {
                      const [e4, n5] = this.scroll.descendant(s2.LeafBlot, t4 - 1);
                      e4 instanceof a.A ? "\n" !== e4.value()[n5] && (h2 = true) : e4 instanceof s2.EmbedBlot && e4.statics.scope === s2.Scope.INLINE_BLOT && (h2 = true);
                    }
                    if (this.scroll.insertAt(t4, o3, n4.insert[o3]), l3) {
                      const [e4] = this.scroll.descendant(s2.LeafBlot, t4);
                      if (e4) {
                        const t5 = Object.assign({}, (0, r.Ji)(e4));
                        c2 = i.xb.diff(t5, c2) || {};
                      }
                    }
                  }
                  e3 += l2;
                } else if (o2.push(n4), null !== n4.retain && "object" == typeof n4.retain) {
                  const e4 = Object.keys(n4.retain)[0];
                  if (null == e4) return t4;
                  this.scroll.updateEmbedAt(t4, e4, n4.retain[e4]);
                }
                Object.keys(c2).forEach(((e4) => {
                  this.scroll.formatAt(t4, l2, e4, c2[e4]);
                }));
                const d2 = h2 ? 1 : 0, f2 = u2 ? 1 : 0;
                return e3 += d2 + f2, o2.retain(d2), o2.delete(f2), t4 + l2 + d2 + f2;
              }), 0), o2.reduce(((t4, e4) => "number" == typeof e4.delete ? (this.scroll.deleteAt(t4, e4.delete), t4) : t4 + i.Op.length(e4)), 0), this.scroll.batchEnd(), this.scroll.optimize(), this.update(n3);
            }
            deleteText(t3, e3) {
              return this.scroll.deleteAt(t3, e3), this.update(new i.Ay().retain(t3).delete(e3));
            }
            formatLine(t3, e3) {
              let n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
              this.scroll.update(), Object.keys(n3).forEach(((s4) => {
                this.scroll.lines(t3, Math.max(e3, 1)).forEach(((t4) => {
                  t4.format(s4, n3[s4]);
                }));
              })), this.scroll.optimize();
              const s3 = new i.Ay().retain(t3).retain(e3, (0, h.A)(n3));
              return this.update(s3);
            }
            formatText(t3, e3) {
              let n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
              Object.keys(n3).forEach(((s4) => {
                this.scroll.formatAt(t3, e3, s4, n3[s4]);
              }));
              const s3 = new i.Ay().retain(t3).retain(e3, (0, h.A)(n3));
              return this.update(s3);
            }
            getContents(t3, e3) {
              return this.delta.slice(t3, t3 + e3);
            }
            getDelta() {
              return this.scroll.lines().reduce(((t3, e3) => t3.concat(e3.delta())), new i.Ay());
            }
            getFormat(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, n3 = [], i2 = [];
              0 === e3 ? this.scroll.path(t3).forEach(((t4) => {
                const [e4] = t4;
                e4 instanceof r.Ay ? n3.push(e4) : e4 instanceof s2.LeafBlot && i2.push(e4);
              })) : (n3 = this.scroll.lines(t3, e3), i2 = this.scroll.descendants(s2.LeafBlot, t3, e3));
              const [o2, l2] = [n3, i2].map(((t4) => {
                const e4 = t4.shift();
                if (null == e4) return {};
                let n4 = (0, r.Ji)(e4);
                for (; Object.keys(n4).length > 0; ) {
                  const e5 = t4.shift();
                  if (null == e5) return n4;
                  n4 = m((0, r.Ji)(e5), n4);
                }
                return n4;
              }));
              return { ...o2, ...l2 };
            }
            getHTML(t3, e3) {
              const [n3, s3] = this.scroll.line(t3);
              if (n3) {
                const i2 = n3.length();
                return n3.length() >= s3 + e3 && (0 !== s3 || e3 !== i2) ? p(n3, s3, e3, true) : p(this.scroll, t3, e3, true);
              }
              return "";
            }
            getText(t3, e3) {
              return this.getContents(t3, e3).filter(((t4) => "string" == typeof t4.insert)).map(((t4) => t4.insert)).join("");
            }
            insertContents(t3, e3) {
              const n3 = b(e3), s3 = new i.Ay().retain(t3).concat(n3);
              return this.scroll.insertContents(t3, n3), this.update(s3);
            }
            insertEmbed(t3, e3, n3) {
              return this.scroll.insertAt(t3, e3, n3), this.update(new i.Ay().retain(t3).insert({ [e3]: n3 }));
            }
            insertText(t3, e3) {
              let n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
              return e3 = e3.replace(/\r\n/g, "\n").replace(/\r/g, "\n"), this.scroll.insertAt(t3, e3), Object.keys(n3).forEach(((s3) => {
                this.scroll.formatAt(t3, e3.length, s3, n3[s3]);
              })), this.update(new i.Ay().retain(t3).insert(e3, (0, h.A)(n3)));
            }
            isBlank() {
              if (0 === this.scroll.children.length) return true;
              if (this.scroll.children.length > 1) return false;
              const t3 = this.scroll.children.head;
              if (t3?.statics.blotName !== r.Ay.blotName) return false;
              const e3 = t3;
              return !(e3.children.length > 1) && e3.children.head instanceof o.A;
            }
            removeFormat(t3, e3) {
              const n3 = this.getText(t3, e3), [s3, r2] = this.scroll.line(t3 + e3);
              let o2 = 0, l2 = new i.Ay();
              null != s3 && (o2 = s3.length() - r2, l2 = s3.delta().slice(r2, r2 + o2 - 1).insert("\n"));
              const a3 = this.getContents(t3, e3 + o2).diff(new i.Ay().insert(n3).concat(l2)), c2 = new i.Ay().retain(t3).concat(a3);
              return this.applyDelta(c2);
            }
            update(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : void 0;
              const s3 = this.delta;
              if (1 === e3.length && "characterData" === e3[0].type && e3[0].target.data.match(d) && this.scroll.find(e3[0].target)) {
                const o2 = this.scroll.find(e3[0].target), a3 = (0, r.Ji)(o2), c2 = o2.offset(this.scroll), h2 = e3[0].oldValue.replace(l.A.CONTENTS, ""), u2 = new i.Ay().insert(h2), d2 = new i.Ay().insert(o2.value()), f2 = n3 && { oldRange: y(n3.oldRange, -c2), newRange: y(n3.newRange, -c2) };
                t3 = new i.Ay().retain(c2).concat(u2.diff(d2, f2)).reduce(((t4, e4) => e4.insert ? t4.insert(e4.insert, a3) : t4.push(e4)), new i.Ay()), this.delta = s3.compose(t3);
              } else this.delta = this.getDelta(), t3 && (0, u.A)(s3.compose(t3), this.delta) || (t3 = s3.diff(this.delta, n3));
              return t3;
            }
          }, N = n2(200), v = /* @__PURE__ */ new WeakMap(), E4 = n2(78), x = n2(266), L = n2(746), S = class {
            isComposing = false;
            constructor(t3, e3) {
              this.scroll = t3, this.emitter = e3, this.setupListeners();
            }
            setupListeners() {
              this.scroll.domNode.addEventListener("compositionstart", ((t3) => {
                this.isComposing || this.handleCompositionStart(t3);
              })), this.scroll.domNode.addEventListener("compositionend", ((t3) => {
                this.isComposing && queueMicrotask((() => {
                  this.handleCompositionEnd(t3);
                }));
              }));
            }
            handleCompositionStart(t3) {
              const e3 = t3.target instanceof Node ? this.scroll.find(t3.target, true) : null;
              !e3 || e3 instanceof L.A || (this.emitter.emit(N.A.events.COMPOSITION_BEFORE_START, t3), this.scroll.batchStart(), this.emitter.emit(N.A.events.COMPOSITION_START, t3), this.isComposing = true);
            }
            handleCompositionEnd(t3) {
              this.emitter.emit(N.A.events.COMPOSITION_BEFORE_END, t3), this.scroll.batchEnd(), this.emitter.emit(N.A.events.COMPOSITION_END, t3), this.isComposing = false;
            }
          }, T = n2(609);
          const k = (t3) => {
            const e3 = t3.getBoundingClientRect(), n3 = "offsetWidth" in t3 && Math.abs(e3.width) / t3.offsetWidth || 1, s3 = "offsetHeight" in t3 && Math.abs(e3.height) / t3.offsetHeight || 1;
            return { top: e3.top, right: e3.left + t3.clientWidth * n3, bottom: e3.top + t3.clientHeight * s3, left: e3.left };
          }, O2 = (t3) => {
            const e3 = parseInt(t3, 10);
            return Number.isNaN(e3) ? 0 : e3;
          }, w = (t3, e3, n3, s3, i2, r2) => t3 < n3 && e3 > s3 ? 0 : t3 < n3 ? -(n3 - t3 + i2) : e3 > s3 ? e3 - t3 > s3 - n3 ? t3 + i2 - n3 : e3 - s3 + r2 : 0;
          const C = ["block", "break", "cursor", "inline", "scroll", "text"];
          const q = (0, E4.A)("quill"), R2 = new s2.Registry();
          s2.ParentBlot.uiClass = "ql-ui";
          class B {
            static DEFAULTS = { bounds: null, modules: { clipboard: true, keyboard: true, history: true, uploader: true }, placeholder: "", readOnly: false, registry: R2, theme: "default" };
            static events = N.A.events;
            static sources = N.A.sources;
            static version = "2.0.3";
            static imports = { delta: i.Ay, parchment: s2, "core/module": x.A, "core/theme": T.A };
            static debug(t3) {
              true === t3 && (t3 = "log"), E4.A.level(t3);
            }
            static find(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
              return v.get(t3) || R2.find(t3, e3);
            }
            static import(t3) {
              return null == this.imports[t3] && q.error(`Cannot import ${t3}. Are you sure it was registered?`), this.imports[t3];
            }
            static register() {
              if ("string" != typeof (arguments.length <= 0 ? void 0 : arguments[0])) {
                const t3 = arguments.length <= 0 ? void 0 : arguments[0], e3 = !!(arguments.length <= 1 ? void 0 : arguments[1]), n3 = "attrName" in t3 ? t3.attrName : t3.blotName;
                "string" == typeof n3 ? this.register(`formats/${n3}`, t3, e3) : Object.keys(t3).forEach(((n4) => {
                  this.register(n4, t3[n4], e3);
                }));
              } else {
                const t3 = arguments.length <= 0 ? void 0 : arguments[0], e3 = arguments.length <= 1 ? void 0 : arguments[1], n3 = !!(arguments.length <= 2 ? void 0 : arguments[2]);
                null == this.imports[t3] || n3 || q.warn(`Overwriting ${t3} with`, e3), this.imports[t3] = e3, (t3.startsWith("blots/") || t3.startsWith("formats/")) && e3 && "boolean" != typeof e3 && "abstract" !== e3.blotName && R2.register(e3), "function" == typeof e3.register && e3.register(R2);
              }
            }
            constructor(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
              if (this.options = (function(t4, e4) {
                const n4 = I2(t4);
                if (!n4) throw new Error("Invalid Quill container");
                const i2 = !e4.theme || e4.theme === B.DEFAULTS.theme ? T.A : B.import(`themes/${e4.theme}`);
                if (!i2) throw new Error(`Invalid theme ${e4.theme}. Did you register it?`);
                const { modules: r3, ...o3 } = B.DEFAULTS, { modules: l2, ...a3 } = i2.DEFAULTS;
                let c2 = D(e4.modules);
                null != c2 && c2.toolbar && c2.toolbar.constructor !== Object && (c2 = { ...c2, toolbar: { container: c2.toolbar } });
                const h2 = { ...D(r3), ...D(l2), ...c2 }, u2 = { ...o3, ...M5(a3), ...M5(e4) };
                let d2 = e4.registry;
                return d2 ? e4.formats && q.warn('Ignoring "formats" option because "registry" is specified') : d2 = e4.formats ? ((t5, e5, n5) => {
                  const i3 = new s2.Registry();
                  return C.forEach(((t6) => {
                    const n6 = e5.query(t6);
                    n6 && i3.register(n6);
                  })), t5.forEach(((t6) => {
                    let s3 = e5.query(t6);
                    s3 || n5.error(`Cannot register "${t6}" specified in "formats" config. Are you sure it was registered?`);
                    let r4 = 0;
                    for (; s3; ) if (i3.register(s3), s3 = "blotName" in s3 ? s3.requiredContainer ?? null : null, r4 += 1, r4 > 100) {
                      n5.error(`Cycle detected in registering blot requiredContainer: "${t6}"`);
                      break;
                    }
                  })), i3;
                })(e4.formats, u2.registry, q) : u2.registry, { ...u2, registry: d2, container: n4, theme: i2, modules: Object.entries(h2).reduce(((t5, e5) => {
                  let [n5, s3] = e5;
                  if (!s3) return t5;
                  const i3 = B.import(`modules/${n5}`);
                  return null == i3 ? (q.error(`Cannot load ${n5} module. Are you sure you registered it?`), t5) : { ...t5, [n5]: { ...i3.DEFAULTS || {}, ...s3 } };
                }), {}), bounds: I2(u2.bounds) };
              })(t3, e3), this.container = this.options.container, null == this.container) return void q.error("Invalid Quill container", t3);
              this.options.debug && B.debug(this.options.debug);
              const n3 = this.container.innerHTML.trim();
              this.container.classList.add("ql-container"), this.container.innerHTML = "", v.set(this.container, this), this.root = this.addContainer("ql-editor"), this.root.classList.add("ql-blank"), this.emitter = new N.A();
              const r2 = s2.ScrollBlot.blotName, o2 = this.options.registry.query(r2);
              if (!o2 || !("blotName" in o2)) throw new Error(`Cannot initialize Quill without "${r2}" blot`);
              if (this.scroll = new o2(this.options.registry, this.root, { emitter: this.emitter }), this.editor = new A5(this.scroll), this.selection = new c.A(this.scroll, this.emitter), this.composition = new S(this.scroll, this.emitter), this.theme = new this.options.theme(this, this.options), this.keyboard = this.theme.addModule("keyboard"), this.clipboard = this.theme.addModule("clipboard"), this.history = this.theme.addModule("history"), this.uploader = this.theme.addModule("uploader"), this.theme.addModule("input"), this.theme.addModule("uiNode"), this.theme.init(), this.emitter.on(N.A.events.EDITOR_CHANGE, ((t4) => {
                t4 === N.A.events.TEXT_CHANGE && this.root.classList.toggle("ql-blank", this.editor.isBlank());
              })), this.emitter.on(N.A.events.SCROLL_UPDATE, ((t4, e4) => {
                const n4 = this.selection.lastRange, [s3] = this.selection.getRange(), i2 = n4 && s3 ? { oldRange: n4, newRange: s3 } : void 0;
                U.call(this, (() => this.editor.update(null, e4, i2)), t4);
              })), this.emitter.on(N.A.events.SCROLL_EMBED_UPDATE, ((t4, e4) => {
                const n4 = this.selection.lastRange, [s3] = this.selection.getRange(), r3 = n4 && s3 ? { oldRange: n4, newRange: s3 } : void 0;
                U.call(this, (() => {
                  const n5 = new i.Ay().retain(t4.offset(this)).retain({ [t4.statics.blotName]: e4 });
                  return this.editor.update(n5, [], r3);
                }), B.sources.USER);
              })), n3) {
                const t4 = this.clipboard.convert({ html: `${n3}<p><br></p>`, text: "\n" });
                this.setContents(t4);
              }
              this.history.clear(), this.options.placeholder && this.root.setAttribute("data-placeholder", this.options.placeholder), this.options.readOnly && this.disable(), this.allowReadOnlyEdits = false;
            }
            addContainer(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : null;
              if ("string" == typeof t3) {
                const e4 = t3;
                (t3 = document.createElement("div")).classList.add(e4);
              }
              return this.container.insertBefore(t3, e3), t3;
            }
            blur() {
              this.selection.setRange(null);
            }
            deleteText(t3, e3, n3) {
              return [t3, e3, , n3] = _2(t3, e3, n3), U.call(this, (() => this.editor.deleteText(t3, e3)), n3, t3, -1 * e3);
            }
            disable() {
              this.enable(false);
            }
            editReadOnly(t3) {
              this.allowReadOnlyEdits = true;
              const e3 = t3();
              return this.allowReadOnlyEdits = false, e3;
            }
            enable() {
              let t3 = !(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0];
              this.scroll.enable(t3), this.container.classList.toggle("ql-disabled", !t3);
            }
            focus() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
              this.selection.focus(), t3.preventScroll || this.scrollSelectionIntoView();
            }
            format(t3, e3) {
              let n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : N.A.sources.API;
              return U.call(this, (() => {
                if (!this.hasFocus()) {
                  this.root.focus({ preventScroll: true });
                  const t4 = this.selection.rangeToNative(this.selection.savedRange);
                  this.selection.setNativeRange(...t4);
                }
                const [n4] = this.selection.getRange();
                let r2 = new i.Ay();
                if (null == n4) return r2;
                if (this.scroll.query(t3, s2.Scope.BLOCK)) r2 = this.editor.formatLine(n4.index, n4.length, { [t3]: e3 });
                else {
                  if (0 === n4.length) return this.selection.format(t3, e3), r2;
                  r2 = this.editor.formatText(n4.index, n4.length, { [t3]: e3 });
                }
                return this.setSelection(n4, N.A.sources.SILENT), r2;
              }), n3);
            }
            formatLine(t3, e3, n3, s3, i2) {
              let r2;
              return [t3, e3, r2, i2] = _2(t3, e3, n3, s3, i2), U.call(this, (() => this.editor.formatLine(t3, e3, r2)), i2, t3, 0);
            }
            formatText(t3, e3, n3, s3, i2) {
              let r2;
              return [t3, e3, r2, i2] = _2(t3, e3, n3, s3, i2), U.call(this, (() => this.editor.formatText(t3, e3, r2)), i2, t3, 0);
            }
            getBounds(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, n3 = null;
              if (n3 = "number" == typeof t3 ? this.selection.getBounds(t3, e3) : this.selection.getBounds(t3.index, t3.length), !n3) return null;
              const s3 = this.container.getBoundingClientRect();
              return { bottom: n3.bottom - s3.top, height: n3.height, left: n3.left - s3.left, right: n3.right - s3.left, top: n3.top - s3.top, width: n3.width };
            }
            getContents() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : this.getLength() - t3;
              return [t3, e3] = _2(t3, e3), this.editor.getContents(t3, e3);
            }
            getFormat() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : this.getSelection(true), e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
              return "number" == typeof t3 ? this.editor.getFormat(t3, e3) : this.editor.getFormat(t3.index, t3.length);
            }
            getIndex(t3) {
              return t3.offset(this.scroll);
            }
            getLength() {
              return this.scroll.length();
            }
            getLeaf(t3) {
              return this.scroll.leaf(t3);
            }
            getLine(t3) {
              return this.scroll.line(t3);
            }
            getLines() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : Number.MAX_VALUE;
              return "number" != typeof t3 ? this.scroll.lines(t3.index, t3.length) : this.scroll.lines(t3, e3);
            }
            getModule(t3) {
              return this.theme.modules[t3];
            }
            getSelection() {
              return arguments.length > 0 && void 0 !== arguments[0] && arguments[0] && this.focus(), this.update(), this.selection.getRange()[0];
            }
            getSemanticHTML() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, e3 = arguments.length > 1 ? arguments[1] : void 0;
              return "number" == typeof t3 && (e3 = e3 ?? this.getLength() - t3), [t3, e3] = _2(t3, e3), this.editor.getHTML(t3, e3);
            }
            getText() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0, e3 = arguments.length > 1 ? arguments[1] : void 0;
              return "number" == typeof t3 && (e3 = e3 ?? this.getLength() - t3), [t3, e3] = _2(t3, e3), this.editor.getText(t3, e3);
            }
            hasFocus() {
              return this.selection.hasFocus();
            }
            insertEmbed(t3, e3, n3) {
              let s3 = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : B.sources.API;
              return U.call(this, (() => this.editor.insertEmbed(t3, e3, n3)), s3, t3);
            }
            insertText(t3, e3, n3, s3, i2) {
              let r2;
              return [t3, , r2, i2] = _2(t3, 0, n3, s3, i2), U.call(this, (() => this.editor.insertText(t3, e3, r2)), i2, t3, e3.length);
            }
            isEnabled() {
              return this.scroll.isEnabled();
            }
            off() {
              return this.emitter.off(...arguments);
            }
            on() {
              return this.emitter.on(...arguments);
            }
            once() {
              return this.emitter.once(...arguments);
            }
            removeFormat(t3, e3, n3) {
              return [t3, e3, , n3] = _2(t3, e3, n3), U.call(this, (() => this.editor.removeFormat(t3, e3)), n3, t3);
            }
            scrollRectIntoView(t3) {
              ((t4, e3) => {
                const n3 = t4.ownerDocument;
                let s3 = e3, i2 = t4;
                for (; i2; ) {
                  const t5 = i2 === n3.body, e4 = t5 ? { top: 0, right: window.visualViewport?.width ?? n3.documentElement.clientWidth, bottom: window.visualViewport?.height ?? n3.documentElement.clientHeight, left: 0 } : k(i2), o2 = getComputedStyle(i2), l2 = w(s3.left, s3.right, e4.left, e4.right, O2(o2.scrollPaddingLeft), O2(o2.scrollPaddingRight)), a3 = w(s3.top, s3.bottom, e4.top, e4.bottom, O2(o2.scrollPaddingTop), O2(o2.scrollPaddingBottom));
                  if (l2 || a3) if (t5) n3.defaultView?.scrollBy(l2, a3);
                  else {
                    const { scrollLeft: t6, scrollTop: e5 } = i2;
                    a3 && (i2.scrollTop += a3), l2 && (i2.scrollLeft += l2);
                    const n4 = i2.scrollLeft - t6, r3 = i2.scrollTop - e5;
                    s3 = { left: s3.left - n4, top: s3.top - r3, right: s3.right - n4, bottom: s3.bottom - r3 };
                  }
                  i2 = t5 || "fixed" === o2.position ? null : (r2 = i2).parentElement || r2.getRootNode().host || null;
                }
                var r2;
              })(this.root, t3);
            }
            scrollIntoView() {
              console.warn("Quill#scrollIntoView() has been deprecated and will be removed in the near future. Please use Quill#scrollSelectionIntoView() instead."), this.scrollSelectionIntoView();
            }
            scrollSelectionIntoView() {
              const t3 = this.selection.lastRange, e3 = t3 && this.selection.getBounds(t3.index, t3.length);
              e3 && this.scrollRectIntoView(e3);
            }
            setContents(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : N.A.sources.API;
              return U.call(this, (() => {
                t3 = new i.Ay(t3);
                const e4 = this.getLength(), n3 = this.editor.deleteText(0, e4), s3 = this.editor.insertContents(0, t3), r2 = this.editor.deleteText(this.getLength() - 1, 1);
                return n3.compose(s3).compose(r2);
              }), e3);
            }
            setSelection(t3, e3, n3) {
              null == t3 ? this.selection.setRange(null, e3 || B.sources.API) : ([t3, e3, , n3] = _2(t3, e3, n3), this.selection.setRange(new c.Q(Math.max(0, t3), e3), n3), n3 !== N.A.sources.SILENT && this.scrollSelectionIntoView());
            }
            setText(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : N.A.sources.API;
              const n3 = new i.Ay().insert(t3);
              return this.setContents(n3, e3);
            }
            update() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : N.A.sources.USER;
              const e3 = this.scroll.update(t3);
              return this.selection.update(t3), e3;
            }
            updateContents(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : N.A.sources.API;
              return U.call(this, (() => (t3 = new i.Ay(t3), this.editor.applyDelta(t3))), e3, true);
            }
          }
          function I2(t3) {
            return "string" == typeof t3 ? document.querySelector(t3) : t3;
          }
          function D(t3) {
            return Object.entries(t3 ?? {}).reduce(((t4, e3) => {
              let [n3, s3] = e3;
              return { ...t4, [n3]: true === s3 ? {} : s3 };
            }), {});
          }
          function M5(t3) {
            return Object.fromEntries(Object.entries(t3).filter(((t4) => void 0 !== t4[1])));
          }
          function U(t3, e3, n3, s3) {
            if (!this.isEnabled() && e3 === N.A.sources.USER && !this.allowReadOnlyEdits) return new i.Ay();
            let r2 = null == n3 ? null : this.getSelection();
            const o2 = this.editor.delta, l2 = t3();
            if (null != r2 && (true === n3 && (n3 = r2.index), null == s3 ? r2 = j(r2, l2, e3) : 0 !== s3 && (r2 = j(r2, n3, s3, e3)), this.setSelection(r2, N.A.sources.SILENT)), l2.length() > 0) {
              const t4 = [N.A.events.TEXT_CHANGE, l2, o2, e3];
              this.emitter.emit(N.A.events.EDITOR_CHANGE, ...t4), e3 !== N.A.sources.SILENT && this.emitter.emit(...t4);
            }
            return l2;
          }
          function _2(t3, e3, n3, s3, i2) {
            let r2 = {};
            return "number" == typeof t3.index && "number" == typeof t3.length ? "number" != typeof e3 ? (i2 = s3, s3 = n3, n3 = e3, e3 = t3.length, t3 = t3.index) : (e3 = t3.length, t3 = t3.index) : "number" != typeof e3 && (i2 = s3, s3 = n3, n3 = e3, e3 = 0), "object" == typeof n3 ? (r2 = n3, i2 = s3) : "string" == typeof n3 && (null != s3 ? r2[n3] = s3 : i2 = n3), [t3, e3, r2, i2 = i2 || N.A.sources.API];
          }
          function j(t3, e3, n3, s3) {
            const i2 = "number" == typeof n3 ? n3 : 0;
            if (null == t3) return null;
            let r2, o2;
            return e3 && "function" == typeof e3.transformPosition ? [r2, o2] = [t3.index, t3.index + t3.length].map(((t4) => e3.transformPosition(t4, s3 !== N.A.sources.USER))) : [r2, o2] = [t3.index, t3.index + t3.length].map(((t4) => t4 < e3 || t4 === e3 && s3 === N.A.sources.USER ? t4 : i2 >= 0 ? t4 + i2 : Math.max(e3, t4 + i2))), new c.Q(r2, o2 - r2);
          }
        }, 298: function(t2, e2, n2) {
          n2.d(e2, { Q: function() {
            return h;
          } });
          var s2 = n2(3), i = n2(200), r = n2(78), o = n2(857), l = n2(697);
          const a = (0, r.A)("quill:selection"), c = (t3) => {
            try {
              return "getSelection" in t3 && "function" == typeof t3.getSelection ? t3.getSelection() : window.getSelection();
            } catch {
              return null;
            }
          };
          class h {
            constructor(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
              this.index = t3, this.length = e3;
            }
          }
          function u(t3, e3) {
            try {
              e3.parentNode;
            } catch (t4) {
              return false;
            }
            return t3.contains(e3);
          }
          e2.A = class {
            constructor(t3, e3) {
              this.emitter = e3, this.scroll = t3, this.composing = false, this.mouseDown = false, this.root = this.scroll.domNode, this.rootDocument = this.root.getRootNode(), this.cursor = this.scroll.create("cursor", this), this.savedRange = new h(0, 0), this.lastRange = this.savedRange, this.lastNative = null, this.handleComposition(), this.handleDragging(), this.emitter.listenDOM("selectionchange", this.rootDocument, (() => {
                this.mouseDown || this.composing || setTimeout(this.update.bind(this, i.A.sources.USER), 1);
              })), this.emitter.on(i.A.events.SCROLL_BEFORE_UPDATE, (() => {
                if (!this.hasFocus()) return;
                const t4 = this.getNativeRange();
                null != t4 && t4.start.node !== this.cursor.textNode && this.emitter.once(i.A.events.SCROLL_UPDATE, ((e4, n3) => {
                  try {
                    this.root.contains(t4.start.node) && this.root.contains(t4.end.node) && this.setNativeRange(t4.start.node, t4.start.offset, t4.end.node, t4.end.offset);
                    const s3 = n3.some(((t5) => "characterData" === t5.type || "childList" === t5.type || "attributes" === t5.type && t5.target === this.root));
                    this.update(s3 ? i.A.sources.SILENT : e4);
                  } catch (t5) {
                  }
                }));
              })), this.emitter.on(i.A.events.SCROLL_OPTIMIZE, ((t4, e4) => {
                if (e4.range) {
                  const { startNode: t5, startOffset: n3, endNode: s3, endOffset: r2 } = e4.range;
                  this.setNativeRange(t5, n3, s3, r2), this.update(i.A.sources.SILENT);
                }
              })), this.update(i.A.sources.SILENT);
            }
            handleComposition() {
              this.emitter.on(i.A.events.COMPOSITION_BEFORE_START, (() => {
                this.composing = true;
              })), this.emitter.on(i.A.events.COMPOSITION_END, (() => {
                if (this.composing = false, this.cursor.parent) {
                  const t3 = this.cursor.restore();
                  if (!t3) return;
                  setTimeout((() => {
                    this.setNativeRange(t3.startNode, t3.startOffset, t3.endNode, t3.endOffset);
                  }), 1);
                }
              }));
            }
            handleDragging() {
              this.emitter.listenDOM("mousedown", document.body, (() => {
                this.mouseDown = true;
              })), this.emitter.listenDOM("mouseup", document.body, (() => {
                this.mouseDown = false, this.update(i.A.sources.USER);
              }));
            }
            focus() {
              this.hasFocus() || (this.root.focus({ preventScroll: true }), this.setRange(this.savedRange));
            }
            format(t3, e3) {
              this.scroll.update();
              const n3 = this.getNativeRange();
              if (null != n3 && n3.native.collapsed && !this.scroll.query(t3, s2.Scope.BLOCK)) {
                if (n3.start.node !== this.cursor.textNode) {
                  const t4 = this.scroll.find(n3.start.node, false);
                  if (null == t4) return;
                  if (t4 instanceof s2.LeafBlot) {
                    const e4 = t4.split(n3.start.offset);
                    t4.parent.insertBefore(this.cursor, e4);
                  } else t4.insertBefore(this.cursor, n3.start.node);
                  this.cursor.attach();
                }
                this.cursor.format(t3, e3), this.scroll.optimize(), this.setNativeRange(this.cursor.textNode, this.cursor.textNode.data.length), this.update();
              }
            }
            getBounds(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0;
              const n3 = this.scroll.length();
              let s3;
              t3 = Math.min(t3, n3 - 1), e3 = Math.min(t3 + e3, n3 - 1) - t3;
              let [i2, r2] = this.scroll.leaf(t3);
              if (null == i2) return null;
              if (e3 > 0 && r2 === i2.length()) {
                const [e4] = this.scroll.leaf(t3 + 1);
                if (e4) {
                  const [n4] = this.scroll.line(t3), [s4] = this.scroll.line(t3 + 1);
                  n4 === s4 && (i2 = e4, r2 = 0);
                }
              }
              [s3, r2] = i2.position(r2, true);
              const o2 = document.createRange();
              if (e3 > 0) return o2.setStart(s3, r2), [i2, r2] = this.scroll.leaf(t3 + e3), null == i2 ? null : ([s3, r2] = i2.position(r2, true), o2.setEnd(s3, r2), o2.getBoundingClientRect());
              let l2, a3 = "left";
              if (s3 instanceof Text) {
                if (!s3.data.length) return null;
                r2 < s3.data.length ? (o2.setStart(s3, r2), o2.setEnd(s3, r2 + 1)) : (o2.setStart(s3, r2 - 1), o2.setEnd(s3, r2), a3 = "right"), l2 = o2.getBoundingClientRect();
              } else {
                if (!(i2.domNode instanceof Element)) return null;
                l2 = i2.domNode.getBoundingClientRect(), r2 > 0 && (a3 = "right");
              }
              return { bottom: l2.top + l2.height, height: l2.height, left: l2[a3], right: l2[a3], top: l2.top, width: 0 };
            }
            getNativeRange() {
              const t3 = ((t4) => {
                const e4 = c(t4);
                return e4?.anchorNode ? !e4 || !("getComposedRanges" in e4) || "function" != typeof e4.getComposedRanges || t4 instanceof ShadowRoot && "getSelection" in t4 ? e4.getRangeAt(0) : e4.getComposedRanges(t4)[0] : null;
              })(this.rootDocument);
              if (null == t3) return null;
              const e3 = this.normalizeNative(t3);
              return a.info("getNativeRange", e3), e3;
            }
            getRange() {
              const t3 = this.scroll.domNode;
              if ("isConnected" in t3 && !t3.isConnected) return [null, null];
              const e3 = this.getNativeRange();
              return null == e3 ? [null, null] : [this.normalizedToRange(e3), e3];
            }
            hasFocus() {
              const t3 = this.rootDocument;
              return t3.activeElement === this.root || null != t3.activeElement && u(this.root, t3.activeElement);
            }
            normalizedToRange(t3) {
              const e3 = [[t3.start.node, t3.start.offset]];
              t3.native.collapsed || e3.push([t3.end.node, t3.end.offset]);
              const n3 = e3.map(((t4) => {
                const [e4, n4] = t4, i3 = this.scroll.find(e4, true), r3 = i3.offset(this.scroll);
                return 0 === n4 ? r3 : i3 instanceof s2.LeafBlot ? r3 + i3.index(e4, n4) : r3 + i3.length();
              })), i2 = Math.min(Math.max(...n3), this.scroll.length() - 1), r2 = Math.min(i2, ...n3);
              return new h(r2, i2 - r2);
            }
            normalizeNative(t3) {
              if (!u(this.root, t3.startContainer) || !t3.collapsed && !u(this.root, t3.endContainer)) return null;
              const e3 = { start: { node: t3.startContainer, offset: t3.startOffset }, end: { node: t3.endContainer, offset: t3.endOffset }, native: t3 };
              return [e3.start, e3.end].forEach(((t4) => {
                let { node: e4, offset: n3 } = t4;
                for (; !(e4 instanceof Text) && e4.childNodes.length > 0; ) if (e4.childNodes.length > n3) e4 = e4.childNodes[n3], n3 = 0;
                else {
                  if (e4.childNodes.length !== n3) break;
                  e4 = e4.lastChild, n3 = e4 instanceof Text ? e4.data.length : e4.childNodes.length > 0 ? e4.childNodes.length : e4.childNodes.length + 1;
                }
                t4.node = e4, t4.offset = n3;
              })), e3;
            }
            rangeToNative(t3) {
              const e3 = this.scroll.length(), n3 = (t4, n4) => {
                t4 = Math.min(e3 - 1, t4);
                const [s3, i2] = this.scroll.leaf(t4);
                return s3 ? s3.position(i2, n4) : [null, -1];
              };
              return [...n3(t3.index, false), ...n3(t3.index + t3.length, true)];
            }
            setNativeRange(t3, e3) {
              let n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : t3, s3 = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : e3, i2 = arguments.length > 4 && void 0 !== arguments[4] && arguments[4];
              if (a.info("setNativeRange", t3, e3, n3, s3), null != t3 && (null == this.root.parentNode || null == t3.parentNode || null == n3.parentNode)) return;
              const r2 = c(this.rootDocument);
              if (null != r2) if (null != t3) {
                this.hasFocus() || this.root.focus({ preventScroll: true });
                const { native: o2 } = this.getNativeRange() || {};
                (null == o2 || i2 || t3 !== o2.startContainer || e3 !== o2.startOffset || n3 !== o2.endContainer || s3 !== o2.endOffset) && (t3 instanceof Element && "BR" === t3.tagName && (e3 = Array.from(t3.parentNode.childNodes).indexOf(t3), t3 = t3.parentNode), n3 instanceof Element && "BR" === n3.tagName && (s3 = Array.from(n3.parentNode.childNodes).indexOf(n3), n3 = n3.parentNode), t3 && n3 && "number" == typeof e3 && "number" == typeof s3 && r2.setBaseAndExtent(t3, e3, n3, s3));
              } else r2.removeAllRanges(), this.root.blur();
            }
            setRange(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] && arguments[1], n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : i.A.sources.API;
              if ("string" == typeof e3 && (n3 = e3, e3 = false), a.info("setRange", t3), null != t3) {
                const n4 = this.rangeToNative(t3);
                this.setNativeRange(...n4, e3);
              } else this.setNativeRange(null);
              this.update(n3);
            }
            update() {
              let t3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : i.A.sources.USER;
              const e3 = this.lastRange, [n3, s3] = this.getRange();
              if (this.lastRange = n3, this.lastNative = s3, null != this.lastRange && (this.savedRange = this.lastRange), !(0, l.A)(e3, this.lastRange)) {
                if (!this.composing && null != s3 && s3.native.collapsed && s3.start.node !== this.cursor.textNode) {
                  const t4 = this.cursor.restore();
                  t4 && this.setNativeRange(t4.startNode, t4.startOffset, t4.endNode, t4.endOffset);
                }
                const n4 = [i.A.events.SELECTION_CHANGE, (0, o.A)(this.lastRange), (0, o.A)(e3), t3];
                this.emitter.emit(i.A.events.EDITOR_CHANGE, ...n4), t3 !== i.A.sources.SILENT && this.emitter.emit(...n4);
              }
            }
          };
        }, 609: function(t2, e2) {
          class n2 {
            static DEFAULTS = { modules: {} };
            static themes = { default: n2 };
            modules = {};
            constructor(t3, e3) {
              this.quill = t3, this.options = e3;
            }
            init() {
              Object.keys(this.options.modules).forEach(((t3) => {
                null == this.modules[t3] && this.addModule(t3);
              }));
            }
            addModule(t3) {
              const e3 = this.quill.constructor.import(`modules/${t3}`);
              return this.modules[t3] = new e3(this.quill, this.options.modules[t3] || {}), this.modules[t3];
            }
          }
          e2.A = n2;
        }, 857: function(t2, e2) {
          e2.A = function(t3) {
            return JSON.parse(JSON.stringify(t3));
          };
        }, 697: function(t2, e2) {
          function n2(t3) {
            return t3 !== Object(t3);
          }
          e2.A = function t3(e3, s2) {
            if (e3 === s2) return true;
            if (n2(e3) || n2(s2)) return e3 === s2;
            if (Object.keys(e3).length !== Object.keys(s2).length) return false;
            for (const n3 in e3) {
              if (!(n3 in s2)) return false;
              if (!t3(e3[n3], s2[n3])) return false;
            }
            return true;
          };
        }, 276: function(t2, e2, n2) {
          n2.d(e2, { Hu: function() {
            return l;
          }, gS: function() {
            return r;
          }, qh: function() {
            return o;
          } });
          var s2 = n2(3);
          const i = { scope: s2.Scope.BLOCK, whitelist: ["right", "center", "justify"] }, r = new s2.Attributor("align", "align", i), o = new s2.ClassAttributor("align", "ql-align", i), l = new s2.StyleAttributor("align", "text-align", i);
        }, 922: function(t2, e2, n2) {
          n2.d(e2, { l: function() {
            return r;
          }, s: function() {
            return o;
          } });
          var s2 = n2(3), i = n2(638);
          const r = new s2.ClassAttributor("background", "ql-bg", { scope: s2.Scope.INLINE }), o = new i.a2("background", "background-color", { scope: s2.Scope.INLINE });
        }, 404: function(t2, e2, n2) {
          n2.d(e2, { Ay: function() {
            return u;
          }, Cy: function() {
            return d;
          } });
          var s2 = n2(698), i = n2(36), r = n2(541), o = n2(850), l = n2(508), a = n2(580), c = n2(543);
          class h extends a.A {
            static create(t3) {
              const e3 = super.create(t3);
              return e3.setAttribute("spellcheck", "false"), e3;
            }
            code(t3, e3) {
              return this.children.map(((t4) => t4.length() <= 1 ? "" : t4.domNode.innerText)).join("\n").slice(t3, t3 + e3);
            }
            html(t3, e3) {
              return `<pre>
${(0, l.X)(this.code(t3, e3))}
</pre>`;
            }
          }
          class u extends s2.Ay {
            static TAB = "  ";
            static register() {
              c.Ay.register(h);
            }
          }
          class d extends o.A {
          }
          d.blotName = "code", d.tagName = "CODE", u.blotName = "code-block", u.className = "ql-code-block", u.tagName = "DIV", h.blotName = "code-block-container", h.className = "ql-code-block-container", h.tagName = "DIV", h.allowedChildren = [u], u.allowedChildren = [l.A, i.A, r.A], u.requiredContainer = h;
        }, 638: function(t2, e2, n2) {
          n2.d(e2, { JM: function() {
            return o;
          }, a2: function() {
            return i;
          }, g3: function() {
            return r;
          } });
          var s2 = n2(3);
          class i extends s2.StyleAttributor {
            value(t3) {
              let e3 = super.value(t3);
              return e3.startsWith("rgb(") ? (e3 = e3.replace(/^[^\d]+/, "").replace(/[^\d]+$/, ""), `#${e3.split(",").map(((t4) => `00${parseInt(t4, 10).toString(16)}`.slice(-2))).join("")}`) : e3;
            }
          }
          const r = new s2.ClassAttributor("color", "ql-color", { scope: s2.Scope.INLINE }), o = new i("color", "color", { scope: s2.Scope.INLINE });
        }, 912: function(t2, e2, n2) {
          n2.d(e2, { Mc: function() {
            return r;
          }, VL: function() {
            return l;
          }, sY: function() {
            return o;
          } });
          var s2 = n2(3);
          const i = { scope: s2.Scope.BLOCK, whitelist: ["rtl"] }, r = new s2.Attributor("direction", "dir", i), o = new s2.ClassAttributor("direction", "ql-direction", i), l = new s2.StyleAttributor("direction", "direction", i);
        }, 772: function(t2, e2, n2) {
          n2.d(e2, { q: function() {
            return r;
          }, z: function() {
            return l;
          } });
          var s2 = n2(3);
          const i = { scope: s2.Scope.INLINE, whitelist: ["serif", "monospace"] }, r = new s2.ClassAttributor("font", "ql-font", i);
          class o extends s2.StyleAttributor {
            value(t3) {
              return super.value(t3).replace(/["']/g, "");
            }
          }
          const l = new o("font", "font-family", i);
        }, 664: function(t2, e2, n2) {
          n2.d(e2, { U: function() {
            return i;
          }, r: function() {
            return r;
          } });
          var s2 = n2(3);
          const i = new s2.ClassAttributor("size", "ql-size", { scope: s2.Scope.INLINE, whitelist: ["small", "large", "huge"] }), r = new s2.StyleAttributor("size", "font-size", { scope: s2.Scope.INLINE, whitelist: ["10px", "18px", "32px"] });
        }, 584: function(t2, e2, n2) {
          n2.d(e2, { Ay: function() {
            return O2;
          } });
          var s2 = n2(3), i = n2(398), r = n2(698), o = n2(78), l = n2(266), a = n2(543), c = n2(276), h = n2(922), u = n2(404), d = n2(638), f = n2(912), p = n2(772), m = n2(664), g = n2(123);
          const b = /font-weight:\s*normal/, y = ["P", "OL", "UL"], A5 = (t3) => t3 && y.includes(t3.tagName), N = /\bmso-list:[^;]*ignore/i, v = /\bmso-list:[^;]*\bl(\d+)/i, E4 = /\bmso-list:[^;]*\blevel(\d+)/i, x = [function(t3) {
            "urn:schemas-microsoft-com:office:word" === t3.documentElement.getAttribute("xmlns:w") && ((t4) => {
              const e3 = Array.from(t4.querySelectorAll("[style*=mso-list]")), n3 = [], s3 = [];
              e3.forEach(((t5) => {
                (t5.getAttribute("style") || "").match(N) ? n3.push(t5) : s3.push(t5);
              })), n3.forEach(((t5) => t5.parentNode?.removeChild(t5)));
              const i2 = t4.documentElement.innerHTML, r2 = s3.map(((t5) => ((t6, e4) => {
                const n4 = t6.getAttribute("style"), s4 = n4?.match(v);
                if (!s4) return null;
                const i3 = Number(s4[1]), r3 = n4?.match(E4), o2 = r3 ? Number(r3[1]) : 1, l2 = new RegExp(`@list l${i3}:level${o2}\\s*\\{[^\\}]*mso-level-number-format:\\s*([\\w-]+)`, "i"), a3 = e4.match(l2);
                return { id: i3, indent: o2, type: a3 && "bullet" === a3[1] ? "bullet" : "ordered", element: t6 };
              })(t5, i2))).filter(((t5) => t5));
              for (; r2.length; ) {
                const t5 = [];
                let e4 = r2.shift();
                for (; e4; ) t5.push(e4), e4 = r2.length && r2[0]?.element === e4.element.nextElementSibling && r2[0].id === e4.id ? r2.shift() : null;
                const n4 = document.createElement("ul");
                t5.forEach(((t6) => {
                  const e5 = document.createElement("li");
                  e5.setAttribute("data-list", t6.type), t6.indent > 1 && e5.setAttribute("class", "ql-indent-" + (t6.indent - 1)), e5.innerHTML = t6.element.innerHTML, n4.appendChild(e5);
                }));
                const s4 = t5[0]?.element, { parentNode: i3 } = s4 ?? {};
                s4 && i3?.replaceChild(n4, s4), t5.slice(1).forEach(((t6) => {
                  let { element: e5 } = t6;
                  i3?.removeChild(e5);
                }));
              }
            })(t3);
          }, function(t3) {
            t3.querySelector('[id^="docs-internal-guid-"]') && (((t4) => {
              Array.from(t4.querySelectorAll('b[style*="font-weight"]')).filter(((t5) => t5.getAttribute("style")?.match(b))).forEach(((e3) => {
                const n3 = t4.createDocumentFragment();
                n3.append(...e3.childNodes), e3.parentNode?.replaceChild(n3, e3);
              }));
            })(t3), ((t4) => {
              Array.from(t4.querySelectorAll("br")).filter(((t5) => A5(t5.previousElementSibling) && A5(t5.nextElementSibling))).forEach(((t5) => {
                t5.parentNode?.removeChild(t5);
              }));
            })(t3));
          }];
          const L = (0, o.A)("quill:clipboard"), S = [[Node.TEXT_NODE, function(t3, e3, n3) {
            let s3 = t3.data;
            if ("O:P" === t3.parentElement?.tagName) return e3.insert(s3.trim());
            if (!B(t3)) {
              if (0 === s3.trim().length && s3.includes("\n") && !(function(t4, e4) {
                return t4.previousElementSibling && t4.nextElementSibling && !q(t4.previousElementSibling, e4) && !q(t4.nextElementSibling, e4);
              })(t3, n3)) return e3;
              s3 = s3.replace(/[^\S\u00a0]/g, " "), s3 = s3.replace(/ {2,}/g, " "), (null == t3.previousSibling && null != t3.parentElement && q(t3.parentElement, n3) || t3.previousSibling instanceof Element && q(t3.previousSibling, n3)) && (s3 = s3.replace(/^ /, "")), (null == t3.nextSibling && null != t3.parentElement && q(t3.parentElement, n3) || t3.nextSibling instanceof Element && q(t3.nextSibling, n3)) && (s3 = s3.replace(/ $/, "")), s3 = s3.replaceAll(" ", " ");
            }
            return e3.insert(s3);
          }], [Node.TEXT_NODE, M5], ["br", function(t3, e3) {
            return C(e3, "\n") || e3.insert("\n"), e3;
          }], [Node.ELEMENT_NODE, M5], [Node.ELEMENT_NODE, function(t3, e3, n3) {
            const r2 = n3.query(t3);
            if (null == r2) return e3;
            if (r2.prototype instanceof s2.EmbedBlot) {
              const e4 = {}, s3 = r2.value(t3);
              if (null != s3) return e4[r2.blotName] = s3, new i.Ay().insert(e4, r2.formats(t3, n3));
            } else if (r2.prototype instanceof s2.BlockBlot && !C(e3, "\n") && e3.insert("\n"), "blotName" in r2 && "formats" in r2 && "function" == typeof r2.formats) return w(e3, r2.blotName, r2.formats(t3, n3), n3);
            return e3;
          }], [Node.ELEMENT_NODE, function(t3, e3, n3) {
            const i2 = s2.Attributor.keys(t3), r2 = s2.ClassAttributor.keys(t3), o2 = s2.StyleAttributor.keys(t3), l2 = {};
            return i2.concat(r2).concat(o2).forEach(((e4) => {
              let i3 = n3.query(e4, s2.Scope.ATTRIBUTE);
              null != i3 && (l2[i3.attrName] = i3.value(t3), l2[i3.attrName]) || (i3 = T[e4], null == i3 || i3.attrName !== e4 && i3.keyName !== e4 || (l2[i3.attrName] = i3.value(t3) || void 0), i3 = k[e4], null == i3 || i3.attrName !== e4 && i3.keyName !== e4 || (i3 = k[e4], l2[i3.attrName] = i3.value(t3) || void 0));
            })), Object.entries(l2).reduce(((t4, e4) => {
              let [s3, i3] = e4;
              return w(t4, s3, i3, n3);
            }), e3);
          }], [Node.ELEMENT_NODE, function(t3, e3, n3) {
            const s3 = {}, r2 = t3.style || {};
            return "italic" === r2.fontStyle && (s3.italic = true), "underline" === r2.textDecoration && (s3.underline = true), "line-through" === r2.textDecoration && (s3.strike = true), (r2.fontWeight?.startsWith("bold") || parseInt(r2.fontWeight, 10) >= 700) && (s3.bold = true), e3 = Object.entries(s3).reduce(((t4, e4) => {
              let [s4, i2] = e4;
              return w(t4, s4, i2, n3);
            }), e3), parseFloat(r2.textIndent || 0) > 0 ? new i.Ay().insert("	").concat(e3) : e3;
          }], ["li", function(t3, e3, n3) {
            const s3 = n3.query(t3);
            if (null == s3 || "list" !== s3.blotName || !C(e3, "\n")) return e3;
            let r2 = -1, o2 = t3.parentNode;
            for (; null != o2; ) ["OL", "UL"].includes(o2.tagName) && (r2 += 1), o2 = o2.parentNode;
            return r2 <= 0 ? e3 : e3.reduce(((t4, e4) => e4.insert ? e4.attributes && "number" == typeof e4.attributes.indent ? t4.push(e4) : t4.insert(e4.insert, { indent: r2, ...e4.attributes || {} }) : t4), new i.Ay());
          }], ["ol, ul", function(t3, e3, n3) {
            const s3 = t3;
            let i2 = "OL" === s3.tagName ? "ordered" : "bullet";
            const r2 = s3.getAttribute("data-checked");
            return r2 && (i2 = "true" === r2 ? "checked" : "unchecked"), w(e3, "list", i2, n3);
          }], ["pre", function(t3, e3, n3) {
            const s3 = n3.query("code-block");
            return w(e3, "code-block", !s3 || !("formats" in s3) || "function" != typeof s3.formats || s3.formats(t3, n3), n3);
          }], ["tr", function(t3, e3, n3) {
            const s3 = "TABLE" === t3.parentElement?.tagName ? t3.parentElement : t3.parentElement?.parentElement;
            return null != s3 ? w(e3, "table", Array.from(s3.querySelectorAll("tr")).indexOf(t3) + 1, n3) : e3;
          }], ["b", D("bold")], ["i", D("italic")], ["strike", D("strike")], ["style", function() {
            return new i.Ay();
          }]], T = [c.gS, f.Mc].reduce(((t3, e3) => (t3[e3.keyName] = e3, t3)), {}), k = [c.Hu, h.s, d.JM, f.VL, p.z, m.r].reduce(((t3, e3) => (t3[e3.keyName] = e3, t3)), {});
          class O2 extends l.A {
            static DEFAULTS = { matchers: [] };
            constructor(t3, e3) {
              super(t3, e3), this.quill.root.addEventListener("copy", ((t4) => this.onCaptureCopy(t4, false))), this.quill.root.addEventListener("cut", ((t4) => this.onCaptureCopy(t4, true))), this.quill.root.addEventListener("paste", this.onCapturePaste.bind(this)), this.matchers = [], S.concat(this.options.matchers ?? []).forEach(((t4) => {
                let [e4, n3] = t4;
                this.addMatcher(e4, n3);
              }));
            }
            addMatcher(t3, e3) {
              this.matchers.push([t3, e3]);
            }
            convert(t3) {
              let { html: e3, text: n3 } = t3, s3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
              if (s3[u.Ay.blotName]) return new i.Ay().insert(n3 || "", { [u.Ay.blotName]: s3[u.Ay.blotName] });
              if (!e3) return new i.Ay().insert(n3 || "", s3);
              const r2 = this.convertHTML(e3);
              return C(r2, "\n") && (null == r2.ops[r2.ops.length - 1].attributes || s3.table) ? r2.compose(new i.Ay().retain(r2.length() - 1).delete(1)) : r2;
            }
            normalizeHTML(t3) {
              ((t4) => {
                t4.documentElement && x.forEach(((e3) => {
                  e3(t4);
                }));
              })(t3);
            }
            convertHTML(t3) {
              const e3 = new DOMParser().parseFromString(t3, "text/html");
              this.normalizeHTML(e3);
              const n3 = e3.body, s3 = /* @__PURE__ */ new WeakMap(), [i2, r2] = this.prepareMatching(n3, s3);
              return I2(this.quill.scroll, n3, i2, r2, s3);
            }
            dangerouslyPasteHTML(t3, e3) {
              let n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : a.Ay.sources.API;
              if ("string" == typeof t3) {
                const n4 = this.convert({ html: t3, text: "" });
                this.quill.setContents(n4, e3), this.quill.setSelection(0, a.Ay.sources.SILENT);
              } else {
                const s3 = this.convert({ html: e3, text: "" });
                this.quill.updateContents(new i.Ay().retain(t3).concat(s3), n3), this.quill.setSelection(t3 + s3.length(), a.Ay.sources.SILENT);
              }
            }
            onCaptureCopy(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
              if (t3.defaultPrevented) return;
              t3.preventDefault();
              const [n3] = this.quill.selection.getRange();
              if (null == n3) return;
              const { html: s3, text: i2 } = this.onCopy(n3, e3);
              t3.clipboardData?.setData("text/plain", i2), t3.clipboardData?.setData("text/html", s3), e3 && (0, g.Xo)({ range: n3, quill: this.quill });
            }
            normalizeURIList(t3) {
              return t3.split(/\r?\n/).filter(((t4) => "#" !== t4[0])).join("\n");
            }
            onCapturePaste(t3) {
              if (t3.defaultPrevented || !this.quill.isEnabled()) return;
              t3.preventDefault();
              const e3 = this.quill.getSelection(true);
              if (null == e3) return;
              const n3 = t3.clipboardData?.getData("text/html");
              let s3 = t3.clipboardData?.getData("text/plain");
              if (!n3 && !s3) {
                const e4 = t3.clipboardData?.getData("text/uri-list");
                e4 && (s3 = this.normalizeURIList(e4));
              }
              const i2 = Array.from(t3.clipboardData?.files || []);
              if (!n3 && i2.length > 0) this.quill.uploader.upload(e3, i2);
              else {
                if (n3 && i2.length > 0) {
                  const t4 = new DOMParser().parseFromString(n3, "text/html");
                  if (1 === t4.body.childElementCount && "IMG" === t4.body.firstElementChild?.tagName) return void this.quill.uploader.upload(e3, i2);
                }
                this.onPaste(e3, { html: n3, text: s3 });
              }
            }
            onCopy(t3) {
              const e3 = this.quill.getText(t3);
              return { html: this.quill.getSemanticHTML(t3), text: e3 };
            }
            onPaste(t3, e3) {
              let { text: n3, html: s3 } = e3;
              const r2 = this.quill.getFormat(t3.index), o2 = this.convert({ text: n3, html: s3 }, r2);
              L.log("onPaste", o2, { text: n3, html: s3 });
              const l2 = new i.Ay().retain(t3.index).delete(t3.length).concat(o2);
              this.quill.updateContents(l2, a.Ay.sources.USER), this.quill.setSelection(l2.length() - t3.length, a.Ay.sources.SILENT), this.quill.scrollSelectionIntoView();
            }
            prepareMatching(t3, e3) {
              const n3 = [], s3 = [];
              return this.matchers.forEach(((i2) => {
                const [r2, o2] = i2;
                switch (r2) {
                  case Node.TEXT_NODE:
                    s3.push(o2);
                    break;
                  case Node.ELEMENT_NODE:
                    n3.push(o2);
                    break;
                  default:
                    Array.from(t3.querySelectorAll(r2)).forEach(((t4) => {
                      if (e3.has(t4)) {
                        const n4 = e3.get(t4);
                        n4?.push(o2);
                      } else e3.set(t4, [o2]);
                    }));
                }
              })), [n3, s3];
            }
          }
          function w(t3, e3, n3, s3) {
            return s3.query(e3) ? t3.reduce(((t4, s4) => {
              if (!s4.insert) return t4;
              if (s4.attributes && s4.attributes[e3]) return t4.push(s4);
              const i2 = n3 ? { [e3]: n3 } : {};
              return t4.insert(s4.insert, { ...i2, ...s4.attributes });
            }), new i.Ay()) : t3;
          }
          function C(t3, e3) {
            let n3 = "";
            for (let s3 = t3.ops.length - 1; s3 >= 0 && n3.length < e3.length; --s3) {
              const e4 = t3.ops[s3];
              if ("string" != typeof e4.insert) break;
              n3 = e4.insert + n3;
            }
            return n3.slice(-1 * e3.length) === e3;
          }
          function q(t3, e3) {
            if (!(t3 instanceof Element)) return false;
            const n3 = e3.query(t3);
            return !(n3 && n3.prototype instanceof s2.EmbedBlot) && ["address", "article", "blockquote", "canvas", "dd", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "iframe", "li", "main", "nav", "ol", "output", "p", "pre", "section", "table", "td", "tr", "ul", "video"].includes(t3.tagName.toLowerCase());
          }
          const R2 = /* @__PURE__ */ new WeakMap();
          function B(t3) {
            return null != t3 && (R2.has(t3) || ("PRE" === t3.tagName ? R2.set(t3, true) : R2.set(t3, B(t3.parentNode))), R2.get(t3));
          }
          function I2(t3, e3, n3, s3, r2) {
            return e3.nodeType === e3.TEXT_NODE ? s3.reduce(((n4, s4) => s4(e3, n4, t3)), new i.Ay()) : e3.nodeType === e3.ELEMENT_NODE ? Array.from(e3.childNodes || []).reduce(((i2, o2) => {
              let l2 = I2(t3, o2, n3, s3, r2);
              return o2.nodeType === e3.ELEMENT_NODE && (l2 = n3.reduce(((e4, n4) => n4(o2, e4, t3)), l2), l2 = (r2.get(o2) || []).reduce(((e4, n4) => n4(o2, e4, t3)), l2)), i2.concat(l2);
            }), new i.Ay()) : new i.Ay();
          }
          function D(t3) {
            return (e3, n3, s3) => w(n3, t3, true, s3);
          }
          function M5(t3, e3, n3) {
            if (!C(e3, "\n")) {
              if (q(t3, n3) && (t3.childNodes.length > 0 || t3 instanceof HTMLParagraphElement)) return e3.insert("\n");
              if (e3.length() > 0 && t3.nextSibling) {
                let s3 = t3.nextSibling;
                for (; null != s3; ) {
                  if (q(s3, n3)) return e3.insert("\n");
                  const t4 = n3.query(s3);
                  if (t4 && t4.prototype instanceof r.zo) return e3.insert("\n");
                  s3 = s3.firstChild;
                }
              }
            }
            return e3;
          }
        }, 123: function(t2, e2, n2) {
          n2.d(e2, { Ay: function() {
            return u;
          }, Xo: function() {
            return b;
          } });
          var s2 = n2(398), i = n2(3), r = n2(543), o = n2(78), l = n2(266), a = n2(697);
          const c = (0, o.A)("quill:keyboard"), h = /Mac/i.test(navigator.platform) ? "metaKey" : "ctrlKey";
          class u extends l.A {
            static match(t3, e3) {
              return !["altKey", "ctrlKey", "metaKey", "shiftKey"].some(((n3) => !!e3[n3] !== t3[n3] && null !== e3[n3])) && (e3.key === t3.key || e3.key === t3.which);
            }
            constructor(t3, e3) {
              super(t3, e3), this.bindings = {}, Object.keys(this.options.bindings).forEach(((t4) => {
                this.options.bindings[t4] && this.addBinding(this.options.bindings[t4]);
              })), this.addBinding({ key: "Enter", shiftKey: null }, this.handleEnter), this.addBinding({ key: "Enter", metaKey: null, ctrlKey: null, altKey: null }, (() => {
              })), /Firefox/i.test(navigator.userAgent) ? (this.addBinding({ key: "Backspace" }, { collapsed: true }, this.handleBackspace), this.addBinding({ key: "Delete" }, { collapsed: true }, this.handleDelete)) : (this.addBinding({ key: "Backspace" }, { collapsed: true, prefix: /^.?$/ }, this.handleBackspace), this.addBinding({ key: "Delete" }, { collapsed: true, suffix: /^.?$/ }, this.handleDelete)), this.addBinding({ key: "Backspace" }, { collapsed: false }, this.handleDeleteRange), this.addBinding({ key: "Delete" }, { collapsed: false }, this.handleDeleteRange), this.addBinding({ key: "Backspace", altKey: null, ctrlKey: null, metaKey: null, shiftKey: null }, { collapsed: true, offset: 0 }, this.handleBackspace), this.listen();
            }
            addBinding(t3) {
              let e3 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n3 = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
              const s3 = (function(t4) {
                if ("string" == typeof t4 || "number" == typeof t4) t4 = { key: t4 };
                else {
                  if ("object" != typeof t4) return null;
                  t4 = { ...t4 };
                }
                return t4.shortKey && (t4[h] = t4.shortKey, delete t4.shortKey), t4;
              })(t3);
              null != s3 ? ("function" == typeof e3 && (e3 = { handler: e3 }), "function" == typeof n3 && (n3 = { handler: n3 }), (Array.isArray(s3.key) ? s3.key : [s3.key]).forEach(((t4) => {
                const i2 = { ...s3, key: t4, ...e3, ...n3 };
                this.bindings[i2.key] = this.bindings[i2.key] || [], this.bindings[i2.key].push(i2);
              }))) : c.warn("Attempted to add invalid keyboard binding", s3);
            }
            listen() {
              this.quill.root.addEventListener("keydown", ((t3) => {
                if (t3.defaultPrevented || t3.isComposing) return;
                if (229 === t3.keyCode && ("Enter" === t3.key || "Backspace" === t3.key)) return;
                const e3 = (this.bindings[t3.key] || []).concat(this.bindings[t3.which] || []).filter(((e4) => u.match(t3, e4)));
                if (0 === e3.length) return;
                const n3 = r.Ay.find(t3.target, true);
                if (n3 && n3.scroll !== this.quill.scroll) return;
                const s3 = this.quill.getSelection();
                if (null == s3 || !this.quill.hasFocus()) return;
                const [o2, l2] = this.quill.getLine(s3.index), [c2, h2] = this.quill.getLeaf(s3.index), [d2, f2] = 0 === s3.length ? [c2, h2] : this.quill.getLeaf(s3.index + s3.length), p5 = c2 instanceof i.TextBlot ? c2.value().slice(0, h2) : "", m2 = d2 instanceof i.TextBlot ? d2.value().slice(f2) : "", g2 = { collapsed: 0 === s3.length, empty: 0 === s3.length && o2.length() <= 1, format: this.quill.getFormat(s3), line: o2, offset: l2, prefix: p5, suffix: m2, event: t3 };
                e3.some(((t4) => {
                  if (null != t4.collapsed && t4.collapsed !== g2.collapsed) return false;
                  if (null != t4.empty && t4.empty !== g2.empty) return false;
                  if (null != t4.offset && t4.offset !== g2.offset) return false;
                  if (Array.isArray(t4.format)) {
                    if (t4.format.every(((t5) => null == g2.format[t5]))) return false;
                  } else if ("object" == typeof t4.format && !Object.keys(t4.format).every(((e4) => true === t4.format[e4] ? null != g2.format[e4] : false === t4.format[e4] ? null == g2.format[e4] : (0, a.A)(t4.format[e4], g2.format[e4])))) return false;
                  return !(null != t4.prefix && !t4.prefix.test(g2.prefix) || null != t4.suffix && !t4.suffix.test(g2.suffix) || true === t4.handler.call(this, s3, g2, t4));
                })) && t3.preventDefault();
              }));
            }
            handleBackspace(t3, e3) {
              const n3 = /[\uD800-\uDBFF][\uDC00-\uDFFF]$/.test(e3.prefix) ? 2 : 1;
              if (0 === t3.index || this.quill.getLength() <= 1) return;
              let i2 = {};
              const [o2] = this.quill.getLine(t3.index);
              let l2 = new s2.Ay().retain(t3.index - n3).delete(n3);
              if (0 === e3.offset) {
                const [e4] = this.quill.getLine(t3.index - 1);
                if (e4 && !("block" === e4.statics.blotName && e4.length() <= 1)) {
                  const e5 = o2.formats(), n4 = this.quill.getFormat(t3.index - 1, 1);
                  if (i2 = s2.xb.diff(e5, n4) || {}, Object.keys(i2).length > 0) {
                    const e6 = new s2.Ay().retain(t3.index + o2.length() - 2).retain(1, i2);
                    l2 = l2.compose(e6);
                  }
                }
              }
              this.quill.updateContents(l2, r.Ay.sources.USER), this.quill.focus();
            }
            handleDelete(t3, e3) {
              const n3 = /^[\uD800-\uDBFF][\uDC00-\uDFFF]/.test(e3.suffix) ? 2 : 1;
              if (t3.index >= this.quill.getLength() - n3) return;
              let i2 = {};
              const [o2] = this.quill.getLine(t3.index);
              let l2 = new s2.Ay().retain(t3.index).delete(n3);
              if (e3.offset >= o2.length() - 1) {
                const [e4] = this.quill.getLine(t3.index + 1);
                if (e4) {
                  const n4 = o2.formats(), r2 = this.quill.getFormat(t3.index, 1);
                  i2 = s2.xb.diff(n4, r2) || {}, Object.keys(i2).length > 0 && (l2 = l2.retain(e4.length() - 1).retain(1, i2));
                }
              }
              this.quill.updateContents(l2, r.Ay.sources.USER), this.quill.focus();
            }
            handleDeleteRange(t3) {
              b({ range: t3, quill: this.quill }), this.quill.focus();
            }
            handleEnter(t3, e3) {
              const n3 = Object.keys(e3.format).reduce(((t4, n4) => (this.quill.scroll.query(n4, i.Scope.BLOCK) && !Array.isArray(e3.format[n4]) && (t4[n4] = e3.format[n4]), t4)), {}), o2 = new s2.Ay().retain(t3.index).delete(t3.length).insert("\n", n3);
              this.quill.updateContents(o2, r.Ay.sources.USER), this.quill.setSelection(t3.index + 1, r.Ay.sources.SILENT), this.quill.focus();
            }
          }
          const d = { bindings: { bold: m("bold"), italic: m("italic"), underline: m("underline"), indent: { key: "Tab", format: ["blockquote", "indent", "list"], handler(t3, e3) {
            return !(!e3.collapsed || 0 === e3.offset) || (this.quill.format("indent", "+1", r.Ay.sources.USER), false);
          } }, outdent: { key: "Tab", shiftKey: true, format: ["blockquote", "indent", "list"], handler(t3, e3) {
            return !(!e3.collapsed || 0 === e3.offset) || (this.quill.format("indent", "-1", r.Ay.sources.USER), false);
          } }, "outdent backspace": { key: "Backspace", collapsed: true, shiftKey: null, metaKey: null, ctrlKey: null, altKey: null, format: ["indent", "list"], offset: 0, handler(t3, e3) {
            null != e3.format.indent ? this.quill.format("indent", "-1", r.Ay.sources.USER) : null != e3.format.list && this.quill.format("list", false, r.Ay.sources.USER);
          } }, "indent code-block": f(true), "outdent code-block": f(false), "remove tab": { key: "Tab", shiftKey: true, collapsed: true, prefix: /\t$/, handler(t3) {
            this.quill.deleteText(t3.index - 1, 1, r.Ay.sources.USER);
          } }, tab: { key: "Tab", handler(t3, e3) {
            if (e3.format.table) return true;
            this.quill.history.cutoff();
            const n3 = new s2.Ay().retain(t3.index).delete(t3.length).insert("	");
            return this.quill.updateContents(n3, r.Ay.sources.USER), this.quill.history.cutoff(), this.quill.setSelection(t3.index + 1, r.Ay.sources.SILENT), false;
          } }, "blockquote empty enter": { key: "Enter", collapsed: true, format: ["blockquote"], empty: true, handler() {
            this.quill.format("blockquote", false, r.Ay.sources.USER);
          } }, "list empty enter": { key: "Enter", collapsed: true, format: ["list"], empty: true, handler(t3, e3) {
            const n3 = { list: false };
            e3.format.indent && (n3.indent = false), this.quill.formatLine(t3.index, t3.length, n3, r.Ay.sources.USER);
          } }, "checklist enter": { key: "Enter", collapsed: true, format: { list: "checked" }, handler(t3) {
            const [e3, n3] = this.quill.getLine(t3.index), i2 = { ...e3.formats(), list: "checked" }, o2 = new s2.Ay().retain(t3.index).insert("\n", i2).retain(e3.length() - n3 - 1).retain(1, { list: "unchecked" });
            this.quill.updateContents(o2, r.Ay.sources.USER), this.quill.setSelection(t3.index + 1, r.Ay.sources.SILENT), this.quill.scrollSelectionIntoView();
          } }, "header enter": { key: "Enter", collapsed: true, format: ["header"], suffix: /^$/, handler(t3, e3) {
            const [n3, i2] = this.quill.getLine(t3.index), o2 = new s2.Ay().retain(t3.index).insert("\n", e3.format).retain(n3.length() - i2 - 1).retain(1, { header: null });
            this.quill.updateContents(o2, r.Ay.sources.USER), this.quill.setSelection(t3.index + 1, r.Ay.sources.SILENT), this.quill.scrollSelectionIntoView();
          } }, "table backspace": { key: "Backspace", format: ["table"], collapsed: true, offset: 0, handler() {
          } }, "table delete": { key: "Delete", format: ["table"], collapsed: true, suffix: /^$/, handler() {
          } }, "table enter": { key: "Enter", shiftKey: null, format: ["table"], handler(t3) {
            const e3 = this.quill.getModule("table");
            if (e3) {
              const [n3, i2, o2, l2] = e3.getTable(t3), a3 = (function(t4, e4, n4, s3) {
                return null == e4.prev && null == e4.next ? null == n4.prev && null == n4.next ? 0 === s3 ? -1 : 1 : null == n4.prev ? -1 : 1 : null == e4.prev ? -1 : null == e4.next ? 1 : null;
              })(0, i2, o2, l2);
              if (null == a3) return;
              let c2 = n3.offset();
              if (a3 < 0) {
                const e4 = new s2.Ay().retain(c2).insert("\n");
                this.quill.updateContents(e4, r.Ay.sources.USER), this.quill.setSelection(t3.index + 1, t3.length, r.Ay.sources.SILENT);
              } else if (a3 > 0) {
                c2 += n3.length();
                const t4 = new s2.Ay().retain(c2).insert("\n");
                this.quill.updateContents(t4, r.Ay.sources.USER), this.quill.setSelection(c2, r.Ay.sources.USER);
              }
            }
          } }, "table tab": { key: "Tab", shiftKey: null, format: ["table"], handler(t3, e3) {
            const { event: n3, line: s3 } = e3, i2 = s3.offset(this.quill.scroll);
            n3.shiftKey ? this.quill.setSelection(i2 - 1, r.Ay.sources.USER) : this.quill.setSelection(i2 + s3.length(), r.Ay.sources.USER);
          } }, "list autofill": { key: " ", shiftKey: null, collapsed: true, format: { "code-block": false, blockquote: false, table: false }, prefix: /^\s*?(\d+\.|-|\*|\[ ?\]|\[x\])$/, handler(t3, e3) {
            if (null == this.quill.scroll.query("list")) return true;
            const { length: n3 } = e3.prefix, [i2, o2] = this.quill.getLine(t3.index);
            if (o2 > n3) return true;
            let l2;
            switch (e3.prefix.trim()) {
              case "[]":
              case "[ ]":
                l2 = "unchecked";
                break;
              case "[x]":
                l2 = "checked";
                break;
              case "-":
              case "*":
                l2 = "bullet";
                break;
              default:
                l2 = "ordered";
            }
            this.quill.insertText(t3.index, " ", r.Ay.sources.USER), this.quill.history.cutoff();
            const a3 = new s2.Ay().retain(t3.index - o2).delete(n3 + 1).retain(i2.length() - 2 - o2).retain(1, { list: l2 });
            return this.quill.updateContents(a3, r.Ay.sources.USER), this.quill.history.cutoff(), this.quill.setSelection(t3.index - n3, r.Ay.sources.SILENT), false;
          } }, "code exit": { key: "Enter", collapsed: true, format: ["code-block"], prefix: /^$/, suffix: /^\s*$/, handler(t3) {
            const [e3, n3] = this.quill.getLine(t3.index);
            let i2 = 2, o2 = e3;
            for (; null != o2 && o2.length() <= 1 && o2.formats()["code-block"]; ) if (o2 = o2.prev, i2 -= 1, i2 <= 0) {
              const i3 = new s2.Ay().retain(t3.index + e3.length() - n3 - 2).retain(1, { "code-block": null }).delete(1);
              return this.quill.updateContents(i3, r.Ay.sources.USER), this.quill.setSelection(t3.index - 1, r.Ay.sources.SILENT), false;
            }
            return true;
          } }, "embed left": p("ArrowLeft", false), "embed left shift": p("ArrowLeft", true), "embed right": p("ArrowRight", false), "embed right shift": p("ArrowRight", true), "table down": g(false), "table up": g(true) } };
          function f(t3) {
            return { key: "Tab", shiftKey: !t3, format: { "code-block": true }, handler(e3, n3) {
              let { event: s3 } = n3;
              const i2 = this.quill.scroll.query("code-block"), { TAB: o2 } = i2;
              if (0 === e3.length && !s3.shiftKey) return this.quill.insertText(e3.index, o2, r.Ay.sources.USER), void this.quill.setSelection(e3.index + o2.length, r.Ay.sources.SILENT);
              const l2 = 0 === e3.length ? this.quill.getLines(e3.index, 1) : this.quill.getLines(e3);
              let { index: a3, length: c2 } = e3;
              l2.forEach(((e4, n4) => {
                t3 ? (e4.insertAt(0, o2), 0 === n4 ? a3 += o2.length : c2 += o2.length) : e4.domNode.textContent.startsWith(o2) && (e4.deleteAt(0, o2.length), 0 === n4 ? a3 -= o2.length : c2 -= o2.length);
              })), this.quill.update(r.Ay.sources.USER), this.quill.setSelection(a3, c2, r.Ay.sources.SILENT);
            } };
          }
          function p(t3, e3) {
            return { key: t3, shiftKey: e3, altKey: null, ["ArrowLeft" === t3 ? "prefix" : "suffix"]: /^$/, handler(n3) {
              let { index: s3 } = n3;
              "ArrowRight" === t3 && (s3 += n3.length + 1);
              const [o2] = this.quill.getLeaf(s3);
              return !(o2 instanceof i.EmbedBlot && ("ArrowLeft" === t3 ? e3 ? this.quill.setSelection(n3.index - 1, n3.length + 1, r.Ay.sources.USER) : this.quill.setSelection(n3.index - 1, r.Ay.sources.USER) : e3 ? this.quill.setSelection(n3.index, n3.length + 1, r.Ay.sources.USER) : this.quill.setSelection(n3.index + n3.length + 1, r.Ay.sources.USER), 1));
            } };
          }
          function m(t3) {
            return { key: t3[0], shortKey: true, handler(e3, n3) {
              this.quill.format(t3, !n3.format[t3], r.Ay.sources.USER);
            } };
          }
          function g(t3) {
            return { key: t3 ? "ArrowUp" : "ArrowDown", collapsed: true, format: ["table"], handler(e3, n3) {
              const s3 = t3 ? "prev" : "next", i2 = n3.line, o2 = i2.parent[s3];
              if (null != o2) {
                if ("table-row" === o2.statics.blotName) {
                  let t4 = o2.children.head, e4 = i2;
                  for (; null != e4.prev; ) e4 = e4.prev, t4 = t4.next;
                  const s4 = t4.offset(this.quill.scroll) + Math.min(n3.offset, t4.length() - 1);
                  this.quill.setSelection(s4, 0, r.Ay.sources.USER);
                }
              } else {
                const e4 = i2.table()[s3];
                null != e4 && (t3 ? this.quill.setSelection(e4.offset(this.quill.scroll) + e4.length() - 1, 0, r.Ay.sources.USER) : this.quill.setSelection(e4.offset(this.quill.scroll), 0, r.Ay.sources.USER));
              }
              return false;
            } };
          }
          function b(t3) {
            let { quill: e3, range: n3 } = t3;
            const i2 = e3.getLines(n3);
            let o2 = {};
            if (i2.length > 1) {
              const t4 = i2[0].formats(), e4 = i2[i2.length - 1].formats();
              o2 = s2.xb.diff(e4, t4) || {};
            }
            e3.deleteText(n3, r.Ay.sources.USER), Object.keys(o2).length > 0 && e3.formatLine(n3.index, 1, o2, r.Ay.sources.USER), e3.setSelection(n3.index, r.Ay.sources.SILENT);
          }
          u.DEFAULTS = d;
        }, 398: function(t2, e2, n2) {
          n2.d(e2, { Ay: function() {
            return L;
          }, Op: function() {
            return A5;
          }, xb: function() {
            return y;
          } });
          var s2, i, r = Object.create, o = Object.defineProperty, l = Object.getOwnPropertyDescriptor, a = Object.getOwnPropertyNames, c = Object.getPrototypeOf, h = Object.prototype.hasOwnProperty, u = ((t3, e3, n3) => (n3 = null != t3 ? r(c(t3)) : {}, ((t4, e4, n4, s3) => {
            if (e4 && "object" == typeof e4 || "function" == typeof e4) for (let n5 of a(e4)) h.call(t4, n5) || void 0 === n5 || o(t4, n5, { get: () => e4[n5], enumerable: !(s3 = l(e4, n5)) || s3.enumerable });
            return t4;
          })(t3 && t3.__esModule ? n3 : o(n3, "default", { value: t3, enumerable: true }), t3)))((s2 = { "node_modules/.pnpm/fast-diff@1.3.0/node_modules/fast-diff/diff.js"(t3, e3) {
            var n3 = -1;
            function s3(t4, e4, p6, m3, g3) {
              if (t4 === e4) return t4 ? [[0, t4]] : [];
              if (null != p6) {
                var b4 = (function(t5, e5, n4) {
                  var s4 = "number" == typeof n4 ? { index: n4, length: 0 } : n4.oldRange, i3 = "number" == typeof n4 ? null : n4.newRange, r3 = t5.length, o3 = e5.length;
                  if (0 === s4.length && (null === i3 || 0 === i3.length)) {
                    var l3 = s4.index, a4 = t5.slice(0, l3), c3 = t5.slice(l3), h3 = i3 ? i3.index : null, u3 = l3 + o3 - r3;
                    if ((null === h3 || h3 === u3) && !(u3 < 0 || u3 > o3)) {
                      var d3 = e5.slice(0, u3);
                      if ((m4 = e5.slice(u3)) === c3) {
                        var f3 = Math.min(l3, u3);
                        if ((b5 = a4.slice(0, f3)) === (N3 = d3.slice(0, f3))) return y2(b5, a4.slice(f3), d3.slice(f3), c3);
                      }
                    }
                    if (null === h3 || h3 === l3) {
                      var p7 = l3, m4 = (d3 = e5.slice(0, p7), e5.slice(p7));
                      if (d3 === a4) {
                        var g4 = Math.min(r3 - p7, o3 - p7);
                        if ((A8 = c3.slice(c3.length - g4)) === (v3 = m4.slice(m4.length - g4))) return y2(a4, c3.slice(0, c3.length - g4), m4.slice(0, m4.length - g4), A8);
                      }
                    }
                  }
                  if (s4.length > 0 && i3 && 0 === i3.length) {
                    var b5 = t5.slice(0, s4.index), A8 = t5.slice(s4.index + s4.length);
                    if (!(o3 < (f3 = b5.length) + (g4 = A8.length))) {
                      var N3 = e5.slice(0, f3), v3 = e5.slice(o3 - g4);
                      if (b5 === N3 && A8 === v3) return y2(b5, t5.slice(f3, r3 - g4), e5.slice(f3, o3 - g4), A8);
                    }
                  }
                  return null;
                })(t4, e4, p6);
                if (b4) return b4;
              }
              var A7 = r2(t4, e4), N2 = t4.substring(0, A7);
              A7 = l2(t4 = t4.substring(A7), e4 = e4.substring(A7));
              var v2 = t4.substring(t4.length - A7), E5 = (function(t5, e5) {
                var o3;
                if (!t5) return [[1, e5]];
                if (!e5) return [[n3, t5]];
                var a4 = t5.length > e5.length ? t5 : e5, c3 = t5.length > e5.length ? e5 : t5, h3 = a4.indexOf(c3);
                if (-1 !== h3) return o3 = [[1, a4.substring(0, h3)], [0, c3], [1, a4.substring(h3 + c3.length)]], t5.length > e5.length && (o3[0][0] = o3[2][0] = n3), o3;
                if (1 === c3.length) return [[n3, t5], [1, e5]];
                var u3 = (function(t6, e6) {
                  var n4 = t6.length > e6.length ? t6 : e6, s4 = t6.length > e6.length ? e6 : t6;
                  if (n4.length < 4 || 2 * s4.length < n4.length) return null;
                  function i3(t7, e7, n5) {
                    for (var s5, i4, o5, a6, c5 = t7.substring(n5, n5 + Math.floor(t7.length / 4)), h5 = -1, u5 = ""; -1 !== (h5 = e7.indexOf(c5, h5 + 1)); ) {
                      var d5 = r2(t7.substring(n5), e7.substring(h5)), f5 = l2(t7.substring(0, n5), e7.substring(0, h5));
                      u5.length < f5 + d5 && (u5 = e7.substring(h5 - f5, h5) + e7.substring(h5, h5 + d5), s5 = t7.substring(0, n5 - f5), i4 = t7.substring(n5 + d5), o5 = e7.substring(0, h5 - f5), a6 = e7.substring(h5 + d5));
                    }
                    return 2 * u5.length >= t7.length ? [s5, i4, o5, a6, u5] : null;
                  }
                  var o4, a5, c4, h4, u4, d4 = i3(n4, s4, Math.ceil(n4.length / 4)), f4 = i3(n4, s4, Math.ceil(n4.length / 2));
                  return d4 || f4 ? (o4 = f4 ? d4 && d4[4].length > f4[4].length ? d4 : f4 : d4, t6.length > e6.length ? (a5 = o4[0], c4 = o4[1], h4 = o4[2], u4 = o4[3]) : (h4 = o4[0], u4 = o4[1], a5 = o4[2], c4 = o4[3]), [a5, c4, h4, u4, o4[4]]) : null;
                })(t5, e5);
                if (u3) {
                  var d3 = u3[0], f3 = u3[1], p7 = u3[2], m4 = u3[3], g4 = u3[4], b5 = s3(d3, p7), y3 = s3(f3, m4);
                  return b5.concat([[0, g4]], y3);
                }
                return (function(t6, e6) {
                  for (var s4 = t6.length, r3 = e6.length, o4 = Math.ceil((s4 + r3) / 2), l3 = o4, a5 = 2 * o4, c4 = new Array(a5), h4 = new Array(a5), u4 = 0; u4 < a5; u4++) c4[u4] = -1, h4[u4] = -1;
                  c4[l3 + 1] = 0, h4[l3 + 1] = 0;
                  for (var d4 = s4 - r3, f4 = d4 % 2 != 0, p8 = 0, m5 = 0, g5 = 0, b6 = 0, y4 = 0; y4 < o4; y4++) {
                    for (var A8 = -y4 + p8; A8 <= y4 - m5; A8 += 2) {
                      for (var N3 = l3 + A8, v3 = (T = A8 === -y4 || A8 !== y4 && c4[N3 - 1] < c4[N3 + 1] ? c4[N3 + 1] : c4[N3 - 1] + 1) - A8; T < s4 && v3 < r3 && t6.charAt(T) === e6.charAt(v3); ) T++, v3++;
                      if (c4[N3] = T, T > s4) m5 += 2;
                      else if (v3 > r3) p8 += 2;
                      else if (f4 && (L2 = l3 + d4 - A8) >= 0 && L2 < a5 && -1 !== h4[L2] && T >= (x2 = s4 - h4[L2])) return i2(t6, e6, T, v3);
                    }
                    for (var E6 = -y4 + g5; E6 <= y4 - b6; E6 += 2) {
                      for (var x2, L2 = l3 + E6, S = (x2 = E6 === -y4 || E6 !== y4 && h4[L2 - 1] < h4[L2 + 1] ? h4[L2 + 1] : h4[L2 - 1] + 1) - E6; x2 < s4 && S < r3 && t6.charAt(s4 - x2 - 1) === e6.charAt(r3 - S - 1); ) x2++, S++;
                      if (h4[L2] = x2, x2 > s4) b6 += 2;
                      else if (S > r3) g5 += 2;
                      else if (!f4) {
                        var T;
                        if ((N3 = l3 + d4 - E6) >= 0 && N3 < a5 && -1 !== c4[N3] && (v3 = l3 + (T = c4[N3]) - N3, T >= (x2 = s4 - x2))) return i2(t6, e6, T, v3);
                      }
                    }
                  }
                  return [[n3, t6], [1, e6]];
                })(t5, e5);
              })(t4 = t4.substring(0, t4.length - A7), e4 = e4.substring(0, e4.length - A7));
              return N2 && E5.unshift([0, N2]), v2 && E5.push([0, v2]), f2(E5, g3), m3 && (function(t5) {
                for (var e5 = false, s4 = [], i3 = 0, r3 = null, p7 = 0, m4 = 0, g4 = 0, b5 = 0, y3 = 0; p7 < t5.length; ) 0 == t5[p7][0] ? (s4[i3++] = p7, m4 = b5, g4 = y3, b5 = 0, y3 = 0, r3 = t5[p7][1]) : (1 == t5[p7][0] ? b5 += t5[p7][1].length : y3 += t5[p7][1].length, r3 && r3.length <= Math.max(m4, g4) && r3.length <= Math.max(b5, y3) && (t5.splice(s4[i3 - 1], 0, [n3, r3]), t5[s4[i3 - 1] + 1][0] = 1, i3--, p7 = --i3 > 0 ? s4[i3 - 1] : -1, m4 = 0, g4 = 0, b5 = 0, y3 = 0, r3 = null, e5 = true)), p7++;
                for (e5 && f2(t5), (function(t6) {
                  function e6(t7, e7) {
                    if (!t7 || !e7) return 6;
                    var n5 = t7.charAt(t7.length - 1), s6 = e7.charAt(0), i5 = n5.match(a3), r5 = s6.match(a3), o4 = i5 && n5.match(c2), l3 = r5 && s6.match(c2), f4 = o4 && n5.match(h2), p9 = l3 && s6.match(h2), m6 = f4 && t7.match(u2), g6 = p9 && e7.match(d2);
                    return m6 || g6 ? 5 : f4 || p9 ? 4 : i5 && !o4 && l3 ? 3 : o4 || l3 ? 2 : i5 || r5 ? 1 : 0;
                  }
                  for (var n4 = 1; n4 < t6.length - 1; ) {
                    if (0 == t6[n4 - 1][0] && 0 == t6[n4 + 1][0]) {
                      var s5 = t6[n4 - 1][1], i4 = t6[n4][1], r4 = t6[n4 + 1][1], o3 = l2(s5, i4);
                      if (o3) {
                        var f3 = i4.substring(i4.length - o3);
                        s5 = s5.substring(0, s5.length - o3), i4 = f3 + i4.substring(0, i4.length - o3), r4 = f3 + r4;
                      }
                      for (var p8 = s5, m5 = i4, g5 = r4, b6 = e6(s5, i4) + e6(i4, r4); i4.charAt(0) === r4.charAt(0); ) {
                        s5 += i4.charAt(0), i4 = i4.substring(1) + r4.charAt(0), r4 = r4.substring(1);
                        var y4 = e6(s5, i4) + e6(i4, r4);
                        y4 >= b6 && (b6 = y4, p8 = s5, m5 = i4, g5 = r4);
                      }
                      t6[n4 - 1][1] != p8 && (p8 ? t6[n4 - 1][1] = p8 : (t6.splice(n4 - 1, 1), n4--), t6[n4][1] = m5, g5 ? t6[n4 + 1][1] = g5 : (t6.splice(n4 + 1, 1), n4--));
                    }
                    n4++;
                  }
                })(t5), p7 = 1; p7 < t5.length; ) {
                  if (t5[p7 - 1][0] == n3 && 1 == t5[p7][0]) {
                    var A8 = t5[p7 - 1][1], N3 = t5[p7][1], v3 = o2(A8, N3), E6 = o2(N3, A8);
                    v3 >= E6 ? (v3 >= A8.length / 2 || v3 >= N3.length / 2) && (t5.splice(p7, 0, [0, N3.substring(0, v3)]), t5[p7 - 1][1] = A8.substring(0, A8.length - v3), t5[p7 + 1][1] = N3.substring(v3), p7++) : (E6 >= A8.length / 2 || E6 >= N3.length / 2) && (t5.splice(p7, 0, [0, A8.substring(0, E6)]), t5[p7 - 1][0] = 1, t5[p7 - 1][1] = N3.substring(0, N3.length - E6), t5[p7 + 1][0] = n3, t5[p7 + 1][1] = A8.substring(E6), p7++), p7++;
                  }
                  p7++;
                }
              })(E5), E5;
            }
            function i2(t4, e4, n4, i3) {
              var r3 = t4.substring(0, n4), o3 = e4.substring(0, i3), l3 = t4.substring(n4), a4 = e4.substring(i3), c3 = s3(r3, o3), h3 = s3(l3, a4);
              return c3.concat(h3);
            }
            function r2(t4, e4) {
              if (!t4 || !e4 || t4.charAt(0) !== e4.charAt(0)) return 0;
              for (var n4 = 0, s4 = Math.min(t4.length, e4.length), i3 = s4, r3 = 0; n4 < i3; ) t4.substring(r3, i3) == e4.substring(r3, i3) ? r3 = n4 = i3 : s4 = i3, i3 = Math.floor((s4 - n4) / 2 + n4);
              return p5(t4.charCodeAt(i3 - 1)) && i3--, i3;
            }
            function o2(t4, e4) {
              var n4 = t4.length, s4 = e4.length;
              if (0 == n4 || 0 == s4) return 0;
              n4 > s4 ? t4 = t4.substring(n4 - s4) : n4 < s4 && (e4 = e4.substring(0, n4));
              var i3 = Math.min(n4, s4);
              if (t4 == e4) return i3;
              for (var r3 = 0, o3 = 1; ; ) {
                var l3 = t4.substring(i3 - o3), a4 = e4.indexOf(l3);
                if (-1 == a4) return r3;
                o3 += a4, 0 != a4 && t4.substring(i3 - o3) != e4.substring(0, o3) || (r3 = o3, o3++);
              }
            }
            function l2(t4, e4) {
              if (!t4 || !e4 || t4.slice(-1) !== e4.slice(-1)) return 0;
              for (var n4 = 0, s4 = Math.min(t4.length, e4.length), i3 = s4, r3 = 0; n4 < i3; ) t4.substring(t4.length - i3, t4.length - r3) == e4.substring(e4.length - i3, e4.length - r3) ? r3 = n4 = i3 : s4 = i3, i3 = Math.floor((s4 - n4) / 2 + n4);
              return m2(t4.charCodeAt(t4.length - i3)) && i3--, i3;
            }
            var a3 = /[^a-zA-Z0-9]/, c2 = /\s/, h2 = /[\r\n]/, u2 = /\n\r?\n$/, d2 = /^\r?\n\r?\n/;
            function f2(t4, e4) {
              t4.push([0, ""]);
              for (var s4, i3 = 0, o3 = 0, a4 = 0, c3 = "", h3 = ""; i3 < t4.length; ) if (i3 < t4.length - 1 && !t4[i3][1]) t4.splice(i3, 1);
              else switch (t4[i3][0]) {
                case 1:
                  a4++, h3 += t4[i3][1], i3++;
                  break;
                case n3:
                  o3++, c3 += t4[i3][1], i3++;
                  break;
                case 0:
                  var u3 = i3 - a4 - o3 - 1;
                  if (e4) {
                    if (u3 >= 0 && b3(t4[u3][1])) {
                      var d3 = t4[u3][1].slice(-1);
                      if (t4[u3][1] = t4[u3][1].slice(0, -1), c3 = d3 + c3, h3 = d3 + h3, !t4[u3][1]) {
                        t4.splice(u3, 1), i3--;
                        var p6 = u3 - 1;
                        t4[p6] && 1 === t4[p6][0] && (a4++, h3 = t4[p6][1] + h3, p6--), t4[p6] && t4[p6][0] === n3 && (o3++, c3 = t4[p6][1] + c3, p6--), u3 = p6;
                      }
                    }
                    g2(t4[i3][1]) && (d3 = t4[i3][1].charAt(0), t4[i3][1] = t4[i3][1].slice(1), c3 += d3, h3 += d3);
                  }
                  if (i3 < t4.length - 1 && !t4[i3][1]) {
                    t4.splice(i3, 1);
                    break;
                  }
                  if (c3.length > 0 || h3.length > 0) {
                    c3.length > 0 && h3.length > 0 && (0 !== (s4 = r2(h3, c3)) && (u3 >= 0 ? t4[u3][1] += h3.substring(0, s4) : (t4.splice(0, 0, [0, h3.substring(0, s4)]), i3++), h3 = h3.substring(s4), c3 = c3.substring(s4)), 0 !== (s4 = l2(h3, c3)) && (t4[i3][1] = h3.substring(h3.length - s4) + t4[i3][1], h3 = h3.substring(0, h3.length - s4), c3 = c3.substring(0, c3.length - s4)));
                    var m3 = a4 + o3;
                    0 === c3.length && 0 === h3.length ? (t4.splice(i3 - m3, m3), i3 -= m3) : 0 === c3.length ? (t4.splice(i3 - m3, m3, [1, h3]), i3 = i3 - m3 + 1) : 0 === h3.length ? (t4.splice(i3 - m3, m3, [n3, c3]), i3 = i3 - m3 + 1) : (t4.splice(i3 - m3, m3, [n3, c3], [1, h3]), i3 = i3 - m3 + 2);
                  }
                  0 !== i3 && 0 === t4[i3 - 1][0] ? (t4[i3 - 1][1] += t4[i3][1], t4.splice(i3, 1)) : i3++, a4 = 0, o3 = 0, c3 = "", h3 = "";
              }
              "" === t4[t4.length - 1][1] && t4.pop();
              var y3 = false;
              for (i3 = 1; i3 < t4.length - 1; ) 0 === t4[i3 - 1][0] && 0 === t4[i3 + 1][0] && (t4[i3][1].substring(t4[i3][1].length - t4[i3 - 1][1].length) === t4[i3 - 1][1] ? (t4[i3][1] = t4[i3 - 1][1] + t4[i3][1].substring(0, t4[i3][1].length - t4[i3 - 1][1].length), t4[i3 + 1][1] = t4[i3 - 1][1] + t4[i3 + 1][1], t4.splice(i3 - 1, 1), y3 = true) : t4[i3][1].substring(0, t4[i3 + 1][1].length) == t4[i3 + 1][1] && (t4[i3 - 1][1] += t4[i3 + 1][1], t4[i3][1] = t4[i3][1].substring(t4[i3 + 1][1].length) + t4[i3 + 1][1], t4.splice(i3 + 1, 1), y3 = true)), i3++;
              y3 && f2(t4, e4);
            }
            function p5(t4) {
              return t4 >= 55296 && t4 <= 56319;
            }
            function m2(t4) {
              return t4 >= 56320 && t4 <= 57343;
            }
            function g2(t4) {
              return m2(t4.charCodeAt(0));
            }
            function b3(t4) {
              return p5(t4.charCodeAt(t4.length - 1));
            }
            function y2(t4, e4, s4, i3) {
              return b3(t4) || g2(i3) ? null : (function(t5) {
                for (var e5 = [], n4 = 0; n4 < t5.length; n4++) t5[n4][1].length > 0 && e5.push(t5[n4]);
                return e5;
              })([[0, t4], [n3, e4], [1, s4], [0, i3]]);
            }
            function A6(t4, e4, n4, i3) {
              return s3(t4, e4, n4, i3, true);
            }
            A6.INSERT = 1, A6.DELETE = n3, A6.EQUAL = 0, e3.exports = A6;
          } }, function() {
            return i || (0, s2[a(s2)[0]])((i = { exports: {} }).exports, i), i.exports;
          })()), d = function(t3) {
            return JSON.parse(JSON.stringify(t3));
          };
          function f(t3) {
            return t3 !== Object(t3);
          }
          var p, m, g = function t3(e3, n3) {
            if (e3 === n3) return true;
            if (f(e3) || f(n3)) return e3 === n3;
            if (Object.keys(e3).length !== Object.keys(n3).length) return false;
            for (let s3 in e3) {
              if (!(s3 in n3)) return false;
              if (!t3(e3[s3], n3[s3])) return false;
            }
            return true;
          };
          (m = p || (p = {})).compose = function(t3 = {}, e3 = {}, n3 = false) {
            "object" != typeof t3 && (t3 = {}), "object" != typeof e3 && (e3 = {});
            let s3 = d(e3);
            n3 || (s3 = Object.keys(s3).reduce(((t4, e4) => (null != s3[e4] && (t4[e4] = s3[e4]), t4)), {}));
            for (const n4 in t3) void 0 !== t3[n4] && void 0 === e3[n4] && (s3[n4] = t3[n4]);
            return Object.keys(s3).length > 0 ? s3 : void 0;
          }, m.diff = function(t3 = {}, e3 = {}) {
            "object" != typeof t3 && (t3 = {}), "object" != typeof e3 && (e3 = {});
            const n3 = Object.keys(t3).concat(Object.keys(e3)).reduce(((n4, s3) => (g(t3[s3], e3[s3]) || (n4[s3] = void 0 === e3[s3] ? null : e3[s3]), n4)), {});
            return Object.keys(n3).length > 0 ? n3 : void 0;
          }, m.invert = function(t3 = {}, e3 = {}) {
            t3 = t3 || {};
            const n3 = Object.keys(e3).reduce(((n4, s3) => (e3[s3] !== t3[s3] && void 0 !== t3[s3] && (n4[s3] = e3[s3]), n4)), {});
            return Object.keys(t3).reduce(((n4, s3) => (t3[s3] !== e3[s3] && void 0 === e3[s3] && (n4[s3] = null), n4)), n3);
          }, m.transform = function(t3, e3, n3 = false) {
            if ("object" != typeof t3) return e3;
            if ("object" != typeof e3) return;
            if (!n3) return e3;
            const s3 = Object.keys(e3).reduce(((n4, s4) => (void 0 === t3[s4] && (n4[s4] = e3[s4]), n4)), {});
            return Object.keys(s3).length > 0 ? s3 : void 0;
          };
          var b, y = p;
          (b || (b = {})).length = function(t3) {
            return "number" == typeof t3.delete ? t3.delete : "number" == typeof t3.retain ? t3.retain : "object" == typeof t3.retain && null !== t3.retain ? 1 : "string" == typeof t3.insert ? t3.insert.length : 1;
          };
          var A5 = b, N = class {
            ops;
            index;
            offset;
            constructor(t3) {
              this.ops = t3, this.index = 0, this.offset = 0;
            }
            hasNext() {
              return this.peekLength() < 1 / 0;
            }
            next(t3) {
              t3 || (t3 = 1 / 0);
              const e3 = this.ops[this.index];
              if (e3) {
                const n3 = this.offset, s3 = A5.length(e3);
                if (t3 >= s3 - n3 ? (t3 = s3 - n3, this.index += 1, this.offset = 0) : this.offset += t3, "number" == typeof e3.delete) return { delete: t3 };
                {
                  const s4 = {};
                  return e3.attributes && (s4.attributes = e3.attributes), "number" == typeof e3.retain ? s4.retain = t3 : "object" == typeof e3.retain && null !== e3.retain ? s4.retain = e3.retain : "string" == typeof e3.insert ? s4.insert = e3.insert.substr(n3, t3) : s4.insert = e3.insert, s4;
                }
              }
              return { retain: 1 / 0 };
            }
            peek() {
              return this.ops[this.index];
            }
            peekLength() {
              return this.ops[this.index] ? A5.length(this.ops[this.index]) - this.offset : 1 / 0;
            }
            peekType() {
              const t3 = this.ops[this.index];
              return t3 ? "number" == typeof t3.delete ? "delete" : "number" == typeof t3.retain || "object" == typeof t3.retain && null !== t3.retain ? "retain" : "insert" : "retain";
            }
            rest() {
              if (this.hasNext()) {
                if (0 === this.offset) return this.ops.slice(this.index);
                {
                  const t3 = this.offset, e3 = this.index, n3 = this.next(), s3 = this.ops.slice(this.index);
                  return this.offset = t3, this.index = e3, [n3].concat(s3);
                }
              }
              return [];
            }
          }, v = String.fromCharCode(0), E4 = (t3, e3) => {
            if ("object" != typeof t3 || null === t3) throw new Error("cannot retain a " + typeof t3);
            if ("object" != typeof e3 || null === e3) throw new Error("cannot retain a " + typeof e3);
            const n3 = Object.keys(t3)[0];
            if (!n3 || n3 !== Object.keys(e3)[0]) throw new Error(`embed types not matched: ${n3} != ${Object.keys(e3)[0]}`);
            return [n3, t3[n3], e3[n3]];
          }, x = class t3 {
            static Op = A5;
            static OpIterator = N;
            static AttributeMap = y;
            static handlers = {};
            static registerEmbed(t4, e3) {
              this.handlers[t4] = e3;
            }
            static unregisterEmbed(t4) {
              delete this.handlers[t4];
            }
            static getHandler(t4) {
              const e3 = this.handlers[t4];
              if (!e3) throw new Error(`no handlers for embed type "${t4}"`);
              return e3;
            }
            ops;
            inverted;
            constructor(t4) {
              Array.isArray(t4) ? this.ops = t4 : null != t4 && Array.isArray(t4.ops) ? (this.ops = t4.ops, this.inverted = t4.inverted) : this.ops = [];
            }
            insert(t4, e3) {
              const n3 = {};
              return "string" == typeof t4 && 0 === t4.length ? this : (n3.insert = t4, null != e3 && "object" == typeof e3 && Object.keys(e3).length > 0 && (n3.attributes = e3), this.push(n3));
            }
            delete(t4) {
              return t4 <= 0 ? this : this.push({ delete: t4 });
            }
            retain(t4, e3) {
              if ("number" == typeof t4 && t4 <= 0) return this;
              const n3 = { retain: t4 };
              return null != e3 && "object" == typeof e3 && Object.keys(e3).length > 0 && (n3.attributes = e3), this.push(n3);
            }
            push(t4) {
              let e3 = this.ops.length, n3 = this.ops[e3 - 1];
              if (t4 = d(t4), "object" == typeof n3) {
                if ("number" == typeof t4.delete && "number" == typeof n3.delete) return this.ops[e3 - 1] = { delete: n3.delete + t4.delete }, this;
                if ("number" == typeof n3.delete && null != t4.insert && (e3 -= 1, n3 = this.ops[e3 - 1], "object" != typeof n3)) return this.ops.unshift(t4), this;
                if (g(t4.attributes, n3.attributes)) {
                  if ("string" == typeof t4.insert && "string" == typeof n3.insert) return this.ops[e3 - 1] = { insert: n3.insert + t4.insert }, "object" == typeof t4.attributes && (this.ops[e3 - 1].attributes = t4.attributes), this;
                  if ("number" == typeof t4.retain && "number" == typeof n3.retain) return this.ops[e3 - 1] = { retain: n3.retain + t4.retain }, "object" == typeof t4.attributes && (this.ops[e3 - 1].attributes = t4.attributes), this;
                }
              }
              return e3 === this.ops.length ? this.ops.push(t4) : this.ops.splice(e3, 0, t4), this;
            }
            chop() {
              const t4 = this.ops[this.ops.length - 1];
              return t4 && "number" == typeof t4.retain && !t4.attributes && this.ops.pop(), this;
            }
            filter(t4) {
              return this.ops.filter(t4);
            }
            forEach(t4) {
              this.ops.forEach(t4);
            }
            map(t4) {
              return this.ops.map(t4);
            }
            partition(t4) {
              const e3 = [], n3 = [];
              return this.forEach(((s3) => {
                (t4(s3) ? e3 : n3).push(s3);
              })), [e3, n3];
            }
            reduce(t4, e3) {
              return this.ops.reduce(t4, e3);
            }
            changeLength() {
              return this.reduce(((t4, e3) => e3.insert ? t4 + A5.length(e3) : e3.delete ? t4 - e3.delete : t4), 0);
            }
            length() {
              return this.reduce(((t4, e3) => t4 + A5.length(e3)), 0);
            }
            slice(e3 = 0, n3 = 1 / 0) {
              const s3 = [], i2 = new N(this.ops);
              let r2 = 0;
              for (; r2 < n3 && i2.hasNext(); ) {
                let t4;
                r2 < e3 ? t4 = i2.next(e3 - r2) : (t4 = i2.next(n3 - r2), s3.push(t4)), r2 += A5.length(t4);
              }
              return new t3(s3);
            }
            compose(e3) {
              const n3 = new N(this.ops), s3 = new N(e3.ops), i2 = [], r2 = s3.peek();
              if (null != r2 && "number" == typeof r2.retain && null == r2.attributes) {
                let t4 = r2.retain;
                for (; "insert" === n3.peekType() && n3.peekLength() <= t4; ) t4 -= n3.peekLength(), i2.push(n3.next());
                r2.retain - t4 > 0 && s3.next(r2.retain - t4);
              }
              const o2 = new t3(i2);
              for (; n3.hasNext() || s3.hasNext(); ) if ("insert" === s3.peekType()) o2.push(s3.next());
              else if ("delete" === n3.peekType()) o2.push(n3.next());
              else {
                const e4 = Math.min(n3.peekLength(), s3.peekLength()), i3 = n3.next(e4), r3 = s3.next(e4);
                if (r3.retain) {
                  const l2 = {};
                  if ("number" == typeof i3.retain) l2.retain = "number" == typeof r3.retain ? e4 : r3.retain;
                  else if ("number" == typeof r3.retain) null == i3.retain ? l2.insert = i3.insert : l2.retain = i3.retain;
                  else {
                    const e5 = null == i3.retain ? "insert" : "retain", [n4, s4, o3] = E4(i3[e5], r3.retain), a4 = t3.getHandler(n4);
                    l2[e5] = { [n4]: a4.compose(s4, o3, "retain" === e5) };
                  }
                  const a3 = y.compose(i3.attributes, r3.attributes, "number" == typeof i3.retain);
                  if (a3 && (l2.attributes = a3), o2.push(l2), !s3.hasNext() && g(o2.ops[o2.ops.length - 1], l2)) {
                    const e5 = new t3(n3.rest());
                    return o2.concat(e5).chop();
                  }
                } else "number" == typeof r3.delete && ("number" == typeof i3.retain || "object" == typeof i3.retain && null !== i3.retain) && o2.push(r3);
              }
              return o2.chop();
            }
            concat(e3) {
              const n3 = new t3(this.ops.slice());
              return e3.ops.length > 0 && (n3.push(e3.ops[0]), n3.ops = n3.ops.concat(e3.ops.slice(1))), n3;
            }
            diff(e3, n3) {
              if (this.ops === e3.ops) return new t3();
              const s3 = [this, e3].map(((t4) => t4.map(((n4) => {
                if (null != n4.insert) return "string" == typeof n4.insert ? n4.insert : v;
                throw new Error("diff() called " + (t4 === e3 ? "on" : "with") + " non-document");
              })).join(""))), i2 = new t3(), r2 = (0, u.default)(s3[0], s3[1], n3, true), o2 = new N(this.ops), l2 = new N(e3.ops);
              return r2.forEach(((t4) => {
                let e4 = t4[1].length;
                for (; e4 > 0; ) {
                  let n4 = 0;
                  switch (t4[0]) {
                    case u.default.INSERT:
                      n4 = Math.min(l2.peekLength(), e4), i2.push(l2.next(n4));
                      break;
                    case u.default.DELETE:
                      n4 = Math.min(e4, o2.peekLength()), o2.next(n4), i2.delete(n4);
                      break;
                    case u.default.EQUAL:
                      n4 = Math.min(o2.peekLength(), l2.peekLength(), e4);
                      const t5 = o2.next(n4), s4 = l2.next(n4);
                      g(t5.insert, s4.insert) ? i2.retain(n4, y.diff(t5.attributes, s4.attributes)) : i2.push(s4).delete(n4);
                  }
                  e4 -= n4;
                }
              })), i2.chop();
            }
            eachLine(e3, n3 = "\n") {
              const s3 = new N(this.ops);
              let i2 = new t3(), r2 = 0;
              for (; s3.hasNext(); ) {
                if ("insert" !== s3.peekType()) return;
                const o2 = s3.peek(), l2 = A5.length(o2) - s3.peekLength(), a3 = "string" == typeof o2.insert ? o2.insert.indexOf(n3, l2) - l2 : -1;
                if (a3 < 0) i2.push(s3.next());
                else if (a3 > 0) i2.push(s3.next(a3));
                else {
                  if (false === e3(i2, s3.next(1).attributes || {}, r2)) return;
                  r2 += 1, i2 = new t3();
                }
              }
              i2.length() > 0 && e3(i2, {}, r2);
            }
            invert(e3) {
              const n3 = new t3();
              return this.reduce(((s3, i2) => {
                if (i2.insert) n3.delete(A5.length(i2));
                else {
                  if ("number" == typeof i2.retain && null == i2.attributes) return n3.retain(i2.retain), s3 + i2.retain;
                  if (i2.delete || "number" == typeof i2.retain) {
                    const t4 = i2.delete || i2.retain;
                    return e3.slice(s3, s3 + t4).forEach(((t5) => {
                      i2.delete ? n3.push(t5) : i2.retain && i2.attributes && n3.retain(A5.length(t5), y.invert(i2.attributes, t5.attributes));
                    })), s3 + t4;
                  }
                  if ("object" == typeof i2.retain && null !== i2.retain) {
                    const r2 = e3.slice(s3, s3 + 1), o2 = new N(r2.ops).next(), [l2, a3, c2] = E4(i2.retain, o2.insert), h2 = t3.getHandler(l2);
                    return n3.retain({ [l2]: h2.invert(a3, c2) }, y.invert(i2.attributes, o2.attributes)), s3 + 1;
                  }
                }
                return s3;
              }), 0), n3.chop();
            }
            transform(e3, n3 = false) {
              if (n3 = !!n3, "number" == typeof e3) return this.transformPosition(e3, n3);
              const s3 = e3, i2 = new N(this.ops), r2 = new N(s3.ops), o2 = new t3();
              for (; i2.hasNext() || r2.hasNext(); ) if ("insert" !== i2.peekType() || !n3 && "insert" === r2.peekType()) if ("insert" === r2.peekType()) o2.push(r2.next());
              else {
                const e4 = Math.min(i2.peekLength(), r2.peekLength()), s4 = i2.next(e4), l2 = r2.next(e4);
                if (s4.delete) continue;
                if (l2.delete) o2.push(l2);
                else {
                  const i3 = s4.retain, r3 = l2.retain;
                  let a3 = "object" == typeof r3 && null !== r3 ? r3 : e4;
                  if ("object" == typeof i3 && null !== i3 && "object" == typeof r3 && null !== r3) {
                    const e5 = Object.keys(i3)[0];
                    if (e5 === Object.keys(r3)[0]) {
                      const s5 = t3.getHandler(e5);
                      s5 && (a3 = { [e5]: s5.transform(i3[e5], r3[e5], n3) });
                    }
                  }
                  o2.retain(a3, y.transform(s4.attributes, l2.attributes, n3));
                }
              }
              else o2.retain(A5.length(i2.next()));
              return o2.chop();
            }
            transformPosition(t4, e3 = false) {
              e3 = !!e3;
              const n3 = new N(this.ops);
              let s3 = 0;
              for (; n3.hasNext() && s3 <= t4; ) {
                const i2 = n3.peekLength(), r2 = n3.peekType();
                n3.next(), "delete" !== r2 ? ("insert" === r2 && (s3 < t4 || !e3) && (t4 += i2), s3 += i2) : t4 -= Math.min(i2, t4 - s3);
              }
              return t4;
            }
          }, L = x;
          module.exports = x, module.exports.default = x;
        }, 3: function(t2, e2, n2) {
          n2.r(e2), n2.d(e2, { Attributor: function() {
            return i;
          }, AttributorStore: function() {
            return d;
          }, BlockBlot: function() {
            return L;
          }, ClassAttributor: function() {
            return c;
          }, ContainerBlot: function() {
            return T;
          }, EmbedBlot: function() {
            return k;
          }, InlineBlot: function() {
            return E4;
          }, LeafBlot: function() {
            return g;
          }, ParentBlot: function() {
            return N;
          }, Registry: function() {
            return l;
          }, Scope: function() {
            return s2;
          }, ScrollBlot: function() {
            return C;
          }, StyleAttributor: function() {
            return u;
          }, TextBlot: function() {
            return R2;
          } });
          var s2 = ((t3) => (t3[t3.TYPE = 3] = "TYPE", t3[t3.LEVEL = 12] = "LEVEL", t3[t3.ATTRIBUTE = 13] = "ATTRIBUTE", t3[t3.BLOT = 14] = "BLOT", t3[t3.INLINE = 7] = "INLINE", t3[t3.BLOCK = 11] = "BLOCK", t3[t3.BLOCK_BLOT = 10] = "BLOCK_BLOT", t3[t3.INLINE_BLOT = 6] = "INLINE_BLOT", t3[t3.BLOCK_ATTRIBUTE = 9] = "BLOCK_ATTRIBUTE", t3[t3.INLINE_ATTRIBUTE = 5] = "INLINE_ATTRIBUTE", t3[t3.ANY = 15] = "ANY", t3))(s2 || {});
          class i {
            constructor(t3, e3, n3 = {}) {
              this.attrName = t3, this.keyName = e3;
              const i2 = s2.TYPE & s2.ATTRIBUTE;
              this.scope = null != n3.scope ? n3.scope & s2.LEVEL | i2 : s2.ATTRIBUTE, null != n3.whitelist && (this.whitelist = n3.whitelist);
            }
            static keys(t3) {
              return Array.from(t3.attributes).map(((t4) => t4.name));
            }
            add(t3, e3) {
              return !!this.canAdd(t3, e3) && (t3.setAttribute(this.keyName, e3), true);
            }
            canAdd(t3, e3) {
              return null == this.whitelist || ("string" == typeof e3 ? this.whitelist.indexOf(e3.replace(/["']/g, "")) > -1 : this.whitelist.indexOf(e3) > -1);
            }
            remove(t3) {
              t3.removeAttribute(this.keyName);
            }
            value(t3) {
              const e3 = t3.getAttribute(this.keyName);
              return this.canAdd(t3, e3) && e3 ? e3 : "";
            }
          }
          class r extends Error {
            constructor(t3) {
              super(t3 = "[Parchment] " + t3), this.message = t3, this.name = this.constructor.name;
            }
          }
          const o = class t3 {
            constructor() {
              this.attributes = {}, this.classes = {}, this.tags = {}, this.types = {};
            }
            static find(t4, e3 = false) {
              if (null == t4) return null;
              if (this.blots.has(t4)) return this.blots.get(t4) || null;
              if (e3) {
                let n3 = null;
                try {
                  n3 = t4.parentNode;
                } catch {
                  return null;
                }
                return this.find(n3, e3);
              }
              return null;
            }
            create(e3, n3, s3) {
              const i2 = this.query(n3);
              if (null == i2) throw new r(`Unable to create ${n3} blot`);
              const o2 = i2, l2 = n3 instanceof Node || n3.nodeType === Node.TEXT_NODE ? n3 : o2.create(s3), a3 = new o2(e3, l2, s3);
              return t3.blots.set(a3.domNode, a3), a3;
            }
            find(e3, n3 = false) {
              return t3.find(e3, n3);
            }
            query(t4, e3 = s2.ANY) {
              let n3;
              return "string" == typeof t4 ? n3 = this.types[t4] || this.attributes[t4] : t4 instanceof Text || t4.nodeType === Node.TEXT_NODE ? n3 = this.types.text : "number" == typeof t4 ? t4 & s2.LEVEL & s2.BLOCK ? n3 = this.types.block : t4 & s2.LEVEL & s2.INLINE && (n3 = this.types.inline) : t4 instanceof Element && ((t4.getAttribute("class") || "").split(/\s+/).some(((t5) => (n3 = this.classes[t5], !!n3))), n3 = n3 || this.tags[t4.tagName]), null == n3 ? null : "scope" in n3 && e3 & s2.LEVEL & n3.scope && e3 & s2.TYPE & n3.scope ? n3 : null;
            }
            register(...t4) {
              return t4.map(((t5) => {
                const e3 = "blotName" in t5, n3 = "attrName" in t5;
                if (!e3 && !n3) throw new r("Invalid definition");
                if (e3 && "abstract" === t5.blotName) throw new r("Cannot register abstract class");
                const s3 = e3 ? t5.blotName : n3 ? t5.attrName : void 0;
                return this.types[s3] = t5, n3 ? "string" == typeof t5.keyName && (this.attributes[t5.keyName] = t5) : e3 && (t5.className && (this.classes[t5.className] = t5), t5.tagName && (Array.isArray(t5.tagName) ? t5.tagName = t5.tagName.map(((t6) => t6.toUpperCase())) : t5.tagName = t5.tagName.toUpperCase(), (Array.isArray(t5.tagName) ? t5.tagName : [t5.tagName]).forEach(((e4) => {
                  (null == this.tags[e4] || null == t5.className) && (this.tags[e4] = t5);
                })))), t5;
              }));
            }
          };
          o.blots = /* @__PURE__ */ new WeakMap();
          let l = o;
          function a(t3, e3) {
            return (t3.getAttribute("class") || "").split(/\s+/).filter(((t4) => 0 === t4.indexOf(`${e3}-`)));
          }
          const c = class extends i {
            static keys(t3) {
              return (t3.getAttribute("class") || "").split(/\s+/).map(((t4) => t4.split("-").slice(0, -1).join("-")));
            }
            add(t3, e3) {
              return !!this.canAdd(t3, e3) && (this.remove(t3), t3.classList.add(`${this.keyName}-${e3}`), true);
            }
            remove(t3) {
              a(t3, this.keyName).forEach(((e3) => {
                t3.classList.remove(e3);
              })), 0 === t3.classList.length && t3.removeAttribute("class");
            }
            value(t3) {
              const e3 = (a(t3, this.keyName)[0] || "").slice(this.keyName.length + 1);
              return this.canAdd(t3, e3) ? e3 : "";
            }
          };
          function h(t3) {
            const e3 = t3.split("-"), n3 = e3.slice(1).map(((t4) => t4[0].toUpperCase() + t4.slice(1))).join("");
            return e3[0] + n3;
          }
          const u = class extends i {
            static keys(t3) {
              return (t3.getAttribute("style") || "").split(";").map(((t4) => t4.split(":")[0].trim()));
            }
            add(t3, e3) {
              return !!this.canAdd(t3, e3) && (t3.style[h(this.keyName)] = e3, true);
            }
            remove(t3) {
              t3.style[h(this.keyName)] = "", t3.getAttribute("style") || t3.removeAttribute("style");
            }
            value(t3) {
              const e3 = t3.style[h(this.keyName)];
              return this.canAdd(t3, e3) ? e3 : "";
            }
          }, d = class {
            constructor(t3) {
              this.attributes = {}, this.domNode = t3, this.build();
            }
            attribute(t3, e3) {
              e3 ? t3.add(this.domNode, e3) && (null != t3.value(this.domNode) ? this.attributes[t3.attrName] = t3 : delete this.attributes[t3.attrName]) : (t3.remove(this.domNode), delete this.attributes[t3.attrName]);
            }
            build() {
              this.attributes = {};
              const t3 = l.find(this.domNode);
              if (null == t3) return;
              const e3 = i.keys(this.domNode), n3 = c.keys(this.domNode), r2 = u.keys(this.domNode);
              e3.concat(n3).concat(r2).forEach(((e4) => {
                const n4 = t3.scroll.query(e4, s2.ATTRIBUTE);
                n4 instanceof i && (this.attributes[n4.attrName] = n4);
              }));
            }
            copy(t3) {
              Object.keys(this.attributes).forEach(((e3) => {
                const n3 = this.attributes[e3].value(this.domNode);
                t3.format(e3, n3);
              }));
            }
            move(t3) {
              this.copy(t3), Object.keys(this.attributes).forEach(((t4) => {
                this.attributes[t4].remove(this.domNode);
              })), this.attributes = {};
            }
            values() {
              return Object.keys(this.attributes).reduce(((t3, e3) => (t3[e3] = this.attributes[e3].value(this.domNode), t3)), {});
            }
          }, f = class {
            constructor(t3, e3) {
              this.scroll = t3, this.domNode = e3, l.blots.set(e3, this), this.prev = null, this.next = null;
            }
            static create(t3) {
              if (null == this.tagName) throw new r("Blot definition missing tagName");
              let e3, n3;
              return Array.isArray(this.tagName) ? ("string" == typeof t3 ? (n3 = t3.toUpperCase(), parseInt(n3, 10).toString() === n3 && (n3 = parseInt(n3, 10))) : "number" == typeof t3 && (n3 = t3), e3 = "number" == typeof n3 ? document.createElement(this.tagName[n3 - 1]) : n3 && this.tagName.indexOf(n3) > -1 ? document.createElement(n3) : document.createElement(this.tagName[0])) : e3 = document.createElement(this.tagName), this.className && e3.classList.add(this.className), e3;
            }
            get statics() {
              return this.constructor;
            }
            attach() {
            }
            clone() {
              const t3 = this.domNode.cloneNode(false);
              return this.scroll.create(t3);
            }
            detach() {
              null != this.parent && this.parent.removeChild(this), l.blots.delete(this.domNode);
            }
            deleteAt(t3, e3) {
              this.isolate(t3, e3).remove();
            }
            formatAt(t3, e3, n3, i2) {
              const r2 = this.isolate(t3, e3);
              if (null != this.scroll.query(n3, s2.BLOT) && i2) r2.wrap(n3, i2);
              else if (null != this.scroll.query(n3, s2.ATTRIBUTE)) {
                const t4 = this.scroll.create(this.statics.scope);
                r2.wrap(t4), t4.format(n3, i2);
              }
            }
            insertAt(t3, e3, n3) {
              const s3 = null == n3 ? this.scroll.create("text", e3) : this.scroll.create(e3, n3), i2 = this.split(t3);
              this.parent.insertBefore(s3, i2 || void 0);
            }
            isolate(t3, e3) {
              const n3 = this.split(t3);
              if (null == n3) throw new Error("Attempt to isolate at end");
              return n3.split(e3), n3;
            }
            length() {
              return 1;
            }
            offset(t3 = this.parent) {
              return null == this.parent || this === t3 ? 0 : this.parent.children.offset(this) + this.parent.offset(t3);
            }
            optimize(t3) {
              this.statics.requiredContainer && !(this.parent instanceof this.statics.requiredContainer) && this.wrap(this.statics.requiredContainer.blotName);
            }
            remove() {
              null != this.domNode.parentNode && this.domNode.parentNode.removeChild(this.domNode), this.detach();
            }
            replaceWith(t3, e3) {
              const n3 = "string" == typeof t3 ? this.scroll.create(t3, e3) : t3;
              return null != this.parent && (this.parent.insertBefore(n3, this.next || void 0), this.remove()), n3;
            }
            split(t3, e3) {
              return 0 === t3 ? this : this.next;
            }
            update(t3, e3) {
            }
            wrap(t3, e3) {
              const n3 = "string" == typeof t3 ? this.scroll.create(t3, e3) : t3;
              if (null != this.parent && this.parent.insertBefore(n3, this.next || void 0), "function" != typeof n3.appendChild) throw new r(`Cannot wrap ${t3}`);
              return n3.appendChild(this), n3;
            }
          };
          f.blotName = "abstract";
          let p = f;
          const m = class extends p {
            static value(t3) {
              return true;
            }
            index(t3, e3) {
              return this.domNode === t3 || this.domNode.compareDocumentPosition(t3) & Node.DOCUMENT_POSITION_CONTAINED_BY ? Math.min(e3, 1) : -1;
            }
            position(t3, e3) {
              let n3 = Array.from(this.parent.domNode.childNodes).indexOf(this.domNode);
              return t3 > 0 && (n3 += 1), [this.parent.domNode, n3];
            }
            value() {
              return { [this.statics.blotName]: this.statics.value(this.domNode) || true };
            }
          };
          m.scope = s2.INLINE_BLOT;
          const g = m;
          class b {
            constructor() {
              this.head = null, this.tail = null, this.length = 0;
            }
            append(...t3) {
              if (this.insertBefore(t3[0], null), t3.length > 1) {
                const e3 = t3.slice(1);
                this.append(...e3);
              }
            }
            at(t3) {
              const e3 = this.iterator();
              let n3 = e3();
              for (; n3 && t3 > 0; ) t3 -= 1, n3 = e3();
              return n3;
            }
            contains(t3) {
              const e3 = this.iterator();
              let n3 = e3();
              for (; n3; ) {
                if (n3 === t3) return true;
                n3 = e3();
              }
              return false;
            }
            indexOf(t3) {
              const e3 = this.iterator();
              let n3 = e3(), s3 = 0;
              for (; n3; ) {
                if (n3 === t3) return s3;
                s3 += 1, n3 = e3();
              }
              return -1;
            }
            insertBefore(t3, e3) {
              null != t3 && (this.remove(t3), t3.next = e3, null != e3 ? (t3.prev = e3.prev, null != e3.prev && (e3.prev.next = t3), e3.prev = t3, e3 === this.head && (this.head = t3)) : null != this.tail ? (this.tail.next = t3, t3.prev = this.tail, this.tail = t3) : (t3.prev = null, this.head = this.tail = t3), this.length += 1);
            }
            offset(t3) {
              let e3 = 0, n3 = this.head;
              for (; null != n3; ) {
                if (n3 === t3) return e3;
                e3 += n3.length(), n3 = n3.next;
              }
              return -1;
            }
            remove(t3) {
              this.contains(t3) && (null != t3.prev && (t3.prev.next = t3.next), null != t3.next && (t3.next.prev = t3.prev), t3 === this.head && (this.head = t3.next), t3 === this.tail && (this.tail = t3.prev), this.length -= 1);
            }
            iterator(t3 = this.head) {
              return () => {
                const e3 = t3;
                return null != t3 && (t3 = t3.next), e3;
              };
            }
            find(t3, e3 = false) {
              const n3 = this.iterator();
              let s3 = n3();
              for (; s3; ) {
                const i2 = s3.length();
                if (t3 < i2 || e3 && t3 === i2 && (null == s3.next || 0 !== s3.next.length())) return [s3, t3];
                t3 -= i2, s3 = n3();
              }
              return [null, 0];
            }
            forEach(t3) {
              const e3 = this.iterator();
              let n3 = e3();
              for (; n3; ) t3(n3), n3 = e3();
            }
            forEachAt(t3, e3, n3) {
              if (e3 <= 0) return;
              const [s3, i2] = this.find(t3);
              let r2 = t3 - i2;
              const o2 = this.iterator(s3);
              let l2 = o2();
              for (; l2 && r2 < t3 + e3; ) {
                const s4 = l2.length();
                t3 > r2 ? n3(l2, t3 - r2, Math.min(e3, r2 + s4 - t3)) : n3(l2, 0, Math.min(s4, t3 + e3 - r2)), r2 += s4, l2 = o2();
              }
            }
            map(t3) {
              return this.reduce(((e3, n3) => (e3.push(t3(n3)), e3)), []);
            }
            reduce(t3, e3) {
              const n3 = this.iterator();
              let s3 = n3();
              for (; s3; ) e3 = t3(e3, s3), s3 = n3();
              return e3;
            }
          }
          function y(t3, e3) {
            const n3 = e3.find(t3);
            if (n3) return n3;
            try {
              return e3.create(t3);
            } catch {
              const n4 = e3.create(s2.INLINE);
              return Array.from(t3.childNodes).forEach(((t4) => {
                n4.domNode.appendChild(t4);
              })), t3.parentNode && t3.parentNode.replaceChild(n4.domNode, t3), n4.attach(), n4;
            }
          }
          const A5 = class t3 extends p {
            constructor(t4, e3) {
              super(t4, e3), this.uiNode = null, this.build();
            }
            appendChild(t4) {
              this.insertBefore(t4);
            }
            attach() {
              super.attach(), this.children.forEach(((t4) => {
                t4.attach();
              }));
            }
            attachUI(e3) {
              null != this.uiNode && this.uiNode.remove(), this.uiNode = e3, t3.uiClass && this.uiNode.classList.add(t3.uiClass), this.uiNode.setAttribute("contenteditable", "false"), this.domNode.insertBefore(this.uiNode, this.domNode.firstChild);
            }
            build() {
              this.children = new b(), Array.from(this.domNode.childNodes).filter(((t4) => t4 !== this.uiNode)).reverse().forEach(((t4) => {
                try {
                  const e3 = y(t4, this.scroll);
                  this.insertBefore(e3, this.children.head || void 0);
                } catch (t5) {
                  if (t5 instanceof r) return;
                  throw t5;
                }
              }));
            }
            deleteAt(t4, e3) {
              if (0 === t4 && e3 === this.length()) return this.remove();
              this.children.forEachAt(t4, e3, ((t5, e4, n3) => {
                t5.deleteAt(e4, n3);
              }));
            }
            descendant(e3, n3 = 0) {
              const [s3, i2] = this.children.find(n3);
              return null == e3.blotName && e3(s3) || null != e3.blotName && s3 instanceof e3 ? [s3, i2] : s3 instanceof t3 ? s3.descendant(e3, i2) : [null, -1];
            }
            descendants(e3, n3 = 0, s3 = Number.MAX_VALUE) {
              let i2 = [], r2 = s3;
              return this.children.forEachAt(n3, s3, ((n4, s4, o2) => {
                (null == e3.blotName && e3(n4) || null != e3.blotName && n4 instanceof e3) && i2.push(n4), n4 instanceof t3 && (i2 = i2.concat(n4.descendants(e3, s4, r2))), r2 -= o2;
              })), i2;
            }
            detach() {
              this.children.forEach(((t4) => {
                t4.detach();
              })), super.detach();
            }
            enforceAllowedChildren() {
              let e3 = false;
              this.children.forEach(((n3) => {
                e3 || this.statics.allowedChildren.some(((t4) => n3 instanceof t4)) || (n3.statics.scope === s2.BLOCK_BLOT ? (null != n3.next && this.splitAfter(n3), null != n3.prev && this.splitAfter(n3.prev), n3.parent.unwrap(), e3 = true) : n3 instanceof t3 ? n3.unwrap() : n3.remove());
              }));
            }
            formatAt(t4, e3, n3, s3) {
              this.children.forEachAt(t4, e3, ((t5, e4, i2) => {
                t5.formatAt(e4, i2, n3, s3);
              }));
            }
            insertAt(t4, e3, n3) {
              const [s3, i2] = this.children.find(t4);
              if (s3) s3.insertAt(i2, e3, n3);
              else {
                const t5 = null == n3 ? this.scroll.create("text", e3) : this.scroll.create(e3, n3);
                this.appendChild(t5);
              }
            }
            insertBefore(t4, e3) {
              null != t4.parent && t4.parent.children.remove(t4);
              let n3 = null;
              this.children.insertBefore(t4, e3 || null), t4.parent = this, null != e3 && (n3 = e3.domNode), (this.domNode.parentNode !== t4.domNode || this.domNode.nextSibling !== n3) && this.domNode.insertBefore(t4.domNode, n3), t4.attach();
            }
            length() {
              return this.children.reduce(((t4, e3) => t4 + e3.length()), 0);
            }
            moveChildren(t4, e3) {
              this.children.forEach(((n3) => {
                t4.insertBefore(n3, e3);
              }));
            }
            optimize(t4) {
              if (super.optimize(t4), this.enforceAllowedChildren(), null != this.uiNode && this.uiNode !== this.domNode.firstChild && this.domNode.insertBefore(this.uiNode, this.domNode.firstChild), 0 === this.children.length) if (null != this.statics.defaultChild) {
                const t5 = this.scroll.create(this.statics.defaultChild.blotName);
                this.appendChild(t5);
              } else this.remove();
            }
            path(e3, n3 = false) {
              const [s3, i2] = this.children.find(e3, n3), r2 = [[this, e3]];
              return s3 instanceof t3 ? r2.concat(s3.path(i2, n3)) : (null != s3 && r2.push([s3, i2]), r2);
            }
            removeChild(t4) {
              this.children.remove(t4);
            }
            replaceWith(e3, n3) {
              const s3 = "string" == typeof e3 ? this.scroll.create(e3, n3) : e3;
              return s3 instanceof t3 && this.moveChildren(s3), super.replaceWith(s3);
            }
            split(t4, e3 = false) {
              if (!e3) {
                if (0 === t4) return this;
                if (t4 === this.length()) return this.next;
              }
              const n3 = this.clone();
              return this.parent && this.parent.insertBefore(n3, this.next || void 0), this.children.forEachAt(t4, this.length(), ((t5, s3, i2) => {
                const r2 = t5.split(s3, e3);
                null != r2 && n3.appendChild(r2);
              })), n3;
            }
            splitAfter(t4) {
              const e3 = this.clone();
              for (; null != t4.next; ) e3.appendChild(t4.next);
              return this.parent && this.parent.insertBefore(e3, this.next || void 0), e3;
            }
            unwrap() {
              this.parent && this.moveChildren(this.parent, this.next || void 0), this.remove();
            }
            update(t4, e3) {
              const n3 = [], s3 = [];
              t4.forEach(((t5) => {
                t5.target === this.domNode && "childList" === t5.type && (n3.push(...t5.addedNodes), s3.push(...t5.removedNodes));
              })), s3.forEach(((t5) => {
                if (null != t5.parentNode && "IFRAME" !== t5.tagName && document.body.compareDocumentPosition(t5) & Node.DOCUMENT_POSITION_CONTAINED_BY) return;
                const e4 = this.scroll.find(t5);
                null != e4 && (null == e4.domNode.parentNode || e4.domNode.parentNode === this.domNode) && e4.detach();
              })), n3.filter(((t5) => t5.parentNode === this.domNode && t5 !== this.uiNode)).sort(((t5, e4) => t5 === e4 ? 0 : t5.compareDocumentPosition(e4) & Node.DOCUMENT_POSITION_FOLLOWING ? 1 : -1)).forEach(((t5) => {
                let e4 = null;
                null != t5.nextSibling && (e4 = this.scroll.find(t5.nextSibling));
                const n4 = y(t5, this.scroll);
                (n4.next !== e4 || null == n4.next) && (null != n4.parent && n4.parent.removeChild(this), this.insertBefore(n4, e4 || void 0));
              })), this.enforceAllowedChildren();
            }
          };
          A5.uiClass = "";
          const N = A5, v = class t3 extends N {
            static create(t4) {
              return super.create(t4);
            }
            static formats(e3, n3) {
              const s3 = n3.query(t3.blotName);
              if (null == s3 || e3.tagName !== s3.tagName) {
                if ("string" == typeof this.tagName) return true;
                if (Array.isArray(this.tagName)) return e3.tagName.toLowerCase();
              }
            }
            constructor(t4, e3) {
              super(t4, e3), this.attributes = new d(this.domNode);
            }
            format(e3, n3) {
              if (e3 !== this.statics.blotName || n3) {
                const t4 = this.scroll.query(e3, s2.INLINE);
                if (null == t4) return;
                t4 instanceof i ? this.attributes.attribute(t4, n3) : n3 && (e3 !== this.statics.blotName || this.formats()[e3] !== n3) && this.replaceWith(e3, n3);
              } else this.children.forEach(((e4) => {
                e4 instanceof t3 || (e4 = e4.wrap(t3.blotName, true)), this.attributes.copy(e4);
              })), this.unwrap();
            }
            formats() {
              const t4 = this.attributes.values(), e3 = this.statics.formats(this.domNode, this.scroll);
              return null != e3 && (t4[this.statics.blotName] = e3), t4;
            }
            formatAt(t4, e3, n3, i2) {
              null != this.formats()[n3] || this.scroll.query(n3, s2.ATTRIBUTE) ? this.isolate(t4, e3).format(n3, i2) : super.formatAt(t4, e3, n3, i2);
            }
            optimize(e3) {
              super.optimize(e3);
              const n3 = this.formats();
              if (0 === Object.keys(n3).length) return this.unwrap();
              const s3 = this.next;
              s3 instanceof t3 && s3.prev === this && (function(t4, e4) {
                if (Object.keys(t4).length !== Object.keys(e4).length) return false;
                for (const n4 in t4) if (t4[n4] !== e4[n4]) return false;
                return true;
              })(n3, s3.formats()) && (s3.moveChildren(this), s3.remove());
            }
            replaceWith(t4, e3) {
              const n3 = super.replaceWith(t4, e3);
              return this.attributes.copy(n3), n3;
            }
            update(t4, e3) {
              super.update(t4, e3), t4.some(((t5) => t5.target === this.domNode && "attributes" === t5.type)) && this.attributes.build();
            }
            wrap(e3, n3) {
              const s3 = super.wrap(e3, n3);
              return s3 instanceof t3 && this.attributes.move(s3), s3;
            }
          };
          v.allowedChildren = [v, g], v.blotName = "inline", v.scope = s2.INLINE_BLOT, v.tagName = "SPAN";
          const E4 = v, x = class t3 extends N {
            static create(t4) {
              return super.create(t4);
            }
            static formats(e3, n3) {
              const s3 = n3.query(t3.blotName);
              if (null == s3 || e3.tagName !== s3.tagName) {
                if ("string" == typeof this.tagName) return true;
                if (Array.isArray(this.tagName)) return e3.tagName.toLowerCase();
              }
            }
            constructor(t4, e3) {
              super(t4, e3), this.attributes = new d(this.domNode);
            }
            format(e3, n3) {
              const r2 = this.scroll.query(e3, s2.BLOCK);
              null != r2 && (r2 instanceof i ? this.attributes.attribute(r2, n3) : e3 !== this.statics.blotName || n3 ? n3 && (e3 !== this.statics.blotName || this.formats()[e3] !== n3) && this.replaceWith(e3, n3) : this.replaceWith(t3.blotName));
            }
            formats() {
              const t4 = this.attributes.values(), e3 = this.statics.formats(this.domNode, this.scroll);
              return null != e3 && (t4[this.statics.blotName] = e3), t4;
            }
            formatAt(t4, e3, n3, i2) {
              null != this.scroll.query(n3, s2.BLOCK) ? this.format(n3, i2) : super.formatAt(t4, e3, n3, i2);
            }
            insertAt(t4, e3, n3) {
              if (null == n3 || null != this.scroll.query(e3, s2.INLINE)) super.insertAt(t4, e3, n3);
              else {
                const s3 = this.split(t4);
                if (null == s3) throw new Error("Attempt to insertAt after block boundaries");
                {
                  const t5 = this.scroll.create(e3, n3);
                  s3.parent.insertBefore(t5, s3);
                }
              }
            }
            replaceWith(t4, e3) {
              const n3 = super.replaceWith(t4, e3);
              return this.attributes.copy(n3), n3;
            }
            update(t4, e3) {
              super.update(t4, e3), t4.some(((t5) => t5.target === this.domNode && "attributes" === t5.type)) && this.attributes.build();
            }
          };
          x.blotName = "block", x.scope = s2.BLOCK_BLOT, x.tagName = "P", x.allowedChildren = [E4, x, g];
          const L = x, S = class extends N {
            checkMerge() {
              return null !== this.next && this.next.statics.blotName === this.statics.blotName;
            }
            deleteAt(t3, e3) {
              super.deleteAt(t3, e3), this.enforceAllowedChildren();
            }
            formatAt(t3, e3, n3, s3) {
              super.formatAt(t3, e3, n3, s3), this.enforceAllowedChildren();
            }
            insertAt(t3, e3, n3) {
              super.insertAt(t3, e3, n3), this.enforceAllowedChildren();
            }
            optimize(t3) {
              super.optimize(t3), this.children.length > 0 && null != this.next && this.checkMerge() && (this.next.moveChildren(this), this.next.remove());
            }
          };
          S.blotName = "container", S.scope = s2.BLOCK_BLOT;
          const T = S, k = class extends g {
            static formats(t3, e3) {
            }
            format(t3, e3) {
              super.formatAt(0, this.length(), t3, e3);
            }
            formatAt(t3, e3, n3, s3) {
              0 === t3 && e3 === this.length() ? this.format(n3, s3) : super.formatAt(t3, e3, n3, s3);
            }
            formats() {
              return this.statics.formats(this.domNode, this.scroll);
            }
          }, O2 = { attributes: true, characterData: true, characterDataOldValue: true, childList: true, subtree: true }, w = class extends N {
            constructor(t3, e3) {
              super(null, e3), this.registry = t3, this.scroll = this, this.build(), this.observer = new MutationObserver(((t4) => {
                this.update(t4);
              })), this.observer.observe(this.domNode, O2), this.attach();
            }
            create(t3, e3) {
              return this.registry.create(this, t3, e3);
            }
            find(t3, e3 = false) {
              const n3 = this.registry.find(t3, e3);
              return n3 ? n3.scroll === this ? n3 : e3 ? this.find(n3.scroll.domNode.parentNode, true) : null : null;
            }
            query(t3, e3 = s2.ANY) {
              return this.registry.query(t3, e3);
            }
            register(...t3) {
              return this.registry.register(...t3);
            }
            build() {
              null != this.scroll && super.build();
            }
            detach() {
              super.detach(), this.observer.disconnect();
            }
            deleteAt(t3, e3) {
              this.update(), 0 === t3 && e3 === this.length() ? this.children.forEach(((t4) => {
                t4.remove();
              })) : super.deleteAt(t3, e3);
            }
            formatAt(t3, e3, n3, s3) {
              this.update(), super.formatAt(t3, e3, n3, s3);
            }
            insertAt(t3, e3, n3) {
              this.update(), super.insertAt(t3, e3, n3);
            }
            optimize(t3 = [], e3 = {}) {
              super.optimize(e3);
              const n3 = e3.mutationsMap || /* @__PURE__ */ new WeakMap();
              let s3 = Array.from(this.observer.takeRecords());
              for (; s3.length > 0; ) t3.push(s3.pop());
              const i2 = (t4, e4 = true) => {
                null == t4 || t4 === this || null != t4.domNode.parentNode && (n3.has(t4.domNode) || n3.set(t4.domNode, []), e4 && i2(t4.parent));
              }, r2 = (t4) => {
                n3.has(t4.domNode) && (t4 instanceof N && t4.children.forEach(r2), n3.delete(t4.domNode), t4.optimize(e3));
              };
              let o2 = t3;
              for (let e4 = 0; o2.length > 0; e4 += 1) {
                if (e4 >= 100) throw new Error("[Parchment] Maximum optimize iterations reached");
                for (o2.forEach(((t4) => {
                  const e5 = this.find(t4.target, true);
                  null != e5 && (e5.domNode === t4.target && ("childList" === t4.type ? (i2(this.find(t4.previousSibling, false)), Array.from(t4.addedNodes).forEach(((t5) => {
                    const e6 = this.find(t5, false);
                    i2(e6, false), e6 instanceof N && e6.children.forEach(((t6) => {
                      i2(t6, false);
                    }));
                  }))) : "attributes" === t4.type && i2(e5.prev)), i2(e5));
                })), this.children.forEach(r2), o2 = Array.from(this.observer.takeRecords()), s3 = o2.slice(); s3.length > 0; ) t3.push(s3.pop());
              }
            }
            update(t3, e3 = {}) {
              t3 = t3 || this.observer.takeRecords();
              const n3 = /* @__PURE__ */ new WeakMap();
              t3.map(((t4) => {
                const e4 = this.find(t4.target, true);
                return null == e4 ? null : n3.has(e4.domNode) ? (n3.get(e4.domNode).push(t4), null) : (n3.set(e4.domNode, [t4]), e4);
              })).forEach(((t4) => {
                null != t4 && t4 !== this && n3.has(t4.domNode) && t4.update(n3.get(t4.domNode) || [], e3);
              })), e3.mutationsMap = n3, n3.has(this.domNode) && super.update(n3.get(this.domNode), e3), this.optimize(t3, e3);
            }
          };
          w.blotName = "scroll", w.defaultChild = L, w.allowedChildren = [L, T], w.scope = s2.BLOCK_BLOT, w.tagName = "DIV";
          const C = w, q = class t3 extends g {
            static create(t4) {
              return document.createTextNode(t4);
            }
            static value(t4) {
              return t4.data;
            }
            constructor(t4, e3) {
              super(t4, e3), this.text = this.statics.value(this.domNode);
            }
            deleteAt(t4, e3) {
              this.domNode.data = this.text = this.text.slice(0, t4) + this.text.slice(t4 + e3);
            }
            index(t4, e3) {
              return this.domNode === t4 ? e3 : -1;
            }
            insertAt(t4, e3, n3) {
              null == n3 ? (this.text = this.text.slice(0, t4) + e3 + this.text.slice(t4), this.domNode.data = this.text) : super.insertAt(t4, e3, n3);
            }
            length() {
              return this.text.length;
            }
            optimize(e3) {
              super.optimize(e3), this.text = this.statics.value(this.domNode), 0 === this.text.length ? this.remove() : this.next instanceof t3 && this.next.prev === this && (this.insertAt(this.length(), this.next.value()), this.next.remove());
            }
            position(t4, e3 = false) {
              return [this.domNode, t4];
            }
            split(t4, e3 = false) {
              if (!e3) {
                if (0 === t4) return this;
                if (t4 === this.length()) return this.next;
              }
              const n3 = this.scroll.create(this.domNode.splitText(t4));
              return this.parent.insertBefore(n3, this.next || void 0), this.text = this.statics.value(this.domNode), n3;
            }
            update(t4, e3) {
              t4.some(((t5) => "characterData" === t5.type && t5.target === this.domNode)) && (this.text = this.statics.value(this.domNode));
            }
            value() {
              return this.text;
            }
          };
          q.blotName = "text", q.scope = s2.INLINE_BLOT;
          const R2 = q;
        } }, e = {};
        function n(s2) {
          var i = e[s2];
          if (void 0 !== i) return i.exports;
          var r = e[s2] = { exports: {} };
          return t[s2](r, r.exports, n), r.exports;
        }
        n.d = function(t2, e2) {
          for (var s2 in e2) n.o(e2, s2) && !n.o(t2, s2) && Object.defineProperty(t2, s2, { enumerable: true, get: e2[s2] });
        }, n.o = function(t2, e2) {
          return Object.prototype.hasOwnProperty.call(t2, e2);
        }, n.r = function(t2) {
          "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t2, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(t2, "__esModule", { value: true });
        };
        var s = {};
        return (function() {
          n.d(s, { default: function() {
            return K;
          } });
          var t2 = n(729), e2 = n(276), i = n(912), r = n(3);
          class o extends r.ClassAttributor {
            add(t3, e3) {
              let n2 = 0;
              if ("+1" === e3 || "-1" === e3) {
                const s2 = this.value(t3) || 0;
                n2 = "+1" === e3 ? s2 + 1 : s2 - 1;
              } else "number" == typeof e3 && (n2 = e3);
              return 0 === n2 ? (this.remove(t3), true) : super.add(t3, n2.toString());
            }
            canAdd(t3, e3) {
              return super.canAdd(t3, e3) || super.canAdd(t3, parseInt(e3, 10));
            }
            value(t3) {
              return parseInt(super.value(t3), 10) || void 0;
            }
          }
          var l = new o("indent", "ql-indent", { scope: r.Scope.BLOCK, whitelist: [1, 2, 3, 4, 5, 6, 7, 8] }), a = n(698);
          class c extends a.Ay {
            static blotName = "blockquote";
            static tagName = "blockquote";
          }
          var h = c;
          class u extends a.Ay {
            static blotName = "header";
            static tagName = ["H1", "H2", "H3", "H4", "H5", "H6"];
            static formats(t3) {
              return this.tagName.indexOf(t3.tagName) + 1;
            }
          }
          var d = u, f = n(580), p = n(543);
          class m extends f.A {
          }
          m.blotName = "list-container", m.tagName = "OL";
          class g extends a.Ay {
            static create(t3) {
              const e3 = super.create();
              return e3.setAttribute("data-list", t3), e3;
            }
            static formats(t3) {
              return t3.getAttribute("data-list") || void 0;
            }
            static register() {
              p.Ay.register(m);
            }
            constructor(t3, e3) {
              super(t3, e3);
              const n2 = e3.ownerDocument.createElement("span"), s2 = (n3) => {
                if (!t3.isEnabled()) return;
                const s3 = this.statics.formats(e3, t3);
                "checked" === s3 ? (this.format("list", "unchecked"), n3.preventDefault()) : "unchecked" === s3 && (this.format("list", "checked"), n3.preventDefault());
              };
              n2.addEventListener("mousedown", s2), n2.addEventListener("touchstart", s2), this.attachUI(n2);
            }
            format(t3, e3) {
              t3 === this.statics.blotName && e3 ? this.domNode.setAttribute("data-list", e3) : super.format(t3, e3);
            }
          }
          g.blotName = "list", g.tagName = "LI", m.allowedChildren = [g], g.requiredContainer = m;
          var b = n(922), y = n(638), A5 = n(772), N = n(664), v = n(850);
          class E4 extends v.A {
            static blotName = "bold";
            static tagName = ["STRONG", "B"];
            static create() {
              return super.create();
            }
            static formats() {
              return true;
            }
            optimize(t3) {
              super.optimize(t3), this.domNode.tagName !== this.statics.tagName[0] && this.replaceWith(this.statics.blotName);
            }
          }
          var x = E4;
          class L extends v.A {
            static blotName = "link";
            static tagName = "A";
            static SANITIZED_URL = "about:blank";
            static PROTOCOL_WHITELIST = ["http", "https", "mailto", "tel", "sms"];
            static create(t3) {
              const e3 = super.create(t3);
              return e3.setAttribute("href", this.sanitize(t3)), e3.setAttribute("rel", "noopener noreferrer"), e3.setAttribute("target", "_blank"), e3;
            }
            static formats(t3) {
              return t3.getAttribute("href");
            }
            static sanitize(t3) {
              return S(t3, this.PROTOCOL_WHITELIST) ? t3 : this.SANITIZED_URL;
            }
            format(t3, e3) {
              t3 === this.statics.blotName && e3 ? this.domNode.setAttribute("href", this.constructor.sanitize(e3)) : super.format(t3, e3);
            }
          }
          function S(t3, e3) {
            const n2 = document.createElement("a");
            n2.href = t3;
            const s2 = n2.href.slice(0, n2.href.indexOf(":"));
            return e3.indexOf(s2) > -1;
          }
          class T extends v.A {
            static blotName = "script";
            static tagName = ["SUB", "SUP"];
            static create(t3) {
              return "super" === t3 ? document.createElement("sup") : "sub" === t3 ? document.createElement("sub") : super.create(t3);
            }
            static formats(t3) {
              return "SUB" === t3.tagName ? "sub" : "SUP" === t3.tagName ? "super" : void 0;
            }
          }
          var k = T;
          class O2 extends v.A {
            static blotName = "underline";
            static tagName = "U";
          }
          var w = O2;
          const C = ["alt", "height", "width"];
          class q extends r.EmbedBlot {
            static blotName = "image";
            static tagName = "IMG";
            static create(t3) {
              const e3 = super.create(t3);
              return "string" == typeof t3 && e3.setAttribute("src", this.sanitize(t3)), e3;
            }
            static formats(t3) {
              return C.reduce(((e3, n2) => (t3.hasAttribute(n2) && (e3[n2] = t3.getAttribute(n2)), e3)), {});
            }
            static match(t3) {
              return /\.(jpe?g|gif|png)$/.test(t3) || /^data:image\/.+;base64/.test(t3);
            }
            static sanitize(t3) {
              return S(t3, ["http", "https", "data"]) ? t3 : "//:0";
            }
            static value(t3) {
              return t3.getAttribute("src");
            }
            format(t3, e3) {
              C.indexOf(t3) > -1 ? e3 ? this.domNode.setAttribute(t3, e3) : this.domNode.removeAttribute(t3) : super.format(t3, e3);
            }
          }
          var R2 = q;
          const B = ["height", "width"];
          class I2 extends a.zo {
            static blotName = "video";
            static className = "ql-video";
            static tagName = "IFRAME";
            static create(t3) {
              const e3 = super.create(t3);
              return e3.setAttribute("frameborder", "0"), e3.setAttribute("allowfullscreen", "true"), e3.setAttribute("src", this.sanitize(t3)), e3;
            }
            static formats(t3) {
              return B.reduce(((e3, n2) => (t3.hasAttribute(n2) && (e3[n2] = t3.getAttribute(n2)), e3)), {});
            }
            static sanitize(t3) {
              return L.sanitize(t3);
            }
            static value(t3) {
              return t3.getAttribute("src");
            }
            format(t3, e3) {
              B.indexOf(t3) > -1 ? e3 ? this.domNode.setAttribute(t3, e3) : this.domNode.removeAttribute(t3) : super.format(t3, e3);
            }
            html() {
              const { video: t3 } = this.value();
              return `<a href="${t3}">${t3}</a>`;
            }
          }
          var D = I2, M5 = n(404), U = n(398), _2 = n(78), j = n(266);
          const P = (0, _2.A)("quill:toolbar");
          class z extends j.A {
            constructor(t3, e3) {
              if (super(t3, e3), Array.isArray(this.options.container)) {
                const e4 = document.createElement("div");
                e4.setAttribute("role", "toolbar"), (function(t4, e5) {
                  Array.isArray(e5[0]) || (e5 = [e5]), e5.forEach(((e6) => {
                    const n2 = document.createElement("span");
                    n2.classList.add("ql-formats"), e6.forEach(((t5) => {
                      if ("string" == typeof t5) F(n2, t5);
                      else {
                        const e7 = Object.keys(t5)[0], s2 = t5[e7];
                        Array.isArray(s2) ? (function(t6, e8, n3) {
                          const s3 = document.createElement("select");
                          s3.classList.add(`ql-${e8}`), n3.forEach(((t7) => {
                            const e9 = document.createElement("option");
                            false !== t7 ? e9.setAttribute("value", String(t7)) : e9.setAttribute("selected", "selected"), s3.appendChild(e9);
                          })), t6.appendChild(s3);
                        })(n2, e7, s2) : F(n2, e7, s2);
                      }
                    })), t4.appendChild(n2);
                  }));
                })(e4, this.options.container), t3.container?.parentNode?.insertBefore(e4, t3.container), this.container = e4;
              } else if ("string" == typeof this.options.container) {
                const e4 = t3.container.getRootNode();
                this.container = e4.querySelector(this.options.container);
              } else this.container = this.options.container;
              this.container instanceof HTMLElement ? (this.container.classList.add("ql-toolbar"), this.controls = [], this.handlers = {}, this.options.handlers && Object.keys(this.options.handlers).forEach(((t4) => {
                const e4 = this.options.handlers?.[t4];
                e4 && this.addHandler(t4, e4);
              })), Array.from(this.container.querySelectorAll("button, select")).forEach(((t4) => {
                this.attach(t4);
              })), this.quill.on(p.Ay.events.EDITOR_CHANGE, (() => {
                const [t4] = this.quill.selection.getRange();
                this.update(t4);
              }))) : P.error("Container required for toolbar", this.options);
            }
            addHandler(t3, e3) {
              this.handlers[t3] = e3;
            }
            attach(t3) {
              let e3 = Array.from(t3.classList).find(((t4) => 0 === t4.indexOf("ql-")));
              if (!e3) return;
              if (e3 = e3.slice(3), "BUTTON" === t3.tagName && t3.setAttribute("type", "button"), null == this.handlers[e3] && null == this.quill.scroll.query(e3)) return void P.warn("ignoring attaching to nonexistent format", e3, t3);
              const n2 = "SELECT" === t3.tagName ? "change" : "click";
              t3.addEventListener(n2, ((n3) => {
                let s2;
                if ("SELECT" === t3.tagName) {
                  if (t3.selectedIndex < 0) return;
                  const e4 = t3.options[t3.selectedIndex];
                  s2 = !e4.hasAttribute("selected") && (e4.value || false);
                } else s2 = !t3.classList.contains("ql-active") && (t3.value || !t3.hasAttribute("value")), n3.preventDefault();
                this.quill.focus();
                const [i2] = this.quill.selection.getRange();
                if (null != this.handlers[e3]) this.handlers[e3].call(this, s2);
                else if (this.quill.scroll.query(e3).prototype instanceof r.EmbedBlot) {
                  if (s2 = prompt(`Enter ${e3}`), !s2) return;
                  this.quill.updateContents(new U.Ay().retain(i2.index).delete(i2.length).insert({ [e3]: s2 }), p.Ay.sources.USER);
                } else this.quill.format(e3, s2, p.Ay.sources.USER);
                this.update(i2);
              })), this.controls.push([e3, t3]);
            }
            update(t3) {
              const e3 = null == t3 ? {} : this.quill.getFormat(t3);
              this.controls.forEach(((n2) => {
                const [s2, i2] = n2;
                if ("SELECT" === i2.tagName) {
                  let n3 = null;
                  if (null == t3) n3 = null;
                  else if (null == e3[s2]) n3 = i2.querySelector("option[selected]");
                  else if (!Array.isArray(e3[s2])) {
                    let t4 = e3[s2];
                    "string" == typeof t4 && (t4 = t4.replace(/"/g, '\\"')), n3 = i2.querySelector(`option[value="${t4}"]`);
                  }
                  null == n3 ? (i2.value = "", i2.selectedIndex = -1) : n3.selected = true;
                } else if (null == t3) i2.classList.remove("ql-active"), i2.setAttribute("aria-pressed", "false");
                else if (i2.hasAttribute("value")) {
                  const t4 = e3[s2], n3 = t4 === i2.getAttribute("value") || null != t4 && t4.toString() === i2.getAttribute("value") || null == t4 && !i2.getAttribute("value");
                  i2.classList.toggle("ql-active", n3), i2.setAttribute("aria-pressed", n3.toString());
                } else {
                  const t4 = null != e3[s2];
                  i2.classList.toggle("ql-active", t4), i2.setAttribute("aria-pressed", t4.toString());
                }
              }));
            }
          }
          function F(t3, e3, n2) {
            const s2 = document.createElement("button");
            s2.setAttribute("type", "button"), s2.classList.add(`ql-${e3}`), s2.setAttribute("aria-pressed", "false"), null != n2 ? (s2.value = n2, s2.setAttribute("aria-label", `${e3}: ${n2}`)) : s2.setAttribute("aria-label", e3), t3.appendChild(s2);
          }
          z.DEFAULTS = {}, z.DEFAULTS = { container: null, handlers: { clean() {
            const t3 = this.quill.getSelection();
            if (null != t3) if (0 === t3.length) {
              const t4 = this.quill.getFormat();
              Object.keys(t4).forEach(((t5) => {
                null != this.quill.scroll.query(t5, r.Scope.INLINE) && this.quill.format(t5, false, p.Ay.sources.USER);
              }));
            } else this.quill.removeFormat(t3.index, t3.length, p.Ay.sources.USER);
          }, direction(t3) {
            const { align: e3 } = this.quill.getFormat();
            "rtl" === t3 && null == e3 ? this.quill.format("align", "right", p.Ay.sources.USER) : t3 || "right" !== e3 || this.quill.format("align", false, p.Ay.sources.USER), this.quill.format("direction", t3, p.Ay.sources.USER);
          }, indent(t3) {
            const e3 = this.quill.getSelection(), n2 = this.quill.getFormat(e3), s2 = parseInt(n2.indent || 0, 10);
            if ("+1" === t3 || "-1" === t3) {
              let e4 = "+1" === t3 ? 1 : -1;
              "rtl" === n2.direction && (e4 *= -1), this.quill.format("indent", s2 + e4, p.Ay.sources.USER);
            }
          }, link(t3) {
            true === t3 && (t3 = prompt("Enter link URL:")), this.quill.format("link", t3, p.Ay.sources.USER);
          }, list(t3) {
            const e3 = this.quill.getSelection(), n2 = this.quill.getFormat(e3);
            "check" === t3 ? "checked" === n2.list || "unchecked" === n2.list ? this.quill.format("list", false, p.Ay.sources.USER) : this.quill.format("list", "unchecked", p.Ay.sources.USER) : this.quill.format("list", t3, p.Ay.sources.USER);
          } } }, t2.default.register({ "attributors/attribute/direction": i.Mc, "attributors/class/align": e2.qh, "attributors/class/background": b.l, "attributors/class/color": y.g3, "attributors/class/direction": i.sY, "attributors/class/font": A5.q, "attributors/class/size": N.U, "attributors/style/align": e2.Hu, "attributors/style/background": b.s, "attributors/style/color": y.JM, "attributors/style/direction": i.VL, "attributors/style/font": A5.z, "attributors/style/size": N.r }, true), t2.default.register({ "formats/align": e2.qh, "formats/direction": i.sY, "formats/indent": l, "formats/background": b.s, "formats/color": y.JM, "formats/font": A5.q, "formats/size": N.U, "formats/blockquote": h, "formats/code-block": M5.Ay, "formats/header": d, "formats/list": g, "formats/bold": x, "formats/code": M5.Cy, "formats/italic": class extends x {
            static blotName = "italic";
            static tagName = ["EM", "I"];
          }, "formats/link": L, "formats/script": k, "formats/strike": class extends x {
            static blotName = "strike";
            static tagName = ["S", "STRIKE"];
          }, "formats/underline": w, "formats/image": R2, "formats/video": D, "modules/toolbar": z }, true);
          var K = t2.default;
        })(), s.default;
      })();
    }));
  })(vaadinQuill);
  return vaadinQuill.exports;
}
requireVaadinQuill();
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
const Quill = window.Quill;
const QuillCodeBlockContainer = Quill.import("formats/code-block-container");
class CodeBlockContainer extends QuillCodeBlockContainer {
  html(index, length) {
    const markup = super.html(index, length);
    const tempDiv = document.createElement("div");
    tempDiv.innerHTML = markup;
    const preTag = tempDiv.querySelector("pre");
    if (preTag) {
      preTag.setAttribute("spellcheck", "false");
      return preTag.outerHTML;
    }
    return markup;
  }
}
Quill.register("formats/code-block-container", CodeBlockContainer, true);
const NAVIGATION_KEYS = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End", "PageUp", "PageDown"];
const HANDLERS = [
  "bold",
  "italic",
  "underline",
  "strike",
  "header",
  "script",
  "list",
  "align",
  "blockquote",
  "code-block"
];
const SOURCE = {
  API: "api",
  USER: "user",
  SILENT: "silent"
};
const STATE = {
  DEFAULT: 0,
  FOCUSED: 1,
  CLICKED: 2
};
const DEFAULT_I18N$3 = {
  undo: "undo",
  redo: "redo",
  bold: "bold",
  italic: "italic",
  underline: "underline",
  strike: "strike",
  color: "color",
  background: "background",
  h1: "h1",
  h2: "h2",
  h3: "h3",
  subscript: "subscript",
  superscript: "superscript",
  listOrdered: "list ordered",
  listBullet: "list bullet",
  outdent: "outdent",
  indent: "indent",
  alignLeft: "align left",
  alignCenter: "align center",
  alignRight: "align right",
  image: "image",
  link: "link",
  blockquote: "blockquote",
  codeBlock: "code block",
  clean: "clean",
  linkDialogTitle: "Link address",
  ok: "OK",
  cancel: "Cancel",
  remove: "Remove"
};
const RichTextEditorMixin = (superClass) => class RichTextEditorMixinClass extends I18nMixin(DEFAULT_I18N$3, superClass) {
  static get properties() {
    return {
      /**
       * Value is a list of the operations which describe change to the document.
       * Each of those operations describe the change at the current index.
       * They can be an `insert`, `delete` or `retain`. The format is as follows:
       *
       * ```js
       *  [
       *    { insert: 'Hello World' },
       *    { insert: '!', attributes: { bold: true }}
       *  ]
       * ```
       *
       * See also https://github.com/quilljs/delta for detailed documentation.
       */
      value: {
        type: String,
        notify: true,
        value: "",
        sync: true
      },
      /**
       * HTML representation of the rich text editor content.
       */
      htmlValue: {
        type: String,
        notify: true,
        readOnly: true
      },
      /**
       * When true, the user can not modify, nor copy the editor content.
       */
      disabled: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * When true, the user can not modify the editor content, but can copy it.
       */
      readonly: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * The list of colors used by the background and text color
       * selection controls. Should contain an array of HEX strings.
       *
       * When user selects `#000000` (black) as a text color,
       * or `#ffffff` (white) as a background color, it resets
       * the corresponding format for the selected text.
       */
      colorOptions: {
        type: Array,
        value: () => {
          return [
            "#000000",
            "#e60000",
            "#ff9900",
            "#ffff00",
            "#008a00",
            "#0066cc",
            "#9933ff",
            "#ffffff",
            "#facccc",
            "#ffebcc",
            "#ffffcc",
            "#cce8cc",
            "#cce0f5",
            "#ebd6ff",
            "#bbbbbb",
            "#f06666",
            "#ffc266",
            "#ffff66",
            "#66b966",
            "#66a3e0",
            "#c285ff",
            "#888888",
            "#a10000",
            "#b26b00",
            "#b2b200",
            "#006100",
            "#0047b2",
            "#6b24b2",
            "#444444",
            "#5c0000",
            "#663d00",
            "#666600",
            "#003700",
            "#002966",
            "#3d1466"
          ];
        }
      },
      /** @private */
      _editor: {
        type: Object,
        sync: true
      },
      /**
       * Stores old value
       * @private
       */
      __oldValue: String,
      /** @private */
      __lastCommittedChange: {
        type: String,
        value: ""
      },
      /** @private */
      _linkEditing: {
        type: Boolean,
        value: false
      },
      /** @private */
      _linkRange: {
        type: Object,
        value: null
      },
      /** @private */
      _linkIndex: {
        type: Number,
        value: null
      },
      /** @private */
      _linkUrl: {
        type: String,
        value: ""
      },
      /** @private */
      _colorEditing: {
        type: Boolean,
        value: false
      },
      /** @private */
      _colorValue: {
        type: String,
        value: ""
      },
      /** @private */
      _backgroundEditing: {
        type: Boolean,
        value: false
      },
      /** @private */
      _backgroundValue: {
        type: String,
        value: ""
      }
    };
  }
  static get observers() {
    return ["_valueChanged(value, _editor)", "_disabledChanged(disabled, readonly, _editor)"];
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The properties are used e.g. as the tooltips for the editor toolbar
   * buttons.
   *
   * @type {!RichTextEditorI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @private */
  get _toolbarButtons() {
    return Array.from(this.shadowRoot.querySelectorAll('[part="toolbar"] button')).filter((btn) => {
      return btn.clientHeight > 0;
    });
  }
  /**
   * @param {string} prop
   * @param {?string} oldVal
   * @param {?string} newVal
   * @protected
   */
  attributeChangedCallback(prop, oldVal, newVal) {
    super.attributeChangedCallback(prop, oldVal, newVal);
    if (prop === "dir") {
      this.__dir = newVal;
      this.__setDirection(newVal);
    }
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    this._editor.emitter.disconnect();
  }
  /** @private */
  __setDirection(dir) {
    if (!this._editor) {
      return;
    }
    const alignAttributor = Quill.import("attributors/class/align");
    alignAttributor.whitelist = [dir === "rtl" ? "left" : "right", "center", "justify"];
    Quill.register(alignAttributor, true);
    const alignGroup = this._toolbar.querySelector('[part~="toolbar-group-alignment"]');
    if (dir === "rtl") {
      alignGroup.querySelector('[part~="toolbar-button-align-left"]').value = "left";
      alignGroup.querySelector('[part~="toolbar-button-align-right"]').value = "";
    } else {
      alignGroup.querySelector('[part~="toolbar-button-align-left"]').value = "";
      alignGroup.querySelector('[part~="toolbar-button-align-right"]').value = "right";
    }
    this._editor.getModule("toolbar").update(this._editor.getSelection());
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this._editor.emitter.connect();
  }
  /** @protected */
  ready() {
    super.ready();
    this._toolbarConfig = this._prepareToolbar();
    this._toolbar = this._toolbarConfig.container;
    this._addToolbarListeners();
    const editor = this.shadowRoot.querySelector('[part="content"]');
    this._editor = new Quill(editor, {
      modules: {
        toolbar: this._toolbarConfig
      }
    });
    this.__patchToolbar();
    this.__patchKeyboard();
    this.__setDirection(this.__dir);
    const editorContent = editor.querySelector(".ql-editor");
    editorContent.setAttribute("role", "textbox");
    editorContent.setAttribute("aria-multiline", "true");
    this._editor.on("text-change", () => {
      const timeout = 200;
      this.__debounceSetValue = Debouncer.debounce(this.__debounceSetValue, timeOut.after(timeout), () => {
        this.value = JSON.stringify(this._editor.getContents().ops);
      });
    });
    this._editor.on("editor-change", () => {
      const selection = this._editor.getSelection();
      if (selection) {
        const format2 = this._editor.getFormat(selection.index, selection.length);
        this._toolbar.style.setProperty("--_color-value", format2.color || null);
        this._toolbar.style.setProperty("--_background-value", format2.background || null);
      }
    });
    editorContent.addEventListener("keydown", (e) => {
      if (e.key === "Escape") {
        if (!this.__tabBindings) {
          this.__tabBindings = this._editor.keyboard.bindings.Tab;
          this._editor.keyboard.bindings.Tab = null;
        }
      } else if (this.__tabBindings) {
        this._editor.keyboard.bindings.Tab = this.__tabBindings;
        this.__tabBindings = null;
      }
    });
    editorContent.addEventListener("keydown", (e) => {
      if (NAVIGATION_KEYS.includes(e.key)) {
        requestAnimationFrame(() => {
          const selection = this._editor.getSelection();
          if (selection) {
            this._editor.getModule("toolbar").update(selection);
          }
        });
      }
    });
    editorContent.addEventListener("blur", () => {
      if (this.__tabBindings) {
        this._editor.keyboard.bindings.Tab = this.__tabBindings;
        this.__tabBindings = null;
      }
    });
    editorContent.addEventListener("focusout", () => {
      if (this._toolbarState === STATE.FOCUSED) {
        this._cleanToolbarState();
      } else {
        this.__emitChangeEvent();
      }
    });
    editorContent.addEventListener("focus", () => {
      if (this._toolbarState === STATE.CLICKED && !this._linkEditing) {
        this._cleanToolbarState();
      }
    });
    this._editor.on("selection-change", this.__announceFormatting.bind(this));
    this.__flushPendingHtmlValue();
    this.querySelector('[slot="color-popup"]').target = this.shadowRoot.querySelector("#btn-color");
    this.querySelector('[slot="background-popup"]').target = this.shadowRoot.querySelector("#btn-background");
    this._tooltip = document.createElement("vaadin-tooltip");
    this._tooltip.slot = "tooltip";
    this._tooltip.ariaTarget = null;
    this.append(this._tooltip);
    const buttons = this.shadowRoot.querySelectorAll('[part~="toolbar-button"]');
    buttons.forEach((button) => {
      button.addEventListener("mouseenter", this.__showTooltip.bind(this));
      button.addEventListener("focusin", this.__showTooltip.bind(this));
    });
  }
  /** @private */
  __showTooltip({ type, target }) {
    if (type === "focusin" && !isKeyboardActive()) {
      return;
    }
    this._tooltip.target = target;
    this._tooltip.text = target.ariaLabel;
    this._tooltip._stateController.open({
      focus: type === "focusin",
      hover: type === "mouseenter"
    });
  }
  /** @private */
  _prepareToolbar() {
    const clean = Quill.imports["modules/toolbar"].DEFAULTS.handlers.clean;
    const self2 = this;
    const toolbar2 = {
      container: this.shadowRoot.querySelector('[part="toolbar"]'),
      handlers: {
        clean() {
          self2._markToolbarClicked();
          clean.call(this);
        }
      }
    };
    HANDLERS.forEach((handler) => {
      toolbar2.handlers[handler] = (value) => {
        this._markToolbarClicked();
        this._editor.format(handler, value, SOURCE.USER);
      };
    });
    return toolbar2;
  }
  /** @private */
  _addToolbarListeners() {
    const buttons = this._toolbarButtons;
    const toolbar2 = this._toolbar;
    buttons.forEach((button, index) => index > 0 && button.setAttribute("tabindex", "-1"));
    toolbar2.addEventListener("keydown", (e) => {
      if ([37, 39].indexOf(e.keyCode) > -1) {
        e.preventDefault();
        let index = buttons.indexOf(e.target);
        buttons[index].setAttribute("tabindex", "-1");
        let step;
        if (e.keyCode === 39) {
          step = 1;
        } else if (e.keyCode === 37) {
          step = -1;
        }
        index = (buttons.length + index + step) % buttons.length;
        buttons[index].removeAttribute("tabindex");
        buttons[index].focus();
      }
      if (e.keyCode === 27 || e.key === "Tab" && !e.shiftKey) {
        e.preventDefault();
        this._editor.focus();
      }
    });
    toolbar2.addEventListener("mousedown", (e) => {
      if (buttons.indexOf(e.composedPath()[0]) > -1) {
        this._markToolbarFocused();
      }
    });
  }
  /** @private */
  _markToolbarClicked() {
    this._toolbarState = STATE.CLICKED;
  }
  /** @private */
  _markToolbarFocused() {
    this._toolbarState = STATE.FOCUSED;
  }
  /** @private */
  _cleanToolbarState() {
    this._toolbarState = STATE.DEFAULT;
  }
  /** @private */
  __patchToolbar() {
    const toolbar2 = this._editor.getModule("toolbar");
    const update = toolbar2.update;
    toolbar2.controls.push(["link", this.shadowRoot.querySelector('[part~="toolbar-button-link"]')]);
    toolbar2.update = function(range2) {
      update.call(toolbar2, range2);
      toolbar2.controls.forEach((pair) => {
        const input = pair[1];
        const isActive = input.classList.contains("ql-active");
        input.part.toggle("toolbar-button-pressed", isActive);
      });
    };
  }
  /** @private */
  __patchKeyboard() {
    const focusToolbar = () => {
      this._markToolbarFocused();
      this._toolbar.querySelector("button:not([tabindex])").focus();
    };
    const keyboard = this._editor.keyboard;
    keyboard.addBinding({ key: "Tab", shiftKey: true, handler: focusToolbar });
    keyboard.addBinding({ key: "F10", altKey: true, handler: focusToolbar });
  }
  /** @private */
  __emitChangeEvent() {
    let lastCommittedChange = this.__lastCommittedChange;
    if (this.__debounceSetValue && this.__debounceSetValue.isActive()) {
      lastCommittedChange = this.value;
      this.__debounceSetValue.flush();
    }
    if (lastCommittedChange !== this.value) {
      this.dispatchEvent(new CustomEvent("change", { bubbles: true, cancelable: false }));
      this.__lastCommittedChange = this.value;
    }
  }
  /** @private */
  _onLinkClick() {
    const range2 = this._editor.getSelection();
    if (range2) {
      const LinkBlot = Quill.imports["formats/link"];
      const [link, offset2] = this._editor.scroll.descendant(LinkBlot, range2.index);
      if (link != null) {
        this._linkRange = { index: range2.index - offset2, length: link.length() };
        this._linkUrl = LinkBlot.formats(link.domNode);
      } else if (range2.length === 0) {
        this._linkIndex = range2.index;
      }
      this._linkEditing = true;
    }
  }
  /** @private */
  _applyLink(link) {
    if (link) {
      this._markToolbarClicked();
      this._editor.focus();
      this._editor.format("link", link, SOURCE.USER);
      this._editor.getModule("toolbar").update(this._editor.selection.savedRange);
    }
    this._closeLinkDialog();
  }
  /** @private */
  _insertLink(link, position) {
    if (link) {
      this._markToolbarClicked();
      this._editor.insertText(position, link, { link });
      this._editor.setSelection(position, link.length);
    }
    this._closeLinkDialog();
  }
  /** @private */
  _updateLink(link, range2) {
    this._markToolbarClicked();
    this._editor.formatText(range2, "link", link, SOURCE.USER);
    this._closeLinkDialog();
  }
  /** @private */
  _removeLink() {
    this._markToolbarClicked();
    if (this._linkRange != null) {
      this._editor.formatText(this._linkRange, { link: false, color: false }, SOURCE.USER);
    }
    this._closeLinkDialog();
  }
  /** @private */
  _closeLinkDialog() {
    this._linkEditing = false;
    this._linkUrl = "";
    this._linkIndex = null;
    this._linkRange = null;
  }
  /** @private */
  _onLinkEditConfirm() {
    if (this._linkIndex != null) {
      this._insertLink(this._linkUrl, this._linkIndex);
    } else if (this._linkRange) {
      this._updateLink(this._linkUrl, this._linkRange);
    } else {
      this._applyLink(this._linkUrl);
    }
  }
  /** @private */
  _onLinkEditCancel() {
    this._closeLinkDialog();
    this._editor.focus();
  }
  /** @private */
  _onLinkEditRemove() {
    this._removeLink();
    this._closeLinkDialog();
  }
  /** @private */
  _onLinkKeydown(e) {
    if (e.keyCode === 13) {
      e.preventDefault();
      e.stopPropagation();
      this._onLinkEditConfirm();
      this._closeLinkDialog();
    }
  }
  /** @private */
  __onColorClick() {
    this._tooltip.opened = false;
    this._colorEditing = true;
  }
  /** @private */
  __onColorSelected(event) {
    const color2 = event.detail.color;
    this._colorValue = color2 === "#000000" ? null : color2;
    this._markToolbarClicked();
    this._editor.focus();
    this._editor.format("color", this._colorValue, SOURCE.USER);
    this._toolbar.style.setProperty("--_color-value", this._colorValue);
    this._colorEditing = false;
  }
  /** @private */
  __onBackgroundClick() {
    this._tooltip.opened = false;
    this._backgroundEditing = true;
  }
  /** @private */
  __onBackgroundSelected(event) {
    const color2 = event.detail.color;
    this._backgroundValue = color2 === "#ffffff" ? null : color2;
    this._markToolbarClicked();
    this._editor.focus();
    this._editor.format("background", this._backgroundValue, SOURCE.USER);
    this._toolbar.style.setProperty("--_background-value", this._backgroundValue);
    this._backgroundEditing = false;
  }
  /** @private */
  __updateHtmlValue() {
    let content2 = this._editor.getSemanticHTML();
    content2 = content2.replace(/class="([^"]*)"/gu, (_match, group1) => {
      const classes = group1.split(" ").filter((className) => {
        return !className.startsWith("ql-") || className.startsWith("ql-align") || className.startsWith("ql-indent");
      });
      return `class="${classes.join(" ")}"`;
    });
    content2 = this.__processQuillClasses(content2);
    this._setHtmlValue(content2);
  }
  /** @private */
  __processQuillClasses(content2) {
    const tempDiv = document.createElement("div");
    tempDiv.innerHTML = content2;
    const elementsToProcess = tempDiv.querySelectorAll('[class*="ql-align"], [class*="ql-indent"]');
    elementsToProcess.forEach((element) => {
      this.__processAlignClasses(element);
      this.__processIndentClasses(element);
      element.removeAttribute("class");
    });
    return tempDiv.innerHTML;
  }
  /** @private */
  __processAlignClasses(element) {
    let styleText = element.getAttribute("style") || "";
    const alignments = [this.__dir === "rtl" ? "left" : "right", "center", "justify"];
    alignments.forEach((align) => {
      if (element.classList.contains(`ql-align-${align}`)) {
        const newStyle = `text-align: ${align}`;
        styleText = styleText ? `${styleText}; ${newStyle}` : newStyle;
        element.setAttribute("style", styleText);
        element.classList.remove(`ql-align-${align}`);
      }
    });
  }
  /** @private */
  __processIndentClasses(element) {
    const indentClass = Array.from(element.classList).find((className) => className.startsWith("ql-indent-"));
    if (indentClass) {
      const level = parseInt(indentClass.replace("ql-indent-", "").trim(), 10);
      const tabs = "	".repeat(level);
      const firstChild = element.firstChild;
      if (firstChild && firstChild.nodeType === Node.TEXT_NODE) {
        firstChild.textContent = tabs + firstChild.textContent;
      } else if (element.childNodes.length > 0) {
        const tabNode = document.createTextNode(tabs);
        element.insertBefore(tabNode, element.firstChild);
      } else {
        element.textContent = tabs;
      }
      element.classList.remove(indentClass);
    }
  }
  /**
   * Sets content represented by HTML snippet into the editor.
   * The snippet is interpreted by [Quill's Clipboard matchers](https://quilljs.com/docs/modules/clipboard/#matchers),
   * which may not produce the exactly input HTML.
   *
   * **NOTE:** Improper handling of HTML can lead to cross site scripting (XSS) and failure to sanitize
   * properly is both notoriously error-prone and a leading cause of web vulnerabilities.
   * This method is aptly named to ensure the developer has taken the necessary precautions.
   * @param {string} htmlValue
   */
  dangerouslySetHtmlValue(htmlValue) {
    if (!this._editor) {
      this.__savePendingHtmlValue(htmlValue);
      return;
    }
    if (!getComputedStyle(this).display) {
      this.__savePendingHtmlValue(htmlValue);
      const observer = new IntersectionObserver(() => {
        if (getComputedStyle(this).display) {
          this.__flushPendingHtmlValue();
          observer.disconnect();
        }
      });
      observer.observe(this);
      return;
    }
    const whitespaceCharacters = {
      "	": "__VAADIN_RICH_TEXT_EDITOR_TAB",
      "  ": "__VAADIN_RICH_TEXT_EDITOR_DOUBLE_SPACE"
    };
    Object.entries(whitespaceCharacters).forEach(([character, replacement]) => {
      htmlValue = htmlValue.replaceAll(/>[^<]*</gu, (match2) => match2.replaceAll(character, replacement));
    });
    const deltaFromHtml = this._editor.clipboard.convert({ html: htmlValue });
    Object.entries(whitespaceCharacters).forEach(([character, replacement]) => {
      deltaFromHtml.ops.forEach((op) => {
        if (typeof op.insert === "string") {
          op.insert = op.insert.replaceAll(replacement, character);
        }
      });
    });
    this._editor.setContents(deltaFromHtml, SOURCE.API);
  }
  /** @private */
  __savePendingHtmlValue(htmlValue) {
    this.__pendingHtmlValue = htmlValue;
    this.value = "";
  }
  /** @private */
  __flushPendingHtmlValue() {
    if (this.__pendingHtmlValue) {
      this.dangerouslySetHtmlValue(this.__pendingHtmlValue);
    }
  }
  /** @private */
  __announceFormatting() {
    const timeout = 200;
    const announcer = this.shadowRoot.querySelector(".announcer");
    announcer.textContent = "";
    this.__debounceAnnounceFormatting = Debouncer.debounce(
      this.__debounceAnnounceFormatting,
      timeOut.after(timeout),
      () => {
        const formatting = Array.from(this.shadowRoot.querySelectorAll('[part="toolbar"] .ql-active')).map((button) => button.getAttribute("aria-label")).join(", ");
        announcer.textContent = formatting;
      }
    );
  }
  /** @private */
  _clear() {
    this._editor.deleteText(0, this._editor.getLength(), SOURCE.SILENT);
    this.__updateHtmlValue();
  }
  /** @private */
  _undo(e) {
    e.preventDefault();
    this._editor.history.undo();
    this._editor.focus();
  }
  /** @private */
  _redo(e) {
    e.preventDefault();
    this._editor.history.redo();
    this._editor.focus();
  }
  /** @private */
  _toggleToolbarDisabled(disable2) {
    const buttons = this._toolbarButtons;
    if (disable2) {
      buttons.forEach((btn) => btn.setAttribute("disabled", "true"));
    } else {
      buttons.forEach((btn) => btn.removeAttribute("disabled"));
    }
  }
  /** @private */
  _onImageTouchEnd(e) {
    e.preventDefault();
    this._onImageClick();
  }
  /** @private */
  _onImageClick() {
    this.$.fileInput.value = "";
    this.$.fileInput.click();
  }
  /** @private */
  _uploadImage(e) {
    const fileInput = e.target;
    if (fileInput.files != null && fileInput.files[0] != null) {
      const reader = new FileReader();
      reader.onload = (e2) => {
        const image = e2.target.result;
        const range2 = this._editor.getSelection(true);
        this._editor.updateContents(
          new Quill.imports.delta().retain(range2.index).delete(range2.length).insert({ image }),
          SOURCE.USER
        );
        this._markToolbarClicked();
        this._editor.setSelection(range2.index + 1, SOURCE.SILENT);
        fileInput.value = "";
      };
      reader.readAsDataURL(fileInput.files[0]);
    }
  }
  /** @private */
  _disabledChanged(disabled, readonly, editor) {
    if (disabled === void 0 || readonly === void 0 || editor === void 0) {
      return;
    }
    if (disabled || readonly) {
      editor.enable(false);
      if (disabled) {
        this._toggleToolbarDisabled(true);
      }
    } else {
      editor.enable();
      if (this.__oldDisabled) {
        this._toggleToolbarDisabled(false);
      }
    }
    this.__oldDisabled = disabled;
  }
  /** @private */
  _valueChanged(value, editor) {
    if (value && this.__pendingHtmlValue) {
      this.__pendingHtmlValue = void 0;
    }
    if (editor === void 0) {
      return;
    }
    if (value == null || value === '[{"insert":"\\n"}]') {
      this.value = "";
      return;
    }
    if (value === "") {
      this._clear();
      return;
    }
    let parsedValue;
    try {
      parsedValue = JSON.parse(value);
      if (Array.isArray(parsedValue)) {
        this.__oldValue = value;
      } else {
        throw new Error(`expected JSON string with array of objects, got: ${value}`);
      }
    } catch (err) {
      this.value = this.__oldValue;
      console.error("Invalid value set to rich-text-editor:", err);
      return;
    }
    const delta = new Quill.imports.delta(parsedValue);
    if (JSON.stringify(editor.getContents()) !== JSON.stringify(delta)) {
      editor.setContents(delta, SOURCE.SILENT);
    }
    this.__updateHtmlValue();
    if (this._toolbarState === STATE.CLICKED) {
      this._cleanToolbarState();
      this.__emitChangeEvent();
    } else if (!this._editor.hasFocus()) {
      this.__lastCommittedChange = this.value;
    }
  }
};
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See https://vaadin.com/commercial-license-and-service-terms for the full
 * license.
 */
class RichTextEditor extends RichTextEditorMixin(
  ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))
) {
  static get is() {
    return "vaadin-rich-text-editor";
  }
  static get cvdlName() {
    return "vaadin-rich-text-editor";
  }
  static get styles() {
    return richTextEditorStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-rich-text-editor-container">
        <!-- Create toolbar container -->
        <div part="toolbar" role="toolbar">
          <span part="toolbar-group toolbar-group-history">
            <!-- Undo and Redo -->
            <button
              id="btn-undo"
              type="button"
              part="toolbar-button toolbar-button-undo"
              aria-label="${this.__effectiveI18n.undo}"
              @click="${this._undo}"
            ></button>

            <button
              id="btn-redo"
              type="button"
              part="toolbar-button toolbar-button-redo"
              aria-label="${this.__effectiveI18n.redo}"
              @click="${this._redo}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-emphasis">
            <!-- Bold -->
            <button
              id="btn-bold"
              class="ql-bold"
              part="toolbar-button toolbar-button-bold"
              aria-label="${this.__effectiveI18n.bold}"
            ></button>

            <!-- Italic -->
            <button
              id="btn-italic"
              class="ql-italic"
              part="toolbar-button toolbar-button-italic"
              aria-label="${this.__effectiveI18n.italic}"
            ></button>

            <!-- Underline -->
            <button
              id="btn-underline"
              class="ql-underline"
              part="toolbar-button toolbar-button-underline"
              aria-label="${this.__effectiveI18n.underline}"
            ></button>

            <!-- Strike -->
            <button
              id="btn-strike"
              class="ql-strike"
              part="toolbar-button toolbar-button-strike"
              aria-label="${this.__effectiveI18n.strike}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-style">
            <!-- Color -->
            <button
              id="btn-color"
              type="button"
              part="toolbar-button toolbar-button-color"
              aria-label="${this.__effectiveI18n.color}"
              @click="${this.__onColorClick}"
            ></button>
            <!-- Background -->
            <button
              id="btn-background"
              type="button"
              part="toolbar-button toolbar-button-background"
              aria-label="${this.__effectiveI18n.background}"
              @click="${this.__onBackgroundClick}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-heading">
            <!-- Header buttons -->
            <button
              id="btn-h1"
              type="button"
              class="ql-header"
              value="1"
              part="toolbar-button toolbar-button-h1"
              aria-label="${this.__effectiveI18n.h1}"
            ></button>
            <button
              id="btn-h2"
              type="button"
              class="ql-header"
              value="2"
              part="toolbar-button toolbar-button-h2"
              aria-label="${this.__effectiveI18n.h2}"
            ></button>
            <button
              id="btn-h3"
              type="button"
              class="ql-header"
              value="3"
              part="toolbar-button toolbar-button-h3"
              aria-label="${this.__effectiveI18n.h3}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-glyph-transformation">
            <!-- Subscript and superscript -->
            <button
              id="btn-subscript"
              class="ql-script"
              value="sub"
              part="toolbar-button toolbar-button-subscript"
              aria-label="${this.__effectiveI18n.subscript}"
            ></button>
            <button
              id="btn-superscript"
              class="ql-script"
              value="super"
              part="toolbar-button toolbar-button-superscript"
              aria-label="${this.__effectiveI18n.superscript}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-list">
            <!-- List buttons -->
            <button
              id="btn-ol"
              type="button"
              class="ql-list"
              value="ordered"
              part="toolbar-button toolbar-button-list-ordered"
              aria-label="${this.__effectiveI18n.listOrdered}"
            ></button>
            <button
              id="btn-ul"
              type="button"
              class="ql-list"
              value="bullet"
              part="toolbar-button toolbar-button-list-bullet"
              aria-label="${this.__effectiveI18n.listBullet}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-indent">
            <!-- Decrease -->
            <button
              id="btn-outdent"
              type="button"
              class="ql-indent"
              value="-1"
              part="toolbar-button toolbar-button-outdent"
              aria-label="${this.__effectiveI18n.outdent}"
            ></button>
            <!-- Increase -->
            <button
              id="btn-indent"
              type="button"
              class="ql-indent"
              value="+1"
              part="toolbar-button toolbar-button-indent"
              aria-label="${this.__effectiveI18n.indent}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-alignment">
            <!-- Align buttons -->
            <button
              id="btn-left"
              type="button"
              class="ql-align"
              value=""
              part="toolbar-button toolbar-button-align-left"
              aria-label="${this.__effectiveI18n.alignLeft}"
            ></button>
            <button
              id="btn-center"
              type="button"
              class="ql-align"
              value="center"
              part="toolbar-button toolbar-button-align-center"
              aria-label="${this.__effectiveI18n.alignCenter}"
            ></button>
            <button
              id="btn-right"
              type="button"
              class="ql-align"
              value="right"
              part="toolbar-button toolbar-button-align-right"
              aria-label="${this.__effectiveI18n.alignRight}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-rich-text">
            <!-- Image -->
            <button
              id="btn-image"
              type="button"
              part="toolbar-button toolbar-button-image"
              aria-label="${this.__effectiveI18n.image}"
              @touchend="${this._onImageTouchEnd}"
              @click="${this._onImageClick}"
            ></button>
            <!-- Link -->
            <button
              id="btn-link"
              type="button"
              part="toolbar-button toolbar-button-link"
              aria-label="${this.__effectiveI18n.link}"
              @click="${this._onLinkClick}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-block">
            <!-- Blockquote -->
            <button
              id="btn-blockquote"
              type="button"
              class="ql-blockquote"
              part="toolbar-button toolbar-button-blockquote"
              aria-label="${this.__effectiveI18n.blockquote}"
            ></button>
            <!-- Code block -->
            <button
              id="btn-code"
              type="button"
              class="ql-code-block"
              part="toolbar-button toolbar-button-code-block"
              aria-label="${this.__effectiveI18n.codeBlock}"
            ></button>
          </span>

          <span part="toolbar-group toolbar-group-format">
            <!-- Clean -->
            <button
              id="btn-clean"
              type="button"
              class="ql-clean"
              part="toolbar-button toolbar-button-clean"
              aria-label="${this.__effectiveI18n.clean}"
            ></button>
          </span>

          <input
            id="fileInput"
            type="file"
            accept="image/png, image/gif, image/jpeg, image/bmp, image/x-icon"
            @change="${this._uploadImage}"
          />
        </div>

        <div part="content"></div>

        <div class="announcer" aria-live="polite"></div>
      </div>

      <slot name="tooltip"></slot>

      <slot name="link-dialog"></slot>

      <slot name="color-popup"></slot>

      <slot name="background-popup"></slot>
    `;
  }
  /**
   * Override update to render slotted overlays into light DOM after rendering shadow DOM.
   * @param changedProperties
   * @protected
   */
  update(changedProperties) {
    super.update(changedProperties);
    this.__renderSlottedOverlays();
  }
  /** @private */
  __renderSlottedOverlays() {
    render$1(
      html`
        <vaadin-confirm-dialog
          slot="link-dialog"
          cancel-button-visible
          reject-theme="error"
          .opened="${this._linkEditing}"
          .header="${this.__effectiveI18n.linkDialogTitle}"
          .confirmText="${this.__effectiveI18n.ok}"
          .rejectText="${this.__effectiveI18n.remove}"
          .cancelText="${this.__effectiveI18n.cancel}"
          .rejectButtonVisible="${!!this._linkRange}"
          @confirm="${this._onLinkEditConfirm}"
          @cancel="${this._onLinkEditCancel}"
          @reject="${this._onLinkEditRemove}"
          @opened-changed="${this._onLinkEditingChanged}"
        >
          <vaadin-text-field
            .value="${this._linkUrl}"
            style="width: 100%;"
            @keydown="${this._onLinkKeydown}"
            @value-changed="${this._onLinkUrlChanged}"
          ></vaadin-text-field>
        </vaadin-confirm-dialog>

        <vaadin-rich-text-editor-popup
          slot="color-popup"
          .colors="${["#000000", ...[...this.colorOptions].filter((c) => c !== "#000000")]}"
          .opened="${this._colorEditing}"
          @color-selected="${this.__onColorSelected}"
          @opened-changed="${this.__onColorEditingChanged}"
        ></vaadin-rich-text-editor-popup>

        <vaadin-rich-text-editor-popup
          slot="background-popup"
          .colors="${["#ffffff", ...[...this.colorOptions].filter((c) => c !== "#ffffff")]}"
          .opened="${this._backgroundEditing}"
          @color-selected="${this.__onBackgroundSelected}"
          @opened-changed="${this.__onBackgroundEditingChanged}"
        ></vaadin-rich-text-editor-popup>
      `,
      this,
      { host: this }
    );
  }
  /** @private */
  __onBackgroundEditingChanged(event) {
    this._backgroundEditing = event.detail.value;
  }
  /** @private */
  __onColorEditingChanged(event) {
    this._colorEditing = event.detail.value;
  }
  /** @private */
  _onLinkEditingChanged(event) {
    if (event.detail.value) {
      const confirmDialog = event.target;
      const urlField = confirmDialog.querySelector("vaadin-text-field");
      confirmDialog.$.overlay.addEventListener(
        "vaadin-overlay-open",
        () => {
          urlField.focus({ focusVisible: isKeyboardActive() });
        },
        { once: true }
      );
    }
    this._linkEditing = event.detail.value;
  }
  /** @private */
  _onLinkUrlChanged(event) {
    this._linkUrl = event.detail.value;
  }
}
defineCustomElement(RichTextEditor);
window.Vaadin.Flow.selectConnector = {};
window.Vaadin.Flow.selectConnector.initLazy = (select) => {
  if (select.$connector) {
    return;
  }
  select.$connector = {};
  select.renderer = (root) => {
    const listBox = select.querySelector("vaadin-select-list-box");
    if (listBox) {
      if (root.firstChild) {
        root.removeChild(root.firstChild);
      }
      root.appendChild(listBox);
    }
  };
};
const _window$1 = window;
_window$1.Vaadin ||= {};
_window$1.Vaadin.Flow ||= {};
_window$1.Vaadin.Flow.tooltip ||= {};
Object.assign(_window$1.Vaadin.Flow.tooltip, {
  setDefaultHideDelay: (hideDelay) => Tooltip$2.setDefaultHideDelay(hideDelay),
  setDefaultFocusDelay: (focusDelay) => Tooltip$2.setDefaultFocusDelay(focusDelay),
  setDefaultHoverDelay: (hoverDelay) => Tooltip$2.setDefaultHoverDelay(hoverDelay)
});
const { defaultHideDelay, defaultFocusDelay, defaultHoverDelay } = _window$1.Vaadin.Flow.tooltip;
if (defaultHideDelay) {
  Tooltip$2.setDefaultHideDelay(defaultHideDelay);
}
if (defaultFocusDelay) {
  Tooltip$2.setDefaultFocusDelay(defaultFocusDelay);
}
if (defaultHoverDelay) {
  Tooltip$2.setDefaultHoverDelay(defaultHoverDelay);
}
document.addEventListener("click", (event) => {
  const target = event.composedPath().find((node) => node.hasAttribute && node.hasAttribute("disableonclick"));
  if (target) {
    target.disabled = true;
  }
});
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function containsQueryParams(actual, expected) {
  return [...expected.entries()].every(([key2, value]) => {
    return actual.getAll(key2).includes(value);
  });
}
function matchPaths(actual, expected, matchOptions = { matchNested: false }) {
  const base2 = document.baseURI;
  const actualUrl = new URL(actual, base2);
  const expectedUrl = new URL(expected, base2);
  const matchesOrigin = actualUrl.origin === expectedUrl.origin;
  const matchesPath = matchOptions.matchNested ? actualUrl.pathname === expectedUrl.pathname || actualUrl.pathname.startsWith(`${expectedUrl.pathname}/`) : actualUrl.pathname === expectedUrl.pathname;
  return matchesOrigin && matchesPath && containsQueryParams(actualUrl.searchParams, expectedUrl.searchParams);
}
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const location$1 = {
  get pathname() {
    return document.location.pathname;
  },
  get search() {
    return document.location.search;
  }
};
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const sharedStyles = css$h`
  :host {
    display: flex;
    flex-direction: column;
    min-width: 0;
    max-width: 100%;
    gap: var(--vaadin-side-nav-items-gap, var(--vaadin-gap-s));
    cursor: default;
    -webkit-tap-highlight-color: transparent;
  }

  :host([hidden]),
  [hidden] {
    display: none !important;
  }

  button {
    appearance: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: inherit;
    cursor: var(--vaadin-clickable-cursor);
    flex: none;
  }

  [part='toggle-button'] {
    border-radius: var(--vaadin-side-nav-item-border-radius, var(--vaadin-radius-s));
    color: var(--vaadin-text-color-secondary);
  }

  [part='toggle-button']::before {
    content: '';
    display: block;
    background: currentColor;
    mask: var(--_vaadin-icon-chevron-down) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
    width: var(--vaadin-icon-size, 1lh);
    height: var(--vaadin-icon-size, 1lh);
    rotate: -90deg;
  }

  :host([dir='rtl']) [part='toggle-button']::before {
    scale: -1;
  }

  :host(:is(vaadin-side-nav-item[expanded], vaadin-side-nav:not([collapsed]))) [part='toggle-button'] {
    rotate: 90deg;
  }

  :host([dir='rtl']:is(vaadin-side-nav-item[expanded], vaadin-side-nav:not([collapsed]))) [part='toggle-button'] {
    rotate: -90deg;
  }

  @media (prefers-reduced-motion: no-preference) {
    [part='toggle-button'] {
      transition: rotate 150ms;
    }
  }

  :host([disabled]) [part='toggle-button'] {
    opacity: 0.5;
  }

  [part='children'] {
    padding: 0;
    margin: 0;
    list-style-type: none;
    display: flex;
    flex-direction: column;
    gap: var(--vaadin-side-nav-items-gap, var(--vaadin-gap-s));
  }

  [part='children'] slot {
    --_icon-indent-2: var(--_icon-indent);
  }

  :focus-visible {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }

  @media (forced-colors: active) {
    [part='toggle-button']::before {
      background: CanvasText;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const sideNavItem = css$h`
  [part='content'] {
    display: flex;
    align-items: center;
    min-width: 0;
    max-width: 100%;
    padding: var(
      --vaadin-side-nav-item-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
    --_gap: var(--vaadin-side-nav-item-gap, var(--vaadin-gap-s));
    gap: var(--_gap);
    font-size: var(--vaadin-side-nav-item-font-size, 1em);
    font-weight: var(--vaadin-side-nav-item-font-weight, 500);
    line-height: var(--vaadin-side-nav-item-line-height, inherit);
    color: var(--vaadin-side-nav-item-text-color, var(--vaadin-text-color-secondary));
    background: var(--vaadin-side-nav-item-background, transparent);
    background-origin: border-box;
    border: var(--vaadin-side-nav-item-border-width, 0) solid var(--vaadin-side-nav-item-border-color, transparent);
    border-radius: var(--vaadin-side-nav-item-border-radius, var(--vaadin-radius-m));
    cursor: var(--vaadin-clickable-cursor);
    touch-action: manipulation;
    contain: layout;
  }

  :host([current]) [part='content'] {
    --vaadin-side-nav-item-background: var(--vaadin-background-container);
    --vaadin-side-nav-item-text-color: var(--vaadin-text-color);
  }

  :host([disabled]) {
    --vaadin-clickable-cursor: var(--vaadin-disabled-cursor);
  }

  :host([disabled]) [part='content'] {
    --vaadin-side-nav-item-text-color: var(--vaadin-text-color-disabled);
  }

  :host(:not([has-children])) {
    gap: 0;
  }

  [part='link'] {
    flex: auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: inherit;
    text-decoration: none;
    color: inherit;
    outline: 0;
  }

  :host(:not([has-children])) [part='toggle-button'] {
    display: none !important;
  }

  slot:not([name]) {
    display: block;
    flex: auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Don't clip ascenders or descenders */
    padding-block: 0.25em;
    margin-block: -0.25em;
  }

  slot:is([name='prefix'], [name='suffix'])::slotted(*) {
    flex: none;
  }

  [part='content']:not(:has([href])):has([part='toggle-button']:focus-visible),
  [part='content']:has(:not([part='toggle-button']):focus-visible),
  [part='content']:has([href]) [part='toggle-button']:focus-visible {
    outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
  }

  [part='content']:not(:has([href])) [part='toggle-button']:focus-visible {
    outline: 0;
  }

  /* Hierarchy indentation */
  [part='content']::before {
    content: '';
    width: calc(
      var(--vaadin-side-nav-child-indent, 1em) * var(--_level, 0) + var(--_icon-indent, 0) *
        (var(--vaadin-icon-size, 1lh) + var(--_gap))
    );
    flex: none;
    margin-inline-start: calc(var(--_gap) * -1);
  }

  [part='children'] {
    --_level: calc(var(--_level-2, 0) + 1);
  }

  [part='children'] ::slotted(*) {
    --_level-2: var(--_level);
  }

  @media (forced-colors: active) {
    [part='content'] {
      border: 1px solid Canvas !important;
    }

    :host([current]) [part='content'] {
      color: Highlight !important;
      border-color: Highlight !important;
    }

    :host([disabled]) [part='content'] {
      --vaadin-side-nav-item-text-color: GrayText !important;
    }

    :host([disabled]) [part='toggle-button']::before {
      background: GrayText !important;
    }
  }
`;
const sideNavItemStyles = [sharedStyles, screenReaderOnly, sideNavItem];
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N$2 = {
  toggle: "Toggle child items"
};
class ChildrenController extends SlotController {
  constructor(host, slotName) {
    super(host, slotName, null, { observe: true, multiple: true });
  }
  /**
   * @protected
   * @override
   */
  initAddedNode() {
    this.host.requestUpdate();
  }
  /**
   * @protected
   * @override
   */
  teardownNode() {
    this.host.requestUpdate();
  }
}
const SideNavChildrenMixin = (superClass) => class SideNavChildrenMixin extends I18nMixin(DEFAULT_I18N$2, superClass) {
  static get properties() {
    return {
      /**
       * Count of child items.
       * @protected
       */
      _itemsCount: {
        type: Number,
        value: 0
      }
    };
  }
  constructor() {
    super();
    this._childrenController = new ChildrenController(this, this._itemsSlotName);
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following structure and default values:
   * ```js
   * {
   *   toggle: 'Toggle child items'
   * }
   * ```
   * @type {!SideNavI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /**
   * List of child items of this component.
   * @protected
   */
  get _items() {
    return this._childrenController.nodes;
  }
  /**
   * Name of the slot to be used for children.
   * @protected
   */
  get _itemsSlotName() {
    return "children";
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    this.addController(this._childrenController);
  }
  /**
   * @protected
   * @override
   */
  willUpdate(props) {
    super.willUpdate(props);
    this._itemsCount = this._items.length;
  }
  /**
   * @protected
   * @override
   */
  updated(props) {
    super.updated(props);
    if (props.has("_itemsCount")) {
      this.toggleAttribute("has-children", this._itemsCount > 0);
    }
    if (props.has("_itemsCount") || props.has("__effectiveI18n")) {
      this._items.forEach((item) => {
        item.i18n = this.__effectiveI18n;
      });
    }
  }
};
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class SideNavItem extends SideNavChildrenMixin(
  DisabledMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-side-nav-item";
  }
  static get properties() {
    return {
      /**
       * The path to navigate to
       */
      path: {
        type: String
      },
      /**
       * The list of alternative paths matching this item
       *
       * @type {!Array<string>}
       */
      pathAliases: {
        type: Array,
        value: () => []
      },
      /**
       * Whether to show the child items or not
       *
       */
      expanded: {
        type: Boolean,
        value: false,
        notify: true,
        reflectToAttribute: true
      },
      /**
       * Whether to also match nested paths / routes. `false` by default.
       *
       * When enabled, an item with the path `/path` is considered current when
       * the browser URL is `/path`, `/path/child`, `/path/child/grandchild`,
       * etc.
       *
       * Note that this only affects matching of the URLs path, not the base
       * origin or query parameters.
       *
       * @attr {boolean} match-nested
       */
      matchNested: {
        type: Boolean,
        value: false
      },
      /**
       * Whether the item's path matches the current browser URL.
       *
       * A match occurs when both share the same base origin (like https://example.com),
       * the same path (like /path/to/page), and the browser URL contains at least
       * all the query parameters with the same values from the item's path.
       *
       * See [`matchNested`](#/elements/vaadin-side-nav-item#property-matchNested) for how to change the path matching behavior.
       *
       * The state is updated when the item is added to the DOM or when the browser
       * navigates to a new page.
       *
       */
      current: {
        type: Boolean,
        value: false,
        readOnly: true,
        reflectToAttribute: true
      },
      /**
       * The target of the link. Works only when `path` is set.
       */
      target: {
        type: String
      },
      /**
       * Whether to exclude the item from client-side routing. When enabled,
       * this causes the item to behave like a regular anchor, causing a full
       * page reload. This only works with supported routers, such as the one
       * provided in Vaadin apps, or when using the side nav `onNavigate` hook.
       *
       * @attr {boolean} router-ignore
       */
      routerIgnore: {
        type: Boolean,
        value: false
      },
      /** @private */
      __tooltipText: {
        type: String
      }
    };
  }
  static get styles() {
    return sideNavItemStyles;
  }
  constructor() {
    super();
    this.__boundUpdateCurrent = this.__updateCurrent.bind(this);
  }
  /** @protected */
  get _button() {
    return this.shadowRoot.querySelector("button");
  }
  /**
   * @protected
   * @override
   */
  firstUpdated() {
    super.firstUpdated();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "listitem");
    }
  }
  /**
   * @protected
   * @override
   */
  updated(props) {
    super.updated(props);
    if (props.has("path") || props.has("pathAliases") || props.has("matchNested")) {
      this.__updateCurrent();
    }
    if (props.has("disabled") || props.has("_itemsCount")) {
      this._items.forEach((item) => {
        item.disabled = this.disabled;
      });
    }
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    this.__updateCurrent();
    window.addEventListener("popstate", this.__boundUpdateCurrent);
    window.addEventListener("vaadin-navigated", this.__boundUpdateCurrent);
    window.addEventListener("side-nav-location-changed", this.__boundUpdateCurrent);
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    window.removeEventListener("popstate", this.__boundUpdateCurrent);
    window.removeEventListener("vaadin-navigated", this.__boundUpdateCurrent);
    window.removeEventListener("side-nav-location-changed", this.__boundUpdateCurrent);
  }
  /** @protected */
  render() {
    return html`
      <div id="content" part="content" @click="${this._onContentClick}">
        <a
          id="link"
          ?disabled="${this.disabled}"
          tabindex="${this.disabled || this.path == null ? "-1" : "0"}"
          href="${ifDefined(this.disabled ? null : this.path)}"
          target="${ifDefined(this.target)}"
          ?router-ignore="${this.routerIgnore}"
          part="link"
          aria-current="${this.current ? "page" : "false"}"
        >
          <slot name="prefix"></slot>
          <slot></slot>
          <div class="sr-only">${this.__tooltipText}</div>
          <slot name="suffix"></slot>
        </a>
        <button
          part="toggle-button"
          ?disabled="${this.disabled}"
          @click="${this._onButtonClick}"
          aria-controls="children"
          aria-expanded="${this.expanded}"
          aria-labelledby="link i18n"
        ></button>
      </div>
      <ul part="children" role="list" ?hidden="${!this.expanded}" aria-hidden="${this.expanded ? "false" : "true"}">
        <slot name="children"></slot>
      </ul>
      <div hidden id="i18n">${this.__effectiveI18n.toggle}</div>
      <slot name="tooltip"></slot>
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this._tooltipController = new TooltipController(this);
    this._tooltipController.setTarget(this.$.content);
    this._tooltipController.setAriaTarget(null);
    this._tooltipController.addEventListener("tooltip-changed", (event) => {
      const { node } = event.detail;
      if (node) {
        this.__tooltipText = node.textContent.trim();
        node.setAttribute("aria-hidden", "true");
      } else {
        this.__tooltipText = "";
      }
    });
    this.addController(this._tooltipController);
  }
  /** @private */
  _onButtonClick(event) {
    event.stopPropagation();
    this.__toggleExpanded();
  }
  /** @private */
  _onContentClick(e) {
    if (this.path && !e.composedPath().find((el) => el === this.$.link)) {
      this.$.link.click();
    } else if (this.path == null && this.hasAttribute("has-children") && !this.disabled) {
      this.__toggleExpanded();
    }
  }
  /** @private */
  __toggleExpanded() {
    this.expanded = !this.expanded;
  }
  /** @private */
  __updateCurrent() {
    this._setCurrent(this.__isCurrent());
    if (this.current) {
      this.__expandParentItems();
      this.expanded = this._items.length > 0;
    }
  }
  /** @private */
  __expandParentItems() {
    const sideNav2 = this.closest("vaadin-side-nav");
    if (sideNav2 && sideNav2.noAutoExpand) {
      return;
    }
    const parentItem = this.__getParentItem();
    if (parentItem) {
      parentItem.__expandParentItems();
    }
    this.expanded = true;
  }
  /** @private */
  __getParentItem() {
    return this.parentElement instanceof SideNavItem ? this.parentElement : null;
  }
  /** @private */
  __isCurrent() {
    if (this.path == null) {
      return false;
    }
    const browserPath = `${location$1.pathname}${location$1.search}`;
    const matchOptions = { matchNested: this.matchNested };
    return matchPaths(browserPath, this.path, matchOptions) || this.pathAliases.some((alias) => matchPaths(browserPath, alias, matchOptions));
  }
}
defineCustomElement(SideNavItem);
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const sideNav = css$h`
  :host {
    white-space: nowrap;
    touch-action: manipulation;
  }

  [part='label'] {
    align-self: start;
    display: flex;
    align-items: center;
    justify-content: start;
    gap: var(--vaadin-side-nav-item-gap, var(--vaadin-gap-s));
    padding: var(
      --vaadin-side-nav-item-padding,
      var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
    );
    font-size: var(--vaadin-side-nav-label-font-size, max(11px, 0.875em));
    font-weight: var(--vaadin-side-nav-label-font-weight, 500);
    color: var(--vaadin-side-nav-label-color, var(--vaadin-text-color-secondary));
    line-height: var(--vaadin-side-nav-label-line-height, inherit);
    border-radius: var(--vaadin-side-nav-item-border-radius, var(--vaadin-radius-m));
    touch-action: manipulation;
    min-width: 0;
    max-width: 100%;
  }

  ::slotted([slot='label']) {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    margin: 0;
  }
`;
const sideNavStyles = [sharedStyles, sideNav];
const sideNavSlotStyles = css$h`
  :where(vaadin-side-nav:has(> vaadin-side-nav-item > vaadin-icon[slot='prefix']))::part(children),
  :where(vaadin-side-nav-item:has(> vaadin-side-nav-item[slot='children'] > vaadin-icon[slot='prefix']))::part(
    children
  ) {
    --_icon-indent: calc(var(--_icon-indent-2, 0) + 1);
  }

  :where(vaadin-side-nav-item:has(> vaadin-icon[slot='prefix']))::part(content) {
    --_icon-indent: calc(var(--_icon-indent-2) - 1);
  }

  :where(
    vaadin-side-nav-item:has(> vaadin-icon[slot='prefix']):has(> vaadin-side-nav-item > vaadin-icon[slot='prefix'])
  )::part(children) {
    --_level: var(--_level-2, 0);
  }

  vaadin-side-nav:not(:has([slot='label']))::part(label) {
    display: none;
  }
`;
/**
 * @license
 * Copyright (c) 2023 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class SideNav extends SideNavChildrenMixin(
  SlotStylesMixin(FocusMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))))
) {
  static get is() {
    return "vaadin-side-nav";
  }
  static get shadowRootOptions() {
    return { ...LitElement.shadowRootOptions, delegatesFocus: true };
  }
  static get properties() {
    return {
      /**
       * Whether the side nav is collapsible. When enabled, the toggle icon is shown.
       *
       */
      collapsible: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * Whether the side nav is collapsed. When collapsed, the items are hidden.
       *
       */
      collapsed: {
        type: Boolean,
        value: false,
        notify: true,
        reflectToAttribute: true
      },
      /**
       * Callback function for router integration.
       *
       * When a side nav item link is clicked, this function is called and the default click action is cancelled.
       * This delegates the responsibility of navigation to the function's logic.
       *
       * The click event action is not cancelled in the following cases:
       * - The click event has a modifier (e.g. `metaKey`, `shiftKey`)
       * - The click event is on an external link
       * - The click event is on a link with `target="_blank"`
       * - The function explicitly returns `false`
       *
       * The function receives an object with the properties of the clicked side-nav item:
       * - `path`: The path of the navigation item.
       * - `target`: The target of the navigation item.
       * - `current`: A boolean indicating whether the navigation item is currently selected.
       * - `expanded`: A boolean indicating whether the navigation item is expanded.
       * - `pathAliases`: An array of path aliases for the navigation item.
       * - `originalEvent`: The original DOM event that triggered the navigation.
       *
       * Also see the `location` property for updating the highlighted navigation item on route change.
       *
       * @type {function(Object): boolean | undefined}
       */
      onNavigate: {
        attribute: false
      },
      /**
       * A change to this property triggers an update of the highlighted item in the side navigation. While it typically
       * corresponds to the browser's URL, the specific value assigned to the property is irrelevant. The component has
       * its own internal logic for determining which item is highlighted.
       *
       * The main use case for this property is when the side navigation is used with a client-side router. In this case,
       * the component needs to be informed about route changes so it can update the highlighted item.
       *
       * @type {any}
       */
      location: {
        observer: "__locationChanged"
      },
      /**
       * Whether to expand parent items of the nested matching item after initial
       * rendering or navigation. By default, all the parent items are expanded.
       * Set to true to disable this behavior.
       *
       * @attr {boolean} no-auto-expand
       */
      noAutoExpand: {
        type: Boolean,
        reflectToAttribute: true,
        value: false
      }
    };
  }
  static get styles() {
    return sideNavStyles;
  }
  /** @protected */
  get slotStyles() {
    return [sideNavSlotStyles];
  }
  constructor() {
    super();
    this._labelId = `side-nav-label-${generateUniqueId()}`;
    this.addEventListener("click", this.__onClick);
  }
  /**
   * Name of the slot to be used for children.
   * @protected
   * @override
   */
  get _itemsSlotName() {
    return "";
  }
  /** @protected */
  get focusElement() {
    return this.shadowRoot.querySelector("button");
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    if (!this.hasAttribute("role")) {
      this.setAttribute("role", "navigation");
    }
  }
  /** @protected */
  render() {
    return html`
      ${this.collapsible ? html`
            <button
              part="label"
              @click="${this._onLabelClick}"
              aria-expanded="${!this.collapsed}"
              aria-controls="children"
            >
              <slot name="label" @slotchange="${this._onLabelSlotChange}"></slot>
              <span part="toggle-button" aria-hidden="true"></span>
            </button>
          ` : html`
            <div part="label">
              <slot name="label" @slotchange="${this._onLabelSlotChange}"></slot>
            </div>
          `}
      <ul
        id="children"
        role="list"
        part="children"
        ?hidden="${this.collapsed}"
        aria-hidden="${this.collapsed ? "true" : "false"}"
      >
        <slot></slot>
      </ul>
    `;
  }
  /**
   * @param {Event} event
   * @return {boolean}
   * @protected
   * @override
   */
  _shouldSetFocus(event) {
    return event.composedPath()[0] === this.focusElement;
  }
  /** @private */
  _onLabelClick() {
    if (this.collapsible) {
      this.__toggleCollapsed();
    }
  }
  /** @private */
  _onLabelSlotChange() {
    const label = this.querySelector('[slot="label"]');
    if (label) {
      if (!label.id) {
        label.id = this._labelId;
      }
      this.setAttribute("aria-labelledby", label.id);
    } else {
      this.removeAttribute("aria-labelledby");
    }
  }
  /** @private */
  __locationChanged() {
    window.dispatchEvent(new CustomEvent("side-nav-location-changed"));
  }
  /** @private */
  __toggleCollapsed() {
    this.collapsed = !this.collapsed;
  }
  /** @private */
  __onClick(e) {
    if (!this.onNavigate) {
      return;
    }
    const hasModifier = e.metaKey || e.shiftKey;
    if (hasModifier) {
      return;
    }
    const composedPath = e.composedPath();
    const item = composedPath.find((el) => el.localName && el.localName.includes("side-nav-item"));
    const anchor = composedPath.find((el) => el instanceof HTMLAnchorElement);
    if (!item || !item.shadowRoot.contains(anchor)) {
      return;
    }
    const isRelative = anchor.href && anchor.href.startsWith(location.origin);
    if (!isRelative) {
      return;
    }
    if (item.target === "_blank") {
      return;
    }
    if (item.routerIgnore) {
      return;
    }
    const result = this.onNavigate({
      path: item.path,
      target: item.target,
      current: item.current,
      expanded: item.expanded,
      pathAliases: item.pathAliases,
      originalEvent: e
    });
    if (result !== false) {
      e.preventDefault();
    }
  }
}
defineCustomElement(SideNav);
/**
 * @license
 * Copyright (c) 2026 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const sliderBubbleOverlay = css$h`
  :host {
    --_arrow-size: var(--vaadin-slider-bubble-arrow-size, 8px);
    --_border-width: var(
      --vaadin-slider-bubble-border-width,
      var(--vaadin-tooltip-border-width, var(--vaadin-overlay-border-width, 1px))
    );
    --_default-offset: var(--vaadin-slider-bubble-offset, 2px);
    --_rtl-multiplier: 1;
  }

  :host([dir='rtl']) {
    --_rtl-multiplier: -1;
  }

  [part='overlay'] {
    position: relative;
    overflow: visible;
    max-width: var(--vaadin-tooltip-max-width, 40ch);
    padding: var(
      --vaadin-slider-bubble-padding,
      var(--vaadin-tooltip-padding, var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container))
    );
    border: var(
        --vaadin-slider-bubble-border-width,
        var(--vaadin-tooltip-border-width, var(--vaadin-overlay-border-width, 1px))
      )
      solid
      var(
        --vaadin-slider-bubble-border-color,
        var(--vaadin-tooltip-border-color, var(--vaadin-overlay-border-color, var(--vaadin-border-color-secondary)))
      );
    border-radius: var(
      --vaadin-slider-bubble-border-radius,
      var(--vaadin-tooltip-border-radius, var(--vaadin-radius-m))
    );
    background: var(
      --vaadin-slider-bubble-background,
      var(--vaadin-tooltip-background, var(--vaadin-background-color))
    );
    color: var(--vaadin-slider-bubble-text-color, var(--vaadin-tooltip-text-color, inherit));
    font-size: var(--vaadin-slider-bubble-font-size, var(--vaadin-tooltip-font-size, 0.9em));
    font-weight: var(--vaadin-slider-bubble-font-weight, var(--vaadin-tooltip-font-weight, inherit));
    line-height: var(--vaadin-slider-bubble-line-height, var(--vaadin-tooltip-line-height, inherit));
    box-shadow: var(--vaadin-slider-bubble-shadow, var(--vaadin-tooltip-shadow, 0 3px 8px -1px rgba(0, 0, 0, 0.2)));
  }

  :host([top-aligned]) [part='overlay'] {
    margin-top: var(--vaadin-slider-bubble-offset, calc(var(--_arrow-size) + var(--_default-offset)));
  }

  :host([bottom-aligned]) [part='overlay'] {
    margin-bottom: var(--vaadin-slider-bubble-offset, calc(var(--_arrow-size) + var(--_default-offset)));
  }

  [part='arrow'] {
    display: block;
    position: absolute;
    background: inherit;
    border: inherit;
    border-start-start-radius: var(--vaadin-slider-bubble-arrow-border-radius, 0);
    inset-inline-start: 50%;
    outline: inherit;
    box-shadow: inherit;
    width: var(--_arrow-size);
    height: var(--_arrow-size);
    rotate: 45deg;
    --o: 20px; /* clip-path outset, how far outward it extends to reveal the outline and box shadow */
    --b: var(--_border-width);
    /* We need this elaborate clip-path to allow the arrow bg and border to cover
      the overlay border but prevent the outline and box-shadow from covering it */
    clip-path: polygon(
      calc(var(--o) * -1) calc(var(--o) * -1),
      calc(100% + var(--o) - var(--b)) calc(var(--o) * -1),
      calc(100% - var(--b) * 1.4) 0,
      100% 0,
      calc(100% - var(--b)) var(--b),
      calc(100% - var(--b)) calc(var(--b) + var(--ff, 0px)),
      calc(var(--b) + var(--ff, 0px)) calc(100% - var(--b)),
      calc(var(--b)) calc(100% - var(--b)),
      0 100%,
      0 calc(100% - var(--b) * 1.4),
      calc(var(--o) * -1) calc(100% + var(--o) - var(--b))
    );
  }

  /* Firefox renders a blurry edge for a diagonal clip-path + rotation,
    so we need to extend the clip-path slightly further on the diagonal */
  @supports (-moz-appearance: none) {
    [part='arrow'] {
      --ff: 1px;
    }
  }

  :host([top-aligned]) [part='arrow'] {
    top: 0;
    translate: calc(-50% * var(--_rtl-multiplier)) -50%;
  }

  :host([end-aligned][top-aligned]) [part='arrow'] {
    translate: calc(50% * var(--_rtl-multiplier)) -50%;
  }

  :host([bottom-aligned]) [part='arrow'] {
    bottom: 0;
    rotate: 225deg;
    translate: calc(-50% * var(--_rtl-multiplier)) 50%;
  }

  :host([end-aligned][bottom-aligned]) [part='arrow'] {
    translate: calc(50% * var(--_rtl-multiplier)) 50%;
  }
`;
const sliderBubbleOverlayStyles = [overlayStyles, sliderBubbleOverlay];
/**
 * @license
 * Copyright (c) 2026 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class SliderBubbleOverlay extends PositionMixin(
  OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))))
) {
  static get is() {
    return "vaadin-slider-bubble-overlay";
  }
  static get styles() {
    return sliderBubbleOverlayStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <div part="overlay" id="overlay">
        <div part="arrow"></div>
        <div part="content" id="content"><slot></slot></div>
      </div>
    `;
  }
  /**
   * Override method from `OverlayMixin` to not close on outside click.
   * The bubble overlay `opened` is fully controlled by the slider.
   * @return {boolean}
   * @protected
   * @override
   */
  _shouldCloseOnOutsideClick() {
    return false;
  }
  /**
   * @protected
   * @override
   */
  _updatePosition() {
    super._updatePosition();
    if (!this.positionTarget || !this.opened) {
      return;
    }
    const targetRect = this.positionTarget.getBoundingClientRect();
    const overlayRect = this.$.overlay.getBoundingClientRect();
    const offset2 = targetRect.width / 2 - overlayRect.width / 2;
    if (this.style.left) {
      const left = overlayRect.left + offset2;
      if (left > 0) {
        this.style.left = `${left}px`;
      }
    }
    if (this.style.right) {
      const right = parseFloat(this.style.right) + offset2;
      if (right > 0) {
        this.style.right = `${right}px`;
      }
    }
  }
}
defineCustomElement(SliderBubbleOverlay);
/**
 * @license
 * Copyright (c) 2026 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class SliderBubble extends ThemePropertyMixin(PolylitMixin(LitElement)) {
  static get is() {
    return "vaadin-slider-bubble";
  }
  static get styles() {
    return css$h`
      :host {
        display: contents;
      }
    `;
  }
  static get properties() {
    return {
      /**
       * The thumb element next to which the overlay should be aligned.
       */
      positionTarget: {
        type: Object
      },
      /**
       * Whether the overlay is opened.
       */
      opened: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      }
    };
  }
  /** @protected */
  render() {
    return html`
      <vaadin-slider-bubble-overlay
        id="overlay"
        .owner="${this}"
        .opened="${this.opened}"
        .positionTarget="${this.positionTarget}"
        theme="${ifDefined(this._theme)}"
        vertical-align="bottom"
        no-vertical-overlap
        modeless
        exportparts="overlay, content, arrow"
      >
        <slot></slot>
      </vaadin-slider-bubble-overlay>
    `;
  }
}
defineCustomElement(SliderBubble);
/**
 * @license
 * Copyright 2018 Google LLC
 * SPDX-License-Identifier: BSD-3-Clause
 */
const important = "important";
const importantFlag = " !" + important;
const flagTrim = 0 - importantFlag.length;
class StyleMapDirective extends Directive {
  constructor(partInfo) {
    super(partInfo);
    if (partInfo.type !== PartType.ATTRIBUTE || partInfo.name !== "style" || partInfo.strings?.length > 2) {
      throw new Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.");
    }
  }
  render(styleInfo) {
    return Object.keys(styleInfo).reduce((style, prop) => {
      const value = styleInfo[prop];
      if (value == null) {
        return style;
      }
      prop = prop.includes("-") ? prop : prop.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g, "-$&").toLowerCase();
      return style + `${prop}:${value};`;
    }, "");
  }
  update(part, [styleInfo]) {
    const { style } = part.element;
    if (this._previousStyleProperties === void 0) {
      this._previousStyleProperties = new Set(Object.keys(styleInfo));
      return this.render(styleInfo);
    }
    for (const name of this._previousStyleProperties) {
      if (styleInfo[name] == null) {
        this._previousStyleProperties.delete(name);
        if (name.includes("-")) {
          style.removeProperty(name);
        } else {
          style[name] = null;
        }
      }
    }
    for (const name in styleInfo) {
      const value = styleInfo[name];
      if (value != null) {
        this._previousStyleProperties.add(name);
        const isImportant = typeof value === "string" && value.endsWith(importantFlag);
        if (name.includes("-") || isImportant) {
          style.setProperty(name, isImportant ? value.slice(0, flagTrim) : value, isImportant ? important : "");
        } else {
          style[name] = value;
        }
      }
    }
    return noChange;
  }
}
const styleMap = directive(StyleMapDirective);
/**
 * @license
 * Copyright (c) 2026 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const sliderStyles = css$h`
  :host {
    box-sizing: border-box;
    user-select: none;
    -webkit-user-select: none;
    --_thumb-width: var(--vaadin-slider-thumb-width, 1lh);
    --_thumb-height: var(--vaadin-slider-thumb-height, 1lh);
  }

  :host([hidden]) {
    display: none !important;
  }

  :host([disabled]) {
    cursor: var(--vaadin-disabled-cursor);
    --vaadin-slider-fill-background: linear-gradient(
        var(--vaadin-border-color-secondary),
        var(--vaadin-border-color-secondary)
      )
      var(--vaadin-background-color);
    --vaadin-slider-thumb-background: var(--vaadin-slider-fill-background);
    --vaadin-slider-thumb-border-color: transparent;
  }

  :host([readonly]) {
    --vaadin-slider-fill-background: var(--vaadin-border-color);
    --vaadin-slider-thumb-background: var(--vaadin-background-color);
    --vaadin-slider-thumb-border-color: var(--vaadin-border-color);
    --_outline-style: dashed;
  }

  :host([min-max-visible]) {
    grid-template:
      'label' auto var(--_helper-above-field, 'helper' auto) 'baseline' 0 'input' 1fr 'marks' auto var(
        --_helper-below-field,
        'helper' auto
      )
      'error' auto / 100%;
  }

  #controls {
    grid-area: input;
    display: inline-grid;
    align-items: center;
    width: var(--vaadin-field-default-width, 12em);
    max-width: 100%;
    min-width: 100%;
    --_track-width: calc(100% - var(--_thumb-width));
  }

  :host([has-label]) #controls {
    border-block: var(--vaadin-input-field-border-width, 1px) solid transparent;
    padding-block: var(--vaadin-padding-block-container);
  }

  [part='track'] {
    box-sizing: border-box;
    grid-row: 1;
    grid-column: track-start / track-end;
    display: grid;
    grid-template-columns: subgrid;
    align-items: center;
    width: 100%;
    height: var(--vaadin-slider-track-height, 0.25lh);
    background: var(--vaadin-slider-track-background, var(--vaadin-background-container));
    border-radius: var(--vaadin-slider-track-border-radius, var(--vaadin-radius-m));
    border: var(--vaadin-slider-track-border-width, 0) solid
      var(--vaadin-slider-track-border-color, var(--vaadin-border-color-secondary));
  }

  [part='track-fill'] {
    box-sizing: border-box;
    grid-column: fill-start / fill-end;
    height: 100%;
    background: var(--vaadin-slider-fill-background, var(--vaadin-text-color));
    box-shadow: inset 0 0 0 var(--vaadin-slider-fill-border-width, 1px)
      var(--vaadin-slider-fill-border-color, transparent);
  }

  [part~='thumb'] {
    box-sizing: border-box;
    grid-row: 1;
    grid-column: thumb1;
    width: var(--_thumb-width);
    height: var(--_thumb-height);
    background: var(--vaadin-slider-thumb-background, var(--vaadin-background-color));
    border: var(--vaadin-slider-thumb-border-width, 1px) solid
      var(--vaadin-slider-thumb-border-color, var(--vaadin-text-color));
    border-radius: var(--vaadin-slider-thumb-border-radius, var(--vaadin-radius-l));
  }

  :host([readonly]) [part='track-fill'] {
    border-inline-end: none;
  }

  ::slotted(input) {
    grid-row: 1;
    grid-column: track-start / track-end;
    appearance: none;
    width: 100%;
    height: 100%;
    font: inherit;
    margin: 0;
    background: transparent;
    outline: 0;
    -webkit-tap-highlight-color: transparent;
    cursor: inherit;
    touch-action: none;
    z-index: 999;
  }

  [part='marks'] {
    display: none;
    font-size: var(--vaadin-slider-marks-font-size, 0.75em);
    font-weight: var(--vaadin-slider-marks-font-weight, inherit);
    color: var(--vaadin-slider-marks-color, var(--vaadin-text-color-secondary));
  }

  :host([min-max-visible]) [part='marks'] {
    grid-area: marks;
    display: flex;
    justify-content: space-between;
  }
`;
/**
 * @license
 * Copyright (c) 2026 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const SliderMixin = (superClass) => class SliderMixinClass extends SlotStylesMixin(DisabledMixin(superClass)) {
  static get properties() {
    return {
      /**
       * The minimum allowed value.
       */
      min: {
        type: Number,
        sync: true
      },
      /**
       * The maximum allowed value.
       */
      max: {
        type: Number,
        sync: true
      },
      /**
       * The stepping interval of the slider.
       */
      step: {
        type: Number,
        sync: true
      },
      /**
       * When true, the user cannot modify the value of the slider.
       * The difference between `disabled` and `readonly` is that the
       * read-only slider remains focusable and is announced by screen
       * readers.
       */
      readonly: {
        type: Boolean,
        reflectToAttribute: true
      },
      /**
       * When true, the value bubble is always visible,
       * regardless of focus or hover state.
       * @attr {boolean} value-always-visible
       */
      valueAlwaysVisible: {
        type: Boolean,
        value: false,
        sync: true
      },
      /**
       * When true, displays the min and max values below the slider track.
       * @attr {boolean} min-max-visible
       */
      minMaxVisible: {
        type: Boolean,
        reflectToAttribute: true
      },
      /** @private */
      __value: {
        type: Array,
        sync: true
      }
    };
  }
  /** @protected */
  get slotStyles() {
    const tag = this.localName;
    return [
      `
          ${tag} > input::-webkit-slider-runnable-track {
            height: 100%;
          }

          ${tag} > input::-webkit-slider-thumb {
            appearance: none;
            width: var(--_thumb-width);
            height: 100%;
            /* iOS needs these */
            background: transparent;
            box-shadow: none;
          }

          ${tag} > input::-moz-range-thumb {
            border: 0;
            background: transparent;
            width: var(--_thumb-width);
            height: 100%;
          }

          ${tag}:not([readonly]) > input::-webkit-slider-thumb {
            cursor: var(--vaadin-slider-thumb-cursor, grab);
          }

          ${tag}:not([readonly]) > input::-moz-range-thumb {
            cursor: var(--vaadin-slider-thumb-cursor, grab);
          }

          ${tag}:is([active], [start-active], [end-active]) > input::-webkit-slider-thumb {
            cursor: var(--vaadin-slider-thumb-cursor-active, grabbing);
          }

          ${tag}:is([active], [start-active], [end-active]) > input::-moz-range-thumb {
            cursor: var(--vaadin-slider-thumb-cursor-active, grabbing);
          }

          ${tag}[disabled] > input::-webkit-slider-thumb {
            cursor: var(--vaadin-disabled-cursor, not-allowed);
          }

          ${tag}[disabled] > input::-moz-range-thumb {
            cursor: var(--vaadin-disabled-cursor, not-allowed);
          }
        `
    ];
  }
  constructor() {
    super();
    this.addEventListener("pointerdown", (e) => this.__onPointerDown(e));
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    this.__lastCommittedValue = this.value;
  }
  /**
   * @param {number} value
   * @param {number} index
   * @param {number[]} fullValue
   * @private
   */
  __updateValue(value, index, fullValue = this.__value) {
    const { min: min2, max: max2, step } = this.__getConstraints();
    const minValue = fullValue[index - 1] !== void 0 ? fullValue[index - 1] : min2;
    const maxValue = fullValue[index + 1] !== void 0 ? fullValue[index + 1] : max2;
    const safeValue = Math.min(Math.max(value, minValue), maxValue);
    const precision = this.__getStepPrecision(step);
    const offset2 = safeValue - minValue;
    const nearestOffset = Math.round(offset2 / step) * step;
    const nearestValue = parseFloat((minValue + nearestOffset).toFixed(precision));
    const newValue = nearestValue <= maxValue ? nearestValue : parseFloat((nearestValue - step).toFixed(precision));
    this.__value = fullValue.with(index, newValue);
  }
  /** @private */
  __getStepPrecision(step) {
    const afterDecimal = String(step).split(".")[1];
    return afterDecimal ? afterDecimal.length : 0;
  }
  /**
   * @return {{ min: number, max: number, step: number}}
   * @private
   */
  __getConstraints() {
    return {
      min: this.min !== void 0 ? this.min : 0,
      max: this.max !== void 0 ? this.max : 100,
      step: this.step !== void 0 ? this.step : 1
    };
  }
  /**
   * @param {number} value
   * @return {number}
   * @private
   */
  __getPercentFromValue(value) {
    const { min: min2, max: max2 } = this.__getConstraints();
    if (max2 <= min2) {
      return 0;
    }
    const safeValue = Math.min(Math.max(value, min2), max2);
    return (safeValue - min2) / (max2 - min2);
  }
  /**
   * Updates bubble visibility for a thumb based on trigger state changes.
   * @param {Map} props - Changed properties from willUpdate
   * @param {object} config
   * @param {string} config.active - Active state property name
   * @param {string} config.focused - Focused state property name
   * @param {string} config.hover - Hover state property name
   * @param {string} config.opened - Bubble opened property name
   * @param {string} [config.otherOpened] - Other thumb's opened property (range slider)
   * @private
   */
  __updateBubbleState(props, { active, focused, hover, opened, otherOpened }) {
    if (props.has(active)) {
      if (this[active]) {
        this[hover] = true;
      } else if (props.get(active)) {
        this[opened] = this[hover];
      }
    }
    if (props.has(focused)) {
      if (this[focused]) {
        this[opened] = true;
        if (otherOpened) {
          this[otherOpened] = false;
        }
      } else if (props.get(focused)) {
        this[opened] = this[hover];
      }
    }
    if (props.has(hover)) {
      if (this[hover]) {
        this[opened] = true;
        if (otherOpened) {
          this[otherOpened] = false;
        }
      } else if (props.get(hover)) {
        this[opened] = this[active];
      }
    }
  }
  /**
   * @param {PointerEvent} event
   * @private
   */
  __onPointerDown(event) {
    if (!event.composedPath().includes(this.$.controls)) {
      return;
    }
    if (this.readonly) {
      event.preventDefault();
    }
  }
  /** @private */
  __dispatchInputEvent() {
    this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
  }
  /** @private */
  __detectAndDispatchChange() {
    if (JSON.stringify(this.__lastCommittedValue) !== JSON.stringify(this.value)) {
      this.__lastCommittedValue = this.value;
      this.dispatchEvent(new Event("change", { bubbles: true }));
    }
  }
  /**
   * @param {Event} event
   * @private
   */
  __onChange(event) {
    event.stopPropagation();
    this.__detectAndDispatchChange();
  }
  /**
   * Fired when the slider value changes during user interaction.
   *
   * @event input
   */
  /**
   * Fired when the user commits a value change.
   *
   * @event change
   */
};
/**
 * @license
 * Copyright (c) 2026 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class RangeSlider extends FieldMixin(
  SliderMixin(FocusMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))))
) {
  static get is() {
    return "vaadin-range-slider";
  }
  static get styles() {
    return [
      field,
      sliderStyles,
      css$h`
        :host([focus-ring][start-focused]) [part~='thumb-start'],
        :host([focus-ring][end-focused]) [part~='thumb-end'] {
          outline: var(--vaadin-focus-ring-width) var(--_outline-style, solid) var(--vaadin-focus-ring-color);
          outline-offset: 1px;
        }

        #controls {
          grid-template-columns:
            [track-start]
            calc(var(--start-value) * var(--_track-width))
            [thumb1]
            0
            [fill-start]
            calc((var(--end-value) - var(--start-value)) * var(--_track-width))
            [fill-end thumb2]
            0
            calc((1 - var(--end-value)) * var(--_track-width))
            var(--_thumb-width)
            [track-end];
        }

        [part='track-fill'] {
          margin-inline-start: var(--_thumb-width);
        }

        [part~='thumb-end'] {
          grid-column: thumb2;
        }

        :host([readonly]) [part='track-fill'] {
          border-inline-start: none;
        }

        ::slotted(input:last-of-type) {
          clip-path: inset(
            0 0 0
              clamp(
                0%,
                var(--_thumb-width) / 2 + var(--start-value) * var(--_track-width) +
                  (var(--end-value) - var(--start-value)) * var(--_track-width) / 2,
                100%
              )
          );
        }

        :host([dir='rtl']) ::slotted(input:last-of-type) {
          clip-path: inset(
            0
              clamp(
                0%,
                var(--_thumb-width) / 2 + var(--start-value) * var(--_track-width) +
                  (var(--end-value) - var(--start-value)) * var(--_track-width) / 2,
                100%
              )
              0 0
          );
        }
      `
    ];
  }
  static get experimental() {
    return "sliderComponent";
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  static get properties() {
    return {
      /**
       * The value of the slider.
       */
      value: {
        type: Array,
        value: () => [0, 100],
        notify: true,
        sync: true
      },
      /**
       * Custom accessible name for the start (minimum) input.
       * When not set, defaults to "${label} min" or "min" if no label.
       * @attr {string} accessible-name-start
       */
      accessibleNameStart: {
        type: String
      },
      /**
       * Custom accessible name for the end (maximum) input.
       * When not set, defaults to "${label} max" or "max" if no label.
       * @attr {string} accessible-name-end
       */
      accessibleNameEnd: {
        type: String
      },
      /** @private */
      __startActive: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        attribute: "start-active",
        sync: true
      },
      /** @private */
      __endActive: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        attribute: "end-active",
        sync: true
      },
      /** @private */
      __startFocused: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        attribute: "start-focused",
        sync: true
      },
      /** @private */
      __endFocused: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        attribute: "end-focused",
        sync: true
      },
      /** @private */
      __startHover: {
        type: Boolean,
        value: false,
        sync: true
      },
      /** @private */
      __endHover: {
        type: Boolean,
        value: false,
        sync: true
      },
      /** @private */
      __startBubbleOpened: {
        type: Boolean,
        value: false,
        sync: true
      },
      /** @private */
      __endBubbleOpened: {
        type: Boolean,
        value: false,
        sync: true
      }
    };
  }
  /** @protected */
  render() {
    const [startValue, endValue] = this.__value;
    const startPercent = this.__getPercentFromValue(startValue);
    const endPercent = this.__getPercentFromValue(endValue);
    const { min: min2, max: max2 } = this.__getConstraints();
    return html`
      <div class="vaadin-slider-container">
        <div part="label" @click="${this.focus}">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true"></span>
        </div>

        <div id="controls" style="${styleMap({ "--start-value": startPercent, "--end-value": endPercent })}">
          <div part="track">
            <div part="track-fill"></div>
          </div>
          <div part="thumb thumb-start"></div>
          <div part="thumb thumb-end"></div>
          <slot name="input"></slot>
          <slot name="bubble"></slot>
        </div>

        <div part="marks" aria-hidden="true">
          <span part="min">${min2}</span>
          <span part="max">${max2}</span>
        </div>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>
      </div>
    `;
  }
  constructor() {
    super();
    this.__value = [...this.value];
    this.__inputId0 = `slider-${generateUniqueId()}`;
    this.__inputId1 = `slider-${generateUniqueId()}`;
    this.__onPointerUp = this.__onPointerUp.bind(this);
  }
  /** @protected */
  firstUpdated() {
    super.firstUpdated();
    const inputs = this.querySelectorAll('[slot="input"]');
    this._inputElements = [...inputs];
    this.ariaTarget = this;
    this.__thumbStartElement = this.shadowRoot.querySelector('[part~="thumb-start"]');
    this.__thumbEndElement = this.shadowRoot.querySelector('[part~="thumb-end"]');
    this.__bubbleElements = [...this.querySelectorAll("vaadin-slider-bubble")];
  }
  /** @private */
  __onPointerDown(event) {
    super.__onPointerDown(event);
    const index = this._inputElements.indexOf(event.composedPath()[0]);
    if (!this.readonly && index !== -1) {
      this.toggleAttribute("start-active", index === 0);
      this.toggleAttribute("end-active", index === 1);
      window.addEventListener("pointerup", this.__onPointerUp);
      window.addEventListener("pointercancel", this.__onPointerUp);
    }
  }
  /** @private */
  __onPointerUp() {
    window.removeEventListener("pointerup", this.__onPointerUp);
    window.removeEventListener("pointercancel", this.__onPointerUp);
    this.removeAttribute("start-active");
    this.removeAttribute("end-active");
  }
  /**
   * Override update to render slotted `<input type="range" />`
   * into light DOM after rendering shadow DOM.
   * @protected
   */
  update(props) {
    super.update(props);
    const [startValue, endValue] = this.__value;
    const { min: min2, max: max2, step } = this.__getConstraints();
    render$1(
      html`
        <input
          type="range"
          id="${this.__inputId0}"
          slot="input"
          aria-label="${this.accessibleNameStart || this.__getAriaLabel("min")}"
          .min="${min2}"
          .max="${max2}"
          .step="${step}"
          .value="${startValue}"
          .disabled="${this.disabled}"
          tabindex="${this.disabled ? -1 : 0}"
          @pointerenter="${this.__onStartPointerEnter}"
          @pointermove="${this.__onStartPointerMove}"
          @pointerleave="${this.__onStartPointerLeave}"
          @keydown="${this.__onKeyDown}"
          @input="${this.__onStartInput}"
          @change="${this.__onChange}"
        />
        <input
          type="range"
          id="${this.__inputId1}"
          slot="input"
          aria-label="${this.accessibleNameEnd || this.__getAriaLabel("max")}"
          .min="${min2}"
          .max="${max2}"
          .step="${step}"
          .value="${endValue}"
          .disabled="${this.disabled}"
          tabindex="${this.disabled ? -1 : 0}"
          @pointerenter="${this.__onEndPointerEnter}"
          @pointermove="${this.__onEndPointerMove}"
          @pointerleave="${this.__onEndPointerLeave}"
          @keydown="${this.__onKeyDown}"
          @input="${this.__onEndInput}"
          @change="${this.__onChange}"
        />
        <vaadin-slider-bubble
          slot="bubble"
          .positionTarget="${this.__thumbStartElement}"
          .opened="${this.valueAlwaysVisible || this.__startBubbleOpened}"
          theme="${ifDefined(this._theme)}"
        >
          ${startValue}
        </vaadin-slider-bubble>
        <vaadin-slider-bubble
          slot="bubble"
          .positionTarget="${this.__thumbEndElement}"
          .opened="${this.valueAlwaysVisible || this.__endBubbleOpened}"
          theme="${ifDefined(this._theme)}"
        >
          ${endValue}
        </vaadin-slider-bubble>
      `,
      this,
      { host: this }
    );
  }
  /** @protected */
  willUpdate(props) {
    super.willUpdate(props);
    this.__updateBubbleState(props, {
      active: "__startActive",
      focused: "__startFocused",
      hover: "__startHover",
      opened: "__startBubbleOpened",
      otherOpened: "__endBubbleOpened"
    });
    this.__updateBubbleState(props, {
      active: "__endActive",
      focused: "__endFocused",
      hover: "__endHover",
      opened: "__endBubbleOpened",
      otherOpened: "__startBubbleOpened"
    });
  }
  /** @protected */
  updated(props) {
    super.updated(props);
    if (props.has("value") || props.has("min") || props.has("max") || props.has("step")) {
      const value = [...this.value];
      value.forEach((v, idx) => {
        this.__updateValue(v, idx, value);
      });
    }
  }
  /**
   * @param {FocusOptions=} options
   * @protected
   * @override
   */
  focus(options2) {
    if (this.disabled) {
      return;
    }
    if (this._inputElements) {
      this._inputElements[0].focus();
    }
    super.focus(options2);
  }
  /**
   * @protected
   * @override
   */
  blur() {
    if (this._inputElements) {
      const focusedInput = this._inputElements.find((input) => isElementFocused(input));
      if (focusedInput) {
        focusedInput.blur();
      }
    }
  }
  /**
   * Override method inherited from `FocusMixin` to set
   * state attributes indicating which thumb has focus.
   *
   * @param {boolean} focused
   * @protected
   * @override
   */
  _setFocused(focused) {
    super._setFocused(focused);
    this.__startFocused = isElementFocused(this._inputElements[0]);
    this.__endFocused = isElementFocused(this._inputElements[1]);
  }
  /** @private */
  __getAriaLabel(suffix) {
    return this.label ? `${this.label} ${suffix}` : suffix;
  }
  /** @private */
  __commitValue() {
    this.value = [...this.__value];
  }
  /** @private */
  __onStartInput(event) {
    event.stopPropagation();
    if (parseFloat(event.target.value) > this.__value[1]) {
      event.target.value = this.__value[1];
    }
    const value = event.target.value;
    this.__updateValue(value, 0);
    this.__updateBubble(0);
    this.__dispatchInputEvent();
    this.__commitValue();
  }
  /** @private */
  __onEndInput(event) {
    event.stopPropagation();
    if (parseFloat(event.target.value) < this.__value[0]) {
      event.target.value = this.__value[0];
    }
    const value = event.target.value;
    this.__updateValue(value, 1);
    this.__updateBubble(1);
    this.__dispatchInputEvent();
    this.__commitValue();
  }
  /** @private */
  __isThumbEvent(event, thumb) {
    const rect2 = thumb.getBoundingClientRect();
    return event.clientX >= rect2.left && event.clientX <= rect2.right && event.clientY >= rect2.top && event.clientY <= rect2.bottom;
  }
  /** @private */
  __onStartPointerEnter(event) {
    if (this.__isThumbEvent(event, this.__thumbStartElement)) {
      this.__startHover = true;
    }
  }
  /** @private */
  __onStartPointerMove(event) {
    this.__startHover = this.__isThumbEvent(event, this.__thumbStartElement);
  }
  /** @private */
  __onStartPointerLeave() {
    this.__startHover = false;
  }
  /** @private */
  __onEndPointerEnter(event) {
    if (this.__isThumbEvent(event, this.__thumbEndElement)) {
      this.__endHover = true;
    }
  }
  /** @private */
  __onEndPointerMove(event) {
    this.__endHover = this.__isThumbEvent(event, this.__thumbEndElement);
  }
  /** @private */
  __onEndPointerLeave() {
    this.__endHover = false;
  }
  /** @private */
  __onKeyDown(event) {
    const prevKeys = ["ArrowLeft", "ArrowDown", "PageDown", "Home"];
    const nextKeys = ["ArrowRight", "ArrowUp", "PageUp", "End"];
    const isNextKey = nextKeys.includes(event.key);
    const isPrevKey = prevKeys.includes(event.key);
    if (!isNextKey && !isPrevKey) {
      return;
    }
    const index = this._inputElements.indexOf(event.target);
    if (this.readonly || this.__value[0] === this.__value[1] && (index === 0 && isNextKey || index === 1 && isPrevKey)) {
      event.preventDefault();
    }
  }
  /** @private */
  __updateBubble(idx) {
    this.__bubbleElements[idx].$.overlay._updatePosition();
  }
}
defineCustomElement(RangeSlider);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const splitLayoutStyles = css$h`
  :host {
    display: flex;
    contain: layout;
  }

  :host([hidden]) {
    display: none !important;
  }

  :host([orientation='vertical']) {
    flex-direction: column;
  }

  ::slotted(*) {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
  }

  ::slotted(:not(vaadin-split-layout)) {
    overflow: clip;
  }

  [part='splitter'] {
    --_splitter-size: var(--vaadin-split-layout-splitter-size, 8px);
    --_splitter-target-size: var(--vaadin-split-layout-splitter-target-size, 8px);
    --_handle-size: var(--vaadin-split-layout-handle-size, 4px);
    --_handle-target-size: var(--vaadin-split-layout-handle-target-size, 32px);
    background: var(--vaadin-split-layout-splitter-background, var(--vaadin-background-container-strong));
    flex: none;
    position: relative;
    z-index: 1;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  [part='splitter']::after {
    content: '';
    inset: 0 calc((var(--_splitter-target-size) - var(--_splitter-size)) / -2);
    position: absolute;
  }

  :host([orientation='vertical']) [part='splitter']::after {
    inset: calc((var(--_splitter-target-size) - var(--_splitter-size)) / -2) 0;
  }

  :host(:not([orientation='vertical'])) > [part='splitter'] {
    cursor: ew-resize;
    width: var(--_splitter-size);
  }

  :host([orientation='vertical']) > [part='splitter'] {
    cursor: ns-resize;
    height: var(--_splitter-size);
  }

  [part='handle'] {
    background: var(--vaadin-split-layout-handle-background, var(--vaadin-text-color-secondary));
    border-radius: var(--vaadin-radius-m);
    flex: none;
    width: var(--_handle-size);
    height: var(--_handle-target-size);
    max-height: 50%;
    position: absolute;
  }

  :host([orientation='vertical']) [part='handle'] {
    width: var(--_handle-target-size);
    max-width: 50%;
    height: var(--_handle-size);
    max-height: none;
  }

  [part='handle']::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    height: var(--_handle-target-size);
    width: var(--_handle-target-size);
    transform: translate3d(-50%, -50%, 0);
    border-radius: 50%;
  }

  :host([theme~='small']) > [part='splitter'] {
    --vaadin-split-layout-splitter-size: 1px;
    --vaadin-split-layout-splitter-target-size: 5px;
    --vaadin-split-layout-handle-size: 3px;
  }

  :host([theme~='small']) [part='splitter'] [part='handle'] {
    opacity: 0;
  }

  :host([theme~='small']) [part='splitter']:active [part='handle'] {
    opacity: 1;
  }

  @media (any-hover: hover) {
    :host([theme~='small']) [part='splitter']:hover [part='handle'] {
      opacity: 1;
    }
  }

  @media (forced-colors: active) {
    [part~='splitter'] {
      border: 1px solid;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const SplitLayoutMixin = (superClass) => class SplitLayoutMixin extends superClass {
  static get properties() {
    return {
      /**
       * The split layout's orientation. Possible values are: `horizontal|vertical`.
       */
      orientation: {
        type: String,
        reflectToAttribute: true,
        value: "horizontal"
      },
      /** @private */
      _previousPrimaryPointerEvents: String,
      /** @private */
      _previousSecondaryPointerEvents: String
    };
  }
  /** @protected */
  ready() {
    super.ready();
    this._processChildren();
    this.__observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        this._cleanupNodes(mutation.removedNodes);
      });
      this._processChildren();
    });
    this.__observer.observe(this, { childList: true });
    const splitter = this.$.splitter;
    addListener(splitter, "track", this._onHandleTrack.bind(this));
    addListener(splitter, "down", this._setPointerEventsNone.bind(this));
    addListener(splitter, "up", this._restorePointerEvents.bind(this));
  }
  /** @private */
  _cleanupNodes(nodes) {
    nodes.forEach((node) => {
      if (node.nodeType === Node.ELEMENT_NODE && !(node.parentElement instanceof this.constructor)) {
        const slot = node.getAttribute("slot");
        if (slot) {
          this[`_${slot}Child`] = null;
          node.removeAttribute("slot");
        }
      }
    });
  }
  /** @private */
  _processChildren() {
    const children = [...this.children];
    children.filter((child) => child.hasAttribute("slot")).forEach((child) => this._processChildWithSlot(child));
    children.filter((child) => !child.hasAttribute("slot")).forEach((child, i) => this._processChildWithoutSlot(child, i));
  }
  /** @private */
  _processChildWithSlot(child) {
    const slot = child.getAttribute("slot");
    if (child.__autoSlotted) {
      this[`_${slot}Child`] = null;
      child.removeAttribute("slot");
    } else {
      this[`_${slot}Child`] = child;
    }
  }
  /** @private */
  _processChildWithoutSlot(child, idx) {
    let slotName;
    if (this._primaryChild || this._secondaryChild) {
      slotName = this._primaryChild ? "secondary" : "primary";
    } else {
      slotName = idx === 0 ? "primary" : "secondary";
    }
    this[`_${slotName}Child`] = child;
    child.setAttribute("slot", slotName);
    child.__autoSlotted = true;
  }
  /** @private */
  _setFlexBasis(element, flexBasis, containerSize) {
    flexBasis = Math.max(0, Math.min(flexBasis, containerSize));
    if (flexBasis === 0) {
      flexBasis = 1e-6;
    }
    element.style.flex = `1 1 ${flexBasis}px`;
  }
  /** @private */
  _setPointerEventsNone(event) {
    if (!this._primaryChild || !this._secondaryChild) {
      return;
    }
    this._previousPrimaryPointerEvents = this._primaryChild.style.pointerEvents;
    this._previousSecondaryPointerEvents = this._secondaryChild.style.pointerEvents;
    this._primaryChild.style.pointerEvents = "none";
    this._secondaryChild.style.pointerEvents = "none";
    event.preventDefault();
  }
  /** @private */
  _restorePointerEvents() {
    if (!this._primaryChild || !this._secondaryChild) {
      return;
    }
    this._primaryChild.style.pointerEvents = this._previousPrimaryPointerEvents;
    this._secondaryChild.style.pointerEvents = this._previousSecondaryPointerEvents;
  }
  /** @private */
  _onHandleTrack(event) {
    if (!this._primaryChild || !this._secondaryChild) {
      return;
    }
    const size = this.orientation === "vertical" ? "height" : "width";
    if (event.detail.state === "start") {
      this._startSize = {
        container: this.getBoundingClientRect()[size] - this.$.splitter.getBoundingClientRect()[size],
        primary: this._primaryChild.getBoundingClientRect()[size],
        secondary: this._secondaryChild.getBoundingClientRect()[size]
      };
      return;
    }
    const distance = this.orientation === "vertical" ? event.detail.dy : event.detail.dx;
    const isRtl = this.orientation !== "vertical" && this.__isRTL;
    const dirDistance = isRtl ? -distance : distance;
    this._setFlexBasis(this._primaryChild, this._startSize.primary + dirDistance, this._startSize.container);
    this._setFlexBasis(this._secondaryChild, this._startSize.secondary - dirDistance, this._startSize.container);
    if (event.detail.state === "end") {
      this.dispatchEvent(new CustomEvent("splitter-dragend"));
      delete this._startSize;
    }
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class SplitLayout extends SplitLayoutMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-split-layout";
  }
  static get styles() {
    return splitLayoutStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <slot id="primary" name="primary"></slot>
      <div part="splitter" id="splitter">
        <div part="handle"></div>
      </div>
      <slot id="secondary" name="secondary"></slot>
    `;
  }
  /**
   * Fired after dragging the splitter have ended.
   *
   * @event splitter-dragend
   */
}
defineCustomElement(SplitLayout);
class BigDecimalField extends TextField {
  static get is() {
    return "vaadin-big-decimal-field";
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, is: "vaadin-text-field" };
  }
  static get styles() {
    return [
      ...super.styles,
      css$h`
        :host([dir='rtl']) [part='input-field'] {
          direction: ltr;
        }

        :host([dir='rtl']) [part='input-field'] ::slotted(input) {
          --_lumo-text-field-overflow-mask-image: linear-gradient(to left, transparent, #000 1.25em) !important;
        }
      `
    ];
  }
  static get properties() {
    return {
      _decimalSeparator: {
        type: String,
        value: ".",
        sync: true,
        observer: "__decimalSeparatorChanged"
      }
    };
  }
  ready() {
    super.ready();
    this.inputElement.setAttribute("inputmode", "decimal");
  }
  __decimalSeparatorChanged(separator, oldSeparator) {
    this.allowedCharPattern = "[-+\\d" + separator + "]";
    if (this.value && oldSeparator) {
      this.value = this.value.split(oldSeparator).join(separator);
    }
  }
}
defineCustomElement(BigDecimalField);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const emailFieldStyles = css$h`
  :host([dir='rtl']) [part='input-field'] {
    direction: ltr;
  }

  :host([dir='rtl']) [part='input-field'] ::slotted(input)::placeholder {
    direction: rtl;
    text-align: left;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class EmailField extends TextField {
  static get is() {
    return "vaadin-email-field";
  }
  static get styles() {
    return [...super.styles, emailFieldStyles];
  }
  /** @override */
  static get delegateAttrs() {
    return super.delegateAttrs.filter((attr2) => attr2 !== "autocapitalize");
  }
  constructor() {
    super();
    this._setType("email");
    this.pattern = "^[a-zA-Z0-9_\\-+]+(?:\\.[a-zA-Z0-9_\\-+]+)*@[a-zA-Z0-9\\-.]+\\.[a-zA-Z0-9\\-]{2,}$";
  }
  /** @protected */
  ready() {
    super.ready();
    if (this.inputElement) {
      this.inputElement.autocapitalize = "off";
    }
  }
}
defineCustomElement(EmailField);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const numberFieldStyles = css$h`
  :host([step-buttons-visible]) ::slotted(input) {
    text-align: center;
  }

  [part~='decrease-button']::before {
    mask-image: var(--_vaadin-icon-minus);
  }

  [part~='increase-button']::before {
    mask-image: var(--_vaadin-icon-plus);
  }

  :host([dir='rtl']) [part='input-field'] {
    direction: ltr;
  }

  :host([readonly]) [part$='button'] {
    pointer-events: none;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const BAD_INPUT_STRING = "NaN";
const NumberFieldMixin = (superClass) => class NumberFieldMixinClass extends InputFieldMixin(superClass) {
  static get properties() {
    return {
      /**
       * The minimum value of the field.
       */
      min: {
        type: Number
      },
      /**
       * The maximum value of the field.
       */
      max: {
        type: Number
      },
      /**
       * Specifies the allowed number intervals of the field.
       */
      step: {
        type: Number
      },
      /**
       * Set to true to show increase/decrease buttons.
       * @attr {boolean} step-buttons-visible
       */
      stepButtonsVisible: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      }
    };
  }
  static get observers() {
    return ["_stepChanged(step, inputElement)"];
  }
  static get delegateProps() {
    return [...super.delegateProps, "min", "max"];
  }
  static get constraints() {
    return [...super.constraints, "min", "max", "step"];
  }
  constructor() {
    super();
    this._setType("number");
    this.__onWheel = this.__onWheel.bind(this);
  }
  /** @protected */
  get slotStyles() {
    const tag = this.localName;
    return [
      `
          ${tag} input[type="number"]::-webkit-outer-spin-button,
          ${tag} input[type="number"]::-webkit-inner-spin-button {
            appearance: none;
            margin: 0;
          }

          ${tag} input[type="number"] {
            appearance: textfield;
          }

          ${tag}[dir='rtl'] input[type="number"]::placeholder {
            direction: rtl;
          }

          ${tag}[dir='rtl']:not([step-buttons-visible]) input[type="number"]::placeholder {
            text-align: left;
          }
        `
    ];
  }
  /**
   * Used by `InputControlMixin` as a reference to the clear button element.
   * @protected
   */
  get clearElement() {
    return this.$.clearButton;
  }
  /**
   * Whether the input element's value is unparsable.
   *
   * @private
   */
  get __hasUnparsableValue() {
    return this._inputElementValue === BAD_INPUT_STRING;
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(
      new InputController(this, (input) => {
        this._setInputElement(input);
        this._setFocusElement(input);
        this.stateTarget = input;
        this.ariaTarget = input;
      })
    );
    this.addController(new LabelledInputController(this.inputElement, this._labelController));
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
    this._tooltipController.setPosition("top");
    this._tooltipController.setAriaTarget(this.inputElement);
  }
  /**
   * Override the method from `InputConstraintsMixin`
   * to enforce HTML constraint validation even if
   * the user didn't add any constraints explicitly:
   * the field has to be regardless checked for bad input.
   *
   * @override
   */
  checkValidity() {
    if (this.inputElement) {
      return this.inputElement.checkValidity();
    }
    return !this.invalid;
  }
  /**
   * Override the method from `InputMixin` to add
   * a wheel event listener to the input element.
   *
   * @param {HTMLElement} input
   * @override
   * @protected
   */
  _addInputListeners(input) {
    super._addInputListeners(input);
    input.addEventListener("wheel", this.__onWheel);
  }
  /**
   * Override the method from `InputMixin` to remove
   * the wheel event listener from the input element.
   *
   * @param {HTMLElement} input
   * @override
   * @protected
   */
  _removeInputListeners(input) {
    super._removeInputListeners(input);
    input.removeEventListener("wheel", this.__onWheel);
  }
  /**
   * Prevents default browser behavior for wheel events on the input element
   * when it's focused. More precisely, this prevents the browser from attempting
   * to increment or decrement the value when the mouse wheel is used within
   * the input element.
   *
   * CAVEAT: As a side-effect, this also prevents page scrolling when
   * the pointer is positioned over the field and the field is focused.
   *
   * @param {WheelEvent} event
   * @private
   */
  __onWheel(event) {
    if (this.hasAttribute("focused")) {
      event.preventDefault();
    }
  }
  /** @protected */
  _onDecreaseButtonTouchend(e) {
    if (e.cancelable) {
      e.preventDefault();
      this.__blurActiveElement();
      this._decreaseValue();
    }
  }
  /** @protected */
  _onIncreaseButtonTouchend(e) {
    if (e.cancelable) {
      e.preventDefault();
      this.__blurActiveElement();
      this._increaseValue();
    }
  }
  /** @private */
  __blurActiveElement() {
    const activeElement = getDeepActiveElement();
    if (activeElement && activeElement !== this.inputElement) {
      activeElement.blur();
    }
  }
  /** @protected */
  _onDecreaseButtonClick() {
    this._decreaseValue();
  }
  /** @protected */
  _onIncreaseButtonClick() {
    this._increaseValue();
  }
  /** @private */
  _decreaseValue() {
    this._incrementValue(-1);
  }
  /** @private */
  _increaseValue() {
    this._incrementValue(1);
  }
  /** @private */
  _incrementValue(incr) {
    if (this.disabled || this.readonly) {
      return;
    }
    const step = this.step || 1;
    let value = parseFloat(this.value);
    if (!this.value) {
      if (this.min === 0 && incr < 0 || this.max === 0 && incr > 0 || this.max === 0 && this.min === 0) {
        incr = 0;
        value = 0;
      } else if ((this.max == null || this.max >= 0) && (this.min == null || this.min <= 0)) {
        value = 0;
      } else if (this.min > 0) {
        value = this.min;
        if (this.max < 0 && incr < 0) {
          value = this.max;
        }
        incr = 0;
      } else if (this.max < 0) {
        value = this.max;
        if (incr < 0) {
          incr = 0;
        } else if (this._getIncrement(1, value - step) > this.max) {
          value -= 2 * step;
        } else {
          value -= step;
        }
      }
    } else if (value < this.min) {
      incr = 0;
      value = this.min;
    } else if (value > this.max) {
      incr = 0;
      value = this.max;
    }
    const newValue = this._getIncrement(incr, value);
    if (!this.value || incr === 0 || this._incrementIsInsideTheLimits(incr, value)) {
      this.inputElement.value = String(parseFloat(newValue));
      this.inputElement.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
      this.__commitValueChange();
    }
  }
  /** @private */
  _getIncrement(incr, currentValue) {
    let step = this.step || 1, min2 = this.min || 0;
    const multiplier = Math.max(
      this._getMultiplier(currentValue),
      this._getMultiplier(step),
      this._getMultiplier(min2)
    );
    step *= multiplier;
    currentValue = Math.round(currentValue * multiplier);
    min2 *= multiplier;
    const margin = (currentValue - min2) % step;
    if (incr > 0) {
      return (currentValue - margin + step) / multiplier;
    } else if (incr < 0) {
      return (currentValue - (margin || step)) / multiplier;
    }
    return currentValue / multiplier;
  }
  /** @private */
  _getDecimalCount(number) {
    const s = String(number);
    const i = s.indexOf(".");
    return i === -1 ? 1 : s.length - i - 1;
  }
  /** @private */
  _getMultiplier(number) {
    if (!isNaN(number)) {
      return 10 ** this._getDecimalCount(number);
    }
  }
  /** @private */
  _incrementIsInsideTheLimits(incr, value) {
    if (incr < 0) {
      return this.min == null || this._getIncrement(incr, value) >= this.min;
    } else if (incr > 0) {
      return this.max == null || this._getIncrement(incr, value) <= this.max;
    }
    return this._getIncrement(incr, value) <= this.max && this._getIncrement(incr, value) >= this.min;
  }
  /** @protected */
  _isButtonEnabled(sign2) {
    const incr = sign2 * (this.step || 1);
    const value = parseFloat(this.value);
    return !this.value || !this.disabled && this._incrementIsInsideTheLimits(incr, value);
  }
  /**
   * @param {number} step
   * @param {HTMLElement | undefined} inputElement
   * @protected
   */
  _stepChanged(step, inputElement) {
    if (inputElement) {
      inputElement.step = step || "any";
    }
  }
  /**
   * @param {unknown} newVal
   * @param {unknown} oldVal
   * @protected
   * @override
   */
  _valueChanged(newVal, oldVal) {
    if (newVal && isNaN(parseFloat(newVal))) {
      this.value = "";
    } else if (typeof this.value !== "string") {
      this.value = String(this.value);
    }
    super._valueChanged(this.value, oldVal);
    if (!this.__keepCommittedValue) {
      this.__committedValue = this.value;
      this.__committedUnparsableValueStatus = false;
    }
  }
  /**
   * Override an event listener from `InputControlMixin`
   * to avoid adding a separate listener.
   * @param {!KeyboardEvent} event
   * @protected
   * @override
   */
  _onKeyDown(event) {
    if (event.key === "ArrowUp") {
      event.preventDefault();
      this._increaseValue();
    } else if (event.key === "ArrowDown") {
      event.preventDefault();
      this._decreaseValue();
    }
    super._onKeyDown(event);
  }
  /**
   * Override this method from `InputMixin` to prevent
   * the value change caused by user input from being treated
   * as initiated programmatically by the developer and therefore
   * from getting silently committed by the value observer without
   * any change event. The value change will be committed later
   * on blur or Enter.
   *
   * @param {InputEvent} event
   * @override
   * @protected
   */
  _onInput(event) {
    this.__keepCommittedValue = true;
    super._onInput(event);
    this.__keepCommittedValue = false;
  }
  /**
   * Override this method from `InputControlMixin`
   * to stop propagation of the native change event.
   *
   * @param {Event} event
   * @override
   * @protected
   */
  _onChange(event) {
    event.stopPropagation();
  }
  /**
   * Override this method from `ClearButtonMixin`
   * to properly commit the empty value since
   * the change handler doesn't do that anymore.
   *
   * @param {MouseEvent} event
   * @override
   * @protected
   */
  _onClearAction(event) {
    super._onClearAction(event);
    this.__commitValueChange();
  }
  /**
   * Override this method from `FocusMixin`
   * to commit a possible pending value change on blur.
   *
   * @param {boolean} focused
   * @override
   * @protected
   */
  _setFocused(focused) {
    super._setFocused(focused);
    if (!focused) {
      this.__commitValueChange();
    }
  }
  /**
   * Override this method from `KeyboardMixin`
   * to commit a possible pending value change on Enter.
   *
   * @param {KeyboardEvent} event
   * @override
   * @protected
   */
  _onEnter(event) {
    super._onEnter(event);
    this.__commitValueChange();
  }
  /**
   * Depending on the nature of the value change that has occurred since
   * the last commit attempt, triggers validation and fires an event:
   *
   * Value change             | Event
   * :------------------------|:------------------
   * empty => parsable        | change
   * empty => unparsable      | unparsable-change
   * parsable => empty        | change
   * parsable => parsable     | change
   * parsable => unparsable   | change
   * unparsable => empty      | unparsable-change
   * unparsable => parsable   | change
   * unparsable => unparsable | -
   *
   * Note, there is currently no way to detect unparsable => unparsable changes
   * because the browser doesn't provide access to unparsable values of native
   * [type=number] inputs.
   *
   * @private
   */
  __commitValueChange() {
    if (this.__committedValue !== this.value) {
      this._requestValidation();
      this.dispatchEvent(new CustomEvent("change", { bubbles: true }));
    } else if (this.__committedUnparsableValueStatus !== this.__hasUnparsableValue) {
      this._requestValidation();
      this.dispatchEvent(new CustomEvent("unparsable-change"));
    }
    this.__committedValue = this.value;
    this.__committedUnparsableValueStatus = this.__hasUnparsableValue;
  }
  /** @override */
  get _inputElementValue() {
    if (this.inputElement && this.inputElement.validity.badInput) {
      return BAD_INPUT_STRING;
    }
    return super._inputElementValue;
  }
  /** @override */
  set _inputElementValue(value) {
    super._inputElementValue = value;
  }
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class NumberField extends NumberFieldMixin(ThemableMixin(ElementMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-number-field";
  }
  static get styles() {
    return [inputFieldShared, numberFieldStyles];
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-field-container">
        <div part="label">
          <slot name="label"></slot>
          <span part="required-indicator" aria-hidden="true" @click="${this.focus}"></span>
        </div>

        <vaadin-input-container
          part="input-field"
          .readonly="${this.readonly}"
          .disabled="${this.disabled}"
          .invalid="${this.invalid}"
          theme="${ifDefined(this._theme)}"
        >
          <div
            part="field-button decrease-button"
            ?disabled="${!this._isButtonEnabled(-1, this.value, this.min, this.max, this.step)}"
            ?hidden="${!this.stepButtonsVisible}"
            @click="${this._onDecreaseButtonClick}"
            @touchend="${this._onDecreaseButtonTouchend}"
            aria-hidden="true"
            slot="prefix"
          ></div>
          <slot name="prefix" slot="prefix"></slot>
          <slot name="input"></slot>
          <slot name="suffix" slot="suffix"></slot>
          <div id="clearButton" part="field-button clear-button" slot="suffix" aria-hidden="true"></div>
          <div
            part="field-button increase-button"
            ?disabled="${!this._isButtonEnabled(1, this.value, this.min, this.max, this.step)}"
            ?hidden="${!this.stepButtonsVisible}"
            @click="${this._onIncreaseButtonClick}"
            @touchend="${this._onIncreaseButtonTouchend}"
            aria-hidden="true"
            slot="suffix"
          ></div>
        </vaadin-input-container>

        <div part="helper-text">
          <slot name="helper"></slot>
        </div>

        <div part="error-message">
          <slot name="error-message"></slot>
        </div>

        <slot name="tooltip"></slot>
      </div>
    `;
  }
}
defineCustomElement(NumberField);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class IntegerField extends NumberField {
  static get is() {
    return "vaadin-integer-field";
  }
  constructor() {
    super();
    this.allowedCharPattern = "[-+\\d]";
  }
  /**
   * Override an observer from `InputMixin` to clear the value
   * when trying to type invalid characters.
   * @param {string | undefined} newVal
   * @param {string | undefined} oldVal
   * @protected
   * @override
   */
  _valueChanged(newVal, oldVal) {
    if (newVal !== "" && !this.__isInteger(newVal)) {
      console.warn(`Trying to set non-integer value "${newVal}" to <vaadin-integer-field>. Clearing the value.`);
      this.value = "";
      return;
    }
    super._valueChanged(newVal, oldVal);
  }
  /**
   * Override an observer from `NumberField` to reset the step
   * property when an invalid step is set.
   * @param {number} step
   * @param {HTMLElement | undefined} inputElement
   * @protected
   * @override
   */
  _stepChanged(step, inputElement) {
    if (step != null && !this.__hasOnlyDigits(step)) {
      console.warn(
        `<vaadin-integer-field> The \`step\` property must be a positive integer but \`${step}\` was provided, so the property was reset to \`null\`.`
      );
      this.step = null;
      return;
    }
    super._stepChanged(step, inputElement);
  }
  /** @private */
  __isInteger(value) {
    return /^(-\d)?\d*$/u.test(String(value));
  }
  /** @private */
  __hasOnlyDigits(value) {
    return /^\d+$/u.test(String(value));
  }
}
defineCustomElement(IntegerField);
/**
 * @license
 * Copyright 2020 Google LLC
 * SPDX-License-Identifier: BSD-3-Clause
 */
class LiveDirective extends Directive {
  constructor(partInfo) {
    super(partInfo);
    if (!(partInfo.type === PartType.PROPERTY || partInfo.type === PartType.ATTRIBUTE || partInfo.type === PartType.BOOLEAN_ATTRIBUTE)) {
      throw new Error("The `live` directive is not allowed on child or event bindings");
    }
    if (!isSingleExpression(partInfo)) {
      throw new Error("`live` bindings can only contain a single expression");
    }
  }
  render(value) {
    return value;
  }
  update(part, [value]) {
    if (value === noChange || value === nothing) {
      return value;
    }
    const element = part.element;
    const name = part.name;
    if (part.type === PartType.PROPERTY) {
      if (value === element[name]) {
        return noChange;
      }
    } else if (part.type === PartType.BOOLEAN_ATTRIBUTE) {
      if (!!value === element.hasAttribute(name)) {
        return noChange;
      }
    } else if (part.type === PartType.ATTRIBUTE) {
      if (element.getAttribute(name) === String(value)) {
        return noChange;
      }
    }
    setCommittedValue(part);
    return value;
  }
}
const live = directive(LiveDirective);
const _window = window;
_window.Vaadin = _window.Vaadin || {};
_window.Vaadin.setLitRenderer = (component, rendererName, templateExpression, returnChannel, clientCallables, propertyNamespace, appId) => {
  const callablesCreator = (itemKey) => {
    return clientCallables.map((clientCallable) => (...args) => {
      if (itemKey !== void 0) {
        returnChannel(clientCallable, itemKey, args[0] instanceof Event ? [] : [...args]);
      }
    });
  };
  const fnArgs = [
    "html",
    "root",
    "live",
    "appId",
    "itemKey",
    "model",
    "item",
    "index",
    ...clientCallables,
    `return html\`${templateExpression}\``
  ];
  const htmlGenerator = new Function(...fnArgs);
  const renderFunction = (root, model, itemKey) => {
    const { item, index } = model;
    render$1(htmlGenerator(html, root, live, appId, itemKey, model, item, index, ...callablesCreator(itemKey)), root);
  };
  const renderer = (root, _2, model) => {
    const { item } = model;
    if (root.__litRenderer !== renderer) {
      root.innerHTML = "";
      delete root._$litPart$;
      root.__litRenderer = renderer;
    }
    const mappedItem = {};
    for (const key2 in item) {
      if (key2.startsWith(propertyNamespace)) {
        mappedItem[key2.replace(propertyNamespace, "")] = item[key2];
      }
    }
    renderFunction(root, { ...model, item: mappedItem }, item.key);
  };
  renderer.__rendererId = propertyNamespace;
  component[rendererName] = renderer;
};
_window.Vaadin.unsetLitRenderer = (component, rendererName, rendererId) => {
  if (component[rendererName]?.__rendererId === rendererId) {
    component[rendererName] = void 0;
  }
};
window.Vaadin.Flow.treeGridConnector = {};
window.Vaadin.Flow.treeGridConnector.initLazy = function(grid) {
  if (grid.$connector) {
    return;
  }
  window.Vaadin.Flow.gridConnector.initLazy(grid);
  function getViewportRange() {
    const renderedRows = grid._getRenderedRows();
    return [renderedRows[0]?.index ?? 0, renderedRows[renderedRows.length - 1]?.index ?? 0];
  }
  grid._dataProviderController._shouldLoadCachePage = function(cache2, page) {
    return !grid.__pendingScrollToIndexes;
  };
  grid.scrollToIndex = async function(...indexes) {
    grid.__pendingScrollToIndexes = indexes;
    if (!grid.clientHeight || !grid._columnTree || grid._dataProviderController.isLoading()) {
      return;
    }
    const [start2, end] = getViewportRange();
    const padding = Math.floor((end - start2) * 1.5);
    const flatIndex = await grid.$server.setViewportRangeByIndexPath(indexes, padding);
    grid._scrollToFlatIndex(flatIndex);
    delete grid.__pendingScrollToIndexes;
    return flatIndex;
  };
  grid.__getRowLevel = function(row) {
    return row._item?.level ?? 0;
  };
  grid._isExpanded = function(item) {
    return !!item?.expanded;
  };
  grid.expandItem = function(item) {
    if (item !== void 0) {
      grid.$server.updateExpandedState(grid.getItemId(item), true);
    }
  };
  grid.collapseItem = function(item) {
    if (item !== void 0) {
      grid.$server.updateExpandedState(grid.getItemId(item), false);
    }
  };
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const uploadIconStyles = css$h`
  :host {
    display: inline-flex;
  }

  :host::before {
    background: var(--vaadin-upload-icon-color, currentColor);
    content: '';
    display: inline-block;
    flex: none;
    height: var(--vaadin-icon-size, 1lh);
    mask: var(--_vaadin-icon-upload) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
    width: var(--vaadin-icon-size, 1lh);
  }

  :host([hidden]) {
    display: none !important;
  }

  @media (forced-colors: active) {
    :host::before {
      background: CanvasText;
    }
  }
`;
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UploadIcon extends ThemableMixin(LumoInjectionMixin(LitElement)) {
  static get is() {
    return "vaadin-upload-icon";
  }
  static get styles() {
    return uploadIconStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html``;
  }
}
defineCustomElement(UploadIcon);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const template$1 = document.createElement("template");
template$1.innerHTML = `
  <style>
    @font-face {
      font-family: 'vaadin-upload-icons';
      src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAasAAsAAAAABmAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIF5mNtYXAAAAFoAAAAVAAAAFQXVtKMZ2FzcAAAAbwAAAAIAAAACAAAABBnbHlmAAABxAAAAfQAAAH0bBJxYWhlYWQAAAO4AAAANgAAADYPD267aGhlYQAAA/AAAAAkAAAAJAfCA8tobXR4AAAEFAAAACgAAAAoHgAAx2xvY2EAAAQ8AAAAFgAAABYCSgHsbWF4cAAABFQAAAAgAAAAIAAOADVuYW1lAAAEdAAAAhYAAAIWmmcHf3Bvc3QAAAaMAAAAIAAAACAAAwAAAAMDtwGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA6QUDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADgAAAAKAAgAAgACAAEAIOkF//3//wAAAAAAIOkA//3//wAB/+MXBAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAgAA/8AEAAPAABkAMgAAEz4DMzIeAhczLgMjIg4CBycRIScFIRcOAyMiLgInIx4DMzI+AjcXphZGWmo6SH9kQwyADFiGrmJIhXJbIEYBAFoDWv76YBZGXGw8Rn5lRQyADFmIrWBIhHReIkYCWjJVPSIyVnVDXqN5RiVEYTxG/wBa2loyVT0iMlZ1Q16jeUYnRWE5RgAAAAABAIAAAAOAA4AAAgAAExEBgAMAA4D8gAHAAAAAAwAAAAAEAAOAAAIADgASAAAJASElIiY1NDYzMhYVFAYnETMRAgD+AAQA/gAdIyMdHSMjXYADgPyAgCMdHSMjHR0jwAEA/wAAAQANADMD5gNaAAUAACUBNwUBFwHT/jptATMBppMzAU2a4AIgdAAAAAEAOv/6A8YDhgALAAABJwkBBwkBFwkBNwEDxoz+xv7GjAFA/sCMAToBOoz+wAL6jP7AAUCM/sb+xowBQP7AjAE6AAAAAwAA/8AEAAPAAAcACwASAAABFSE1IREhEQEjNTMJAjMRIRECwP6A/sAEAP0AgIACQP7A/sDAAQABQICA/oABgP8AgAHAAUD+wP6AAYAAAAABAAAAAQAAdhiEdV8PPPUACwQAAAAAANX4FR8AAAAA1fgVHwAA/8AEAAPAAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAAAAAQAAAEAAAAAAAAAAAAAAAAAAAAKBAAAAAAAAAAAAAAAAgAAAAQAAAAEAACABAAAAAQAAA0EAAA6BAAAAAAAAAAACgAUAB4AagB4AJwAsADSAPoAAAABAAAACgAzAAMAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEAEwAAAAEAAAAAAAIABwDMAAEAAAAAAAMAEwBaAAEAAAAAAAQAEwDhAAEAAAAAAAUACwA5AAEAAAAAAAYAEwCTAAEAAAAAAAoAGgEaAAMAAQQJAAEAJgATAAMAAQQJAAIADgDTAAMAAQQJAAMAJgBtAAMAAQQJAAQAJgD0AAMAAQQJAAUAFgBEAAMAAQQJAAYAJgCmAAMAAQQJAAoANAE0dmFhZGluLXVwbG9hZC1pY29ucwB2AGEAYQBkAGkAbgAtAHUAcABsAG8AYQBkAC0AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwdmFhZGluLXVwbG9hZC1pY29ucwB2AGEAYQBkAGkAbgAtAHUAcABsAG8AYQBkAC0AaQBjAG8AbgBzdmFhZGluLXVwbG9hZC1pY29ucwB2AGEAYQBkAGkAbgAtAHUAcABsAG8AYQBkAC0AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQBydmFhZGluLXVwbG9hZC1pY29ucwB2AGEAYQBkAGkAbgAtAHUAcABsAG8AYQBkAC0AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format('woff');
      font-weight: normal;
      font-style: normal;
    }
  </style>
`;
document.head.appendChild(template$1.content);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const uploadFileStyles = [
  loaderStyles,
  css$h`
    :host {
      align-items: baseline;
      display: grid;
      gap: var(--vaadin-upload-file-gap, var(--vaadin-gap-s));
      grid-template-columns: var(--vaadin-icon-size, 1lh) minmax(0, 1fr) auto;
      padding: var(--vaadin-upload-file-padding, var(--vaadin-padding-s));
      border-radius: var(--vaadin-upload-file-border-radius, var(--vaadin-radius-m));
    }

    :host(:focus-visible) {
      outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
      outline-offset: calc(var(--vaadin-focus-ring-width) * -1);
    }

    [hidden] {
      display: none;
    }

    [part='thumbnail'],
    [part='loader'] {
      display: none;
      grid-column: 1;
    }

    :host([uploading]) [part='loader'],
    [part='done-icon']:not([hidden]),
    [part='warning-icon']:not([hidden]) {
      display: flex;
      grid-column: 1;
    }

    [part='loader']::before,
    [part='done-icon']::before,
    [part='warning-icon']::before {
      content: '\\2003' / '';
      display: inline-flex;
      align-items: center;
      flex: none;
      height: var(--vaadin-icon-size, 1lh);
      width: var(--vaadin-icon-size, 1lh);
    }

    [part='loader']::before {
      margin: calc(var(--vaadin-spinner-width, 2px) * -1);
    }

    :is([part$='icon'], [part$='button'])::before {
      mask-size: var(--vaadin-icon-visual-size, 100%);
      mask-position: 50%;
      mask-repeat: no-repeat;
    }

    [part='done-icon']::before {
      background: var(--vaadin-upload-file-done-color, currentColor);
      mask-image: var(--_vaadin-icon-checkmark);
    }

    [part='warning-icon']::before {
      background: var(--vaadin-upload-file-warning-color, currentColor);
      mask-image: var(--_vaadin-icon-warn);
    }

    [part='meta'] {
      grid-column: 2;

      & > div {
        cursor: inherit;
      }
    }

    [part='name'] {
      color: var(--vaadin-upload-file-name-color, var(--vaadin-text-color));
      font-size: var(--vaadin-upload-file-name-font-size, inherit);
      font-weight: var(--vaadin-upload-file-name-font-weight, inherit);
      line-height: var(--vaadin-upload-file-name-line-height, inherit);
      overflow: hidden;
      text-overflow: ellipsis;
    }

    [part='status'] {
      color: var(--vaadin-upload-file-status-color, var(--vaadin-text-color-secondary));
      font-size: var(--vaadin-upload-file-status-font-size, inherit);
      font-weight: var(--vaadin-upload-file-status-font-weight, inherit);
      line-height: var(--vaadin-upload-file-status-line-height, inherit);
    }

    [part='error'] {
      color: var(--vaadin-upload-file-error-color, var(--vaadin-text-color));
      font-size: var(--vaadin-upload-file-error-font-size, inherit);
      font-weight: var(--vaadin-upload-file-error-font-weight, inherit);
      line-height: var(--vaadin-upload-file-error-line-height, inherit);
    }

    [part='commands'] {
      display: flex;
      align-items: center;
      gap: var(--vaadin-gap-xs);
      height: var(--vaadin-icon-size, 1lh);
      align-self: center;
    }

    button {
      background: var(--vaadin-upload-file-button-background, transparent);
      border: var(--vaadin-upload-file-button-border-width, 0) solid
        var(--vaadin-upload-file-button-border-color, var(--vaadin-border-color-secondary));
      border-radius: var(--vaadin-upload-file-button-border-radius, var(--vaadin-radius-m));
      color: var(--vaadin-upload-file-button-text-color, var(--vaadin-text-color));
      cursor: var(--vaadin-clickable-cursor);
      flex-shrink: 0;
      font: inherit;
      /* Ensure minimum click target (WCAG) */
      padding: var(--vaadin-upload-file-button-padding, max(0px, (24px - var(--vaadin-icon-size, 1lh)) / 2));
    }

    button:focus-visible {
      outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
    }

    [part='start-button']::before,
    [part='retry-button']::before,
    [part='remove-button']::before {
      background: currentColor;
      content: '\\2003' / '';
      display: flex;
      align-items: center;
      height: var(--vaadin-icon-size, 1lh);
      width: var(--vaadin-icon-size, 1lh);
    }

    [part='start-button']::before {
      mask-image: var(--_vaadin-icon-play);
    }

    [part='retry-button']::before {
      mask-image: var(--_vaadin-icon-refresh);
    }

    [part='remove-button']::before {
      mask-image: var(--_vaadin-icon-cross);
    }

    ::slotted([slot='progress']) {
      grid-column: 2 / -1;
      width: auto;
    }

    :host([complete]) ::slotted([slot='progress']),
    :host([error]) ::slotted([slot='progress']) {
      display: none;
    }

    /* THUMBNAILS VARIANT */

    :host([theme~='thumbnails']) {
      grid-template-columns: max-content 1fr max-content;
      align-items: center;
      background: var(--vaadin-background-container);
      padding: 0;
      contain: content;

      & [part] {
        grid-row: 1;
      }

      & [part='thumbnail'],
      & [part$='icon'] {
        grid-column: 1;
        align-self: stretch;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: 0.2s opacity linear;
        background: var(--vaadin-background-container-strong);
        padding: var(--vaadin-upload-file-padding, var(--vaadin-padding-s));
        contain: content;

        &[hidden] {
          opacity: 0;
        }
      }

      & [part='thumbnail'] > img {
        object-fit: cover;
        position: absolute;
        width: 100%;
        height: 100%;
      }

      & [part='loader']:not([hidden]) {
        place-self: center;
        display: flex;
      }

      & [part='done-icon']::before {
        background: var(--vaadin-upload-file-done-color, currentColor);
        mask-image: var(--_vaadin-icon-file);
      }

      & [part='meta'] {
        padding: var(--vaadin-upload-file-padding, var(--vaadin-padding-s));
        padding-inline: 0;
      }

      & [part='name'] {
        word-break: break-all;
      }

      & [part='commands'] {
        padding: var(--vaadin-upload-padding, var(--vaadin-padding-s));
        padding-inline-start: 0;
      }

      & [part='status'] {
        clip-path: inset(50%);
        width: 1px;
        height: 1px;
        margin: 0;
        overflow: hidden;
        position: absolute;
        white-space: nowrap;
      }

      & [part='error'] {
        font-size: 0.875em;
        line-height: 1.25;
      }

      & ::slotted([slot='progress']) {
        grid-row: auto;
        grid-column: auto;
        position: absolute;
        inset: 0;
        opacity: 0.3;
        pointer-events: none;
        --vaadin-progress-bar-height: auto;
        --vaadin-progress-bar-border-width: 0px;
        --vaadin-progress-bar-border-radius: 0px;
        --vaadin-progress-bar-background: transparent;
      }

      & ::slotted([slot='progress'][indeterminate]) {
        opacity: 0;
      }
    }

    :host([theme~='thumbnails']:not([complete])) [part='thumbnail'],
    :host([theme~='thumbnails'][complete]) [part='thumbnail']:not([hidden]) + [part='done-icon'] {
      display: none;
    }

    /* TODO: queued state styles (no attribute makes this difficult to target) */

    @media (forced-colors: active) {
      :is([part$='icon'], [part$='button'])::before {
        background: CanvasText;
      }
    }
  `
];
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const UploadFileMixin = (superClass) => class UploadFileMixin extends FocusMixin(superClass) {
  static get properties() {
    return {
      /**
       * If true, the user cannot interact with this element.
       */
      disabled: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * True if uploading is completed, false otherwise.
       */
      complete: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * Error message returned by the server, if any.
       */
      errorMessage: {
        type: String,
        value: "",
        observer: "_errorMessageChanged"
      },
      /**
       * The object representing a file.
       */
      file: {
        type: Object
      },
      /**
       * Name of the uploading file.
       */
      fileName: {
        type: String
      },
      /**
       * True if uploading is not started, false otherwise.
       */
      held: {
        type: Boolean,
        value: false
      },
      /**
       * True if remaining time is unknown, false otherwise.
       */
      indeterminate: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * The object used to localize this component.
       */
      i18n: {
        type: Object
      },
      /**
       * Number representing the uploading progress.
       */
      progress: {
        type: Number
      },
      /**
       * Uploading status.
       */
      status: {
        type: String
      },
      /**
       * Indicates whether the element can be focused and where it participates in sequential keyboard navigation.
       * @protected
       */
      tabindex: {
        type: Number,
        value: 0
      },
      /**
       * True if uploading is in progress, false otherwise.
       */
      uploading: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /** @private */
      _progress: {
        type: Object
      },
      /** @private */
      __thumbnail: {
        type: String
      }
    };
  }
  static get observers() {
    return [
      "__updateTabindex(tabindex, disabled)",
      "__updateProgress(_progress, progress, indeterminate)",
      "__updateThumbnail(file)"
    ];
  }
  /** @protected */
  ready() {
    super.ready();
    this.addController(
      new SlotController(this, "progress", "vaadin-progress-bar", {
        initializer: (progress) => {
          this._progress = progress;
        }
      })
    );
    this.shadowRoot.addEventListener("focusin", (e) => {
      const target = e.composedPath()[0];
      if (target.getAttribute("part").endsWith("button")) {
        this._setFocused(false);
      }
    });
    this.shadowRoot.addEventListener("focusout", (e) => {
      if (e.relatedTarget === this) {
        this._setFocused(true);
      }
    });
  }
  /**
   * Override method inherited from `FocusMixin` to mark the file as focused
   * only when the host is focused.
   * @param {Event} event
   * @return {boolean}
   * @protected
   */
  _shouldSetFocus(event) {
    return event.composedPath()[0] === this;
  }
  /** @private */
  __disabledChanged(disabled) {
    if (disabled) {
      this.removeAttribute("tabindex");
    } else {
      this.setAttribute("tabindex", this.tabindex);
    }
  }
  /** @private */
  _errorMessageChanged(errorMessage) {
    this.toggleAttribute("error", Boolean(errorMessage));
  }
  /** @private */
  __updateTabindex(tabindex, disabled) {
    if (disabled) {
      this.removeAttribute("tabindex");
    } else {
      this.setAttribute("tabindex", tabindex);
    }
  }
  /** @private */
  __updateProgress(progress, value, indeterminate) {
    if (progress) {
      progress.value = isNaN(value) ? 0 : value / 100;
      progress.indeterminate = indeterminate;
    }
  }
  /** @private */
  _fireFileEvent(e) {
    e.preventDefault();
    return this.dispatchEvent(
      new CustomEvent(e.target.getAttribute("file-event"), {
        detail: { file: this.file },
        bubbles: true,
        composed: true
      })
    );
  }
  /** @private */
  __updateThumbnail(file) {
    if (this.__thumbnailReader) {
      this.__thumbnailReader.abort();
      this.__thumbnailReader = null;
    }
    if (!file) {
      this.__thumbnail = "";
      return;
    }
    if (file.type && file.type.startsWith("image/") && file instanceof Blob) {
      const reader = new FileReader();
      this.__thumbnailReader = reader;
      reader.onload = (e) => {
        this.__thumbnail = e.target.result;
        this.__thumbnailReader = null;
      };
      reader.readAsDataURL(file);
    } else {
      this.__thumbnail = "";
    }
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UploadFile extends UploadFileMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-upload-file";
  }
  static get styles() {
    return uploadFileStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    const isFileStartVisible = this.held && !this.uploading && !this.complete;
    const isFileRetryVisible = this.errorMessage;
    return html`
      <div part="loader" ?hidden="${!this.uploading}" aria-hidden="true"></div>

      ${this.__thumbnail ? html`<div part="thumbnail">
            <img src="${this.__thumbnail}" alt="${this.fileName}" />
          </div>` : nothing}

      <div part="done-icon" ?hidden="${!this.complete}" aria-hidden="true"></div>
      <div part="warning-icon" ?hidden="${!this.errorMessage}" aria-hidden="true"></div>

      <div part="meta">
        <div part="name" id="name">${this.fileName}</div>
        <div part="status" ?hidden="${!this.status}" id="status">${this.status}</div>
        <div part="error" id="error" ?hidden="${!this.errorMessage}">${this.errorMessage}</div>
      </div>

      <div part="commands">
        <button
          type="button"
          part="start-button"
          file-event="file-start"
          @click="${this._fireFileEvent}"
          ?hidden="${!isFileStartVisible}"
          ?disabled="${this.disabled}"
          aria-label="${this.i18n ? this.i18n.file.start : nothing}"
          aria-describedby="name"
        ></button>
        <button
          type="button"
          part="retry-button"
          file-event="file-retry"
          @click="${this._fireFileEvent}"
          ?hidden="${!isFileRetryVisible}"
          ?disabled="${this.disabled}"
          aria-label="${this.i18n ? this.i18n.file.retry : nothing}"
          aria-describedby="name"
        ></button>
        <button
          type="button"
          part="remove-button"
          file-event="file-abort"
          @click="${this._fireFileEvent}"
          ?disabled="${this.disabled}"
          aria-label="${this.i18n ? this.i18n.file.remove : nothing}"
          aria-describedby="name"
        ></button>
      </div>

      <slot name="progress"></slot>
    `;
  }
  /**
   * Fired when the retry button is pressed. It is listened by `vaadin-upload`
   * which will start a new upload process of this file.
   *
   * @event file-retry
   * @param {Object} detail
   * @param {Object} detail.file file to retry upload of
   */
  /**
   * Fired when the start button is pressed. It is listened by `vaadin-upload`
   * which will start a new upload process of this file.
   *
   * @event file-start
   * @param {Object} detail
   * @param {Object} detail.file file to start upload of
   */
  /**
   * Fired when abort button is pressed. It is listened by `vaadin-upload` which
   * will abort the upload in progress, and then remove the file from the list.
   *
   * @event file-abort
   * @param {Object} detail
   * @param {Object} detail.file file to abort upload of
   */
}
defineCustomElement(UploadFile);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const uploadFileListStyles = css$h`
  :host {
    display: block;
    overflow: auto;
  }

  :host([hidden]) {
    display: none !important;
  }

  [part='list'] {
    list-style-type: none;
    margin: 0;
    padding: 0;
  }

  ::slotted(:first-child) {
    margin-top: var(--vaadin-upload-gap, var(--vaadin-gap-s));
  }

  ::slotted(li:not(:last-of-type)) {
    border-bottom: var(--vaadin-upload-file-list-divider-width, 1px) solid
      var(--vaadin-upload-file-list-divider-color, var(--vaadin-border-color-secondary));
  }

  /* Thumbnails theme variant */
  :host([theme~='thumbnails']) [part='list'] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--vaadin-gap-s);
  }

  :host([theme~='thumbnails']) ::slotted(:first-child) {
    margin-top: 0;
  }

  :host([theme~='thumbnails']) ::slotted(li) {
    border-bottom: none;
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
window.Vaadin = window.Vaadin || {};
window.Vaadin.featureFlags = window.Vaadin.featureFlags || {};
class UploadManager extends EventTarget {
  /** @type {Array<UploadFile>} */
  #files = [];
  /** @type {boolean} */
  #maxFilesReached = false;
  /** @type {boolean} */
  #disabled = false;
  /** @type {Array<UploadFile>} */
  #uploadQueue = [];
  /** @type {number} */
  #activeUploads = 0;
  /** @type {string} */
  #method = "POST";
  /** @type {number} */
  #maxFiles = Infinity;
  /** @type {number} */
  #maxConcurrentUploads = 3;
  /** @type {Record<string, string>} */
  #headers = {};
  /**
   * Create an UploadManager instance.
   * @param {Object} options - Configuration options
   * @param {string} [options.target=''] - The server URL. The default value is an empty string, which means that _window.location_ will be used.
   * @param {string} [options.method='POST'] - HTTP Method used to send the files. Only POST and PUT are allowed.
   * @param {Object} [options.headers={}] - Key-Value map to send to the server.
   * @param {number} [options.timeout=0] - Max time in milliseconds for the entire upload process, if exceeded the request will be aborted. Zero means that there is no timeout.
   * @param {number} [options.maxFiles=Infinity] - Limit of files to upload, by default it is unlimited. If the value is set to one, native file browser will prevent selecting multiple files.
   * @param {number} [options.maxFileSize=Infinity] - Specifies the maximum file size in bytes allowed to upload. Notice that it is a client-side constraint, which will be checked before sending the request. Obviously you need to do the same validation in the server-side and be sure that they are aligned.
   * @param {string} [options.accept=''] - Specifies the types of files that the server accepts. Syntax: a comma-separated list of MIME type patterns (wildcards are allowed) or file extensions. Notice that MIME types are widely supported, while file extensions are only implemented in certain browsers, so avoid using it. Example: accept="video/*,image/tiff" or accept=".pdf,audio/mp3"
   * @param {boolean} [options.noAuto=false] - Prevents upload(s) from immediately uploading upon adding file(s). When set, you must manually trigger uploads using the `uploadFiles` method.
   * @param {boolean} [options.withCredentials=false] - Set the withCredentials flag on the request.
   * @param {string} [options.uploadFormat='raw'] - Specifies the upload format to use when sending files to the server. 'raw': Send file as raw binary data with the file's MIME type as Content-Type (default). 'multipart': Send file using multipart/form-data encoding.
   * @param {number} [options.maxConcurrentUploads=3] - Specifies the maximum number of files that can be uploaded simultaneously. This helps prevent browser performance degradation and XHR limitations when uploading large numbers of files. Files exceeding this limit will be queued and uploaded as active uploads complete.
   * @param {string} [options.formDataName='file'] - Specifies the 'name' property at Content-Disposition for multipart uploads. This property is ignored when uploadFormat is 'raw'.
   * @param {boolean} [options.disabled=false] - Whether the upload manager is disabled. When true, connected components (upload-button, upload-drop-zone) will be automatically disabled.
   */
  constructor(options2 = {}) {
    super();
    if (!window.Vaadin.featureFlags.modularUpload && !window.Vaadin.featureFlags.aiComponents) {
      throw new Error(
        "UploadManager requires the modularUpload feature flag. Enable it with: window.Vaadin.featureFlags.modularUpload = true"
      );
    }
    this.target = options2.target || "";
    this.method = options2.method || "POST";
    this.headers = options2.headers || {};
    this.timeout = options2.timeout || 0;
    this.maxFiles = options2.maxFiles === void 0 ? Infinity : options2.maxFiles;
    this.maxFileSize = options2.maxFileSize === void 0 ? Infinity : options2.maxFileSize;
    this.accept = options2.accept || "";
    this.noAuto = options2.noAuto === void 0 ? false : options2.noAuto;
    this.withCredentials = options2.withCredentials === void 0 ? false : options2.withCredentials;
    this.uploadFormat = options2.uploadFormat || "raw";
    this.maxConcurrentUploads = options2.maxConcurrentUploads === void 0 ? 3 : options2.maxConcurrentUploads;
    this.formDataName = options2.formDataName || "file";
    this.disabled = options2.disabled === void 0 ? false : options2.disabled;
  }
  /**
   * HTTP Method used to send the files. Only POST and PUT are allowed.
   * @type {string}
   */
  get method() {
    return this.#method;
  }
  set method(value) {
    if (value !== "POST" && value !== "PUT") {
      throw new Error(`Invalid method "${value}". Only POST and PUT are allowed.`);
    }
    this.#method = value;
  }
  /**
   * Limit of files to upload, by default it is unlimited.
   * @type {number}
   */
  get maxFiles() {
    return this.#maxFiles;
  }
  set maxFiles(value) {
    if (value < 0) {
      throw new Error(`Invalid maxFiles "${value}". Value must be non-negative.`);
    }
    this.#maxFiles = value;
    this.#updateMaxFilesReached();
  }
  /**
   * Maximum number of files that can be uploaded simultaneously.
   * @type {number}
   */
  get maxConcurrentUploads() {
    return this.#maxConcurrentUploads;
  }
  set maxConcurrentUploads(value) {
    if (value <= 0) {
      throw new Error(`Invalid maxConcurrentUploads "${value}". Value must be positive.`);
    }
    this.#maxConcurrentUploads = value;
  }
  /**
   * Key-Value map to send to the server.
   * @type {Record<string, string>}
   */
  get headers() {
    return this.#headers;
  }
  set headers(value) {
    this.#headers = { ...value };
  }
  /**
   * The array of files being processed, or already uploaded.
   *
   * Each element is a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File)
   * object with a number of extra properties to track the upload process:
   * - `uploadTarget`: The target URL used to upload this file.
   * - `elapsed`: Elapsed time since the upload started.
   * - `remaining`: Number of seconds remaining for the upload to finish.
   * - `progress`: Percentage of the file already uploaded.
   * - `speed`: Upload speed in kB/s.
   * - `size`: File size in bytes.
   * - `total`: The total size of the data being transmitted or processed
   * - `loaded`: Bytes transferred so far.
   * - `status`: Status of the upload process.
   * - `errorKey`: Error key in case the upload failed.
   * - `abort`: True if the file was canceled by the user.
   * - `complete`: True when the file was transferred to the server.
   * - `uploading`: True while transferring data to the server.
   *
   * **Note:** The getter returns a shallow copy of the internal array to prevent
   * external mutation. Modifying the returned array will not affect the manager's state.
   *
   * **Note:** The setter validates files against maxFiles, maxFileSize, and accept constraints.
   * Files that fail validation will be rejected with a 'file-reject' event.
   * @type {Array<UploadFile>}
   */
  get files() {
    return [...this.#files];
  }
  set files(value) {
    const validFiles = [];
    for (const file of value) {
      if (this.#files.includes(file)) {
        validFiles.push(file);
        continue;
      }
      const error2 = this.#validateFile(file, validFiles.length);
      if (error2) {
        this.dispatchEvent(
          new CustomEvent("file-reject", {
            detail: { file, error: error2 }
          })
        );
        continue;
      }
      validFiles.push(file);
    }
    this.#setFiles(validFiles);
  }
  // Internal setter - bypasses validation for internal use only
  #setFiles(value) {
    this.#files = value;
    this.#updateMaxFilesReached();
    this.#notifyFilesChanged();
  }
  /**
   * Specifies if the maximum number of files have been uploaded.
   * @type {boolean}
   * @readonly
   */
  get maxFilesReached() {
    return this.#maxFilesReached;
  }
  /**
   * Whether the upload manager is disabled.
   * When true, connected components (upload-button, upload-drop-zone) will be automatically disabled.
   * @type {boolean}
   */
  get disabled() {
    return this.#disabled;
  }
  set disabled(value) {
    const disabled = Boolean(value);
    if (disabled !== this.#disabled) {
      this.#disabled = disabled;
      this.dispatchEvent(
        new CustomEvent("disabled-changed", {
          detail: { value: disabled }
        })
      );
    }
  }
  /**
   * Add files to the upload list.
   * @param {FileList|File[]} files - Files to add
   */
  addFiles(files) {
    Array.from(files).forEach((file) => this.#addFile(file));
  }
  /**
   * Triggers the upload of any files that are not completed.
   *
   * @param {UploadFile|UploadFile[]} [files] - Files being uploaded. Defaults to all outstanding files.
   */
  uploadFiles(files = this.#files) {
    if (files && !Array.isArray(files)) {
      files = [files];
    }
    files.filter((file) => this.#files.includes(file) && !file.complete).forEach((file) => this.#queueFileUpload(file));
  }
  /**
   * Retry a failed upload.
   * @param {UploadFile} file - The file to retry
   */
  retryUpload(file) {
    this.#retryFileUpload(file);
  }
  /**
   * Abort an upload.
   * @param {UploadFile} file - The file to abort
   */
  abortUpload(file) {
    this.#abortFileUpload(file);
  }
  /**
   * Remove a file from the list.
   * @param {UploadFile} file - The file to remove
   */
  removeFile(file) {
    this.#removeFile(file);
  }
  // ============ Private methods ============
  get #acceptRegexp() {
    if (!this.accept) {
      return null;
    }
    const processedTokens = this.accept.split(",").map((token) => {
      let processedToken = token.trim();
      processedToken = processedToken.replaceAll(/[+.]/gu, String.raw`\$&`);
      if (processedToken.startsWith(String.raw`\.`)) {
        processedToken = `.*${processedToken}$`;
      }
      return processedToken.replaceAll("/*", "/.*");
    });
    return new RegExp(`^(${processedTokens.join("|")})$`, "iu");
  }
  #updateMaxFilesReached() {
    const reached = this.maxFiles >= 0 && this.#files.length >= this.maxFiles;
    if (reached !== this.#maxFilesReached) {
      this.#maxFilesReached = reached;
      this.dispatchEvent(
        new CustomEvent("max-files-reached-changed", {
          detail: { value: reached }
        })
      );
    }
  }
  /**
   * Validates a file against constraints.
   * @param {File} file - The file to validate
   * @param {number} currentCount - Current number of files (for maxFiles check)
   * @returns {string|null} Error code if invalid, null if valid
   */
  #validateFile(file, currentCount) {
    if (currentCount >= this.maxFiles) {
      return "tooManyFiles";
    }
    if (this.maxFileSize >= 0 && file.size > this.maxFileSize) {
      return "fileIsTooBig";
    }
    const re2 = this.#acceptRegexp;
    if (re2 && !(re2.test(file.type) || re2.test(file.name))) {
      return "incorrectFileType";
    }
    return null;
  }
  #addFile(file) {
    const error2 = this.#validateFile(file, this.#files.length);
    if (error2) {
      this.dispatchEvent(
        new CustomEvent("file-reject", {
          detail: { file, error: error2 }
        })
      );
      return;
    }
    file.loaded = 0;
    file.held = true;
    file.formDataName = this.formDataName;
    this.#setFiles([file, ...this.#files]);
    if (!this.noAuto) {
      this.#queueFileUpload(file);
    }
  }
  #removeFile(file) {
    this.#uploadQueue = this.#uploadQueue.filter((f) => f !== file);
    if (file.uploading && !file.held && !file.abort && file.xhr) {
      file.abort = true;
      file.xhr.abort();
    }
    const fileIndex = this.#files.indexOf(file);
    if (fileIndex >= 0) {
      this.#setFiles(this.#files.filter((f) => f !== file));
      this.dispatchEvent(
        new CustomEvent("file-remove", {
          detail: { file, fileIndex }
        })
      );
    }
  }
  #queueFileUpload(file) {
    if (file.uploading) {
      return;
    }
    if (this.#uploadQueue.includes(file)) {
      return;
    }
    file.loaded = 0;
    file.progress = 0;
    file.held = true;
    file.uploading = file.indeterminate = true;
    file.complete = file.abort = file.errorKey = false;
    file.stalled = false;
    this.#notifyFilesChanged();
    this.#uploadQueue.push(file);
    this.#processUploadQueue();
  }
  #processUploadQueue() {
    while (this.#uploadQueue.length > 0 && this.#activeUploads < this.maxConcurrentUploads) {
      const nextFile = this.#uploadQueue.shift();
      if (nextFile) {
        this.#uploadFile(nextFile);
      }
    }
  }
  #uploadFile(file) {
    this.#activeUploads += 1;
    const ini = Date.now();
    const xhr2 = file.xhr = this._createXhr();
    let stalledId;
    xhr2.upload.onprogress = (e) => {
      clearTimeout(stalledId);
      const elapsed = (Date.now() - ini) / 1e3;
      const loaded = e.loaded;
      const total = e.total;
      const rawProgress = total > 0 ? Math.trunc(loaded / total * 100) : 100;
      const progress = Math.max(0, Math.min(100, rawProgress));
      file.loaded = loaded;
      file.progress = progress;
      file.indeterminate = total > 0 ? loaded <= 0 || loaded >= total : false;
      if (file.stalled) {
        file.stalled = false;
      }
      if (file.errorKey) {
        file.indeterminate = file.status = void 0;
      } else if (!file.abort) {
        if (progress < 100) {
          this.#setStatus(file, total, loaded, elapsed);
          stalledId = setTimeout(() => {
            if (file.uploading && !file.abort) {
              file.stalled = true;
              this.#notifyFilesChanged();
            }
          }, 2e3);
        }
      }
      this.#notifyFilesChanged();
      this.dispatchEvent(new CustomEvent("upload-progress", { detail: { file, xhr: xhr2 } }));
    };
    xhr2.onabort = () => {
      clearTimeout(stalledId);
      this.#activeUploads -= 1;
      this.#cleanupXhr(xhr2);
      this.#processUploadQueue();
    };
    xhr2.ontimeout = () => {
      clearTimeout(stalledId);
      file.indeterminate = file.uploading = false;
      file.errorKey = "timeout";
      file.status = "";
      this.#activeUploads -= 1;
      this.#processUploadQueue();
      this.#cleanupXhr(xhr2);
      this.dispatchEvent(new CustomEvent("upload-error", { detail: { file, xhr: xhr2 } }));
      this.#notifyFilesChanged();
    };
    xhr2.onreadystatechange = () => {
      if (xhr2.readyState === 4) {
        clearTimeout(stalledId);
        file.indeterminate = file.uploading = false;
        this.#activeUploads -= 1;
        this.#processUploadQueue();
        this.#cleanupXhr(xhr2);
        if (file.abort || file.errorKey) {
          return;
        }
        file.status = "";
        const evt2 = this.dispatchEvent(
          new CustomEvent("upload-response", {
            detail: { file, xhr: xhr2 },
            cancelable: true
          })
        );
        if (!evt2) {
          return;
        }
        if (xhr2.status === 0) {
          file.errorKey = "serverUnavailable";
        } else if (xhr2.status >= 500) {
          file.errorKey = "unexpectedServerError";
        } else if (xhr2.status === 413) {
          file.errorKey = "fileTooLarge";
        } else if (xhr2.status >= 400) {
          file.errorKey = "forbidden";
        }
        file.complete = !file.errorKey;
        const eventName = file.errorKey ? "upload-error" : "upload-success";
        this.dispatchEvent(new CustomEvent(eventName, { detail: { file, xhr: xhr2 } }));
        file.xhr = null;
        this.#notifyFilesChanged();
      }
    };
    const isRawUpload = this.uploadFormat === "raw";
    if (!file.uploadTarget) {
      file.uploadTarget = this.target;
    }
    const evt = this.dispatchEvent(
      new CustomEvent("upload-before", {
        detail: { file, xhr: xhr2 },
        cancelable: true
      })
    );
    if (!evt) {
      this.#holdFile(file);
      return;
    }
    if (!this.#files.includes(file)) {
      if (!file.abort) {
        this.#activeUploads -= 1;
      }
      this.#cleanupXhr(xhr2);
      this.#processUploadQueue();
      return;
    }
    let requestBody;
    if (isRawUpload) {
      requestBody = file;
    } else {
      const formData = new FormData();
      formData.append(file.formDataName || this.formDataName, file, file.name);
      requestBody = formData;
    }
    xhr2.open(this.method, file.uploadTarget, true);
    this.#configureXhr(xhr2, file, isRawUpload);
    file.held = false;
    xhr2.upload.onloadstart = () => {
      this.dispatchEvent(
        new CustomEvent("upload-start", {
          detail: { file, xhr: xhr2 }
        })
      );
      this.#notifyFilesChanged();
    };
    const eventDetail = {
      file,
      xhr: xhr2,
      uploadFormat: this.uploadFormat,
      requestBody
    };
    if (!isRawUpload) {
      eventDetail.formData = requestBody;
    }
    const uploadEvt = this.dispatchEvent(
      new CustomEvent("upload-request", {
        detail: eventDetail,
        cancelable: true
      })
    );
    if (!uploadEvt) {
      this.#holdFile(file);
      return;
    }
    if (!this.#files.includes(file)) {
      if (!file.abort) {
        this.#activeUploads -= 1;
      }
      this.#cleanupXhr(xhr2);
      this.#processUploadQueue();
      return;
    }
    try {
      xhr2.send(requestBody);
    } catch (e) {
      this.#activeUploads -= 1;
      file.uploading = false;
      file.indeterminate = false;
      file.errorKey = e.message || "sendFailed";
      this.#cleanupXhr(xhr2);
      this.#notifyFilesChanged();
      this.#processUploadQueue();
    }
  }
  /**
   * Creates an XMLHttpRequest instance. Override in tests to mock XHR behavior.
   * @private
   */
  _createXhr() {
    return new XMLHttpRequest();
  }
  /**
   * Reset file state when upload is prevented.
   */
  #holdFile(file) {
    this.#activeUploads -= 1;
    file.uploading = false;
    file.indeterminate = false;
    file.held = true;
    this.#notifyFilesChanged();
    this.#processUploadQueue();
  }
  /**
   * Clean up XHR handlers to prevent memory leaks
   */
  #cleanupXhr(xhr2) {
    if (xhr2) {
      xhr2.upload.onprogress = null;
      xhr2.upload.onloadstart = null;
      xhr2.onreadystatechange = null;
      xhr2.onabort = null;
      xhr2.ontimeout = null;
    }
  }
  #configureXhr(xhr2, file, isRawUpload) {
    Object.entries(this.headers).forEach(([key2, value]) => {
      xhr2.setRequestHeader(key2, value);
    });
    if (isRawUpload) {
      xhr2.setRequestHeader("Content-Type", file.type || "application/octet-stream");
      xhr2.setRequestHeader("X-Filename", encodeURIComponent(file.name));
    }
    if (this.timeout) {
      xhr2.timeout = this.timeout;
    }
    xhr2.withCredentials = this.withCredentials;
  }
  #retryFileUpload(file) {
    const evt = this.dispatchEvent(
      new CustomEvent("upload-retry", {
        detail: { file, xhr: file.xhr },
        cancelable: true
      })
    );
    if (evt) {
      file.uploading = false;
      this.#uploadQueue = this.#uploadQueue.filter((f) => f !== file);
      this.#queueFileUpload(file);
    }
  }
  #abortFileUpload(file) {
    const evt = this.dispatchEvent(
      new CustomEvent("upload-abort", {
        detail: { file, xhr: file.xhr },
        cancelable: true
      })
    );
    if (evt) {
      file.abort = true;
      if (file.xhr) {
        file.xhr.abort();
      }
      this.#removeFile(file);
    }
  }
  #setStatus(file, total, loaded, elapsed) {
    file.elapsed = elapsed;
    file.remaining = loaded > 0 ? Math.ceil(elapsed * (total / loaded - 1)) : 0;
    file.speed = elapsed > 0 ? Math.trunc(loaded / elapsed / 1024) : 0;
    file.total = total;
  }
  #notifyFilesChanged() {
    this.dispatchEvent(
      new CustomEvent("files-changed", {
        detail: { value: this.#files }
      })
    );
  }
}
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N$1 = {
  file: {
    retry: "Retry",
    start: "Start",
    remove: "Remove"
  },
  error: {
    tooManyFiles: "Too Many Files.",
    fileIsTooBig: "File is Too Big.",
    incorrectFileType: "Incorrect File Type."
  },
  uploading: {
    status: {
      connecting: "Connecting...",
      stalled: "Stalled",
      processing: "Processing File...",
      held: "Queued"
    },
    remainingTime: {
      prefix: "remaining time: ",
      unknown: "unknown remaining time"
    },
    error: {
      serverUnavailable: "Upload failed, please try again later",
      unexpectedServerError: "Upload failed due to server error",
      forbidden: "Upload forbidden",
      fileTooLarge: "File is too large"
    }
  },
  units: {
    size: ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
  }
};
const UploadFileListMixin = (superClass) => class UploadFileListMixin extends I18nMixin(DEFAULT_I18N$1, superClass) {
  static get properties() {
    return {
      /**
       * The array of files being processed, or already uploaded.
       * @readonly
       */
      items: {
        type: Array
      },
      /**
       * If true, the user cannot interact with this element.
       */
      disabled: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * Reference to an UploadManager to link this file list to.
       * When set, the file list automatically:
       * - Syncs files from the manager
       * - Forwards retry/abort/start/remove events back to the manager
       * @type {Object | null}
       */
      manager: {
        type: Object,
        value: null,
        observer: "__managerChanged"
      }
    };
  }
  static get observers() {
    return ["__updateItems(items, __effectiveI18n, disabled, _theme)"];
  }
  constructor() {
    super();
    this.__onManagerFilesChanged = this.__onManagerFilesChanged.bind(this);
    this.__onManagerDisabledChanged = this.__onManagerDisabledChanged.bind(this);
    this.__onFileRetry = this.__onFileRetry.bind(this);
    this.__onFileAbort = this.__onFileAbort.bind(this);
    this.__onFileStart = this.__onFileStart.bind(this);
    this.__onFileRemove = this.__onFileRemove.bind(this);
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("file-retry", this.__onFileRetry);
    this.addEventListener("file-abort", this.__onFileAbort);
    this.addEventListener("file-start", this.__onFileStart);
    this.addEventListener("file-remove", this.__onFileRemove);
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (this.manager instanceof UploadManager) {
      this.manager.removeEventListener("files-changed", this.__onManagerFilesChanged);
      this.manager.removeEventListener("disabled-changed", this.__onManagerDisabledChanged);
    }
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this.manager instanceof UploadManager) {
      this.manager.addEventListener("files-changed", this.__onManagerFilesChanged);
      this.manager.addEventListener("disabled-changed", this.__onManagerDisabledChanged);
      this.__syncFromManager();
    }
  }
  /** @private */
  __managerChanged(manager, oldManager) {
    if (oldManager instanceof UploadManager) {
      oldManager.removeEventListener("files-changed", this.__onManagerFilesChanged);
      oldManager.removeEventListener("disabled-changed", this.__onManagerDisabledChanged);
    }
    if (this.isConnected && manager instanceof UploadManager) {
      manager.addEventListener("files-changed", this.__onManagerFilesChanged);
      manager.addEventListener("disabled-changed", this.__onManagerDisabledChanged);
      this.__syncFromManager();
    } else {
      this.items = [];
    }
  }
  /** @private */
  __onManagerFilesChanged() {
    this.__syncFromManager();
  }
  /** @private */
  __onManagerDisabledChanged() {
    this.requestContentUpdate();
  }
  /** @private */
  __syncFromManager() {
    if (this.manager instanceof UploadManager) {
      this.items = [...this.manager.files];
    }
  }
  /** @private */
  __onFileRetry(event) {
    if (this.manager instanceof UploadManager) {
      event.stopPropagation();
      this.manager.retryUpload(event.detail.file);
    }
  }
  /** @private */
  __onFileAbort(event) {
    if (this.manager instanceof UploadManager) {
      event.stopPropagation();
      this.manager.abortUpload(event.detail.file);
    }
  }
  /** @private */
  __onFileStart(event) {
    if (this.manager instanceof UploadManager) {
      event.stopPropagation();
      this.manager.uploadFiles(event.detail.file);
    }
  }
  /** @private */
  __onFileRemove(event) {
    if (this.manager instanceof UploadManager) {
      event.stopPropagation();
      this.manager.removeFile(event.detail.file);
    }
  }
  /** @private */
  __updateItems(items, i18n, _disabled, _theme) {
    if (items && i18n) {
      items.forEach((file) => this.__applyI18nToFile(file));
      this.requestContentUpdate();
    }
  }
  /** @private */
  __applyI18nToFile(file) {
    const i18n = this.__effectiveI18n;
    if (file.total) {
      this.__applyFileSizeStrings(file);
    }
    file.status = this.__getFileStatus(file, i18n);
    this.__applyFileError(file, i18n);
  }
  /** @private */
  __applyFileSizeStrings(file) {
    file.totalStr = this.__formatSize(file.total);
    file.loadedStr = this.__formatSize(file.loaded || 0);
    if (file.elapsed != null) {
      file.elapsedStr = this.__formatTime(file.elapsed, this.__splitTimeByUnits(file.elapsed));
    }
    if (file.remaining != null) {
      file.remainingStr = this.__formatTime(file.remaining, this.__splitTimeByUnits(file.remaining));
    }
  }
  /** @private */
  __getFileStatus(file, i18n) {
    if (file.held && !file.error) {
      return i18n.uploading.status.held;
    }
    if (file.stalled) {
      return i18n.uploading.status.stalled;
    }
    if (file.uploading && file.indeterminate && !file.held) {
      return file.progress === 100 ? i18n.uploading.status.processing : i18n.uploading.status.connecting;
    }
    if (file.uploading && file.progress < 100 && file.total) {
      return this.__formatFileProgress(file);
    }
    return file.status;
  }
  /** @private */
  __applyFileError(file, i18n) {
    if (file.errorKey && i18n.uploading.error[file.errorKey]) {
      file.error = i18n.uploading.error[file.errorKey];
    } else if (!file.errorKey && this.manager instanceof UploadManager) {
      file.error = "";
    }
  }
  /** @private */
  __formatSize(bytes) {
    const i18n = this.__effectiveI18n;
    if (typeof i18n.formatSize === "function") {
      return i18n.formatSize(bytes);
    }
    const base2 = i18n.units.sizeBase || 1e3;
    const unit = Math.trunc(Math.log(bytes) / Math.log(base2));
    const dec = Math.max(0, Math.min(3, unit - 1));
    const size = Number.parseFloat((bytes / base2 ** unit).toFixed(dec));
    return `${size} ${i18n.units.size[unit]}`;
  }
  /** @private */
  __splitTimeByUnits(time) {
    const unitSizes = [60, 60, 24, Infinity];
    const timeValues = [0];
    for (let i = 0; i < unitSizes.length && time > 0; i++) {
      timeValues[i] = time % unitSizes[i];
      time = Math.floor(time / unitSizes[i]);
    }
    return timeValues;
  }
  /** @private */
  __formatTime(seconds, split) {
    const i18n = this.__effectiveI18n;
    if (typeof i18n.formatTime === "function") {
      return i18n.formatTime(seconds, split);
    }
    while (split.length < 3) {
      split.push(0);
    }
    return split.reverse().map((number) => {
      return (number < 10 ? "0" : "") + number;
    }).join(":");
  }
  /** @private */
  __formatFileProgress(file) {
    const i18n = this.__effectiveI18n;
    const remainingTime = file.loaded > 0 ? i18n.uploading.remainingTime.prefix + file.remainingStr : i18n.uploading.remainingTime.unknown;
    return `${file.totalStr}: ${file.progress}% (${remainingTime})`;
  }
  /** @private */
  requestContentUpdate() {
    const { items, __effectiveI18n: i18n, disabled } = this;
    const managerDisabled = this.manager instanceof UploadManager && this.manager.disabled;
    const effectiveDisabled = disabled || managerDisabled;
    render$1(
      html`
          ${items.map(
        (file) => html`
              <li>
                <vaadin-upload-file
                  .disabled="${effectiveDisabled}"
                  .file="${file}"
                  .complete="${file.complete}"
                  .errorMessage="${file.error}"
                  .fileName="${file.name}"
                  .held="${file.held}"
                  .indeterminate="${file.indeterminate}"
                  .progress="${file.progress}"
                  .status="${file.status}"
                  .uploading="${file.uploading}"
                  .i18n="${i18n}"
                  theme="${ifDefined(
          window.Vaadin.featureFlags.modularUpload || window.Vaadin.featureFlags.aiComponents ? this._theme : void 0
        )}"
                ></vaadin-upload-file>
              </li>
            `
      )}
        `,
      this
    );
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UploadFileList extends UploadFileListMixin(ThemableMixin(PolylitMixin(LitElement))) {
  static get is() {
    return "vaadin-upload-file-list";
  }
  static get styles() {
    return uploadFileListStyles;
  }
  /** @protected */
  render() {
    return html`
      <ul part="list">
        <slot></slot>
      </ul>
    `;
  }
}
defineCustomElement(UploadFileList);
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const uploadStyles = css$h`
  :host {
    background: var(--vaadin-upload-background, transparent);
    border: var(--vaadin-upload-border-width, 1px) solid
      var(--vaadin-upload-border-color, var(--vaadin-border-color-secondary));
    border-radius: var(--vaadin-upload-border-radius, var(--vaadin-radius-m));
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: var(--vaadin-upload-padding, var(--vaadin-padding-s));
    position: relative;
  }

  :host([dragover-valid]) {
    --vaadin-upload-background: var(--vaadin-background-container);
    --vaadin-upload-border-color: var(--vaadin-text-color);
    border-style: dashed;
  }

  :host([hidden]) {
    display: none !important;
  }

  [hidden] {
    display: none !important;
  }

  [part='primary-buttons'] {
    align-items: center;
    display: flex;
    gap: var(--vaadin-gap-s);
  }

  [part='drop-label'] {
    align-items: center;
    color: var(--vaadin-upload-drop-label-color, var(--vaadin-text-color));
    display: flex;
    font-size: var(--vaadin-upload-drop-label-font-size, inherit);
    font-weight: var(--vaadin-upload-drop-label-font-weight, inherit);
    gap: var(--vaadin-upload-drop-label-gap, var(--vaadin-gap-s));
    line-height: var(--vaadin-upload-drop-label-line-height, inherit);
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
function getFilesFromDropEvent(dropEvent) {
  async function getFilesFromEntry(entry) {
    if (entry.isFile) {
      return new Promise((resolve) => {
        entry.file(resolve, () => resolve([]));
      });
    } else if (entry.isDirectory) {
      const reader = entry.createReader();
      const entries = await new Promise((resolve) => {
        reader.readEntries(resolve, () => resolve([]));
      });
      const files = await Promise.all(entries.map(getFilesFromEntry));
      return files.flat();
    }
  }
  const containsFolders = Array.from(dropEvent.dataTransfer.items).filter((item) => !!item).filter((item) => typeof item.webkitGetAsEntry === "function").map((item) => item.webkitGetAsEntry()).some((entry) => !!entry && entry.isDirectory);
  if (!containsFolders) {
    return Promise.resolve(dropEvent.dataTransfer.files ? Array.from(dropEvent.dataTransfer.files) : []);
  }
  const filePromises = Array.from(dropEvent.dataTransfer.items).map((item) => item.webkitGetAsEntry()).filter((entry) => !!entry).map(getFilesFromEntry);
  return Promise.all(filePromises).then((files) => files.flat());
}
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const DEFAULT_I18N = {
  dropFiles: {
    one: "Drop file here",
    many: "Drop files here"
  },
  addFiles: {
    one: "Upload File...",
    many: "Upload Files..."
  },
  error: {
    tooManyFiles: "Too Many Files.",
    fileIsTooBig: "File is Too Big.",
    incorrectFileType: "Incorrect File Type."
  },
  uploading: {
    status: {
      connecting: "Connecting...",
      stalled: "Stalled",
      processing: "Processing File...",
      held: "Queued"
    },
    remainingTime: {
      prefix: "remaining time: ",
      unknown: "unknown remaining time"
    },
    error: {
      serverUnavailable: "Upload failed, please try again later",
      unexpectedServerError: "Upload failed due to server error",
      forbidden: "Upload forbidden",
      fileTooLarge: "File is too large"
    }
  },
  file: {
    retry: "Retry",
    start: "Start",
    remove: "Remove"
  },
  units: {
    size: ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
  }
};
class AddButtonController extends SlotController {
  constructor(host) {
    super(host, "add-button", "vaadin-button");
  }
  /**
   * Override method inherited from `SlotController`
   * to add listeners to default and custom node.
   *
   * @param {Node} node
   * @protected
   * @override
   */
  initNode(node) {
    if (node._isDefault) {
      this.defaultNode = node;
    }
    node.addEventListener("touchend", (e) => {
      this.host._onAddFilesTouchEnd(e);
    });
    node.addEventListener("click", (e) => {
      this.host._onAddFilesClick(e);
    });
    this.host._addButton = node;
  }
}
class DropLabelController extends SlotController {
  constructor(host) {
    super(host, "drop-label", "span");
  }
  /**
   * Override method inherited from `SlotController`
   * to add listeners to default and custom node.
   *
   * @param {Node} node
   * @protected
   * @override
   */
  initNode(node) {
    if (node._isDefault) {
      this.defaultNode = node;
    }
    this.host._dropLabel = node;
  }
}
const UploadMixin = (superClass) => class UploadMixin extends I18nMixin(DEFAULT_I18N, superClass) {
  static get properties() {
    return {
      /**
       * If true, the user cannot interact with this element.
       */
      disabled: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      },
      /**
       * Define whether the element supports dropping files on it for uploading.
       * By default it's enabled in desktop and disabled in touch devices
       * because mobile devices do not support drag events in general. Setting
       * it false means that drop is enabled even in touch-devices, and true
       * disables drop in all devices.
       *
       * @default true in touch-devices, false otherwise.
       */
      nodrop: {
        type: Boolean,
        reflectToAttribute: true,
        value: isTouch
      },
      /**
       * The server URL. The default value is an empty string, which means that
       * _window.location_ will be used.
       */
      target: {
        type: String,
        value: ""
      },
      /**
       * HTTP Method used to send the files. Only POST and PUT are allowed.
       */
      method: {
        type: String,
        value: "POST"
      },
      /**
       * Key-Value map to send to the server. If you set this property as an
       * attribute, use a valid JSON string, for example:
       * ```html
       * <vaadin-upload headers='{"X-Foo": "Bar"}'></vaadin-upload>
       * ```
       * @type {object | string}
       */
      headers: {
        type: Object,
        value: {}
      },
      /**
       * Max time in milliseconds for the entire upload process, if exceeded the
       * request will be aborted. Zero means that there is no timeout.
       */
      timeout: {
        type: Number,
        value: 0
      },
      /** @private */
      _dragover: {
        type: Boolean,
        value: false,
        observer: "_dragoverChanged"
      },
      /**
       * The array of files being processed, or already uploaded.
       *
       * Each element is a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File)
       * object with a number of extra properties  to track the upload process:
       * - `uploadTarget`: The target URL used to upload this file.
       * - `elapsed`: Elapsed time since the upload started.
       * - `elapsedStr`: Human-readable elapsed time.
       * - `remaining`: Number of seconds remaining for the upload to finish.
       * - `remainingStr`: Human-readable remaining time for the upload to finish.
       * - `progress`: Percentage of the file already uploaded.
       * - `speed`: Upload speed in kB/s.
       * - `size`: File size in bytes.
       * - `totalStr`: Human-readable total size of the file.
       * - `loaded`: Bytes transferred so far.
       * - `loadedStr`: Human-readable uploaded size at the moment.
       * - `status`: Status of the upload process.
       * - `error`: Error message in case the upload failed.
       * - `abort`: True if the file was canceled by the user.
       * - `complete`: True when the file was transferred to the server.
       * - `uploading`: True while transferring data to the server.
       * @type {!Array<!UploadFile>}
       */
      files: {
        type: Array,
        notify: true,
        value: () => [],
        sync: true
      },
      /**
       * Limit of files to upload, by default it is unlimited. If the value is
       * set to one, native file browser will prevent selecting multiple files.
       * @attr {number} max-files
       */
      maxFiles: {
        type: Number,
        value: Infinity,
        sync: true
      },
      /**
       * Specifies if the maximum number of files have been uploaded
       * @attr {boolean} max-files-reached
       */
      maxFilesReached: {
        type: Boolean,
        value: false,
        notify: true,
        readOnly: true,
        reflectToAttribute: true
      },
      /**
       * Specifies the types of files that the server accepts.
       * Syntax: a comma-separated list of MIME type patterns (wildcards are
       * allowed) or file extensions.
       * Notice that MIME types are widely supported, while file extensions
       * are only implemented in certain browsers, so avoid using it.
       * Example: accept="video/*,image/tiff" or accept=".pdf,audio/mp3"
       */
      accept: {
        type: String,
        value: ""
      },
      /**
       * Specifies the maximum file size in bytes allowed to upload.
       * Notice that it is a client-side constraint, which will be checked before
       * sending the request. Obviously you need to do the same validation in
       * the server-side and be sure that they are aligned.
       * @attr {number} max-file-size
       */
      maxFileSize: {
        type: Number,
        value: Infinity
      },
      /**
       * Specifies if the dragover is validated with maxFiles and
       * accept properties.
       * @private
       */
      _dragoverValid: {
        type: Boolean,
        value: false,
        observer: "_dragoverValidChanged"
      },
      /**
       * Specifies the 'name' property at Content-Disposition for multipart uploads.
       * This property is ignored when uploadFormat is 'raw'.
       * @attr {string} form-data-name
       */
      formDataName: {
        type: String,
        value: "file"
      },
      /**
       * Prevents upload(s) from immediately uploading upon adding file(s).
       * When set, you must manually trigger uploads using the `uploadFiles` method
       * @attr {boolean} no-auto
       */
      noAuto: {
        type: Boolean,
        value: false
      },
      /**
       * Set the withCredentials flag on the request.
       * @attr {boolean} with-credentials
       */
      withCredentials: {
        type: Boolean,
        value: false
      },
      /**
       * Specifies the upload format to use when sending files to the server.
       * - 'raw': Send file as raw binary data with the file's MIME type as Content-Type (default)
       * - 'multipart': Send file using multipart/form-data encoding
       * @attr {string} upload-format
       */
      uploadFormat: {
        type: String,
        value: "raw"
      },
      /**
       * Specifies the maximum number of files that can be uploaded simultaneously.
       * This helps prevent browser performance degradation and XHR limitations when
       * uploading large numbers of files. Files exceeding this limit will be queued
       * and uploaded as active uploads complete.
       * @attr {number} max-concurrent-uploads
       */
      maxConcurrentUploads: {
        type: Number,
        value: 3,
        sync: true
      },
      /**
       * Pass-through to input's capture attribute. Allows user to trigger device inputs
       * such as camera or microphone immediately.
       */
      capture: {
        type: String
      },
      /** @private */
      _addButton: {
        type: Object
      },
      /** @private */
      _dropLabel: {
        type: Object
      },
      /** @private */
      _fileList: {
        type: Object
      },
      /** @private */
      _files: {
        type: Array
      },
      /** @private */
      _uploadQueue: {
        type: Array,
        value: () => []
      },
      /** @private */
      _activeUploads: {
        type: Number,
        value: 0
      }
    };
  }
  static get observers() {
    return [
      "__updateAddButton(_addButton, maxFiles, __effectiveI18n, maxFilesReached, disabled)",
      "__updateDropLabel(_dropLabel, maxFiles, __effectiveI18n)",
      "__updateFileList(_fileList, files, __effectiveI18n, disabled, _theme)",
      "__updateMaxFilesReached(maxFiles, files)"
    ];
  }
  /**
   * The object used to localize this component. To change the default
   * localization, replace this with an object that provides all properties, or
   * just the individual properties you want to change.
   *
   * The object has the following JSON structure and default values:
   *
   * ```js
   * {
   *   dropFiles: {
   *     one: 'Drop file here',
   *     many: 'Drop files here'
   *   },
   *   addFiles: {
   *     one: 'Upload File...',
   *     many: 'Upload Files...'
   *   },
   *   error: {
   *     tooManyFiles: 'Too Many Files.',
   *     fileIsTooBig: 'File is Too Big.',
   *     incorrectFileType: 'Incorrect File Type.'
   *   },
   *   uploading: {
   *     status: {
   *       connecting: 'Connecting...',
   *       stalled: 'Stalled',
   *       processing: 'Processing File...',
   *       held: 'Queued'
   *     },
   *     remainingTime: {
   *       prefix: 'remaining time: ',
   *       unknown: 'unknown remaining time'
   *     },
   *     error: {
   *       serverUnavailable: 'Upload failed, please try again later',
   *       unexpectedServerError: 'Upload failed due to server error',
   *       forbidden: 'Upload forbidden'
   *     }
   *   },
   *   file: {
   *     retry: 'Retry',
   *     start: 'Start',
   *     remove: 'Remove'
   *   },
   *   units: {
   *     size: ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
   *     sizeBase: 1000
   *   },
   *   formatSize: function(bytes) {
   *     // returns the size followed by the best suitable unit
   *   },
   *   formatTime: function(seconds, [secs, mins, hours]) {
   *     // returns a 'HH:MM:SS' string
   *   }
   * }
   * ```
   * @type {!UploadI18n}
   */
  get i18n() {
    return super.i18n;
  }
  set i18n(value) {
    super.i18n = value;
  }
  /** @private */
  get __acceptRegexp() {
    if (!this.accept) {
      return null;
    }
    const processedTokens = this.accept.split(",").map((token) => {
      let processedToken = token.trim();
      processedToken = processedToken.replace(/[+.]/gu, "\\$&");
      if (processedToken.startsWith("\\.")) {
        processedToken = `.*${processedToken}$`;
      }
      return processedToken.replace(/\/\*/gu, "/.*");
    });
    return new RegExp(`^(${processedTokens.join("|")})$`, "iu");
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("dragover", this._onDragover.bind(this));
    this.addEventListener("dragleave", this._onDragleave.bind(this));
    this.addEventListener("drop", this._onDrop.bind(this));
    this.addEventListener("file-retry", this._onFileRetry.bind(this));
    this.addEventListener("file-abort", this._onFileAbort.bind(this));
    this.addEventListener("file-start", this._onFileStart.bind(this));
    this.addEventListener("file-reject", this._onFileReject.bind(this));
    this.addEventListener("upload-start", this._onUploadStart.bind(this));
    this.addEventListener("upload-success", this._onUploadSuccess.bind(this));
    this.addEventListener("upload-error", this._onUploadError.bind(this));
    this._addButtonController = new AddButtonController(this);
    this.addController(this._addButtonController);
    this._dropLabelController = new DropLabelController(this);
    this.addController(this._dropLabelController);
    this.addController(
      new SlotController(this, "file-list", "vaadin-upload-file-list", {
        initializer: (list) => {
          this._fileList = list;
        }
      })
    );
    this.addController(new SlotController(this, "drop-label-icon", "vaadin-upload-icon"));
  }
  /** @private */
  _formatSize(bytes) {
    if (typeof this.__effectiveI18n.formatSize === "function") {
      return this.__effectiveI18n.formatSize(bytes);
    }
    const base2 = this.__effectiveI18n.units.sizeBase || 1e3;
    const unit = ~~(Math.log(bytes) / Math.log(base2));
    const dec = Math.max(0, Math.min(3, unit - 1));
    const size = parseFloat((bytes / base2 ** unit).toFixed(dec));
    return `${size} ${this.__effectiveI18n.units.size[unit]}`;
  }
  /** @private */
  _splitTimeByUnits(time) {
    const unitSizes = [60, 60, 24, Infinity];
    const timeValues = [0];
    for (let i = 0; i < unitSizes.length && time > 0; i++) {
      timeValues[i] = time % unitSizes[i];
      time = Math.floor(time / unitSizes[i]);
    }
    return timeValues;
  }
  /** @private */
  _formatTime(seconds, split) {
    if (typeof this.__effectiveI18n.formatTime === "function") {
      return this.__effectiveI18n.formatTime(seconds, split);
    }
    while (split.length < 3) {
      split.push(0);
    }
    return split.reverse().map((number) => {
      return (number < 10 ? "0" : "") + number;
    }).join(":");
  }
  /** @private */
  _formatFileProgress(file) {
    const remainingTime = file.loaded > 0 ? this.__effectiveI18n.uploading.remainingTime.prefix + file.remainingStr : this.__effectiveI18n.uploading.remainingTime.unknown;
    return `${file.totalStr}: ${file.progress}% (${remainingTime})`;
  }
  /** @private */
  __updateMaxFilesReached(maxFiles, files) {
    this._setMaxFilesReached(maxFiles >= 0 && files.length >= maxFiles);
  }
  /** @private */
  __updateAddButton(addButton, maxFiles, effectiveI18n, maxFilesReached, disabled) {
    if (addButton) {
      addButton.disabled = disabled || maxFilesReached;
      if (addButton === this._addButtonController.defaultNode) {
        addButton.textContent = this._i18nPlural(maxFiles, effectiveI18n.addFiles);
      }
    }
  }
  /** @private */
  __updateDropLabel(dropLabel, maxFiles, effectiveI18n) {
    if (dropLabel && dropLabel === this._dropLabelController.defaultNode) {
      dropLabel.textContent = this._i18nPlural(maxFiles, effectiveI18n.dropFiles);
    }
  }
  /** @private */
  __updateFileList(list, files, effectiveI18n, disabled) {
    if (list) {
      list.items = [...files];
      list.i18n = effectiveI18n;
      list.disabled = disabled;
      if (window.Vaadin && window.Vaadin.featureFlags && (window.Vaadin.featureFlags.modularUpload || window.Vaadin.featureFlags.aiComponents) && this._theme) {
        list.setAttribute("theme", this._theme);
      } else {
        list.removeAttribute("theme");
      }
    }
  }
  /** @private */
  _onDragover(event) {
    event.preventDefault();
    if (!this.nodrop && !this._dragover) {
      this._dragoverValid = !this.maxFilesReached && !this.disabled;
      this._dragover = true;
    }
    event.dataTransfer.dropEffect = !this._dragoverValid || this.nodrop ? "none" : "copy";
  }
  /** @private */
  _onDragleave(event) {
    event.preventDefault();
    if (this._dragover && !this.nodrop) {
      this._dragover = this._dragoverValid = false;
    }
  }
  /** @private */
  async _onDrop(event) {
    if (!this.nodrop && !this.disabled) {
      event.preventDefault();
      this._dragover = this._dragoverValid = false;
      const files = await getFilesFromDropEvent(event);
      this._addFiles(files);
    }
  }
  /** @private */
  _createXhr() {
    return new XMLHttpRequest();
  }
  /** @private */
  _configureXhr(xhr2, file = null, isRawUpload = false) {
    if (typeof this.headers === "string") {
      try {
        this.headers = JSON.parse(this.headers);
      } catch (_2) {
        this.headers = void 0;
      }
    }
    Object.entries(this.headers).forEach(([key2, value]) => {
      xhr2.setRequestHeader(key2, value);
    });
    if (isRawUpload && file) {
      xhr2.setRequestHeader("Content-Type", file.type || "application/octet-stream");
      xhr2.setRequestHeader("X-Filename", encodeURIComponent(file.name));
    }
    if (this.timeout) {
      xhr2.timeout = this.timeout;
    }
    xhr2.withCredentials = this.withCredentials;
  }
  /** @private */
  _setStatus(file, total, loaded, elapsed) {
    file.elapsed = elapsed;
    file.elapsedStr = this._formatTime(file.elapsed, this._splitTimeByUnits(file.elapsed));
    file.remaining = Math.ceil(elapsed * (total / loaded - 1));
    file.remainingStr = this._formatTime(file.remaining, this._splitTimeByUnits(file.remaining));
    file.speed = ~~(total / elapsed / 1024);
    file.totalStr = this._formatSize(total);
    file.loadedStr = this._formatSize(loaded);
    file.status = this._formatFileProgress(file);
  }
  /**
   * Triggers the upload of any files that are not completed
   *
   * @param {!UploadFile | !Array<!UploadFile>=} files - Files being uploaded. Defaults to all outstanding files
   */
  uploadFiles(files = this.files) {
    if (files && !Array.isArray(files)) {
      files = [files];
    }
    files.filter((file) => !file.complete).forEach((file) => this._queueFileUpload(file));
  }
  /** @private */
  _queueFileUpload(file) {
    if (file.uploading) {
      return;
    }
    file.held = true;
    file.uploading = file.indeterminate = true;
    file.complete = file.abort = file.error = false;
    file.status = this.__effectiveI18n.uploading.status.held;
    this._renderFileList();
    this._uploadQueue.push(file);
    this._processUploadQueue();
  }
  /**
   * Process the upload queue by starting uploads for queued files
   * if there is available capacity.
   *
   * @private
   */
  _processUploadQueue() {
    while (this._uploadQueue.length > 0 && this._activeUploads < this.maxConcurrentUploads) {
      const nextFile = this._uploadQueue.shift();
      if (nextFile) {
        this._uploadFile(nextFile);
      }
    }
  }
  /** @private */
  _uploadFile(file) {
    this._activeUploads += 1;
    const ini = Date.now();
    const xhr2 = file.xhr = this._createXhr();
    let stalledId, last;
    xhr2.upload.onprogress = (e) => {
      clearTimeout(stalledId);
      last = Date.now();
      const elapsed = (last - ini) / 1e3;
      const loaded = e.loaded, total = e.total, progress = ~~(loaded / total * 100);
      file.loaded = loaded;
      file.progress = progress;
      file.indeterminate = loaded <= 0 || loaded >= total;
      if (file.error) {
        file.indeterminate = file.status = void 0;
      } else if (!file.abort) {
        if (progress < 100) {
          this._setStatus(file, total, loaded, elapsed);
          stalledId = setTimeout(() => {
            file.status = this.__effectiveI18n.uploading.status.stalled;
            this._renderFileList();
          }, 2e3);
        } else {
          file.loadedStr = file.totalStr;
          file.status = this.__effectiveI18n.uploading.status.processing;
        }
      }
      this._renderFileList();
      this.dispatchEvent(new CustomEvent("upload-progress", { detail: { file, xhr: xhr2 } }));
    };
    xhr2.onabort = () => {
      this._activeUploads -= 1;
      this._processUploadQueue();
    };
    xhr2.onreadystatechange = () => {
      if (xhr2.readyState === 4) {
        clearTimeout(stalledId);
        file.indeterminate = file.uploading = false;
        this._activeUploads -= 1;
        this._processUploadQueue();
        if (file.abort) {
          return;
        }
        file.status = "";
        const evt2 = this.dispatchEvent(
          new CustomEvent("upload-response", {
            detail: { file, xhr: xhr2 },
            cancelable: true
          })
        );
        if (!evt2) {
          return;
        }
        if (xhr2.status === 0) {
          file.error = this.__effectiveI18n.uploading.error.serverUnavailable;
        } else if (xhr2.status >= 500) {
          file.error = this.__effectiveI18n.uploading.error.unexpectedServerError;
        } else if (xhr2.status === 413) {
          file.error = this.__effectiveI18n.uploading.error.fileTooLarge;
        } else if (xhr2.status >= 400) {
          file.error = this.__effectiveI18n.uploading.error.forbidden;
        }
        file.complete = !file.error;
        this.dispatchEvent(
          new CustomEvent(`upload-${file.error ? "error" : "success"}`, {
            detail: { file, xhr: xhr2 }
          })
        );
        this._renderFileList();
      }
    };
    const isRawUpload = this.uploadFormat === "raw";
    if (!file.uploadTarget) {
      file.uploadTarget = this.target || "";
    }
    if (!isRawUpload) {
      file.formDataName = this.formDataName;
    }
    const evt = this.dispatchEvent(
      new CustomEvent("upload-before", {
        detail: { file, xhr: xhr2 },
        cancelable: true
      })
    );
    if (!evt) {
      return;
    }
    let requestBody;
    if (isRawUpload) {
      requestBody = file;
    } else {
      const formData = new FormData();
      formData.append(file.formDataName, file, file.name);
      requestBody = formData;
    }
    xhr2.open(this.method, file.uploadTarget, true);
    this._configureXhr(xhr2, file, isRawUpload);
    file.held = false;
    file.status = this.__effectiveI18n.uploading.status.connecting;
    xhr2.upload.onloadstart = () => {
      this.dispatchEvent(
        new CustomEvent("upload-start", {
          detail: { file, xhr: xhr2 }
        })
      );
      this._renderFileList();
    };
    const eventDetail = {
      file,
      xhr: xhr2,
      uploadFormat: this.uploadFormat,
      requestBody
    };
    if (!isRawUpload) {
      eventDetail.formData = requestBody;
    }
    const uploadEvt = this.dispatchEvent(
      new CustomEvent("upload-request", {
        detail: eventDetail,
        cancelable: true
      })
    );
    if (uploadEvt) {
      xhr2.send(requestBody);
    }
  }
  /** @private */
  _retryFileUpload(file) {
    const evt = this.dispatchEvent(
      new CustomEvent("upload-retry", {
        detail: { file, xhr: file.xhr },
        cancelable: true
      })
    );
    if (evt) {
      this._queueFileUpload(file);
      this._updateFocus(this.files.indexOf(file));
    }
  }
  /** @private */
  _abortFileUpload(file) {
    const evt = this.dispatchEvent(
      new CustomEvent("upload-abort", {
        detail: { file, xhr: file.xhr },
        cancelable: true
      })
    );
    if (evt) {
      file.abort = true;
      if (file.xhr) {
        file.xhr.abort();
      }
      this._removeFile(file);
    }
  }
  /** @private */
  _renderFileList() {
    if (this._fileList && typeof this._fileList.requestContentUpdate === "function") {
      this._fileList.requestContentUpdate();
    }
  }
  /** @private */
  _addFiles(files) {
    Array.prototype.forEach.call(files, this._addFile.bind(this));
  }
  /**
   * Add the file for uploading. Called internally for each file after picking files from dialog or dropping files.
   *
   * @param {!UploadFile} file File being added
   * @protected
   */
  _addFile(file) {
    if (this.maxFilesReached) {
      this.dispatchEvent(
        new CustomEvent("file-reject", {
          detail: { file, error: this.__effectiveI18n.error.tooManyFiles }
        })
      );
      return;
    }
    if (this.maxFileSize >= 0 && file.size > this.maxFileSize) {
      this.dispatchEvent(
        new CustomEvent("file-reject", {
          detail: { file, error: this.__effectiveI18n.error.fileIsTooBig }
        })
      );
      return;
    }
    const re2 = this.__acceptRegexp;
    if (re2 && !(re2.test(file.type) || re2.test(file.name))) {
      this.dispatchEvent(
        new CustomEvent("file-reject", {
          detail: { file, error: this.__effectiveI18n.error.incorrectFileType }
        })
      );
      return;
    }
    file.loaded = 0;
    file.held = true;
    file.status = this.__effectiveI18n.uploading.status.held;
    this.files = [file, ...this.files];
    if (!this.noAuto) {
      this._queueFileUpload(file);
    }
  }
  /** @private */
  _updateFocus(fileIndex) {
    if (this.files.length === 0) {
      this._addButton.focus({ focusVisible: isKeyboardActive() });
      return;
    }
    const lastFileRemoved = fileIndex === this.files.length;
    if (lastFileRemoved) {
      fileIndex -= 1;
    }
    this._fileList.children[fileIndex].firstElementChild.focus({ focusVisible: isKeyboardActive() });
  }
  /**
   * Remove file from upload list. Called internally if file upload was canceled.
   * @param {!UploadFile} file File to remove
   * @protected
   */
  _removeFile(file) {
    this._uploadQueue = this._uploadQueue.filter((f) => f !== file);
    this._processUploadQueue();
    const fileIndex = this.files.indexOf(file);
    if (fileIndex >= 0) {
      this.files = this.files.filter((i) => i !== file);
      this.dispatchEvent(
        new CustomEvent("file-remove", {
          detail: { file },
          bubbles: true,
          composed: true
        })
      );
      this._updateFocus(fileIndex);
    }
  }
  /** @private */
  _onAddFilesTouchEnd(e) {
    e.preventDefault();
    this._onAddFilesClick(e);
  }
  /** @private */
  _onAddFilesClick(e) {
    if (this.maxFilesReached) {
      return;
    }
    e.stopPropagation();
    this.$.fileInput.value = "";
    this.$.fileInput.click();
  }
  /** @private */
  _onFileInputChange(event) {
    this._addFiles(event.target.files);
  }
  /** @private */
  _onFileStart(event) {
    this._queueFileUpload(event.detail.file);
  }
  /** @private */
  _onFileRetry(event) {
    this._retryFileUpload(event.detail.file);
  }
  /** @private */
  _onFileAbort(event) {
    this._abortFileUpload(event.detail.file);
  }
  /** @private */
  _onFileReject(event) {
    announce(`${event.detail.file.name}: ${event.detail.error}`, { mode: "alert" });
  }
  /** @private */
  _onUploadStart(event) {
    announce(`${event.detail.file.name}: 0%`, { mode: "alert" });
  }
  /** @private */
  _onUploadSuccess(event) {
    announce(`${event.detail.file.name}: 100%`, { mode: "alert" });
  }
  /** @private */
  _onUploadError(event) {
    announce(`${event.detail.file.name}: ${event.detail.file.error}`, { mode: "alert" });
  }
  /** @private */
  _dragoverChanged(dragover) {
    if (dragover) {
      this.setAttribute("dragover", dragover);
    } else {
      this.removeAttribute("dragover");
    }
  }
  /** @private */
  _dragoverValidChanged(dragoverValid) {
    if (dragoverValid) {
      this.setAttribute("dragover-valid", dragoverValid);
    } else {
      this.removeAttribute("dragover-valid");
    }
  }
  /** @private */
  _i18nPlural(value, plural) {
    return value === 1 ? plural.one : plural.many;
  }
  /** @protected */
  _isMultiple(maxFiles) {
    return maxFiles !== 1;
  }
};
/**
 * @license
 * Copyright (c) 2016 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Upload extends UploadMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-upload";
  }
  static get styles() {
    return uploadStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  /** @protected */
  render() {
    return html`
      <div part="primary-buttons">
        <slot name="add-button"></slot>
        <div part="drop-label" ?hidden="${this.nodrop}" id="dropLabelContainer" aria-hidden="true">
          <slot name="drop-label-icon"></slot>
          <slot name="drop-label"></slot>
        </div>
      </div>
      <slot name="file-list"></slot>
      <slot></slot>
      <input
        type="file"
        id="fileInput"
        hidden
        @change="${this._onFileInputChange}"
        accept="${this.accept}"
        ?multiple="${this._isMultiple(this.maxFiles)}"
        capture="${ifDefined(this.capture)}"
      />
    `;
  }
  /**
   * Fired when a file cannot be added to the queue due to a constrain:
   *  file-size, file-type or maxFiles
   *
   * @event file-reject
   * @param {Object} detail
   * @param {Object} detail.file the file added
   * @param {string} detail.error the cause
   */
  /**
   * Fired before the XHR is opened. Could be used for changing the request
   * URL. If the default is prevented, then XHR would not be opened.
   *
   * @event upload-before
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded
   * @param {Object} detail.file.uploadTarget the upload request URL, initialized with the value of vaadin-upload `target` property
   */
  /**
   * Fired when the XHR has been opened but not sent yet. Useful for appending
   * data keys to the FormData object, for changing some parameters like
   * headers, etc. If the event is defaultPrevented, `vaadin-upload` will not
   * send the request allowing the user to do something on his own.
   *
   * @event upload-request
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded
   * @param {Object} detail.formData the FormData object
   */
  /**
   * Fired when the XHR is sent.
   *
   * @event upload-start
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded
   */
  /**
   * Fired as many times as the progress is updated.
   *
   * @event upload-progress
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded with loaded info
   */
  /**
   * Fired when we have the actual server response, and before the component
   * analyses it. It's useful for developers to make the upload fail depending
   * on the server response. If the event is defaultPrevented the vaadin-upload
   * will return allowing the user to do something on his own like retry the
   * upload, etc. since he has full access to the `xhr` and `file` objects.
   * Otherwise, if the event is not prevented default `vaadin-upload` continues
   * with the normal workflow checking the `xhr.status` and `file.error`
   * which also might be modified by the user to force a customized response.
   *
   * @event upload-response
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded
   */
  /**
   * Fired in case the upload process succeed.
   *
   * @event upload-success
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded with loaded info
   */
  /**
   * Fired in case the upload process failed.
   *
   * @event upload-error
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded
   */
  /**
   * Fired when retry upload is requested. If the default is prevented, then
   * retry would not be performed.
   *
   * @event upload-retry
   * @param {Object} detail
   * @param {Object} detail.xhr the previous upload xhr
   * @param {Object} detail.file the file being uploaded
   */
  /**
   * Fired when retry abort is requested. If the default is prevented, then the
   * file upload would not be aborted.
   *
   * @event upload-abort
   * @param {Object} detail
   * @param {Object} detail.xhr the xhr
   * @param {Object} detail.file the file being uploaded
   */
}
defineCustomElement(Upload);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const uploadButton = css$h``;
const uploadButtonStyles = [buttonStyles, uploadButton];
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UploadButton extends ButtonMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
  static get is() {
    return "vaadin-upload-button";
  }
  static get styles() {
    return uploadButtonStyles;
  }
  static get properties() {
    return {
      /**
       * Reference to an UploadManager.
       * When set, the button will automatically disable when maxFilesReached
       * becomes true on the manager.
       * @type {Object | null}
       */
      manager: {
        type: Object,
        value: null,
        observer: "__managerChanged"
      },
      /**
       * Capture attribute for mobile file input.
       */
      capture: {
        type: String
      },
      /**
       * True when max files has been reached on the manager.
       */
      maxFilesReached: {
        type: Boolean,
        value: false,
        reflect: true,
        attribute: "max-files-reached"
      }
    };
  }
  constructor() {
    super();
    this.__syncFromManager = this.__syncFromManager.bind(this);
    this.__explicitDisabled = false;
  }
  /**
   * Whether the button is disabled.
   * Returns true if either explicitly disabled, manager is disabled, or maxFilesReached is true.
   * @type {boolean}
   * @override
   */
  get disabled() {
    return super.disabled;
  }
  set disabled(value) {
    this.__explicitDisabled = Boolean(value);
    super.disabled = this.__effectiveDisabled;
  }
  /** @protected */
  render() {
    return html`
      <div class="vaadin-button-container">
        <span part="prefix" aria-hidden="true">
          <slot name="prefix"></slot>
        </span>
        <span part="label">
          <slot></slot>
        </span>
        <span part="suffix" aria-hidden="true">
          <slot name="suffix"></slot>
        </span>
      </div>
      <slot name="tooltip"></slot>
      <input id="fileInput" type="file" hidden @change=${this.__onFileInputChange} />
    `;
  }
  /** @protected */
  ready() {
    super.ready();
    this._tooltipController = new TooltipController(this);
    this.addController(this._tooltipController);
    this.addEventListener("click", () => {
      this.openFilePicker();
    });
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (this.manager instanceof UploadManager) {
      this.manager.removeEventListener("max-files-reached-changed", this.__syncFromManager);
      this.manager.removeEventListener("disabled-changed", this.__syncFromManager);
    }
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this.manager instanceof UploadManager) {
      this.manager.addEventListener("max-files-reached-changed", this.__syncFromManager);
      this.manager.addEventListener("disabled-changed", this.__syncFromManager);
    }
    this.__syncFromManager();
  }
  /**
   * Opens the file picker dialog.
   */
  openFilePicker() {
    if (this.disabled) {
      return;
    }
    this.__updateFileInputAttributes();
    this.$.fileInput.value = "";
    this.$.fileInput.click();
  }
  /** @private */
  __updateFileInputAttributes() {
    const { fileInput } = this.$;
    const accept = this.manager && this.manager.accept;
    if (accept) {
      fileInput.setAttribute("accept", accept);
    } else {
      fileInput.removeAttribute("accept");
    }
    const maxFiles = this.manager && this.manager.maxFiles != null ? this.manager.maxFiles : Infinity;
    fileInput.multiple = maxFiles !== 1;
    if (this.capture) {
      fileInput.setAttribute("capture", this.capture);
    } else {
      fileInput.removeAttribute("capture");
    }
  }
  /** @private */
  __onFileInputChange(event) {
    const files = event.target.files;
    if (this.manager instanceof UploadManager) {
      this.manager.addFiles(files);
    }
  }
  /** @private */
  __managerChanged(manager, oldManager) {
    if (oldManager instanceof UploadManager) {
      oldManager.removeEventListener("max-files-reached-changed", this.__syncFromManager);
      oldManager.removeEventListener("disabled-changed", this.__syncFromManager);
    }
    if (this.isConnected && manager instanceof UploadManager) {
      manager.addEventListener("max-files-reached-changed", this.__syncFromManager);
      manager.addEventListener("disabled-changed", this.__syncFromManager);
      this.__syncFromManager();
    } else if (this.isConnected) {
      this.__syncFromManager();
    }
  }
  /** @private */
  get __effectiveDisabled() {
    const noManager = !(this.manager instanceof UploadManager);
    const managerDisabled = !noManager && this.manager.disabled;
    return this.__explicitDisabled || noManager || managerDisabled || this.maxFilesReached;
  }
  /** @private */
  __syncFromManager() {
    if (this.manager instanceof UploadManager) {
      this.maxFilesReached = this.manager.maxFilesReached;
    } else {
      this.maxFilesReached = false;
    }
    super.disabled = this.__effectiveDisabled;
  }
  /** @override */
  __shouldAllowFocusWhenDisabled() {
    return window.Vaadin.featureFlags.accessibleDisabledButtons;
  }
}
defineCustomElement(UploadButton);
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const uploadDropZoneStyles = css$h`
  :host {
    display: block;
    position: relative;
  }

  :host([dragover])::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--vaadin-background-container);
    opacity: 0.7;
  }

  :host([hidden]) {
    display: none !important;
  }
`;
/**
 * @license
 * Copyright (c) 2000 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class UploadDropZone extends ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))) {
  static get is() {
    return "vaadin-upload-drop-zone";
  }
  static get styles() {
    return uploadDropZoneStyles;
  }
  static get lumoInjector() {
    return { ...super.lumoInjector, includeBaseStyles: true };
  }
  static get properties() {
    return {
      /**
       * Reference to an UploadManager.
       * When set, dropped files will be automatically added to the manager.
       * @type {Object | null}
       */
      manager: {
        type: Object,
        value: null,
        observer: "__managerChanged"
      },
      /**
       * Whether the drop zone is disabled.
       * Returns true if either explicitly disabled, manager is disabled, or no manager is set.
       */
      disabled: {
        type: Boolean,
        value: false
      },
      /**
       * True when max files has been reached on the manager.
       * @readonly
       */
      maxFilesReached: {
        type: Boolean,
        value: false,
        reflect: true,
        attribute: "max-files-reached"
      },
      /** @private */
      __dragover: {
        type: Boolean,
        value: false,
        reflect: true,
        attribute: "dragover"
      }
    };
  }
  /**
   * Whether the drop zone is disabled.
   * Returns true if either explicitly disabled, manager is disabled, or no manager is set.
   * @type {boolean}
   * @override
   */
  get disabled() {
    return this.__effectiveDisabled;
  }
  set disabled(value) {
    if (this.__syncingDisabled) return;
    this.__explicitDisabled = Boolean(value);
    this.__syncDisabledState();
  }
  constructor() {
    super();
    this.__explicitDisabled = false;
    this.__onMaxFilesReachedChanged = this.__onMaxFilesReachedChanged.bind(this);
    this.__syncDisabledState = this.__syncDisabledState.bind(this);
  }
  /** @protected */
  ready() {
    super.ready();
    this.addEventListener("dragover", this.__onDragover.bind(this));
    this.addEventListener("dragleave", this.__onDragleave.bind(this));
    this.addEventListener("drop", this.__onDrop.bind(this));
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    if (this.manager instanceof UploadManager) {
      this.manager.removeEventListener("max-files-reached-changed", this.__onMaxFilesReachedChanged);
      this.manager.removeEventListener("disabled-changed", this.__syncDisabledState);
    }
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    if (this.manager instanceof UploadManager) {
      this.manager.addEventListener("max-files-reached-changed", this.__onMaxFilesReachedChanged);
      this.manager.addEventListener("disabled-changed", this.__syncDisabledState);
      this.maxFilesReached = !!this.manager.maxFilesReached;
    }
    this.__syncDisabledState();
  }
  /** @protected */
  render() {
    return html`<slot></slot>`;
  }
  /** @private */
  get __effectiveDisabled() {
    const noManager = !(this.manager instanceof UploadManager);
    return this.__explicitDisabled || noManager || this.manager.disabled || this.maxFilesReached;
  }
  /** @private */
  __onDragover(event) {
    event.preventDefault();
    if (!this.__effectiveDisabled) {
      this.__dragover = true;
    }
    event.dataTransfer.dropEffect = this.__effectiveDisabled ? "none" : "copy";
  }
  /** @private */
  __onDragleave(event) {
    event.preventDefault();
    if (event.target !== this) {
      return;
    }
    this.__dragover = false;
  }
  /** @private */
  async __onDrop(event) {
    event.preventDefault();
    this.__dragover = false;
    if (!this.__effectiveDisabled) {
      const files = await getFilesFromDropEvent(event);
      this.manager.addFiles(files);
    }
  }
  /** @private */
  __managerChanged(manager, oldManager) {
    if (oldManager instanceof UploadManager) {
      oldManager.removeEventListener("max-files-reached-changed", this.__onMaxFilesReachedChanged);
      oldManager.removeEventListener("disabled-changed", this.__syncDisabledState);
    }
    if (this.isConnected && manager instanceof UploadManager) {
      manager.addEventListener("max-files-reached-changed", this.__onMaxFilesReachedChanged);
      manager.addEventListener("disabled-changed", this.__syncDisabledState);
      this.maxFilesReached = !!manager.maxFilesReached;
    } else {
      this.maxFilesReached = false;
    }
    if (this.isConnected) {
      this.__syncDisabledState();
    }
  }
  /** @private */
  __onMaxFilesReachedChanged(event) {
    this.maxFilesReached = event.detail.value;
    this.__syncDisabledState();
  }
  /** @private */
  __syncDisabledState() {
    if (!this.isConnected) return;
    this.__syncingDisabled = true;
    this.toggleAttribute("disabled", this.__effectiveDisabled);
    this.__syncingDisabled = false;
  }
}
defineCustomElement(UploadDropZone);
class UploadManagerConnector extends HTMLElement {
  constructor() {
    super();
    this.manager = new UploadManager();
    this.uploading = false;
    this.manager.addEventListener("file-remove", (e) => {
      this.dispatchEvent(
        new CustomEvent("file-remove", {
          detail: { fileName: e.detail.file?.name },
          bubbles: false
        })
      );
    });
    this.manager.addEventListener("file-reject", (e) => {
      this.dispatchEvent(
        new CustomEvent("file-reject", {
          detail: {
            fileName: e.detail.file?.name,
            errorMessage: e.detail.error
          },
          bubbles: false
        })
      );
    });
    this.manager.addEventListener("upload-start", () => {
      this.uploading = true;
    });
    const checkAllFinished = () => {
      const isUploading = this.manager.files.some((file) => file.uploading);
      if (this.uploading && !isUploading) {
        this.dispatchEvent(new CustomEvent("all-finished", { bubbles: false }));
      }
      this.uploading = isUploading;
    };
    this.manager.addEventListener("upload-success", checkAllFinished);
    this.manager.addEventListener("upload-error", checkAllFinished);
    this.manager.addEventListener("upload-abort", checkAllFinished);
  }
  attributeChangedCallback(name, oldValue, newValue) {
    if (name === "target" && oldValue !== newValue) {
      this.manager.target = newValue;
    } else if (name === "disabled" && oldValue !== newValue) {
      this.manager.disabled = newValue !== null;
    }
  }
  static get observedAttributes() {
    return ["target", "disabled"];
  }
  set maxFiles(value) {
    this.manager.maxFiles = value;
  }
  set maxFileSize(value) {
    this.manager.maxFileSize = value;
  }
  set accept(value) {
    this.manager.accept = value;
  }
  set noAuto(value) {
    this.manager.noAuto = value;
  }
  set uploadFormat(value) {
    this.manager.uploadFormat = value;
  }
  clearFileList() {
    this.manager.files = [];
  }
}
customElements.define("vaadin-upload-manager-connector", UploadManagerConnector);
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const virtualListStyles = css$h`
  :host {
    /* Don't let these properties inherit */
    --vaadin-virtual-list-padding-block: 0px;
    --vaadin-virtual-list-padding-inline: 0px;
    --vaadin-virtual-list-overflow-indicator-top-opacity: 0;
    --vaadin-virtual-list-overflow-indicator-bottom-opacity: 0;
    display: block;
    height: 400px;
    overflow: auto;
    flex: 1;
    align-self: stretch;
    box-sizing: border-box;
    padding: 0;
    --_indicator-height: var(--vaadin-virtual-list-overflow-indicator-height, 1px);
  }

  :host([hidden]) {
    display: none !important;
  }

  :host(:not([grid])) #items > ::slotted(*) {
    inset-inline: var(--vaadin-virtual-list-padding-inline);
  }

  #items {
    position: relative;
  }

  :host::before,
  :host::after {
    content: '';
    display: block;
    opacity: 0;
    position: sticky;
    inset: 0;
    z-index: 9999;
    pointer-events: none;
    box-sizing: border-box;
    height: var(--_indicator-height);
    background: var(--vaadin-border-color-secondary);
  }

  :host::before {
    margin-bottom: calc(var(--vaadin-virtual-list-padding-block) - var(--_indicator-height));
  }

  :host::after {
    margin-top: calc(var(--vaadin-virtual-list-padding-block) - var(--_indicator-height));
  }

  :host([overflow~='top'])::before {
    opacity: var(--vaadin-virtual-list-overflow-indicator-top-opacity);
  }

  :host([overflow~='bottom'])::after {
    opacity: var(--vaadin-virtual-list-overflow-indicator-bottom-opacity);
  }

  :host([theme~='overflow-indicator-top'][overflow~='top']),
  :host([theme~='overflow-indicators'][overflow~='top']) {
    --vaadin-virtual-list-overflow-indicator-top-opacity: 1;
  }

  :host([theme~='overflow-indicators'][overflow~='bottom']),
  :host([theme~='overflow-indicator-bottom'][overflow~='bottom']) {
    --vaadin-virtual-list-overflow-indicator-bottom-opacity: 1;
  }
`;
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const VirtualListMixin = (superClass) => class VirtualListMixinClass extends superClass {
  static get properties() {
    return {
      /**
       * An array containing items determining how many instances to render.
       * @type {Array<!VirtualListItem> | undefined}
       */
      items: { type: Array, sync: true },
      /**
       * Custom function for rendering the content of every item.
       * Receives three arguments:
       *
       * - `root` The render target element representing one item at a time.
       * - `virtualList` The reference to the `<vaadin-virtual-list>` element.
       * - `model` The object with the properties related with the rendered
       *   item, contains:
       *   - `model.index` The index of the rendered item.
       *   - `model.item` The item.
       * @type {VirtualListRenderer | undefined}
       */
      renderer: { type: Function, sync: true },
      /**
       * A function that generates accessible names for virtual list items.
       * The function gets the item as an argument and the
       * return value should be a string representing that item. The
       * result gets applied to the corresponding virtual list child element
       * as an `aria-label` attribute.
       */
      itemAccessibleNameGenerator: {
        type: Function,
        sync: true
      },
      /** @private */
      __virtualizer: Object
    };
  }
  static get observers() {
    return ["__itemsOrRendererChanged(items, renderer, __virtualizer, itemAccessibleNameGenerator)"];
  }
  /**
   * Gets the index of the first visible item in the viewport.
   *
   * @return {number}
   */
  get firstVisibleIndex() {
    return this.__virtualizer.firstVisibleIndex;
  }
  /**
   * Gets the index of the last visible item in the viewport.
   *
   * @return {number}
   */
  get lastVisibleIndex() {
    return this.__virtualizer.lastVisibleIndex;
  }
  constructor() {
    super();
    this.__onDocumentDragStart = this.__onDocumentDragStart.bind(this);
  }
  /** @protected */
  ready() {
    super.ready();
    this.__virtualizer = new Virtualizer({
      createElements: this.__createElements,
      updateElement: this.__updateElement.bind(this),
      elementsContainer: this,
      scrollTarget: this,
      scrollContainer: this.shadowRoot.querySelector("#items"),
      reorderElements: true
    });
    this.__overflowController = new OverflowController(this);
    this.addController(this.__overflowController);
    this.__updateAria();
  }
  /** @protected */
  connectedCallback() {
    super.connectedCallback();
    document.addEventListener("dragstart", this.__onDocumentDragStart, { capture: true });
    this.__virtualizer.hostConnected();
  }
  /** @protected */
  disconnectedCallback() {
    super.disconnectedCallback();
    document.removeEventListener("dragstart", this.__onDocumentDragStart, { capture: true });
  }
  /**
   * Scroll to a specific index in the virtual list.
   *
   * @param {number} index Index to scroll to
   */
  scrollToIndex(index) {
    this.__virtualizer.scrollToIndex(index);
  }
  /** @private */
  __createElements(count) {
    return [...Array(count)].map(() => document.createElement("div"));
  }
  /** @private */
  __updateAria() {
    this.role = "list";
  }
  /** @private */
  __updateElement(el, index) {
    const item = this.items[index];
    el.ariaSetSize = String(this.items.length);
    el.ariaPosInSet = String(index + 1);
    el.ariaLabel = this.itemAccessibleNameGenerator ? this.itemAccessibleNameGenerator(item) : null;
    this.__updateElementRole(el);
    if (el.__renderer !== this.renderer) {
      el.__renderer = this.renderer;
      this.__clearRenderTargetContent(el);
    }
    if (this.renderer) {
      this.renderer(el, this, { item, index });
    }
  }
  /** @private */
  __updateElementRole(el) {
    el.role = "listitem";
  }
  /**
   * Clears the content of a render target.
   * @private
   */
  __clearRenderTargetContent(element) {
    element.innerHTML = "";
    delete element._$litPart$;
  }
  /** @private */
  __itemsOrRendererChanged(items, renderer, virtualizer) {
    const hasRenderedItems = this.childElementCount > 0;
    if ((renderer || hasRenderedItems) && virtualizer) {
      virtualizer.size = (items || []).length;
      virtualizer.update();
    }
  }
  /**
   * Webkit-based browsers have issues with generating drag images
   * for elements that have children with massive heights. Chromium
   * browsers crash, while Safari experiences significant performance
   * issues. To mitigate these issues, we hide the items container
   * when drag starts to remove it from the drag image.
   *
   * Virtual lists with fewer rows also have issues on Chromium and Safari
   * where the drag image is not properly clipped and may include
   * content outside the virtual list. Temporary inline styles are applied
   * to mitigate this issue.
   *
   * Related issues:
   * - https://github.com/vaadin/web-components/issues/7985
   * - https://issues.chromium.org/issues/383356871
   * - https://github.com/vaadin/web-components/issues/8386
   *
   * @private
   */
  __onDocumentDragStart(e) {
    if (e.target.contains(this)) {
      const elements = [e.target, this.$.items];
      const originalInlineStyles = elements.map((element) => element.style.cssText);
      if (this.scrollHeight > 2e4) {
        this.$.items.style.display = "none";
      }
      if (isChrome) {
        e.target.style.willChange = "transform";
      }
      if (isSafari$1) {
        this.$.items.style.maxHeight = "100%";
      }
      requestAnimationFrame(() => {
        elements.forEach((element, index) => {
          element.style.cssText = originalInlineStyles[index];
        });
      });
    }
  }
  /**
   * Requests an update for the content of the rows.
   * While performing the update, it invokes the renderer passed in the `renderer` property for each visible row.
   *
   * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
   */
  requestContentUpdate() {
    if (this.__virtualizer) {
      this.__virtualizer.update();
    }
  }
};
/**
 * @license
 * Copyright (c) 2021 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class VirtualList extends VirtualListMixin(ThemableMixin(ElementMixin(PolylitMixin(LitElement)))) {
  static get is() {
    return "vaadin-virtual-list";
  }
  static get styles() {
    return virtualListStyles;
  }
  /** @protected */
  render() {
    return html`
      <div id="items">
        <slot></slot>
      </div>
    `;
  }
}
defineCustomElement(VirtualList);
window.Vaadin.Flow.virtualListConnector = {
  initLazy: function(list) {
    if (list.$connector) {
      return;
    }
    const extraItemsBuffer = 20;
    let lastRequestedRange = [0, 0];
    list.$connector = {};
    list.$connector.placeholderItem = { __placeholder: true };
    list.itemAccessibleNameGenerator = (item) => item && item.accessibleName;
    const updateRequestedItem = function() {
      const visibleIndexes = [...list.children].filter((el) => "__virtualListIndex" in el).map((el) => el.__virtualListIndex);
      const firstNeededItem = Math.min(...visibleIndexes);
      const lastNeededItem = Math.max(...visibleIndexes);
      let first = Math.max(0, firstNeededItem - extraItemsBuffer);
      let last = Math.min(lastNeededItem + extraItemsBuffer, list.items.length);
      if (lastRequestedRange[0] != first || lastRequestedRange[1] != last) {
        lastRequestedRange = [first, last];
        const count = 1 + last - first;
        list.$server.setViewportRange(first, count);
      }
    };
    const scheduleUpdateRequest = function() {
      list.__requestDebounce = Debouncer.debounce(list.__requestDebounce, timeOut.after(50), updateRequestedItem);
    };
    requestAnimationFrame(() => updateRequestedItem);
    list.patchVirtualListRenderer = function() {
      if (!list.renderer || list.renderer.__virtualListConnectorPatched) {
        return;
      }
      const originalRenderer = list.renderer;
      const renderer = (root, list2, model) => {
        root.__virtualListIndex = model.index;
        if (model.item === void 0) {
          if (list2.$connector.placeholderElement) {
            if (!root.__hasComponentRendererPlaceholder) {
              root.innerHTML = "";
              delete root._$litPart$;
              root.appendChild(list2.$connector.placeholderElement.cloneNode(true));
              root.__hasComponentRendererPlaceholder = true;
            }
          } else {
            originalRenderer.call(list2, root, list2, {
              ...model,
              item: list2.$connector.placeholderItem
            });
          }
        } else {
          if (root.__hasComponentRendererPlaceholder) {
            root.innerHTML = "";
            root.__hasComponentRendererPlaceholder = false;
          }
          originalRenderer.call(list2, root, list2, model);
        }
        scheduleUpdateRequest();
      };
      renderer.__virtualListConnectorPatched = true;
      renderer.__rendererId = originalRenderer.__rendererId;
      list.renderer = renderer;
    };
    list._createPropertyObserver("renderer", "patchVirtualListRenderer", true);
    list.patchVirtualListRenderer();
    list.items = [];
    list.$connector.set = function(index, items) {
      list.items.splice(index, items.length, ...items);
      list.items = [...list.items];
    };
    list.$connector.clear = function(index, length) {
      const clearCount = Math.min(length, list.items.length - index);
      list.$connector.set(index, [...Array(clearCount)]);
    };
    list.$connector.updateData = function(items) {
      const updatedItemsMap = items.reduce((map, item) => {
        map[item.key] = item;
        return map;
      }, {});
      list.items = list.items.map((item) => {
        if (!item) {
          return item;
        }
        return updatedItemsMap[item.key] || item;
      });
    };
    list.$connector.updateSize = function(newSize) {
      const delta = newSize - list.items.length;
      if (delta > 0) {
        list.items = [...list.items, ...Array(delta)];
      } else if (delta < 0) {
        list.items = list.items.slice(0, newSize);
      }
    };
    list.$connector.setPlaceholderItem = function(placeholderItem = {}, appId) {
      placeholderItem.__placeholder = true;
      list.$connector.placeholderItem = placeholderItem;
      const nodeId = Object.entries(placeholderItem).find(([key2]) => key2.endsWith("_nodeid"));
      list.$connector.placeholderElement = nodeId ? Vaadin.Flow.clients[appId].getByNodeId(nodeId[1]) : null;
    };
  }
};
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
class Lumo extends HTMLElement {
  static get is() {
    return "vaadin-lumo-styles";
  }
}
defineCustomElement(Lumo);
/**
 * @license
 * Copyright (c) 2017 - 2026 Vaadin Ltd.
 * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
 */
const template = document.createElement("template");
template.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg"><defs>
<g id="lumo:align-center"><path d="M167 217c0-18 17-33 38-34H795c21 0 38 15 38 34 0 18-17 33-38 33H205C184 250 167 235 167 217z m83 191c0-18 13-33 29-33H721c16 0 29 15 29 33 0 18-13 33-29 34H279C263 442 250 427 250 408zM250 792c0-18 13-33 29-34H721c16 0 29 15 29 34s-13 33-29 33H279C263 825 250 810 250 792z m-83-192c0-18 17-33 38-33H795c21 0 38 15 38 33s-17 33-38 33H205C184 633 167 618 167 600z" fill-rule="evenodd" clip-rule="evenodd"></path></g>
<g id="lumo:align-left"><path d="M167 217c0-18 17-33 38-34H795c21 0 38 15 38 34 0 18-17 33-38 33H205C184 250 167 235 167 217z m0 191c0-18 13-33 28-33H638c16 0 29 15 29 33 0 18-13 33-29 34H195C179 442 167 427 167 408zM167 792c0-18 13-33 28-34H638c16 0 29 15 29 34s-13 33-29 33H195C179 825 167 810 167 792z m0-192c0-18 17-33 38-33H795c21 0 38 15 38 33s-17 33-38 33H205C184 633 167 618 167 600z" fill-rule="evenodd" clip-rule="evenodd"></path></g>
<g id="lumo:align-right"><path d="M167 217c0-18 17-33 38-34H795c21 0 38 15 38 34 0 18-17 33-38 33H205C184 250 167 235 167 217z m166 191c0-18 13-33 29-33H805c16 0 29 15 28 33 0 18-13 33-28 34H362C346 442 333 427 333 408zM333 792c0-18 13-33 29-34H805c16 0 29 15 28 34s-13 33-28 33H362C346 825 333 810 333 792z m-166-192c0-18 17-33 38-33H795c21 0 38 15 38 33s-17 33-38 33H205C184 633 167 618 167 600z" fill-rule="evenodd" clip-rule="evenodd"></path></g>
<g id="lumo:angle-down"><path d="M283 391c-18-16-46-15-63 4-16 18-15 46 3 63l244 224c17 15 43 15 60 0l250-229c18-16 20-45 3-63-16-18-45-20-63-4l-220 203-214-198z"></path></g>
<g id="lumo:angle-left"><path d="M601 710c16 18 15 46-3 63-18 16-46 15-63-4l-224-244c-15-17-15-43 0-59l229-250c16-18 45-20 63-4 18 16 20 45 3 63l-203 220 198 215z"></path></g>
<g id="lumo:angle-right"><path d="M399 275c-16-18-15-46 3-63 18-16 46-15 63 4l224 244c15 17 15 43 0 59l-229 250c-16 18-45 20-63 4-18-16-20-45-3-63l203-220-198-215z"></path></g>
<g id="lumo:angle-up"><path d="M283 635c-18 16-46 15-63-3-16-18-15-46 3-63l244-224c17-15 43-15 60 0l250 229c18 16 20 45 3 63-16 18-45 20-63 3l-220-202L283 635z"></path></g>
<g id="lumo:arrow-down"><path d="M538 646l125-112c15-14 39-12 53 4 14 15 12 39-4 53l-187 166c0 0 0 0 0 0-14 13-36 12-50 0l-187-166c-15-14-17-37-4-53 14-15 37-17 53-4L462 646V312c0-21 17-38 38-37s38 17 37 37v334z"></path></g>
<g id="lumo:arrow-left"><path d="M375 538l111 125c14 15 12 39-3 53-15 14-39 12-53-4l-166-187c0 0 0 0 0 0-13-14-12-36 0-50l166-187c14-15 37-17 53-4 15 14 17 37 3 53L375 463h333c21 0 38 17 38 37 0 21-17 38-38 38h-333z"></path></g>
<g id="lumo:arrow-right"><path d="M625 538h-333c-21 0-38-17-38-38 0-21 17-38 38-37h333l-111-126c-14-15-12-39 3-53 15-14 39-12 53 4l166 187c13 14 13 36 0 50 0 0 0 0 0 0l-166 187c-14 15-37 17-53 4-15-14-17-37-3-53l111-125z"></path></g>
<g id="lumo:arrow-up"><path d="M538 354V688c0 21-17 38-38 37s-38-17-38-38V354l-125 112c-15 14-39 12-53-4-14-15-12-39 4-53l187-166c14-13 36-13 50 0 0 0 0 0 0 0l187 166c15 14 17 37 4 53-14 15-37 17-53 4L538 354z"></path></g>
<g id="lumo:bar-chart"><path d="M175 500h108c28 0 50 22 50 50v233c0 28-22 50-50 50H175c-28 0-50-22-50-50v-233c0-28 22-50 50-50z m33 67c-9 0-17 7-16 16v167c0 9 7 17 16 17h42c9 0 17-7 17-17v-167c0-9-7-17-17-16H208zM446 167h108c28 0 50 22 50 50v566c0 28-22 50-50 50h-108c-28 0-50-22-50-50V217c0-28 22-50 50-50z m33 66c-9 0-17 7-17 17v500c0 9 7 17 17 17h42c9 0 17-7 16-17V250c0-9-7-17-16-17h-42zM717 333h108c28 0 50 22 50 50v400c0 28-22 50-50 50h-108c-28 0-50-22-50-50V383c0-28 22-50 50-50z m33 67c-9 0-17 7-17 17v333c0 9 7 17 17 17h42c9 0 17-7 16-17v-333c0-9-7-17-16-17h-42z"></path></g>
<g id="lumo:bell"><path d="M367 675H292v-258C292 325 366 250 459 250H458V208c0-23 18-42 42-41 23 0 42 18 42 41v42h-1C634 250 708 325 708 417V675h-75v-258c0-51-41-92-91-92h-84C408 325 367 366 367 417V675z m-159 37c0-21 17-38 38-37h508c21 0 37 17 38 37 0 21-17 38-38 38H246C225 750 208 733 208 713z m230 71h125v32c0 17-14 31-32 31h-62c-17 0-32-14-31-31v-32z"></path></g>
<g id="lumo:calendar"><path d="M375 208h250v-20C625 176 634 167 646 167h41C699 167 708 176 708 188V208h74c23 0 41 19 41 42v42C823 315 804 333 782 333H218C196 333 177 315 177 292V250C177 227 196 208 218 208H292v-20C292 176 301 167 313 167h41C366 167 375 176 375 188V208zM229 375h42C283 375 292 384 292 396v41C292 449 282 458 271 458h-42C217 458 208 449 208 437v-41C208 384 218 375 229 375z m125 0h42C408 375 417 384 417 396v41C417 449 407 458 396 458h-42C342 458 333 449 333 437v-41C333 384 343 375 354 375z m125 0h42C533 375 542 384 542 396v41C542 449 532 458 521 458h-42C467 458 458 449 458 437v-41C458 384 468 375 479 375z m-250 125h42C283 500 292 509 292 521v41C292 574 282 583 271 583h-42C217 583 208 574 208 562v-41C208 509 218 500 229 500z m125 0h42C408 500 417 509 417 521v41C417 574 407 583 396 583h-42C342 583 333 574 333 562v-41C333 509 343 500 354 500z m125 0h42c12 0 21 9 21 21v41C542 574 532 583 521 583h-42C467 583 458 574 458 562v-41C458 509 468 500 479 500z m-250 125h42C283 625 292 634 292 646v41C292 699 282 708 271 708h-42C217 708 208 699 208 687v-41C208 634 218 625 229 625z m125 0h42C408 625 417 634 417 646v41C417 699 407 708 396 708h-42C342 708 333 699 333 687v-41C333 634 343 625 354 625z m125 0h42c12 0 21 9 21 21v41C542 699 532 708 521 708h-42C467 708 458 699 458 687v-41C458 634 468 625 479 625z m125-250h42C658 375 667 384 667 396v41C667 449 657 458 646 458h-42C592 458 583 449 583 437v-41C583 384 593 375 604 375z m0 125h42c12 0 21 9 21 21v41C667 574 657 583 646 583h-42C592 583 583 574 583 562v-41C583 509 593 500 604 500z m0 125h42c12 0 21 9 21 21v41C667 699 657 708 646 708h-42C592 708 583 699 583 687v-41C583 634 593 625 604 625z m125 0h42c12 0 21 9 21 21v41C792 699 782 708 771 708h-42C717 708 708 699 708 687v-41C708 634 718 625 729 625z m-500 125h42C283 750 292 759 292 771v41C292 824 282 833 271 833h-42C217 833 208 824 208 812v-41C208 759 218 750 229 750z m125 0h42C408 750 417 759 417 771v41C417 824 407 833 396 833h-42C342 833 333 824 333 812v-41C333 759 343 750 354 750z m125 0h42c12 0 21 9 21 21v41C542 824 532 833 521 833h-42C467 833 458 824 458 812v-41C458 759 468 750 479 750z m125 0h42c12 0 21 9 21 21v41C667 824 657 833 646 833h-42C592 833 583 824 583 812v-41C583 759 593 750 604 750z m125 0h42c12 0 21 9 21 21v41C792 824 782 833 771 833h-42C717 833 708 824 708 812v-41C708 759 718 750 729 750z m0-250h42c12 0 21 9 21 21v41C792 574 782 583 771 583h-42C717 583 708 574 708 562v-41C708 509 718 500 729 500z m0-125h42C783 375 792 384 792 396v41C792 449 782 458 771 458h-42C717 458 708 449 708 437v-41C708 384 718 375 729 375z"></path></g>
<g id="lumo:checkmark"><path d="M318 493c-15-15-38-15-53 0-15 15-15 38 0 53l136 136c15 15 38 15 53 0l323-322c15-15 15-38 0-53-15-15-38-15-54 0l-295 296-110-110z"></path></g>
<g id="lumo:chevron-down"><path d="M533 654l210-199c9-9 9-23 0-32C739 419 733 417 726 417H274C261 417 250 427 250 439c0 6 2 12 7 16l210 199c18 17 48 17 66 0z"></path></g>
<g id="lumo:chevron-left"><path d="M346 533l199 210c9 9 23 9 32 0 4-4 7-10 6-17V274C583 261 573 250 561 250c-6 0-12 2-16 7l-199 210c-17 18-17 48 0 66z"></path></g>
<g id="lumo:chevron-right"><path d="M654 533L455 743c-9 9-23 9-32 0C419 739 417 733 417 726V274C417 261 427 250 439 250c6 0 12 2 16 7l199 210c17 18 17 48 0 66z"></path></g>
<g id="lumo:chevron-up"><path d="M533 346l210 199c9 9 9 23 0 32-4 4-10 7-17 6H274C261 583 250 573 250 561c0-6 2-12 7-16l210-199c18-17 48-17 66 0z"></path></g>
<g id="lumo:clean"><path d="M250 208v8L368 333h99l-30 70 88 88L592 333H833V208H250M136 208L83 261l291 291L271 792h125l65-153L697 875 750 822 148 220 136 208Z"></path></g>
<g id="lumo:clock"><path d="M538 489l85 85c15 15 15 38 0 53-15 15-38 15-53 0l-93-93a38 38 0 0 1-2-2C467 525 462 515 462 504V308c0-21 17-38 38-37 21 0 38 17 37 37v181zM500 833c-184 0-333-149-333-333s149-333 333-333 333 149 333 333-149 333-333 333z m0-68c146 0 265-118 265-265 0-146-118-265-265-265-146 0-265 118-265 265 0 146 118 265 265 265z"></path></g>
<g id="lumo:cog"><path d="M833 458l-81-18c-8-25-17-50-29-75L767 292 708 233l-72 49c-21-12-46-25-75-30L542 167h-84l-19 79c-25 8-50 17-71 30L296 233 233 296l47 69c-12 21-21 46-29 71L167 458v84l84 25c8 25 17 50 29 75L233 708 292 767l76-44c21 12 46 25 75 29L458 833h84l19-81c25-8 50-17 75-29L708 767l59-59-44-66c12-21 25-46 29-75L833 542v-84z m-333 217c-96 0-175-79-175-175 0-96 79-175 175-175 96 0 175 79 175 175 0 96-79 175-175 175z"></path></g>
<g id="lumo:cross"><path d="M445 500l-142-141c-15-15-15-40 0-56 15-15 40-15 56 0L500 445l141-142c15-15 40-15 56 0 15 15 15 40 0 56L555 500l142 141c15 15 15 40 0 56-15 15-40 15-56 0L500 555l-141 142c-15 15-40 15-56 0-15-15-15-40 0-56L445 500z"></path></g>
<g id="lumo:download"><path d="M538 521l125-112c15-14 39-12 53 4 14 15 12 39-4 53l-187 166a38 38 0 0 1 0 0c-14 13-36 12-50 0l-187-166c-15-14-17-37-4-53 14-15 37-17 53-4L462 521V188c0-21 17-38 38-38s38 17 37 38v333zM758 704c0-21 17-38 38-37 21 0 38 17 37 37v92c0 21-17 38-37 37H204c-21 0-38-17-37-37v-92c0-21 17-38 37-37s38 17 38 37v54h516v-54z"></path></g>
<g id="lumo:drag-handle"><path d="M458 292c0 35-28 63-62 62C361 354 333 326 333 292s28-63 63-63c35 0 63 28 62 63Zm0 208c0 35-28 63-62 62-35 0-63-28-63-62s28-63 63-63c35 0 63 28 62 63Zm0 208c0 35-28 63-62 63-35 0-63-28-63-63s28-63 63-62c35 0 63 28 62 62Zm209-416c0 35-28 63-63 62S542 326 542 292s28-63 62-63S667 257 667 292Zm0 208c0 35-28 63-63 62S542 535 542 500s28-63 62-63 63 28 63 63Zm0 208c0 35-28 63-63 63S542 743 542 708s28-63 62-62 63 28 63 62Z"></path></g>
<g id="lumo:dropdown"><path d="M317 393c-15-14-39-13-53 3-14 15-13 39 3 53l206 189c14 13 36 13 50 0l210-193c15-14 17-38 3-53-14-15-38-17-53-3l-185 171L317 393z"></path></g>
<g id="lumo:edit"><path d="M673 281l62 56-205 233c-9 10-38 24-85 39a8 8 0 0 1-5 0c-4-1-7-6-6-10l0 0c14-47 25-76 35-86l204-232z m37-42l52-59c15-17 41-18 58-2 17 16 18 42 3 59L772 295l-62-56zM626 208l-67 75h-226C305 283 283 306 283 333v334C283 695 306 717 333 717h334c28 0 50-22 50-50v-185L792 398v269C792 736 736 792 667 792H333C264 792 208 736 208 667V333C208 264 264 208 333 208h293z"></path></g>
<g id="lumo:error"><path d="M500 833c-184 0-333-149-333-333s149-333 333-333 333 149 333 333-149 333-333 333z m0-68c146 0 265-118 265-265 0-146-118-265-265-265-146 0-265 118-265 265 0 146 118 265 265 265zM479 292h42c12 0 21 9 20 20l-11 217c0 8-6 13-13 13h-34c-7 0-13-6-13-13l-11-217C459 301 468 292 479 292zM483 608h34c12 0 21 9 20 21v33c0 12-9 21-20 21h-34c-12 0-21-9-21-21v-33c0-12 9-21 21-21z"></path></g>
<g id="lumo:eye"><path d="M500 750c-187 0-417-163-417-250s230-250 417-250 417 163 417 250-230 250-417 250z m-336-231c20 22 47 46 78 69C322 644 411 678 500 678s178-34 258-90c31-22 59-46 78-69 6-7 12-14 16-19-4-6-9-12-16-19-20-22-47-46-78-69C678 356 589 322 500 322s-178 34-258 90c-31 22-59 46-78 69-6 7-12 14-16 19 4 6 9 12 16 19zM500 646c-81 0-146-65-146-146s65-146 146-146 146 65 146 146-65 146-146 146z m0-75c39 0 71-32 71-71 0-39-32-71-71-71-39 0-71 32-71 71 0 39 32 71 71 71z"></path></g>
<g id="lumo:eye-disabled"><path d="M396 735l60-60c15 2 30 3 44 3 89 0 178-34 258-90 31-22 59-46 78-69 6-7 12-14 16-19-4-6-9-12-16-19-20-22-47-46-78-69-8-5-15-11-23-15l50-51C862 397 917 458 917 500c0 87-230 250-417 250-34 0-69-5-104-15zM215 654C138 603 83 542 83 500c0-87 230-250 417-250 34 0 69 5 104 15l-59 60c-15-2-30-3-45-3-89 0-178 34-258 90-31 22-59 46-78 69-6 7-12 14-16 19 4 6 9 12 16 19 20 22 47 46 78 69 8 5 16 11 24 16L215 654z m271-9l159-159c0 5 1 9 1 14 0 81-65 146-146 146-5 0-9 0-14-1z m-131-131C354 510 354 505 354 500c0-81 65-146 146-146 5 0 10 0 14 1l-159 159z m-167 257L780 179c12-12 32-12 44 0 12 12 12 32 0 44L232 815c-12 12-32 12-44 0s-12-32 0-44z"></path></g>
<g id="lumo:indent"><path d="M125 219a31 31 0 0 1 31-32h688a31 31 0 0 1 0 63H156A31 31 0 0 1 125 219z m40 134a31 31 0 0 1 45 0l125 125a31 31 0 0 1 0 44l-125 125A31 31 0 0 1 165 603L268 500 165 397a31 31 0 0 1 0-44zM438 406a31 31 0 0 1 31-31h375a31 31 0 0 1 0 63h-375a31 31 0 0 1-32-32z m-1 188a31 31 0 0 1 32-32h375a31 31 0 0 1 0 63h-375a31 31 0 0 1-32-31zM125 781a31 31 0 0 1 31-31h688a31 31 0 0 1 0 63H156a31 31 0 0 1-31-32z m0 0"></path></g>
<g id="lumo:link"><path d="M667 250h-125v79h125c94 0 171 76 170 171a171 171 0 0 1-170 171h-125V750h125a250 250 0 0 0 250-250c0-138-112-250-250-250M163 500c0-95 77-171 170-171h125V250H333a250 250 0 0 0-250 250 250 250 0 0 0 250 250h125v-79H333c-94 0-171-77-171-171M333 542h334v-84H333v84Z"></path></g>
<g id="lumo:menu"><path d="M167 292c0-23 19-42 41-42h584C815 250 833 268 833 292c0 23-19 42-41 41H208C185 333 167 315 167 292z m0 208c0-23 19-42 41-42h584C815 458 833 477 833 500c0 23-19 42-41 42H208C185 542 167 523 167 500z m0 208c0-23 19-42 41-41h584C815 667 833 685 833 708c0 23-19 42-41 42H208C185 750 167 732 167 708z"></path></g>
<g id="lumo:minus"><path d="M261 461c-22 0-39 18-39 39 0 22 18 39 39 39h478c22 0 39-18 39-39 0-22-18-39-39-39H261z"></path></g>
<g id="lumo:ordered-list"><path d="M138 333V198H136l-43 28v-38l45-31h45V333H138z m-61 128c0-35 27-59 68-59 39 0 66 21 66 53 0 20-11 37-43 64l-29 27v2h74V583H80v-30l55-52c26-24 32-33 33-43 0-13-10-22-24-22-15 0-26 10-26 25v1h-41v-1zM123 759v-31h21c15 0 25-8 25-21 0-13-10-21-25-21-15 0-26 9-26 23h-41c1-34 27-56 68-57 39 0 66 20 66 49 0 20-14 36-33 39v3c24 3 40 19 39 41 0 32-30 54-73 54-41 0-69-22-70-57h43c1 13 11 22 28 22 16 0 27-9 27-22 0-14-10-22-28-22h-21zM333 258c0-18 15-33 34-33h516c18 0 33 15 34 33 0 18-15 33-34 34H367c-18 0-33-15-34-34z m0 250c0-18 15-33 34-33h516c18 0 33 15 34 33s-15 33-34 34H367c-18 0-33-15-34-34z m0 250c0-18 15-33 34-33h516c18 0 33 15 34 33s-15 33-34 34H367c-18 0-33-15-34-34z"></path></g>
<g id="lumo:outdent"><path d="M125 219a31 31 0 0 1 31-32h688a31 31 0 0 1 0 63H156A31 31 0 0 1 125 219z m665 134A31 31 0 0 1 835 397L732 500l103 103a31 31 0 0 1-45 44l-125-125a31 31 0 0 1 0-44l125-125zM125 406A31 31 0 0 1 156 375h375a31 31 0 0 1 0 63h-375A31 31 0 0 1 125 406z m0 188a31 31 0 0 1 31-32h375a31 31 0 0 1 0 63h-375a31 31 0 0 1-31-31z m0 187a31 31 0 0 1 31-31h688a31 31 0 0 1 0 63H156a31 31 0 0 1-31-32z m0 0"></path></g>
<g id="lumo:phone"><path d="M296 208l42-37c17-15 44-13 58 4a42 42 0 0 1 5 7L459 282c12 20 5 45-15 57l-7 4c-17 10-25 30-19 48l20 66a420 420 0 0 0 93 157l41 45c13 14 35 17 51 8l7-5c20-12 45-5 57 16L745 777c12 20 5 45-15 57a42 42 0 0 1-8 4l-52 17c-61 21-129 4-174-43l-50-52c-81-85-141-189-175-302l-24-78c-19-62 0-129 49-172z"></path></g>
<g id="lumo:photo"><path d="M208 167h584c69 0 125 56 125 125v416c0 69-56 125-125 125H208c-69 0-125-56-125-125V292c0-69 56-125 125-125z m584 75H208c-28 0-50 22-50 50v416c0 28 22 50 50 50h584c28 0 50-22 50-50V292c0-28-22-50-50-50zM239 740l167-167c12-12 31-14 45-6l73 43 172-201c13-15 34-18 50-7l95 67v92l-111-78-169 199c-12 14-32 17-47 8l-76-43-111 111H229c2-7 5-13 10-18zM458 427C458 490 407 542 344 542S229 490 229 427c0-63 51-115 115-115S458 364 458 427z m-62 0C396 398 373 375 344 375S292 398 292 427c0 29 23 52 52 52s52-23 52-52z"></path></g>
<g id="lumo:play"><path d="M689 528l-298 175c-13 8-34 8-48 0-6-4-10-9-10-14V311C333 300 348 292 367 292c9 0 17 2 24 5l298 175c26 15 26 40 0 56z"></path></g>
<g id="lumo:plus"><path d="M461 461H261c-22 0-39 18-39 39 0 22 18 39 39 39h200v200c0 22 18 39 39 39 22 0 39-18 39-39v-200h200c22 0 39-18 39-39 0-22-18-39-39-39h-200V261c0-22-18-39-39-39-22 0-39 18-39 39v200z"></path></g>
<g id="lumo:redo"><path d="M290 614C312 523 393 458 491 458c55 0 106 22 144 57l-88 88c-3 3-5 7-5 11 0 8 6 15 15 15l193-5c17 0 31-15 31-32l5-192c0-4-1-8-4-11-6-6-16-6-22 0l-66 67C641 406 570 375 491 375c-136 0-248 90-281 215-1 2-1 5-1 8-8 44 45 68 73 32 4-5 7-11 8-16z"></path></g>
<g id="lumo:reload"><path d="M500 233V137c0-9 7-16 15-16 4 0 8 2 10 4l133 140c12 12 12 32 0 45l-133 140c-6 6-15 6-21 0C502 447 500 443 500 438V308c-117 0-212 95-212 213 0 117 95 212 212 212 117 0 212-95 212-212 0-21 17-38 38-38s38 17 37 38c0 159-129 288-287 287-159 0-288-129-288-287 0-159 129-288 288-288z"></path></g>
<g id="lumo:resize-handle"><path d="M772 311c12 12 12 32 0 44L355 772c-12 12-32 12-44 0s-12-32 0-44L728 311c12-12 32-12 44 0Zm0 188c12 12 12 32 0 44l-229 229c-12 12-32 12-44 0-12-12-12-32 0-44l229-229c12-12 32-12 44 0Zm0 187c12 12 12 32 0 44l-42 42c-12 12-32 12-44 0-12-12-12-32 0-44l42-42c12-12 32-12 44 0Z" fill-rule="evenodd" clip-rule="evenodd"></path></g>
<g id="lumo:search"><path d="M662 603l131 131c16 16 16 42 0 59-16 16-43 16-59 0l-131-131C562 691 512 708 458 708c-138 0-250-112-250-250 0-138 112-250 250-250 138 0 250 112 250 250 0 54-17 104-46 145zM458 646c104 0 188-84 188-188S562 271 458 271 271 355 271 458s84 188 187 188z"></path></g>
<g id="lumo:undo"><path d="M710 614C688 523 607 458 509 458c-55 0-106 22-144 57l88 88c3 3 5 7 5 11 0 8-6 15-15 15l-193-5c-17 0-31-15-31-32L214 400c0-4 1-8 4-11 6-6 16-6 22 0l66 67C359 406 430 375 509 375c136 0 248 90 281 215 1 2 1 5 1 8 8 44-45 68-73 32-4-5-7-11-8-16z"></path></g>
<g id="lumo:unordered-list"><path d="M146 325c-42 0-67-26-67-63 0-37 25-63 67-63 42 0 67 26 67 63 0 37-25 63-67 63z m0 250c-42 0-67-26-67-63 0-37 25-63 67-63 42 0 67 26 67 63 0 37-25 63-67 63z m0 250c-42 0-67-26-67-63 0-37 25-63 67-63 42 0 67 26 67 63 0 37-25 63-67 63zM333 258c0-18 15-33 34-33h516c18 0 33 15 34 33 0 18-15 33-34 34H367c-18 0-33-15-34-34z m0 250c0-18 15-33 34-33h516c18 0 33 15 34 33s-15 33-34 34H367c-18 0-33-15-34-34z m0 250c0-18 15-33 34-33h516c18 0 33 15 34 33s-15 33-34 34H367c-18 0-33-15-34-34z"></path></g>
<g id="lumo:upload"><path d="M538 279V612a38 38 0 0 1-76 0V279L337 391a38 38 0 1 1-49-57l187-166a38 38 0 0 1 50 0l187 166a38 38 0 1 1-49 57L538 279zM758 713a38 38 0 1 1 75-1v92a38 38 0 0 1-37 38H204a38 38 0 0 1-37-38v-92a38 38 0 1 1 75 1v54h516v-55z"></path></g>
<g id="lumo:user"><path d="M500 500c-69 0-125-56-125-125s56-125 125-125 125 56 125 125-56 125-125 125z m-292 292c0-115 131-208 292-209s292 93 292 209H208z"></path></g>
</defs></svg>`;
Iconset.register("lumo", 1e3, template);
const loadOnDemand = (key2) => {
  return Promise.resolve(0);
};
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};
window.Vaadin.Flow.loadOnDemand = loadOnDemand;
window.Vaadin.Flow.resetFocus = () => {
  let ae = document.activeElement;
  while (ae && ae.shadowRoot) ae = ae.shadowRoot.activeElement;
  return !ae || ae.blur() || ae.focus() || true;
};
