UNPKG

apexcharts

Version:

A JavaScript Chart Library

30,114 lines 1.09 MB
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a2, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a2, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a2, prop, b[prop]);
    }
  return a2;
};
var __spreadProps = (a2, b) => __defProps(a2, __getOwnPropDescs(b));
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __async = (__this, __arguments, generator) => {
  return new Promise((resolve, reject) => {
    var fulfilled = (value) => {
      try {
        step(generator.next(value));
      } catch (e2) {
        reject(e2);
      }
    };
    var rejected = (value) => {
      try {
        step(generator.throw(value));
      } catch (e2) {
        reject(e2);
      }
    };
    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
    step((generator = generator.apply(__this, __arguments)).next());
  });
};
/*!
 * ApexCharts v7.0.0
 * (c) 2018-2026 ApexCharts
 */
class Environment {
  /**
   * Check if running in server-side rendering environment (Node.js)
   * @returns {boolean} True if in SSR/Node.js, false if in browser
   */
  static isSSR() {
    return typeof window === "undefined" || typeof document === "undefined";
  }
  /**
   * Check if running in browser environment
   * @returns {boolean} True if in browser, false if in SSR/Node.js
   */
  static isBrowser() {
    return !this.isSSR();
  }
  /**
   * Check if a specific browser API is available
   * @param {string} api - Name of the API to check (e.g., 'ResizeObserver')
   * @returns {boolean} True if API is available
   */
  static hasAPI(api) {
    if (this.isSSR()) return false;
    return typeof /** @type {any} */
    window[api] !== "undefined";
  }
  /**
   * Returns the global Apex config object regardless of environment.
   * In browser: window.Apex; in SSR/Node.js: global.Apex; fallback: {}.
   * @returns {any}
   */
  static getApex() {
    if (typeof window !== "undefined" && window.Apex) return window.Apex;
    if (typeof global !== "undefined" && global.Apex) return global.Apex;
    return {};
  }
}
class SSRElement {
  /**
   * @param {string} nodeName
   * @param {any} namespaceURI
   */
  constructor(nodeName, namespaceURI = null) {
    this.nodeName = nodeName;
    this.namespaceURI = namespaceURI;
    this.attributes = /* @__PURE__ */ new Map();
    this.children = [];
    this.textContent = "";
    this.style = {};
    this.classList = new SSRClassList();
    this.parentNode = /** @type {SSRElement | null} */
    null;
    this._ssrWidth = void 0;
    this._ssrHeight = void 0;
    this._ssrMode = void 0;
  }
  /**
   * @param {string} name
   * @param {any} value
   */
  setAttribute(name2, value) {
    this.attributes.set(name2, value);
  }
  /**
   * @param {string} name
   */
  getAttribute(name2) {
    return this.attributes.get(name2);
  }
  /**
   * @param {string} name
   */
  removeAttribute(name2) {
    this.attributes.delete(name2);
  }
  /**
   * @param {string} name
   */
  hasAttribute(name2) {
    return this.attributes.has(name2);
  }
  /**
   * @param {any} child
   */
  appendChild(child) {
    if (child && child !== this) {
      if (child.parentNode && child.parentNode !== this) {
        child.parentNode.removeChild(child);
      } else if (child.parentNode === this) {
        const index = this.children.indexOf(child);
        if (index !== -1) this.children.splice(index, 1);
      }
      child.parentNode = this;
      this.children.push(child);
    }
    return child;
  }
  /**
   * @param {any} child
   */
  removeChild(child) {
    const index = this.children.indexOf(child);
    if (index !== -1) {
      this.children.splice(index, 1);
      child.parentNode = null;
    }
    return child;
  }
  /**
   * @param {any} newNode
   * @param {any} referenceNode
   */
  insertBefore(newNode, referenceNode) {
    if (!referenceNode) {
      return this.appendChild(newNode);
    }
    if (newNode.parentNode && newNode.parentNode !== this) {
      newNode.parentNode.removeChild(newNode);
    } else if (newNode.parentNode === this) {
      const existingIndex = this.children.indexOf(newNode);
      if (existingIndex !== -1) this.children.splice(existingIndex, 1);
    }
    const index = this.children.indexOf(referenceNode);
    if (index !== -1) {
      newNode.parentNode = this;
      this.children.splice(index, 0, newNode);
    }
    return newNode;
  }
  cloneNode(deep = false) {
    const clone = new SSRElement(this.nodeName, this.namespaceURI);
    clone.textContent = this.textContent;
    this.attributes.forEach((value, key) => {
      clone.attributes.set(key, value);
    });
    Object.assign(clone.style, this.style);
    if (deep) {
      this.children.forEach((child) => {
        if (child.cloneNode) {
          clone.appendChild(child.cloneNode(true));
        }
      });
    }
    return clone;
  }
  getBoundingClientRect() {
    return {
      width: this._ssrWidth || 0,
      height: this._ssrHeight || 0,
      top: 0,
      left: 0,
      right: this._ssrWidth || 0,
      bottom: this._ssrHeight || 0,
      x: 0,
      y: 0
    };
  }
  getRootNode() {
    let root = this;
    while (root.parentNode) {
      root = root.parentNode;
    }
    return root;
  }
  querySelector() {
    return null;
  }
  querySelectorAll() {
    return [];
  }
  getElementsByClassName() {
    return [];
  }
  addEventListener() {
  }
  removeEventListener() {
  }
  get childNodes() {
    return this.children;
  }
  toString() {
    let attrs = "";
    this.attributes.forEach((value, key) => {
      attrs += ` ${key}="${value}"`;
    });
    if (this.children.length === 0 && !this.textContent) {
      return `<${this.nodeName}${attrs}/>`;
    }
    const childrenStr = this.children.map((c2) => c2.toString()).join("");
    return `<${this.nodeName}${attrs}>${this.textContent}${childrenStr}</${this.nodeName}>`;
  }
  // Property getters/setters
  get innerHTML() {
    return this.children.map((c2) => c2.toString()).join("");
  }
  set innerHTML(value) {
    this.children = [];
    this.textContent = value;
  }
  get outerHTML() {
    return this.toString();
  }
  get isConnected() {
    return true;
  }
}
class SSRClassList {
  constructor() {
    this.classes = /* @__PURE__ */ new Set();
  }
  add(...classNames) {
    classNames.forEach((name2) => this.classes.add(name2));
  }
  remove(...classNames) {
    classNames.forEach((name2) => this.classes.delete(name2));
  }
  /**
   * @param {string} className
   */
  contains(className) {
    return this.classes.has(className);
  }
  /**
   * @param {string} className
   * @param {any} force
   */
  toggle(className, force) {
    if (force === true) {
      this.classes.add(className);
      return true;
    } else if (force === false) {
      this.classes.delete(className);
      return false;
    } else {
      if (this.classes.has(className)) {
        this.classes.delete(className);
        return false;
      } else {
        this.classes.add(className);
        return true;
      }
    }
  }
  toString() {
    return Array.from(this.classes).join(" ");
  }
}
class SSRDOMShim {
  constructor() {
    this.SVGNS = "http://www.w3.org/2000/svg";
    this.XLINKNS = "http://www.w3.org/1999/xlink";
  }
  /**
   * Create SVG element with namespace
   * @param {string} namespaceURI - Namespace URI
   * @param {string} qualifiedName - Element tag name
   * @returns {SSRElement} Mock SVG element
   */
  createElementNS(namespaceURI, qualifiedName) {
    return new SSRElement(qualifiedName, namespaceURI);
  }
  /**
   * Create text node
   * @param {string} data - Text content
   * @returns {object} Text node mock
   */
  createTextNode(data) {
    const node = {
      nodeName: "#text",
      nodeType: 3,
      textContent: data,
      toString() {
        return node.textContent;
      }
    };
    return node;
  }
  /**
   * Query selector (returns null in SSR)
   * @returns {null}
   */
  querySelector() {
    return null;
  }
  /**
   * Query selector all (returns empty array in SSR)
   * @returns {any[]}
   */
  querySelectorAll() {
    return [];
  }
  /**
   * Get computed style (returns empty object in SSR)
   * @returns {object}
   */
  getComputedStyle() {
    return {};
  }
  /**
   * Get bounding client rect for element
   * @param {SSRElement} element - Element to measure
   * @returns {object} Mock dimensions
   */
  getBoundingClientRect(element) {
    if (element && element.getBoundingClientRect) {
      return element.getBoundingClientRect();
    }
    return {
      width: 0,
      height: 0,
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      x: 0,
      y: 0
    };
  }
  /**
   * Create mock XMLSerializer for SSR
   * @returns {object} XMLSerializer mock
   */
  createXMLSerializer() {
    return {
      /**
       * @param {Element} element
       */
      serializeToString(element) {
        return element.toString ? element.toString() : "";
      }
    };
  }
  /**
   * Create mock DOMParser for SSR
   * @returns {object} DOMParser mock
   */
  createDOMParser() {
    return {
      /**
       * @param {string} str
       * @param {string} _type
       */
      parseFromString(str, _type) {
        const root = new SSRElement("root");
        root.innerHTML = str;
        return {
          documentElement: root
        };
      }
    };
  }
}
let shim = null;
let xmlSerializerInstance = null;
let domParserInstance = null;
class BrowserAPIs {
  /**
   * Initialize the SSR shim if in SSR environment
   * Must be called before using other methods
   */
  static init() {
    if (Environment.isSSR() && !shim) {
      shim = new SSRDOMShim();
    }
  }
  /**
   * Create an HTML element
   * @param {string} tagName - Element tag name
   * @returns {HTMLElement} HTML element
   */
  static createElement(tagName) {
    if (Environment.isSSR()) {
      if (!shim) this.init();
      return shim.createElementNS(null, tagName);
    }
    return document.createElement(tagName);
  }
  /**
   * Create an SVG element with namespace
   * @param {string} namespaceURI - Namespace URI
   * @param {string} qualifiedName - Element tag name
   * @returns {HTMLElement} created element
   */
  static createElementNS(namespaceURI, qualifiedName) {
    if (Environment.isSSR()) {
      if (!shim) this.init();
      return shim.createElementNS(namespaceURI, qualifiedName);
    }
    return (
      /** @type {HTMLElement} */
      document.createElementNS(namespaceURI, qualifiedName)
    );
  }
  /**
   * Create a text node
   * @param {string} data - Text content
   * @returns {Text|object} Text node
   */
  static createTextNode(data) {
    if (Environment.isSSR()) {
      if (!shim) this.init();
      return shim.createTextNode(data);
    }
    return document.createTextNode(data);
  }
  /**
   * Query selector
   * @param {string} selector - CSS selector
   * @returns {Element|null}
   */
  static querySelector(selector) {
    if (Environment.isSSR()) {
      return null;
    }
    return document.querySelector(selector);
  }
  /**
   * Query selector all
   * @param {string} selector - CSS selector
   * @returns {NodeList|any[]}
   */
  static querySelectorAll(selector) {
    if (Environment.isSSR()) {
      return [];
    }
    return document.querySelectorAll(selector);
  }
  /**
   * Get computed style for an element
   * @param {Element} element - Element to get styles for
   * @returns {CSSStyleDeclaration|object}
   */
  static getComputedStyle(element) {
    if (Environment.isSSR()) {
      return {};
    }
    return window.getComputedStyle(element);
  }
  /**
   * Evaluate a media query. Returns the live MediaQueryList in a browser (so
   * callers can attach a `change` listener) or null under SSR / when
   * unsupported. Facet (#13) uses this for `theme.follow: 'os'`.
   * @param {string} query
   * @returns {MediaQueryList|null}
   */
  static matchMedia(query) {
    if (Environment.isSSR() || typeof window.matchMedia !== "function") {
      return null;
    }
    try {
      return window.matchMedia(query);
    } catch (e2) {
      return null;
    }
  }
  /**
   * Get bounding client rect for an element
   * @param {Element} element - Element to measure
   * @returns {DOMRect|object}
   */
  static getBoundingClientRect(element) {
    if (Environment.isSSR()) {
      if (!shim) this.init();
      return shim.getBoundingClientRect(element);
    }
    return element ? element.getBoundingClientRect() : {
      width: 0,
      height: 0,
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      x: 0,
      y: 0
    };
  }
  /**
   * Get XMLSerializer instance
   * @returns {XMLSerializer|object}
   */
  static getXMLSerializer() {
    if (Environment.isSSR()) {
      if (!shim) this.init();
      if (!xmlSerializerInstance) {
        xmlSerializerInstance = shim.createXMLSerializer();
      }
      return xmlSerializerInstance;
    }
    if (!xmlSerializerInstance) {
      xmlSerializerInstance = new XMLSerializer();
    }
    return xmlSerializerInstance;
  }
  /**
   * Get DOMParser instance
   * @returns {DOMParser|object}
   */
  static getDOMParser() {
    if (Environment.isSSR()) {
      if (!shim) this.init();
      if (!domParserInstance) {
        domParserInstance = shim.createDOMParser();
      }
      return domParserInstance;
    }
    if (!domParserInstance) {
      domParserInstance = new DOMParser();
    }
    return domParserInstance;
  }
  /**
   * Add event listener to window
   * @param {string} event - Event name
   * @param {EventListenerOrEventListenerObject} handler - Event handler
   * @param {object} options - Event options
   */
  static addWindowEventListener(event, handler, options2) {
    if (Environment.isBrowser()) {
      window.addEventListener(event, handler, options2);
    }
  }
  /**
   * Remove event listener from window
   * @param {string} event - Event name
   * @param {EventListenerOrEventListenerObject} handler - Event handler
   * @param {object} options - Event options
   */
  static removeWindowEventListener(event, handler, options2) {
    if (Environment.isBrowser()) {
      window.removeEventListener(event, handler, options2);
    }
  }
  /**
   * Request animation frame
   * @param {FrameRequestCallback} callback - Callback function
   * @returns {number|null}
   */
  static requestAnimationFrame(callback) {
    if (Environment.isBrowser()) {
      return window.requestAnimationFrame(callback);
    }
    callback(0);
    return null;
  }
  /**
   * Cancel animation frame
   * @param {number} id - Animation frame ID
   */
  static cancelAnimationFrame(id) {
    if (Environment.isBrowser() && id) {
      window.cancelAnimationFrame(id);
    }
  }
  /**
   * Check if element exists
   * @param {Element} element - Element to check
   * @returns {boolean}
   */
  static elementExists(element) {
    if (!element) return false;
    if (Environment.isSSR()) {
      return element._ssrMode === true || element.nodeName !== void 0;
    }
    return element.getRootNode ? element.getRootNode({ composed: true }) === document || element.isConnected : false;
  }
  /**
   * Get window object (or null in SSR)
   * @returns {Window|null}
   */
  static getWindow() {
    return Environment.isBrowser() ? window : null;
  }
  /**
   * Get document object (or null in SSR)
   * @returns {Document|null}
   */
  static getDocument() {
    return Environment.isBrowser() ? document : null;
  }
  /**
   * Get the shim instance (for testing purposes)
   * @returns {SSRDOMShim|null}
   */
  static _getShim() {
    return shim;
  }
  /**
   * Reset the shim instance (for testing purposes)
   */
  static _resetShim() {
    shim = null;
    xmlSerializerInstance = null;
    domParserInstance = null;
  }
}
const fnIds = /* @__PURE__ */ new WeakMap();
let fnSeq = 0;
let Utils$1 = class Utils {
  /**
   * @param {*} item
   */
  static isObject(item) {
    return item && typeof item === "object" && !Array.isArray(item);
  }
  // Type checking that works across different window objects
  /**
   * @param {string} type
   * @param {string} val
   */
  static is(type, val) {
    return Object.prototype.toString.call(val) === "[object " + type + "]";
  }
  static isSafari() {
    return Environment.isBrowser() && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
  }
  // to extend defaults with user options
  // credit: http://stackoverflow.com/questions/27936772/deep-object-merging-in-es6-es7#answer-34749873
  /**
   * @param {any} target
   * @param {any} source
   */
  static extend(target, source) {
    if (!this.isObject(target) && this.isObject(source)) {
      return this.clone(source);
    }
    const output = Object.assign({}, target);
    if (this.isObject(target) && this.isObject(source)) {
      Object.keys(source).forEach((key) => {
        if (this.isObject(source[key])) {
          if (!(key in target)) {
            Object.assign(output, {
              [key]: source[key]
            });
          } else {
            output[key] = this.extend(target[key], source[key]);
          }
        } else {
          Object.assign(output, {
            [key]: source[key]
          });
        }
      });
    }
    return output;
  }
  /**
   * @param {any[]} arrToExtend
   * @param {any} resultArr
   */
  static extendArray(arrToExtend, resultArr) {
    const extendedArr = [];
    arrToExtend.map((item) => {
      extendedArr.push(Utils.extend(resultArr, item));
    });
    arrToExtend = extendedArr;
    return arrToExtend;
  }
  // If month counter exceeds 12, it starts again from 1
  /**
   * @param {number} month
   */
  static monthMod(month) {
    return month % 12;
  }
  /**
   * clone object with optional shallow copy for performance
   * @param {*} source - Source object to clone
   * @param {WeakMap<any, any>} visited - Circular reference tracker
   * @param {boolean} shallow - If true, performs shallow copy (default: false)
   * @returns {*} Cloned object
   */
  static clone(source, visited = /* @__PURE__ */ new WeakMap(), shallow = false) {
    if (source === null || typeof source !== "object") {
      return source;
    }
    if (visited.has(source)) {
      return visited.get(source);
    }
    let cloneResult;
    if (Array.isArray(source)) {
      if (shallow) {
        cloneResult = source.slice();
      } else {
        cloneResult = [];
        visited.set(source, cloneResult);
        for (let i2 = 0; i2 < source.length; i2++) {
          cloneResult[i2] = this.clone(source[i2], visited, false);
        }
      }
    } else if (source instanceof Date) {
      cloneResult = new Date(source.getTime());
    } else {
      if (shallow) {
        cloneResult = Object.assign({}, source);
      } else {
        cloneResult = {};
        visited.set(source, cloneResult);
        for (const prop in source) {
          if (Object.prototype.hasOwnProperty.call(source, prop)) {
            cloneResult[prop] = this.clone(
              /** @type {Record<string,any>} */
              source[prop],
              visited,
              false
            );
          }
        }
      }
    }
    return cloneResult;
  }
  /**
   * Shallow clone for performance when deep clone isn't needed
   * @param {*} source - Source to clone
   * @returns {*} Shallow cloned object
   */
  static shallowClone(source) {
    if (source === null || typeof source !== "object") {
      return source;
    }
    if (Array.isArray(source)) {
      return source.slice();
    }
    return Object.assign({}, source);
  }
  /**
   * Serialize options for an equality check, with functions included.
   *
   * `JSON.stringify` DROPS function values, so two configs differing only in a
   * callback stringify identically. The update path used that comparison to skip
   * redundant renders, which silently swallowed any update that changed only a
   * function: a new `plotOptions.unit.positions` (a whole layout), a new
   * `dataLabels.formatter`, a new custom tooltip.
   *
   * Functions are compared BY IDENTITY: the same function twice still compares
   * equal (so the skip keeps working), a different one does not. A caller who
   * passes a fresh closure on every update gets a render every time, which is
   * the safe direction to err in - the closure may capture new state.
   *
   * @param {any} options
   * @returns {string}
   */
  static stringifyForCompare(options2) {
    return JSON.stringify(options2, (_key, value) => {
      if (typeof value !== "function") return value;
      let id = fnIds.get(value);
      if (id === void 0) {
        id = ++fnSeq;
        fnIds.set(value, id);
      }
      return `__apx_fn_${id}`;
    });
  }
  /**
   * Fast shallow equality check for objects
   * @param {Object} obj1 - First object
   * @param {Object} obj2 - Second object
   * @returns {boolean} True if shallowly equal
   */
  static shallowEqual(obj1, obj2) {
    if (obj1 === obj2) return true;
    if (!obj1 || !obj2) return false;
    if (typeof obj1 !== "object" || typeof obj2 !== "object") {
      return obj1 === obj2;
    }
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);
    if (keys1.length !== keys2.length) return false;
    for (const key of keys1) {
      if (
        /** @type {Record<string,any>} */
        obj1[key] !== /** @type {Record<string,any>} */
        obj2[key]
      )
        return false;
    }
    return true;
  }
  /**
   * @param {number} x
   */
  static log10(x) {
    return Math.log(x) / Math.LN10;
  }
  /**
   * @param {number} x
   */
  static roundToBase10(x) {
    return Math.pow(10, Math.floor(Math.log10(x)));
  }
  /**
   * @param {number} x
   * @param {number} base
   */
  static roundToBase(x, base) {
    return Math.pow(base, Math.floor(Math.log(x) / Math.log(base)));
  }
  /**
   * @param {any} val
   */
  static parseNumber(val) {
    if (typeof val === "number" || val === null) return val;
    return parseFloat(val);
  }
  /**
   * @param {number} num
   */
  static stripNumber(num, precision = 2) {
    return Number.isInteger(num) ? num : parseFloat(num.toPrecision(precision));
  }
  static randomId() {
    return (Math.random() + 1).toString(36).substring(4);
  }
  /**
   * @param {number} num
   */
  static noExponents(num) {
    if (num.toString().includes("e")) {
      return Math.round(num);
    }
    return num;
  }
  /**
   * @param {any} element
   */
  static elementExists(element) {
    if (!element || !element.isConnected) {
      return false;
    }
    return true;
  }
  /**
   * @param {any} el
   */
  static getDimensions(el) {
    if (!el) return [0, 0];
    if (Environment.isSSR()) {
      return [el._ssrWidth || 400, el._ssrHeight || 300];
    }
    let computedStyle;
    try {
      computedStyle = getComputedStyle(el, null);
    } catch (e2) {
      return [el.clientWidth || 0, el.clientHeight || 0];
    }
    let elementWidth = el.clientWidth;
    let elementHeight = el.clientHeight;
    if (!elementWidth || !elementHeight) {
      const rect = el.getBoundingClientRect();
      elementWidth = elementWidth || rect.width;
      elementHeight = elementHeight || rect.height;
    }
    elementHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom);
    elementWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);
    return [elementWidth, elementHeight];
  }
  /**
   * @returns {any}
   * @param {any} element
   */
  static getBoundingClientRect(element) {
    if (!element) {
      return {
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        width: 0,
        height: 0,
        x: 0,
        y: 0
      };
    }
    if (Environment.isSSR()) {
      return BrowserAPIs.getBoundingClientRect(element);
    }
    const rect = element.getBoundingClientRect();
    return {
      top: rect.top,
      right: rect.right,
      bottom: rect.bottom,
      left: rect.left,
      width: element.clientWidth,
      height: element.clientHeight,
      x: rect.left,
      y: rect.top
    };
  }
  /**
   * @param {any[]} arr
   */
  static getLargestStringFromArr(arr) {
    return arr.reduce((a2, b) => {
      if (Array.isArray(b)) {
        b = b.reduce((aa, bb) => aa.length > bb.length ? aa : bb);
      }
      return a2.length > b.length ? a2 : b;
    }, 0);
  }
  // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-12342275
  static hexToRgba(hex = "#999999", opacity = 0.6) {
    if (hex.substring(0, 1) !== "#") {
      hex = "#999999";
    }
    const hexStr = hex.replace("#", "");
    const h2 = hexStr.match(new RegExp("(.{" + hexStr.length / 3 + "})", "g")) || [];
    for (let i2 = 0; i2 < h2.length; i2++) {
      h2[i2] = parseInt(h2[i2].length === 1 ? h2[i2] + h2[i2] : h2[i2], 16);
    }
    if (typeof opacity !== "undefined") h2.push(opacity);
    return "rgba(" + h2.join(",") + ")";
  }
  /**
   * @param {string} rgba
   */
  static getOpacityFromRGBA(rgba) {
    return parseFloat(rgba.replace(/^.*,(.+)\)/, "$1"));
  }
  /**
   * Parse a #RGB or #RRGGBB hex colour string into [r,g,b] in 0–255.
   * Returns null for invalid input. Used by getContrastRatio.
   * @param {string} hex
   * @returns {[number, number, number] | null}
   */
  static parseHex(hex) {
    if (typeof hex !== "string") return null;
    let h2 = hex.trim().replace("#", "");
    if (h2.length === 3) {
      h2 = h2.split("").map((c2) => c2 + c2).join("");
    }
    if (!/^[0-9a-fA-F]{6}$/.test(h2)) return null;
    return [
      parseInt(h2.slice(0, 2), 16),
      parseInt(h2.slice(2, 4), 16),
      parseInt(h2.slice(4, 6), 16)
    ];
  }
  /**
   * Relative luminance per WCAG 2.x (https://www.w3.org/TR/WCAG22/#dfn-relative-luminance).
   * @param {[number, number, number]} rgb 0–255 sRGB triplet
   * @returns {number} 0.0–1.0
   */
  static relativeLuminance([r2, g, b]) {
    const channel = (c2) => {
      const v = c2 / 255;
      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
    };
    return 0.2126 * channel(r2) + 0.7152 * channel(g) + 0.0722 * channel(b);
  }
  /**
   * WCAG contrast ratio between two hex colours. Returns 0 for invalid input.
   * Range: 1 (identical) … 21 (#000 vs #fff).
   * WCAG AA requires ≥ 4.5 for normal text and ≥ 3.0 for large text / UI components.
   * @param {string} hex1
   * @param {string} hex2
   * @returns {number}
   */
  static getContrastRatio(hex1, hex2) {
    const rgb1 = Utils.parseHex(hex1);
    const rgb2 = Utils.parseHex(hex2);
    if (!rgb1 || !rgb2) return 0;
    const l1 = Utils.relativeLuminance(rgb1);
    const l2 = Utils.relativeLuminance(rgb2);
    const lighter = Math.max(l1, l2);
    const darker = Math.min(l1, l2);
    return (lighter + 0.05) / (darker + 0.05);
  }
  /**
   * @param {any} rgb
   */
  static rgb2hex(rgb) {
    rgb = rgb.match(
      /^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i
    );
    return rgb && rgb.length === 4 ? "#" + ("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) + ("0" + parseInt(rgb[2], 10).toString(16)).slice(-2) + ("0" + parseInt(rgb[3], 10).toString(16)).slice(-2) : "";
  }
  /**
   * @param {number} percent
   * @param {string} color
   */
  shadeRGBColor(percent, color) {
    const f = color.split(","), t2 = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = parseInt(f[0].slice(4), 10), G = parseInt(f[1], 10), B = parseInt(f[2], 10);
    return "rgb(" + (Math.round((t2 - R) * p) + R) + "," + (Math.round((t2 - G) * p) + G) + "," + (Math.round((t2 - B) * p) + B) + ")";
  }
  /**
   * @param {number} percent
   * @param {string} color
   */
  shadeHexColor(percent, color) {
    const f = parseInt(color.slice(1), 16), t2 = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 255, B = f & 255;
    return "#" + (16777216 + (Math.round((t2 - R) * p) + R) * 65536 + (Math.round((t2 - G) * p) + G) * 256 + (Math.round((t2 - B) * p) + B)).toString(16).slice(1);
  }
  // beautiful color shading blending code
  // http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
  /**
   * @param {number} p
   * @param {string} color
   */
  shadeColor(p, color) {
    if (Utils.isColorHex(color)) {
      return this.shadeHexColor(p, color);
    } else {
      return this.shadeRGBColor(p, color);
    }
  }
  /**
   * @param {string} color
   */
  static isColorHex(color) {
    return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i.test(color);
  }
  /**
   * @param {string} color
   */
  static isCSSVariable(color) {
    if (typeof color !== "string") return false;
    const value = color.trim();
    return value.startsWith("var(") && value.endsWith(")");
  }
  /**
   * @param {string} color
   */
  static getThemeColor(color) {
    if (!Utils.isCSSVariable(color)) return color;
    if (Environment.isSSR()) return color;
    const tempElem = document.createElement("div");
    tempElem.style.cssText = "position:fixed; left: -9999px; visibility:hidden;";
    tempElem.style.color = color;
    document.body.appendChild(tempElem);
    let computedColor;
    try {
      computedColor = window.getComputedStyle(tempElem).color;
    } finally {
      if (tempElem.parentNode) {
        tempElem.parentNode.removeChild(tempElem);
      }
    }
    return computedColor;
  }
  /**
   * @param {string} color
   * @param {number} opacity
   */
  static applyOpacityToColor(color, opacity) {
    const value = Number(opacity);
    if (!Number.isFinite(value)) return color;
    if (value <= 0) return "transparent";
    if (value >= 1) return color;
    const percent = Math.round(value * 100);
    return `color-mix(in srgb, ${color} ${percent}%, transparent)`;
  }
  /**
   * @param {number} size
   * @param {number} dataPointsLen
   */
  static getPolygonPos(size, dataPointsLen) {
    const dotsArray = [];
    const angle = Math.PI * 2 / dataPointsLen;
    for (let i2 = 0; i2 < dataPointsLen; i2++) {
      const curPos = {};
      curPos.x = size * Math.sin(i2 * angle);
      curPos.y = -size * Math.cos(i2 * angle);
      dotsArray.push(curPos);
    }
    return dotsArray;
  }
  /**
   * @param {number} centerX
   * @param {number} centerY
   * @param {number} radius
   * @param {number} angleInDegrees
   */
  static polarToCartesian(centerX, centerY, radius, angleInDegrees) {
    const angleInRadians = (angleInDegrees - 90) * Math.PI / 180;
    return {
      x: centerX + radius * Math.cos(angleInRadians),
      y: centerY + radius * Math.sin(angleInRadians)
    };
  }
  /**
   * @param {string} str
   */
  static escapeString(str, escapeWith = "x") {
    let newStr = str.toString().slice();
    newStr = newStr.replace(/[` ~!@#$%^&*()|+=?;:'",.<>{}[\]\\/]/gi, escapeWith);
    return newStr;
  }
  /**
   * @param {number} val
   */
  static negToZero(val) {
    return val < 0 ? 0 : val;
  }
  /**
   * @param {any[]} arr
   * @param {number} old_index
   * @param {number} new_index
   */
  static moveIndexInArray(arr, old_index, new_index) {
    if (new_index >= arr.length) {
      let k = new_index - arr.length + 1;
      while (k--) {
        arr.push(void 0);
      }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr;
  }
  /**
   * @param {string} s
   */
  static extractNumber(s2) {
    return parseFloat(s2.replace(/[^\d.]*/g, ""));
  }
  /**
   * @param {any} el
   * @param {string} cls
   */
  static findAncestor(el, cls) {
    while ((el = el.parentElement) && !el.classList.contains(cls)) ;
    return el;
  }
  /**
   * @param {any} el
   * @param {Record<string, any>} styles
   */
  static setELstyles(el, styles) {
    for (const key in styles) {
      if (Object.prototype.hasOwnProperty.call(styles, key)) {
        el.style[key] = styles[key];
      }
    }
  }
  // prevents JS prevision errors when adding
  /**
   * @param {number} a
   * @param {number} b
   */
  static preciseAddition(a2, b) {
    const aDecimals = (String(a2).split(".")[1] || "").length;
    const bDecimals = (String(b).split(".")[1] || "").length;
    const factor = Math.pow(10, Math.max(aDecimals, bDecimals));
    return (Math.round(a2 * factor) + Math.round(b * factor)) / factor;
  }
  /**
   * @param {any} value
   */
  static isNumber(value) {
    return !isNaN(value) && parseFloat(String(Number(value))) === value && !isNaN(parseInt(value, 10));
  }
  /**
   * @param {number} n
   */
  static isFloat(n2) {
    return Number(n2) === n2 && n2 % 1 !== 0;
  }
  static isMsEdge() {
    if (Environment.isSSR()) return false;
    const ua = window.navigator.userAgent;
    const edge = ua.indexOf("Edge/");
    if (edge > 0) {
      return parseInt(ua.substring(edge + 5, ua.indexOf(".", edge)), 10);
    }
    return false;
  }
  //
  // Find the Greatest Common Divisor of two numbers
  //
  /**
   * @param {number} a
   * @param {number} b
   */
  static getGCD(a2, b, p = 7) {
    let factor = Math.pow(10, p - Math.floor(Math.log10(Math.max(a2, b))));
    if (factor > 1) {
      a2 = Math.round(Math.abs(a2) * factor);
      b = Math.round(Math.abs(b) * factor);
    } else {
      factor = 1;
    }
    while (b) {
      const t2 = b;
      b = a2 % b;
      a2 = t2;
    }
    return a2 / factor;
  }
  /**
   * @param {number} n
   */
  static getPrimeFactors(n2) {
    const factors = [];
    let divisor = 2;
    while (n2 >= 2) {
      if (n2 % divisor == 0) {
        factors.push(divisor);
        n2 = n2 / divisor;
      } else {
        divisor++;
      }
    }
    return factors;
  }
  /**
   * @param {number} a
   * @param {number} b
   */
  static mod(a2, b, p = 7) {
    const big = Math.pow(10, p - Math.floor(Math.log10(Math.max(a2, b))));
    a2 = Math.round(Math.abs(a2) * big);
    b = Math.round(Math.abs(b) * big);
    return a2 % b / big;
  }
};
class DateTime {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this.months31 = [1, 3, 5, 7, 8, 10, 12];
    this.months30 = [2, 4, 6, 9, 11];
    this.daysCntOfYear = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
  }
  /**
   * @param {any} date
   */
  isValidDate(date) {
    if (typeof date === "number") {
      return false;
    }
    return !isNaN(this.parseDate(date));
  }
  /**
   * @param {any} dateStr
   */
  getTimeStamp(dateStr) {
    if (isNaN(Date.parse(dateStr))) {
      return dateStr;
    }
    const utc = this.w.config.xaxis.labels.datetimeUTC;
    return !utc ? new Date(dateStr).getTime() : new Date(new Date(dateStr).toISOString().substr(0, 25)).getTime();
  }
  /**
   * @param {any} timestamp
   */
  getDate(timestamp) {
    const utc = this.w.config.xaxis.labels.datetimeUTC;
    return utc ? new Date(new Date(timestamp).toUTCString()) : new Date(timestamp);
  }
  /**
   * @param {string} dateStr
   */
  parseDate(dateStr) {
    const parsed = Date.parse(dateStr);
    if (!isNaN(parsed)) {
      return this.getTimeStamp(dateStr);
    }
    let output = Date.parse(dateStr.replace(/-/g, "/").replace(/[a-z]+/gi, " "));
    output = this.getTimeStamp(output);
    return output;
  }
  // This fixes the difference of x-axis labels between chrome/safari
  // Fixes #1726, #1544, #1485, #1255
  /**
   * @param {string} dateStr
   */
  parseDateWithTimezone(dateStr) {
    return Date.parse(dateStr.replace(/-/g, "/").replace(/[a-z]+/gi, " "));
  }
  // http://stackoverflow.com/questions/14638018/current-time-formatting-with-javascript#answer-14638191
  /**
   * @param {Date} date
   * @param {string} format
   */
  formatDate(date, format) {
    const locale = this.w.globals.locale;
    const utc = this.w.config.xaxis.labels.datetimeUTC;
    const MMMM = ["\0", ...locale.months];
    const MMM = ["", ...locale.shortMonths];
    const dddd = ["", ...locale.days];
    const ddd = ["", ...locale.shortDays];
    function ii(i2, len = 2) {
      let s3 = i2 + "";
      while (s3.length < len) s3 = "0" + s3;
      return s3;
    }
    const y = utc ? date.getUTCFullYear() : date.getFullYear();
    format = format.replace(/(^|[^\\])yyyy+/g, "$1" + y);
    format = format.replace(/(^|[^\\])yy/g, "$1" + y.toString().substr(2, 2));
    format = format.replace(/(^|[^\\])y/g, "$1" + y);
    const M = (utc ? date.getUTCMonth() : date.getMonth()) + 1;
    format = format.replace(/(^|[^\\])MMMM+/g, "$1" + MMMM[0]);
    format = format.replace(/(^|[^\\])MMM/g, "$1" + MMM[0]);
    format = format.replace(/(^|[^\\])MM/g, "$1" + ii(M));
    format = format.replace(/(^|[^\\])M/g, "$1" + M);
    const d = utc ? date.getUTCDate() : date.getDate();
    format = format.replace(/(^|[^\\])dddd+/g, "$1" + dddd[0]);
    format = format.replace(/(^|[^\\])ddd/g, "$1" + ddd[0]);
    format = format.replace(/(^|[^\\])dd/g, "$1" + ii(d));
    format = format.replace(/(^|[^\\])d/g, "$1" + d);
    const H = utc ? date.getUTCHours() : date.getHours();
    format = format.replace(/(^|[^\\])HH+/g, "$1" + ii(H));
    format = format.replace(/(^|[^\\])H/g, "$1" + H);
    const h2 = H > 12 ? H - 12 : H === 0 ? 12 : H;
    format = format.replace(/(^|[^\\])hh+/g, "$1" + ii(h2));
    format = format.replace(/(^|[^\\])h/g, "$1" + h2);
    const m = utc ? date.getUTCMinutes() : date.getMinutes();
    format = format.replace(/(^|[^\\])mm+/g, "$1" + ii(m));
    format = format.replace(/(^|[^\\])m/g, "$1" + m);
    const s2 = utc ? date.getUTCSeconds() : date.getSeconds();
    format = format.replace(/(^|[^\\])ss+/g, "$1" + ii(s2));
    format = format.replace(/(^|[^\\])s/g, "$1" + s2);
    let f = utc ? date.getUTCMilliseconds() : date.getMilliseconds();
    format = format.replace(/(^|[^\\])fff+/g, "$1" + ii(f, 3));
    f = Math.round(f / 10);
    format = format.replace(/(^|[^\\])ff/g, "$1" + ii(f));
    f = Math.round(f / 10);
    format = format.replace(/(^|[^\\])f/g, "$1" + f);
    const T = H < 12 ? "AM" : "PM";
    format = format.replace(/(^|[^\\])TT+/g, "$1" + T);
    format = format.replace(/(^|[^\\])T/g, "$1" + T.charAt(0));
    const t2 = T.toLowerCase();
    format = format.replace(/(^|[^\\])tt+/g, "$1" + t2);
    format = format.replace(/(^|[^\\])t/g, "$1" + t2.charAt(0));
    let tz = -date.getTimezoneOffset();
    let K = utc || !tz ? "Z" : tz > 0 ? "+" : "-";
    if (!utc) {
      tz = Math.abs(tz);
      const tzHrs = Math.floor(tz / 60);
      const tzMin = tz % 60;
      K += ii(tzHrs) + ":" + ii(tzMin);
    }
    format = format.replace(/(^|[^\\])K/g, "$1" + K);
    const day = (utc ? date.getUTCDay() : date.getDay()) + 1;
    format = format.replace(new RegExp(dddd[0], "g"), dddd[day]);
    format = format.replace(new RegExp(ddd[0], "g"), ddd[day]);
    format = format.replace(new RegExp(MMMM[0], "g"), MMMM[M]);
    format = format.replace(new RegExp(MMM[0], "g"), MMM[M]);
    format = format.replace(/\\(.)/g, "$1");
    return format;
  }
  /**
   * @param {number} minX
   * @param {number} maxX
   */
  getTimeUnitsfromTimestamp(minX, maxX) {
    const w = this.w;
    if (w.config.xaxis.min !== void 0) {
      minX = w.config.xaxis.min;
    }
    if (w.config.xaxis.max !== void 0) {
      maxX = w.config.xaxis.max;
    }
    const tsMin = this.getDate(minX);
    const tsMax = this.getDate(maxX);
    const minD = this.formatDate(tsMin, "yyyy MM dd HH mm ss fff").split(" ");
    const maxD = this.formatDate(tsMax, "yyyy MM dd HH mm ss fff").split(" ");
    return {
      minMillisecond: parseInt(minD[6], 10),
      maxMillisecond: parseInt(maxD[6], 10),
      minSecond: parseInt(minD[5], 10),
      maxSecond: parseInt(maxD[5], 10),
      minMinute: parseInt(minD[4], 10),
      maxMinute: parseInt(maxD[4], 10),
      minHour: parseInt(minD[3], 10),
      maxHour: parseInt(maxD[3], 10),
      minDate: parseInt(minD[2], 10),
      maxDate: parseInt(maxD[2], 10),
      minMonth: parseInt(minD[1], 10) - 1,
      maxMonth: parseInt(maxD[1], 10) - 1,
      minYear: parseInt(minD[0], 10),
      maxYear: parseInt(maxD[0], 10)
    };
  }
  /**
   * @param {number} year
   */
  isLeapYear(year) {
    return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
  }
  /**
   * @param {number} month
   * @param {number} year
   * @param {number} subtract
   */
  calculcateLastDaysOfMonth(month, year, subtract) {
    const days = this.determineDaysOfMonths(month, year);
    return days - subtract;
  }
  /**
   * @param {number} year
   */
  determineDaysOfYear(year) {
    let days = 365;
    if (this.isLeapYear(year)) {
      days = 366;
    }
    return days;
  }
  /**
   * @param {number} year
   * @param {number} month
   * @param {number} date
   */
  determineRemainingDaysOfYear(year, month, date) {
    let dayOfYear = this.daysCntOfYear[month] + date;
    if (month > 1 && this.isLeapYear(year)) dayOfYear++;
    return dayOfYear;
  }
  /**
   * @param {number} month
   * @param {number} year
   */
  determineDaysOfMonths(month, year) {
    let days = 30;
    month = Utils$1.monthMod(month);
    switch (true) {
      case this.months30.indexOf(month) > -1:
        if (month === 2) {
          if (this.isLeapYear(year)) {
            days = 29;
          } else {
            days = 28;
          }
        }
        break;
      case this.months31.indexOf(month) > -1:
        days = 31;
        break;
      default:
        days = 31;
        break;
    }
    return days;
  }
  // ───────────────────────────────────────────────────────────────────────────
  // Pure date helpers used by the v6 single-interval TimeScale.
  // Native Date setters/getters do all rollover work (leap years, month
  // length, year crossings), eliminating the manual rollover code that was
  // the source of the historical TimeScale boundary bugs.
  // ───────────────────────────────────────────────────────────────────────────
  /**
   * Extract calendar fields from a timestamp. Month is 0-indexed (matches
   * Date.getMonth / getUTCMonth).
   *
   * @param {number} timestamp
   * @param {boolean} isUTC
   * @returns {{ year: number, month: number, date: number, hour: number, minute: number, second: number, ms: number, weekday: number }}
   */
  getDateFields(timestamp, isUTC) {
    const d = new Date(timestamp);
    return isUTC ? {
      year: d.getUTCFullYear(),
      month: d.getUTCMonth(),
      date: d.getUTCDate(),
      hour: d.getUTCHours(),
      minute: d.getUTCMinutes(),
      second: d.getUTCSeconds(),
      ms: d.getUTCMilliseconds(),
      weekday: d.getUTCDay()
    } : {
      year: d.getFullYear(),
      month: d.getMonth(),
      date: d.getDate(),
      hour: d.getHours(),
      minute: d.getMinutes(),
      second: d.getSeconds(),
      ms: d.getMilliseconds(),
      weekday: d.getDay()
    };
  }
  /**
   * Advance a timestamp by `count` units. Native setters handle cross-month,
   * cross-year, leap-year, and DST rollover correctly.
   *
   * @param {number} timestamp
   * @param {'year'|'month'|'week'|'day'|'hour'|'minute'|'second'} unit
   * @param {number} count  may be negative
   * @param {boolean} isUTC
   * @returns {number}
   */
  addInterval(timestamp, unit, count, isUTC) {
    const d = new Date(timestamp);
    if (isUTC) {
      switch (unit) {
        case "year":
          d.setUTCFullYear(d.getUTCFullYear() + count);
          break;
        case "month":
          d.setUTCMonth(d.getUTCMonth() + count);
          break;
        case "week":
          d.setUTCDate(d.getUTCDate() + count * 7);
          break;
        case "day":
          d.setUTCDate(d.getUTCDate() + count);
          break;
        case "hour":
          d.setUTCHours(d.getUTCHours() + count);
          break;
        case "minute":
          d.setUTCMinutes(d.getUTCMinutes() + count);
          break;
        case "second":
          d.setUTCSeconds(d.getUTCSeconds() + count);
          break;
      }
    } else {
      switch (unit) {
        case "year":
          d.setFullYear(d.getFullYear() + count);
          break;
        case "month":
          d.setMonth(d.getMonth() + count);
          break;
        case "week":
          d.setDate(d.getDate() + count * 7);
          break;
        case "day":
          d.setDate(d.getDate() + count);
          break;
        case "hour":
          d.setHours(d.getHours() + count);
          break;
        case "minute":
          d.setMinutes(d.getMinutes() + count);
          break;
        case "second":
          d.setSeconds(d.getSeconds() + count);
          break;
      }
    }
    return d.getTime();
  }
  /**
   * Snap a timestamp UP to the next boundary aligned with `step` units of
   * `unit`. Returns the input unchanged if already on a boundary. Alignment
   * rules per unit:
   *   - second: 0/step/2*step/... seconds within a minute (step must divide 60)
   *   - minute: 0/step/2*step/... minutes within an hour (step must divide 60)
   *   - hour:   0/step/... hours within a day (step must divide 24)
   *   - day:    every day (step always 1)
   *   - week:   next Monday on a `step`-week stride from a fixed epoch Monday
   *   - month:  Jan/Apr/Jul/Oct for step=3, Jan/Jul for step=6 (step must divide 12)
   *   - year:   year % step === 0
   *
   * @param {number} timestamp
   * @param {'year'|'month'|'week'|'day'|'hour'|'minute'|'second'} unit
   * @param {number} step
   * @param {boolean} isUTC
   * @returns {number}
   */
  ceilToBoundary(timestamp, unit, step, isUTC) {
    const d = new Date(timestamp);
    if (isUTC) {
      switch (unit) {
        case "second": {
          const s2 = d.getUTCSeconds();
          const aligned = Math.ceil(s2 / step) * step;
          if (aligned === s2 && d.getUTCMilliseconds() === 0)
            return timestamp;
          d.setUTCMilliseconds(0);
          d.setUTCSeconds(aligned);
          return d.getTime();
        }
        case "minute": {
          const m = d.getUTCMinutes();
          const aligned = Math.ceil(m / step) * step;
          if (aligned === m && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)
            return timestamp;
          d.setUTCMilliseconds(0);
          d.setUTCSeconds(0);
          d.setUTCMinutes(aligned);
          return d.getTime();
        }
        case "hour": {
          const h2 = d.getUTCHours();
          const aligned = Math.ceil(h2 / step) * step;
          if (aligned === h2 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)
            return timestamp;
          d.setUTCMilliseconds(0);
          d.setUTCSeconds(0);
          d.setUTCMinutes(0);
          d.setUTCHours(aligned);
          return d.getTime();
        }
        case "day": {
          if (d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)
            return timestamp;
          d.setUTCMilliseconds(0);
          d.setUTCSeconds(0);
          d.setUTCMinutes(0);
          d.setUTCHours(0);
          d.setUTCDate(d.getUTCDate() + 1);
          return d.getTime();
        }
        case "week": {
          const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1e3;
          const REF_MONDAY_UTC = Date.UTC(1970, 0, 5);
          d.setUTCMilliseconds(0);
          d.setUTCSeconds(0);
          d.setUTCMinutes(0);
          d.setUTCHours(0);
          const startOfDay = d.getTime();
          const weeksSinceRef = Math.ceil(
            (startOfDay - REF_MONDAY_UTC) / MS_PER_WEEK
          );
          const alignedWeeks = Math.ceil(weeksSinceRef / step) * step;
          const aligned = REF_MONDAY_UTC + alignedWeeks * MS_PER_WEEK;
          if (aligned >= timestamp) return aligned;
          return aligned + step * MS_PER_WEEK;
        }
        case "month": {
          const m = d.getUTCMonth();
          const aligned = Math.ceil(m / step) * step;
          if (aligned === m && d.getUTCDate() === 1 && d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)
            return timestamp;
          d.setUTCMilliseconds(0);
          d.setUTCSeconds(0);
          d.setUTCMinutes(0);
          d.setUTCHours(0);
          d.setUTCDate(1);
          d.setUTCMonth(aligned);
          return d.getTime();
        }
        case "year": {
          const y = d.getUTCFullYear();
          const aligned = Math.ceil(y / step) * step;
          if (aligned === y && d.getUTCMonth() === 0 && d.getUTCDate() === 1 && d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0)
            return timestamp;
          return Date.UTC(aligned, 0, 1);
        }
      }
    } else {
      switch (unit) {
        case "second": {
          const s2 = d.getSeconds();
          const aligned = Math.ceil(s2 / step) * step;
          if (aligned === s2 && d.getMilliseconds() === 0) return timestamp;
          d.setMilliseconds(0);
          d.setSeconds(aligned);
          return d.getTime();
        }
        case "minute": {
          const m = d.getMinutes();
          const aligned = Math.ceil(m / step) * step;
          if (aligned === m && d.getSeconds() === 0 && d.getMilliseconds() === 0)
            return timestamp;
          d.setMilliseconds(0);
          d.setSeconds(0);
          d.setMinutes(aligned);
          return d.getTime();
        }
        case "hour": {
          const h2 = d.getHours();
          const aligned = Math.ceil(h2 / step) * step;
          if (aligned === h2 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)
            return timestamp;
          d.setMilliseconds(0);
          d.setSeconds(0);
          d.setMinutes(0);
          d.setHours(aligned);
          return d.getTime();
        }
        case "day": {
          if (d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)
            return timestamp;
          d.setMilliseconds(0);
          d.setSeconds(0);
          d.setMinutes(0);
          d.setHours(0);
          d.setDate(d.getDate() + 1);
          return d.getTime();
        }
        case "week": {
          const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1e3;
          const REF_MONDAY_LOCAL = new Date(1970, 0, 5).getTime();
          d.setMilliseconds(0);
          d.setSeconds(0);
          d.setMinutes(0);
          d.setHours(0);
          const startOfDay = d.getTime();
          const weeksSinceRef = Math.ceil(
            (startOfDay - REF_MONDAY_LOCAL) / MS_PER_WEEK
          );
          const alignedWeeks = Math.ceil(weeksSinceRef / step) * step;
          const aligned = REF_MONDAY_LOCAL + alignedWeeks * MS_PER_WEEK;
          if (aligned >= timestamp) return aligned;
          return aligned + step * MS_PER_WEEK;
        }
        case "month": {
          const m = d.getMonth();
          const aligned = Math.ceil(m / step) * step;
          if (aligned === m && d.getDate() === 1 && d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)
            return timestamp;
          d.setMilliseconds(0);
          d.setSeconds(0);
          d.setMinutes(0);
          d.setHours(0);
          d.setDate(1);
          d.setMonth(aligned);
          return d.getTime();
        }
        case "year": {
          const y = d.getFullYear();
          const aligned = Math.ceil(y / step) * step;
          if (aligned === y && d.getMonth() === 0 && d.getDate() === 1 && d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 && d.getMilliseconds() === 0)
            return timestamp;
          return new Date(aligned, 0, 1).getTime();
        }
      }
    }
    return timestamp;
  }
  /**
   * Test whether a timestamp falls exactly on a unit boundary (start of year,
   * start of month, start of day, etc.). Used by the multi-resolution
   * formatter to upgrade a tick's display unit to a coarser scale.
   *
   * @param {number} timestamp
   * @param {'year'|'month'|'day'|'hour'|'minute'|'second'} unit
   * @param {boolean} isUTC
   * @returns {boolean}
   */
  isAtBoundary(timestamp, unit, isUTC) {
    const f = this.getDateFields(timestamp, isUTC);
    switch (unit) {
      case "year":
        return f.month === 0 && f.date === 1 && f.hour === 0 && f.minute === 0 && f.second === 0 && f.ms === 0;
      case "month":
        return f.date === 1 && f.hour === 0 && f.minute === 0 && f.second === 0 && f.ms === 0;
      case "day":
        return f.hour === 0 && f.minute === 0 && f.second === 0 && f.ms === 0;
      case "hour":
        return f.minute === 0 && f.second === 0 && f.ms === 0;
      case "minute":
        return f.second === 0 && f.ms === 0;
      case "second":
        return f.ms === 0;
    }
    return false;
  }
}
class Formatters {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this.tooltipKeyFormat = "dd MMM";
  }
  /**
   * @param {Function} fn
   * @param {any} val
   * @param {any} timestamp
   * @param {any} _opts
   */
  xLabelFormat(fn, val, timestamp, _opts) {
    const w = this.w;
    if (w.config.xaxis.type === "datetime") {
      if (w.config.xaxis.labels.formatter === void 0) {
        if (w.config.tooltip.x.formatter === void 0) {
          const datetimeObj = new DateTime(this.w);
          return datetimeObj.formatDate(
            datetimeObj.getDate(val),
            w.config.tooltip.x.format
          );
        }
      }
    }
    return fn(val, timestamp, _opts);
  }
  /**
   * @param {any} val
   */
  defaultGeneralFormatter(val) {
    if (Array.isArray(val)) {
      return val.map((v) => {
        return v;
      });
    } else {
      return val;
    }
  }
  /**
   * @param {any} v
   * @param {ApexYAxis} yaxe
   */
  defaultYFormatter(v, yaxe) {
    const w = this.w;
    if (Utils$1.isNumber(v)) {
      if (w.globals.yValueDecimal !== 0) {
        v = v.toFixed(
          yaxe.decimalsInFloat !== void 0 ? yaxe.decimalsInFloat : w.globals.yValueDecimal
        );
      } else {
        const f = v.toFixed(0);
        v = Number(f) === v ? f : v.toFixed(1);
      }
    }
    return v;
  }
  setLabelFormatters() {
    const w = this.w;
    const fmt = w.formatters;
    fmt.xaxisTooltipFormatter = (val) => {
      return this.defaultGeneralFormatter(val);
    };
    fmt.ttKeyFormatter = (val) => {
      return this.defaultGeneralFormatter(val);
    };
    fmt.ttZFormatter = (val) => {
      return val;
    };
    fmt.legendFormatter = (val) => {
      return this.defaultGeneralFormatter(val);
    };
    if (w.config.xaxis.labels.formatter !== void 0) {
      fmt.xLabelFormatter = w.config.xaxis.labels.formatter;
    } else {
      fmt.xLabelFormatter = (val) => {
        if (Utils$1.isNumber(val)) {
          if (!w.config.xaxis.convertedCatToNumeric && w.config.xaxis.type === "numeric") {
            if (Utils$1.isNumber(w.config.xaxis.decimalsInFloat)) {
              return val.toFixed(w.config.xaxis.decimalsInFloat);
            } else {
              const diff = w.globals.maxX - w.globals.minX;
              if (diff > 0) {
                const step = diff / 10;
                const decimals = Math.max(0, -Math.floor(Math.log10(step)));
                return val.toFixed(decimals);
              }
              return val.toFixed(0);
            }
          }
          if (w.globals.isBarHorizontal) {
            const range = w.globals.maxY - w.globals.minY;
            if (range < 4) {
              return val.toFixed(1);
            }
          }
          return val.toFixed(0);
        }
        return val;
      };
    }
    if (typeof w.config.tooltip.x.formatter === "function") {
      fmt.ttKeyFormatter = w.config.tooltip.x.formatter;
    } else {
      fmt.ttKeyFormatter = fmt.xLabelFormatter;
    }
    if (typeof w.config.xaxis.tooltip.formatter === "function") {
      fmt.xaxisTooltipFormatter = w.config.xaxis.tooltip.formatter;
    }
    if (Array.isArray(w.config.tooltip.y)) {
      fmt.ttVal = w.config.tooltip.y;
    } else {
      if (w.config.tooltip.y.formatter !== void 0) {
        fmt.ttVal = w.config.tooltip.y;
      }
    }
    if (w.config.tooltip.z.formatter !== void 0) {
      fmt.ttZFormatter = w.config.tooltip.z.formatter;
    }
    if (w.config.legend.formatter !== void 0) {
      fmt.legendFormatter = w.config.legend.formatter;
    }
    fmt.yLabelFormatters = [];
    w.config.yaxis.forEach((yaxe, i2) => {
      if (yaxe.labels.formatter !== void 0) {
        fmt.yLabelFormatters[i2] = yaxe.labels.formatter;
      } else if (w.config.chart.type === "violin") {
        const round = (v) => typeof v === "number" && isFinite(v) ? `${Math.round(v * 100) / 100}` : v;
        fmt.yLabelFormatters[i2] = (val) => {
          if (!w.globals.xyCharts) return val;
          return Array.isArray(val) ? val.map(round) : round(val);
        };
      } else {
        fmt.yLabelFormatters[i2] = (val) => {
          if (!w.globals.xyCharts) return val;
          if (Array.isArray(val)) {
            return val.map((v) => {
              return this.defaultYFormatter(v, yaxe);
            });
          } else {
            return this.defaultYFormatter(val, yaxe);
          }
        };
      }
    });
    return w.globals;
  }
  heatmapLabelFormatters() {
    const w = this.w;
    if (w.config.chart.type === "heatmap") {
      w.globals.yAxisScale[0].result = /** @type {any} */
      w.seriesData.seriesNames.slice();
      const longest = (
        /** @type {any} */
        w.seriesData.seriesNames.reduce(
          (a2, b) => a2.length > b.length ? a2 : b,
          0
        )
      );
      w.globals.yAxisScale[0].niceMax = longest;
      w.globals.yAxisScale[0].niceMin = longest;
    }
  }
}
const name = "en";
const options = { "months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], "shortMonths": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], "days": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], "shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], "toolbar": { "exportToSVG": "Download SVG", "exportToPNG": "Download PNG", "exportToCSV": "Download CSV", "menu": "Menu", "selection": "Selection", "selectionZoom": "Selection Zoom", "zoomIn": "Zoom In", "zoomOut": "Zoom Out", "pan": "Panning", "reset": "Reset Zoom", "measure": "Measure" } };
const en = {
  name,
  options
};
class Options {
  constructor() {
    this.yAxis = {
      show: true,
      showAlways: false,
      showForNullSeries: true,
      seriesName: void 0,
      opposite: false,
      reversed: false,
      logarithmic: false,
      logBase: 10,
      tickAmount: void 0,
      stepSize: void 0,
      forceNiceScale: false,
      alignZero: false,
      max: void 0,
      min: void 0,
      floating: false,
      decimalsInFloat: void 0,
      labels: {
        show: true,
        showDuplicates: false,
        minWidth: 0,
        maxWidth: 160,
        offsetX: 0,
        offsetY: 0,
        align: void 0,
        rotate: 0,
        padding: 20,
        style: {
          colors: [],
          fontSize: "11px",
          fontWeight: 400,
          fontFamily: void 0,
          cssClass: ""
        },
        formatter: void 0
      },
      axisBorder: {
        show: false,
        color: "#e0e0e0",
        width: 1,
        offsetX: 0,
        offsetY: 0
      },
      axisTicks: {
        show: false,
        color: "#e0e0e0",
        width: 6,
        offsetX: 0,
        offsetY: 0
      },
      title: {
        text: void 0,
        rotate: -90,
        offsetY: 0,
        offsetX: 0,
        style: {
          color: void 0,
          fontSize: "11px",
          fontWeight: 900,
          fontFamily: void 0,
          cssClass: ""
        }
      },
      tooltip: {
        enabled: false,
        offsetX: 0
      },
      crosshairs: {
        show: true,
        position: "front",
        stroke: {
          color: "#b6b6b6",
          width: 1,
          dashArray: 0
        }
      }
    };
    this.pointAnnotation = {
      id: void 0,
      x: 0,
      y: null,
      yAxisIndex: 0,
      seriesIndex: void 0,
      mouseEnter: void 0,
      mouseLeave: void 0,
      click: void 0,
      marker: {
        size: 4,
        fillColor: "#fff",
        strokeWidth: 2,
        strokeColor: "#333",
        shape: "circle",
        offsetX: 0,
        offsetY: 0,
        // radius: 2, // DEPRECATED
        cssClass: ""
      },
      label: {
        borderColor: "#c2c2c2",
        borderWidth: 1,
        borderRadius: 2,
        text: void 0,
        textAnchor: "middle",
        offsetX: 0,
        offsetY: 0,
        mouseEnter: void 0,
        mouseLeave: void 0,
        click: void 0,
        style: {
          background: "#fff",
          color: void 0,
          fontSize: "11px",
          fontFamily: void 0,
          fontWeight: 400,
          cssClass: "",
          padding: {
            left: 5,
            right: 5,
            top: 2,
            bottom: 2
          }
        }
      },
      customSVG: {
        // this will be deprecated in the next major version as it is going to be replaced with a better alternative below (image)
        SVG: void 0,
        cssClass: void 0,
        offsetX: 0,
        offsetY: 0
      },
      image: {
        path: void 0,
        width: 20,
        height: 20,
        offsetX: 0,
        offsetY: 0
      },
      tooltip: {
        // Show a hover tooltip over the annotation marker, like a regular
        // data point. Lets you surface richer detail than fits in the label.
        enabled: false,
        // Static tooltip content (HTML allowed; array joined with <br/>).
        // Falls back to label.text when omitted.
        text: void 0,
        // formatter({ annotation, seriesIndex, id, w }) => string (HTML).
        // Takes precedence over `text` when provided.
        formatter: void 0,
        // 'light' | 'dark'. Falls back to the global tooltip.theme.
        theme: void 0,
        offsetX: 0,
        offsetY: 0
      }
    };
    this.yAxisAnnotation = {
      id: void 0,
      y: 0,
      y2: null,
      strokeDashArray: 1,
      fillColor: "#c2c2c2",
      borderColor: "#c2c2c2",
      borderWidth: 1,
      opacity: 0.3,
      offsetX: 0,
      offsetY: 0,
      width: "100%",
      yAxisIndex: 0,
      label: {
        borderColor: "#c2c2c2",
        borderWidth: 1,
        borderRadius: 2,
        text: void 0,
        textAnchor: "end",
        position: "right",
        offsetX: 0,
        offsetY: -3,
        mouseEnter: void 0,
        mouseLeave: void 0,
        click: void 0,
        style: {
          background: "#fff",
          color: void 0,
          fontSize: "11px",
          fontFamily: void 0,
          fontWeight: 400,
          cssClass: "",
          padding: {
            left: 5,
            right: 5,
            top: 2,
            bottom: 2
          }
        }
      }
    };
    this.xAxisAnnotation = {
      id: void 0,
      x: 0,
      x2: null,
      strokeDashArray: 1,
      fillColor: "#c2c2c2",
      borderColor: "#c2c2c2",
      borderWidth: 1,
      opacity: 0.3,
      offsetX: 0,
      offsetY: 0,
      label: {
        borderColor: "#c2c2c2",
        borderWidth: 1,
        borderRadius: 2,
        text: void 0,
        textAnchor: "middle",
        orientation: "vertical",
        position: "top",
        offsetX: 0,
        offsetY: 0,
        mouseEnter: void 0,
        mouseLeave: void 0,
        click: void 0,
        style: {
          background: "#fff",
          color: void 0,
          fontSize: "11px",
          fontFamily: void 0,
          fontWeight: 400,
          cssClass: "",
          padding: {
            left: 5,
            right: 5,
            top: 2,
            bottom: 2
          }
        }
      }
    };
    this.text = {
      x: 0,
      y: 0,
      text: "",
      textAnchor: "start",
      foreColor: void 0,
      fontSize: "13px",
      fontFamily: void 0,
      fontWeight: 400,
      appendTo: ".apexcharts-annotations",
      backgroundColor: "transparent",
      borderColor: "#c2c2c2",
      borderRadius: 0,
      borderWidth: 0,
      paddingLeft: 4,
      paddingRight: 4,
      paddingTop: 2,
      paddingBottom: 2
    };
  }
  init() {
    return {
      annotations: {
        yaxis: [this.yAxisAnnotation],
        xaxis: [this.xAxisAnnotation],
        points: [this.pointAnnotation],
        texts: [],
        images: [],
        shapes: []
      },
      // Weave (#1): public plugin platform. Per-chart activation list:
      // { name, options?, order? }. Requires the Weave host to be bundled
      // (`import 'apexcharts/features/weave'`, included in the full bundle) and
      // the plugin registered via ApexCharts.registerPlugin().
      plugins: [],
      // Trellis (#22): small multiples / faceting. Requires the trellis
      // feature (`import 'apexcharts/features/trellis'`, included in the full
      // bundle). Setting `by` makes this chart a trellis HOST: the series
      // array is split into one panel per facet-key value, each panel is a
      // real chart of this chart.type, and the trellis owns everything shared
      // (scale domains, pixel-aligned plot rects, color-by-series-name, one
      // legend/title/toolbar, headers, responsive columns).
      trellis: {
        // Facet accessor: a series-object key name, or (series, i) => key.
        // Series WITHOUT the key repeat in every panel (reference series).
        by: void 0,
        // 2-D faceting (P4): row and/or column facet accessors, forming a
        // FIXED grid of every (row, column) combination in row-major order
        // (no responsive recolumning; panels shrink instead). Mutually
        // exclusive with `by`. Column labels draw once across the top, row
        // labels once down the left. Reference semantics per dimension: a
        // series with only the row key repeats across that row; only the
        // column key, down that column; neither, everywhere.
        row: void 0,
        column: void 0,
        // Missing (row, column) combinations: 'placeholder' mounts a real
        // empty panel (same scales, same geometry, a quiet "no data" label);
        // 'skip' keeps the slot with a tinted blank; 'hide' keeps the slot
        // with nothing at all.
        emptyPanels: "placeholder",
        // Tidy-row input (alternative to `series`): a row table pivoted by
        // the `by`/`x`/`y`/`seriesBy` COLUMN NAMES. Rows win over `series`
        // when both are given. Duplicate (panel, series, x) rows keep the
        // last and warn; aggregate the rows first for sums/means.
        data: void 0,
        // [{ date, region, revenue }, ...]
        x: void 0,
        // x-value column name (tidy form only)
        y: void 0,
        // y-value column name (tidy form only)
        seriesBy: void 0,
        // optional series-name column (tidy form only)
        // Layout
        columns: "auto",
        // 'auto' (fit minPanelWidth) | number
        minPanelWidth: 220,
        // px; drives 'auto' and the responsive collapse
        gap: 12,
        // px between cells
        aspectRatio: 1.6,
        // panel w:h when no explicit height governs
        panelHeight: void 0,
        // px; wins over aspectRatio/chart.height
        order: "first-seen",
        // | 'asc' | 'desc' | string[] | comparator
        limit: void 0,
        // render only the first N panels (warns)
        // Virtualization: 'auto' mounts only the panels intersecting the
        // viewport (plus one row) once the grid exceeds 64 panels; true
        // always virtualizes; false always renders eagerly. Unmounted cells
        // keep their header and a fixed-height skeleton (page height and
        // scroll position never shift); a panel that scrolls out is
        // destroyed with its view state stashed, and a remount restores its
        // zoom window. getPanel(key) returns null for unmounted panels.
        virtualize: "auto",
        // 'auto' | true | false
        // Scale resolution per channel: 'shared' | 'independent'; y also
        // takes 'independent-row' | 'independent-column' in a 2-D grid (one
        // shared domain per row/column: comparable along the group, free
        // across groups). Non-shared y still renders pixel-aligned panels
        // (the gutter pass equalizes axis widths); 'independent' and
        // 'independent-column' force their own y labels on every panel,
        // 'independent-row' keeps them on the first column (ticks are
        // identical along a row).
        scales: {
          x: "shared",
          y: "shared",
          color: "shared",
          size: "shared"
        },
        // Per-cell facet headers.
        header: {
          show: true,
          formatter: void 0,
          // (key, { dimension, index, count }) => string
          style: {
            fontSize: void 0,
            fontWeight: void 0,
            color: void 0
          }
        },
        // Axis-label policy: 'edges' shows y labels on the first column and x
        // labels on each column's bottom panel (label SPACE is always
        // reserved everywhere, so panels stay aligned); 'all' | 'none'.
        axes: {
          labels: "edges"
        },
        legend: "shared",
        // 'shared' | 'none' (per-panel legends are hidden)
        toolbar: "shared",
        // 'shared' | 'none' (zoom / pan / reset)
        // 'panel': tooltip card only in the hovered panel, crosshair sweeps
        // all panels. 'sync': every panel shows its own card at the hovered x.
        // 'grid': ONE card near the cursor with one row per panel at the
        // hovered x (composed from the panels' own tooltips, so every
        // formatter is honored; unmounted virtualized panels have no row).
        tooltip: "panel",
        zoom: "sync",
        // 'sync' (drag/wheel zoom moves every panel) | 'none'
        // Panel promotion: clicking a cell's header expands that panel to
        // the grid's full width, with an "All panels" breadcrumb back
        // (also chart.promotePanel(key) / chart.restorePanels()).
        promote: true,
        // Pie/donut/polarArea only: scale each panel's radius so its AREA is
        // proportional to the panel's total (equal-size pies cannot encode
        // magnitude, which is the honest objection to a pie trellis).
        radiusByTotal: false,
        // Tick-interval target for the shared nice y scale. Panels are small:
        // 3 intervals (up to ~4 labels) keeps the axis from outweighing the data.
        targetTicks: 3,
        // Per-panel option override, applied last:
        // (key, { index, seriesNames }) => partial options
        panel: void 0
      },
      chart: {
        animations: {
          // Master switch — set false to render charts without any animation.
          // Each chart type gets a tailored initial-mount animation by default:
          //   line/area/rangeArea/radar: pen-stroke draw + radial fill bloom
          //   bar/stacked/range/funnel:  grow from baseline (+ stagger)
          //   scatter/bubble:            scale-up pop with overshoot
          //   heatmap:                   diagonal-wave cell reveal
          //   treemap:                   largest-tile-first cascade
          //   pie/donut/polar/gauge:     arc sweep + needle settle
          // Speed is controlled by `speed`; per-element stagger by
          // `animateGradually.enabled` / `animateGradually.delay`.
          enabled: true,
          speed: 800,
          // Cadence (#6): easing for the generic tweens (data-update value
          // transitions, path morphs, marker animate). A registered name, a
          // cubic-bezier [x1,y1,x2,y2] array, or a function (t in [0,1]).
          // 'easeInOutSine' is the historical curve, so the default is
          // behavior-neutral. The tuned initial-draw pen/pop easings are fixed.
          easing: "easeInOutSine",
          animateGradually: {
            // Drives per-element stagger across all chart types. When enabled,
            // bars/heatmap-cells/scatter-points/treemap-tiles reveal in
            // sequence; line/area markers fade in progressively along the
            // draw. `delay` is the requested step in ms (auto-capped per
            // chart so total stagger ≤ ~half the animation duration).
            delay: 150,
            enabled: true
          },
          dynamicAnimation: {
            // Data-change (updateSeries) animation. Independent from the
            // initial-mount animations above.
            enabled: true,
            speed: 350,
            // Easing for data-change morphs only (same accepted forms as
            // `animations.easing`). Unset -> inherit the chart-wide easing,
            // except detected streaming scrolls (rolling window / append
            // under xaxis.range) which default to 'linear' so the window
            // slides at constant velocity instead of pulsing each tick.
            easing: void 0
          },
          chartTypeMorph: {
            // Cross-type morph (updateOptions changing chart.type). Bridges
            // the destroy+recreate flicker by sampling source + target paths
            // into N evenly-spaced perimeter points and tweening point-by-point
            // with rotation-search alignment, so the transition is always smooth
            // and non-self-intersecting even between very different shapes (bar
            // rect ↔ pie wedge / radial arc). Supported pairs include bar ↔
            // pie / donut / radialBar / polarArea / funnel / pyramid (plus the
            // trivial pie ↔ donut ↔ polarArea cases). Falls back to instant
            // snap when types or data shape are incompatible.
            enabled: true,
            speed: 600
          },
          // Honor the OS-level prefers-reduced-motion setting. When true (default)
          // and the user has the accessibility preference enabled, all initial-mount
          // animations are skipped and the chart renders instantly.
          respectReducedMotion: true,
          // Above this many data points, per-element morph + stagger (which
          // spins up one JS-driven animation timeline per path — three chained
          // tweens each in morphSVG) is replaced by a single GPU-composited
          // opacity fade of the whole series. Thousands of candlesticks/bars
          // otherwise jank the main thread on initial render and on every zoom.
          // The fade reuses the existing delayedElements reveal so the result
          // still animates in, just at O(1) cost instead of O(n). Set to 0 to
          // always animate per-element regardless of dataset size.
          largeDatasetThreshold: 1e3
        },
        background: "",
        locales: [en],
        defaultLocale: "en",
        // Perspectives (#10): serializable/shareable view state. Passive:
        // requires `import 'apexcharts/features/perspectives'`. serializeOptions
        // is the whitelist of function-free option paths stored in a token.
        perspectives: {
          serializeOptions: ["theme", "xaxis", "yaxis", "title", "subtitle"]
        },
        // Rewind (#3): undo/redo history. Opt-in (bundle + behavior): requires
        // `import 'apexcharts/features/history'` AND chart.history.enabled.
        history: {
          enabled: false,
          maxDepth: 100,
          coalesceMs: 250,
          keyboard: true
        },
        // Strata (#2): hybrid SVG+canvas series renderer. 'svg' (default) |
        // 'canvas' | 'auto'. 'auto'/'canvas' need the canvas renderer feature
        // (`import 'apexcharts/features/renderer-canvas'`); without it, or with
        // a canvas-unsupported feature (pattern/image fill, color-matrix state
        // filters), selection falls back to 'svg'. Only the series layer is
        // canvas-capable in v1; chrome stays SVG.
        renderer: "svg",
        rendererThreshold: 8e3,
        layers: {
          series: "auto",
          grid: "svg",
          annotations: "svg",
          dataLabels: "svg"
        },
        dropShadow: {
          enabled: false,
          enabledOnSeries: void 0,
          top: 2,
          left: 2,
          blur: 4,
          color: "#000",
          opacity: 0.7
        },
        events: {
          animationEnd: void 0,
          beforeMount: void 0,
          mounted: void 0,
          updated: void 0,
          click: void 0,
          mouseMove: void 0,
          mouseLeave: void 0,
          xAxisLabelClick: void 0,
          legendClick: void 0,
          markerClick: void 0,
          selection: void 0,
          dataPointSelection: void 0,
          dataPointMouseEnter: void 0,
          dataPointMouseLeave: void 0,
          beforeZoom: void 0,
          beforeResetZoom: void 0,
          zoomed: void 0,
          scrolled: void 0,
          brushScrolled: void 0,
          crossFilter: void 0,
          filterChange: void 0,
          annotationDragged: void 0,
          annotationEdited: void 0,
          annotationCreated: void 0,
          annotationStyled: void 0,
          annotationDeleted: void 0,
          measured: void 0,
          keyDown: void 0,
          keyUp: void 0
        },
        foreColor: "#373d3f",
        fontFamily: "Helvetica, Arial, sans-serif",
        height: "auto",
        parentHeightOffset: 15,
        redrawOnParentResize: true,
        redrawOnWindowResize: true,
        id: void 0,
        group: void 0,
        nonce: void 0,
        // Per-chart license key override for the gated premium features
        // (storyboard, link/crossfilter, ink, measure, contextMenu,
        // perspectives, history). Most specific wins: chart.license ->
        // ApexCharts.setLicense() -> window.Apex.license -> unlicensed (trial
        // watermark). Shared across the ApexCharts family. See setLicense().
        license: void 0,
        offsetX: 0,
        offsetY: 0,
        injectStyleSheet: true,
        selection: {
          enabled: false,
          type: "x",
          // selectedPoints: undefined, // default datapoints that should be selected automatically
          fill: {
            color: "#24292e",
            opacity: 0.1
          },
          stroke: {
            width: 1,
            color: "#24292e",
            opacity: 0.4,
            dashArray: 3
          },
          xaxis: {
            min: void 0,
            max: void 0
          },
          yaxis: {
            min: void 0,
            max: void 0
          }
        },
        sparkline: {
          enabled: false
        },
        brush: {
          enabled: false,
          autoScaleYaxis: true,
          target: void 0,
          targets: void 0
        },
        // Linked Views (#4): crossfilter / linked highlighting. Requires the
        // `link` feature. Two modes:
        //   HIGHLIGHT (P1): `enabled` with no `dimension`. Charts sharing a
        //   `chart.group` form a set; brushing a range (needs
        //   `chart.selection.enabled`) dims out-of-range marks in place.
        //   FILTER (P2): set `dimension` (its presence selects this path). Each
        //   chart declares a dimension + reduction over a shared record set
        //   registered with ApexCharts.crossfilter({ id, records }); clicking a
        //   bucket re-aggregates the other charts. See docs/spec.
        link: {
          enabled: false,
          mode: "highlight",
          dimOpacity: 0.2,
          // FILTER-mode config (all optional except dimension):
          id: void 0,
          // crossfilter coordinator id (defaults to chart.group)
          dimension: void 0,
          // (row) => key; presence selects filter mode
          reduce: void 0,
          // 'count' | { sum|avg|min|max: field } | (rows)=>n
          type: void 0,
          // 'category' | 'range' (else inferred from bins)
          bins: void 0,
          // range dims: { width } | { count } | { thresholds }
          order: void 0,
          // category order: 'first-seen' | 'asc' | 'desc' | fn
          seriesName: void 0
          // axis-chart series name (default 'Count')
        },
        // Ink Layer (#7): direct-manipulation annotations. When enabled, every
        // point annotation is draggable (unless it sets draggable:false); or opt
        // in per annotation with annotations.points[].draggable. Clicking an
        // ink-managed annotation opens a floating editor card: rename inline,
        // recolor, toggle bold, step the font size, size/reshape the marker, or
        // delete the note. Axis-line annotations get separate Label and Line
        // color rows, so restyling the label chip never touches the stroke.
        // Requires the `ink` feature. Fires annotationDragged,
        // annotationEdited, annotationStyled and annotationDeleted.
        ink: {
          enabled: false,
          // Show a minimal "add note" tool palette; clicking it arms create
          // mode (the next plot click drops an editable, draggable annotation).
          palette: false,
          // Snap a dragged point / axis-line annotation to the nearest gridline
          // (numeric x + linear y). Undo/redo of ink edits is automatic when the
          // history (Rewind) feature is enabled.
          snap: false,
          // Accent swatches offered by the floating note editor; defaults to a
          // built-in 6-color palette when undefined.
          noteColors: void 0
        },
        // Measure ruler (#18): a measure/delta ruler. Requires the `measure`
        // feature. Hold `key` (default 'm') and drag A->B on the plot, or call
        // chart.startMeasure()/chart.stopMeasure() to arm it. The live ruler
        // reads dx, dy, %change and slope; on release it pins as a data-anchored
        // overlay that re-projects on zoom/resize. Fires `measured`.
        measure: {
          enabled: false,
          // 'span' (default): finance-style vertical band between two x-points
          // with a "change (%) + range" readout, endpoints snapped to the first
          // series. 'free': a diagonal ruler between two arbitrary points.
          mode: "span",
          key: "m",
          pinOnRelease: true,
          // Styling tokens. Every element also carries a stable CSS class
          // (apexcharts-measure-band / -vline / -line / -label-bg / -label,
          // group gets apexcharts-measure-up|down|flat). Colors are left
          // undefined so they resolve config -> `--apx-measure-*` CSS custom
          // property -> built-in default; set them here to force a color from JS.
          colors: {
            up: void 0,
            down: void 0,
            neutral: void 0,
            guide: void 0
          },
          band: true,
          // span mode: shaded band between the two x-positions
          guides: true,
          // span mode: vertical dashed reference lines
          markers: true,
          // endpoint dots on the series line
          // Content: value formatters and a full readout override. `label`
          // receives { from, to, dx, dy, percentChange, slope, mode } and
          // returns a string or string[] (lines).
          format: { x: void 0, y: void 0, percent: void 0 },
          label: void 0
        },
        // Radial Actions (#chrome): right-click / long-press context menu.
        // Requires the `contextMenu` feature. Each action receives the clicked
        // data coordinates, so verbs act at the point (not chart-wide like a
        // toolbar button). `items` is an ordered list of built-in ids
        // ('annotate' | 'xline' | 'yline' | 'measure') and/or custom
        // { id, label, icon, onClick(ctx, { x, y, seriesIndex, dataPointIndex,
        // clientX, clientY }) }. 'measure' is shown only when the measure tool
        // is enabled. `labels` overrides built-in text; `noteText` is the label
        // dropped by 'annotate'.
        contextMenu: {
          enabled: false,
          items: ["annotate", "xline", "yline", "measure"],
          labels: {
            annotate: void 0,
            xline: void 0,
            yline: void 0,
            measure: void 0
          },
          noteText: "Note",
          // 'xline' ("Annotate here") drops a dashed vertical LINE at the
          // clicked x; 'yline' ("Mark this level") a dashed horizontal line at
          // the clicked y. Lines only, never a range rectangle. Like the note,
          // a line is ink-managed when the ink feature is bundled: it opens
          // the floating editor (rename; separate Label and Line color rows,
          // so restyling the chip cannot blank the stroke; delete), drags
          // along its axis, and undoes via Rewind. `line` styles both items.
          line: {
            text: "",
            // label drawn on the line; empty for no label
            strokeDashArray: 4,
            color: void 0
            // undefined keeps the annotation default color
          }
        },
        stacked: false,
        stackOnlyBar: true,
        // mixed chart with stacked bars and line series - incorrect line draw #907
        stackType: "normal",
        // Real-time streaming mode. When enabled, appendData() bounds memory
        // automatically: each series is trimmed to `maxPoints` (when set) or
        // to the visible `xaxis.range` window plus a two-point off-screen
        // runway (so exiting segments slide off the left edge instead of
        // popping). The scroll animation itself needs no opt-in; updates
        // that continue the previous window (appendData, or updateSeries with
        // a shifted fixed-length window) always translate at constant
        // velocity; see modules/animations/StreamScroll.
        streaming: {
          enabled: false,
          maxPoints: void 0
        },
        toolbar: {
          show: true,
          offsetX: 0,
          offsetY: 0,
          tools: {
            download: true,
            selection: true,
            zoom: true,
            zoomin: true,
            zoomout: true,
            pan: true,
            reset: true,
            // Shown only when the measure ruler is active (chart.measure.enabled
            // and the `measure` feature bundled). Toggles the measure tool; set
            // false to keep the ruler key-driven only. See chart.measure.
            measure: true,
            customIcons: []
          },
          export: {
            csv: {
              filename: void 0,
              columnDelimiter: ",",
              headerCategory: "category",
              headerValue: "value",
              categoryFormatter: void 0,
              valueFormatter: void 0
            },
            png: {
              filename: void 0
            },
            svg: {
              filename: void 0
            },
            scale: void 0,
            width: void 0,
            // An exported SVG is a standalone document: it cannot reach the
            // page's @font-face rules, so a custom font falls back to a
            // generic one in the PNG/SVG. When true, matching @font-face
            // rules are inlined as base64 data URIs. See #3617.
            embedFonts: true
          },
          autoSelected: "zoom"
          // accepts -> zoom, pan, selection, measure
        },
        type: "line",
        width: "100%",
        zoom: {
          enabled: true,
          type: "x",
          autoScaleYaxis: false,
          // Wheel and pinch zoom can both be triggered without meaning to (a
          // page scroll or a two-finger swipe over the chart), so 'auto' offers
          // them only when the viewer has a way back: the toolbar's reset
          // button. With the toolbar hidden they stay off, since a zoom nobody
          // asked for and nobody can undo is a trap. Set either to true to
          // force the gesture on regardless (for a page that supplies its own
          // reset control), or false to turn it off outright.
          allowMouseWheelZoom: "auto",
          // Momentum: two-finger pinch-zoom on touch devices. Zooms the x-axis
          // around the pinch centroid (matching the x-only wheel/toolbar zoom),
          // frame-by-frame rather than the 400ms wheel throttle.
          pinch: "auto",
          zoomedArea: {
            fill: {
              color: "#90CAF9",
              opacity: 0.4
            },
            stroke: {
              color: "#0D47A1",
              opacity: 0.4,
              width: 1
            }
          }
        },
        // Momentum: kinetic panning on touch. When a one-finger pan is released
        // with velocity, the chart keeps gliding and decelerates by `friction`
        // each frame, clamping (no elastic overshoot) at the data edges.
        pan: {
          inertia: true,
          friction: 0.92
        },
        accessibility: {
          enabled: true,
          description: void 0,
          announcements: {
            enabled: true
          },
          keyboard: {
            enabled: true,
            navigation: {
              enabled: true,
              wrapAround: false
            }
          }
        },
        dataReducer: {
          enabled: false,
          algorithm: "lttb",
          targetPoints: 250,
          threshold: 500
        }
      },
      parsing: {
        x: void 0,
        y: void 0
      },
      plotOptions: {
        line: {
          isSlopeChart: false,
          colors: {
            threshold: 0,
            colorAboveThreshold: void 0,
            colorBelowThreshold: void 0
          }
        },
        area: {
          fillTo: "origin"
        },
        bar: {
          horizontal: false,
          columnWidth: "70%",
          // should be in percent 0 - 100
          barHeight: "70%",
          // should be in percent 0 - 100
          distributed: false,
          borderRadius: 0,
          borderRadiusApplication: "around",
          // [around, end]
          rangeBarOverlap: true,
          rangeBarGroupRows: false,
          hideZeroBarsWhenGrouped: false,
          isDumbbell: false,
          dumbbellColors: void 0,
          isFunnel: false,
          isFunnel3d: true,
          colors: {
            ranges: [],
            backgroundBarColors: [],
            backgroundBarOpacity: 1,
            backgroundBarRadius: 0
          },
          dataLabels: {
            position: "top",
            // top, center, bottom
            maxItems: 100,
            hideOverflowingLabels: true,
            orientation: "horizontal",
            total: {
              enabled: false,
              formatter: void 0,
              offsetX: 0,
              offsetY: 0,
              style: {
                color: "#373d3f",
                fontSize: "12px",
                fontFamily: void 0,
                fontWeight: 600
              }
            }
          }
        },
        bubble: {
          zScaling: true,
          minBubbleRadius: void 0,
          maxBubbleRadius: void 0,
          // Explicit z window for the size scale. EXPANDS the data's own z
          // extent, never clamps it, so several bubble charts can share one
          // size scale (a trellis pushes the union extent through these).
          minZ: void 0,
          maxZ: void 0
        },
        scatter: {
          // Spread overlapping points apart ("jitter"). Two uses, one engine:
          //  - Strip plot: supply data as { x: 'Category', y: [v1, v2, ...] }.
          //    Each category becomes a band and the values are scattered
          //    horizontally within it. Marker styling comes from the standard
          //    `markers` / `colors` config.
          //  - Overplotting: ordinary { x, y } points get a small random offset
          //    so dense clusters fan out. The underlying data (and tooltip
          //    values) stay exact — only the drawn position moves.
          // Offsets are in axis units (x: 1 = one category step) and are
          // deterministic (stable across re-renders, SSR-safe).
          jitter: {
            enabled: false,
            x: 0,
            // max ± horizontal offset, in x-axis units
            y: 0,
            // max ± vertical offset, in y-axis units
            distributed: false,
            // single series: colour each band differently
            maxPoints: 5e3
            // per band; excess values are stride-thinned
          }
        },
        candlestick: {
          colors: {
            upward: "#00B746",
            downward: "#EF403C"
          },
          wick: {
            useFillColor: true
          }
        },
        boxPlot: {
          colors: {
            upper: "#00E396",
            lower: "#008FFB"
          },
          // Where the whiskers reach when the summary is DERIVED from raw
          // observations (a datum supplying `points` instead of a 5-number y,
          // which needs `apexcharts/features/stats`). Ignored for precomputed
          // summaries, which are drawn exactly as given.
          //   'minmax' → the extremes, so nothing is hidden
          //   'tukey'  → the last observation inside 1.5 * IQR of each
          //              quartile. Points beyond the fence fall outside the
          //              whisker, so pair it with `points.show` or they become
          //              invisible.
          whiskers: "minmax",
          // Optional individual observations ("jitter") overlaid on each box.
          // Inert unless a data point supplies a `points: number[]` array; off
          // by default so existing boxPlot charts are unchanged.
          points: {
            show: false,
            shape: "circle",
            // 'circle' | 'square'
            size: 2.5,
            // radius (px)
            jitter: 0.5,
            // 0..1 fraction of the box half-width to scatter within
            maxPoints: 3e3,
            // cap per box; excess is stride-thinned
            opacity: 0.9,
            // 'series-dark' (default) → a darker shade of the series colour,
            // 'series' → the series colour, or any literal colour string.
            fillColor: "series-dark",
            strokeColor: "#fff",
            strokeWidth: 1
            // Optional `colorScale` (undeclared so a user object merges cleanly)
            // colours each dot by its value: { colors, min, max, steps }
          }
        },
        violin: {
          // Multiply the density-derived half-width. 1 = density's own maxWeight
          // maps to half the category slot.
          bandwidthScale: 1,
          // Kernel density estimation, used only when the density is DERIVED
          // from raw observations (a datum supplying `points`, or a flat number
          // array as `y`, which needs `apexcharts/features/stats`). A
          // precomputed density profile is drawn exactly as given.
          //   bandwidth  → kernel width in value units. Unset uses Silverman's
          //                rule of thumb, which takes the smaller of the
          //                standard deviation and a scaled IQR so one distant
          //                outlier cannot smear the curve flat. Note this is a
          //                statistical parameter, unlike `bandwidthScale`
          //                above, which only scales the drawn width.
          //   resolution → density samples per violin (default 64).
          kde: {
            bandwidth: void 0,
            resolution: 64
          },
          // 'individual' → every violin uses the full slot width (scaled to its
          // own peak). 'group' → all violins share one scale (the densest in the
          // series), so widths stay proportional to density across categories.
          normalize: "individual",
          // Individual observations ("jitter") overlaid on the violin shape.
          points: {
            show: true,
            shape: "circle",
            // 'circle' | 'square'
            size: 2.5,
            // radius (px)
            jitter: 0.5,
            // 0..1 fraction of the half-width to scatter within
            constrainToViolin: true,
            // clamp jitter to the density width at each value
            maxPoints: 3e3,
            // cap per violin; excess is stride-thinned
            opacity: 0.9,
            // Default: a darker shade of each violin's own colour, with a white
            // outline. fillColor accepts 'series-dark' (default), 'series' (the
            // violin's colour as-is), or any literal colour string.
            fillColor: "series-dark",
            strokeColor: "#fff",
            strokeWidth: 1
            // Optional `colorScale` (left undeclared so a user object merges
            // cleanly) colours each dot by its value along a ramp:
            //   { colors: ['#0d0887', … '#f0f921'], min, max, steps }
          }
        },
        histogram: {
          // How the bin width is chosen from the raw observations. A rule name
          // ('auto' | 'fd' | 'sturges' | 'scott' | 'rice' | 'sqrt') or a fixed
          // bin count. 'auto' takes the narrower of Freedman-Diaconis and
          // Sturges, falling back to Sturges when the IQR is 0 (which happens
          // as soon as most values are identical).
          bins: "auto",
          // Explicit bin width in value units. Wins over `bins` when set: use
          // it when the bin boundaries carry meaning (decades, 5-minute
          // buckets) rather than being a statistical choice.
          binWidth: void 0,
          // [min, max] to bin over, instead of the data's own extent. Lets
          // several histograms share one scale.
          range: void 0,
          // y units: 'count' (observations per bin), 'relative' (percent of
          // the series total), or 'density' (count / (n * binWidth), so the
          // total area is 1 and bins of different widths stay comparable).
          normalize: "count",
          // Running total across bins, i.e. a cumulative distribution.
          cumulative: false,
          // With more than one series, draw every distribution across the FULL
          // bin so they overlay, instead of dividing the bin between them. All
          // series already share one set of edges, and comparing two shapes is
          // the reason to put them on one axis; splitting the bin makes the
          // columns stop touching, which reads as a clustered bar chart rather
          // than a distribution. Set false for side-by-side bars.
          //
          // An overlay is unreadable opaque, so it also softens the fill and
          // drops the bin separator stroke. Both remain overridable.
          overlap: true
        },
        heatmap: {
          radius: 2,
          enableShades: true,
          shadeIntensity: 0.5,
          reverseNegativeShade: false,
          distributed: false,
          useFillColorAsStroke: false,
          colorScale: {
            inverse: false,
            ranges: [],
            min: void 0,
            max: void 0,
            // Replaces the default categorical legend with a continuous
            // gradient stripe + a hover indicator arrow. Honors
            // `chart.legend.position` (top / right / bottom / left).
            gradientLegend: {
              enabled: false,
              // Strip length along the legend's long axis. Accepts a number
              // (pixels) or a percentage string. For top/bottom placement the
              // percentage is resolved against the chart's SVG width; for
              // left/right placement, against the SVG height.
              width: "70%",
              height: "70%",
              thickness: 12,
              // Alignment of the strip within the legend area:
              //  - top/bottom: 'start' = left, 'center', 'end' = right
              //  - left/right: 'start' = top,  'center', 'end' = bottom
              align: "center",
              // Number of gradient stops sampled from the shade function when
              // no explicit `ranges` are provided.
              stops: 16,
              // Show min/max labels at the ends of the strip.
              showLabels: true,
              // Show a value tooltip next to the arrow when hovering a cell.
              showHoverValue: true,
              labelStyle: {
                fontSize: "11px",
                fontFamily: void 0,
                colors: void 0
              },
              arrow: {
                size: 8,
                color: void 0
                // falls back to chart.foreColor
              },
              formatter: void 0
              // (val) => string, for min/max + hover value
            }
          }
        },
        funnel: {
          // 'rectangle' preserves the existing centered-rectangle funnel
          // geometry. 'trapezoid' produces continuous sloped sides between
          // consecutive stages (each stage's bottom width matches the next
          // stage's top width).
          shape: "rectangle",
          // For shape: 'trapezoid' only — what to do with the last stage's
          // bottom edge: 'flat' (parallel sides) or 'taper' (taper to a point).
          lastShape: "flat"
        },
        treemap: {
          enableShades: true,
          shadeIntensity: 0.5,
          distributed: false,
          reverseNegativeShade: false,
          useFillColorAsStroke: false,
          borderRadius: 4,
          dataLabels: {
            format: "scale",
            // scale | truncate
            // Skip a tile's label when it would render below this size.
            //
            // With `format: 'scale'` the font size follows the tile's area, so
            // on a dense treemap most tiles ask for text a few pixels tall,
            // which nobody can read. Drawing it is not free: each label has to
            // be built and measured against the DOM, and on a 10k-tile chart
            // that was the entire render cost (~7.5s, versus ~0.1s once the
            // unreadable ones are skipped).
            //
            // The default sits below the smallest label any bundled sample
            // draws, so it only ever removes text that was already illegible.
            // Set 0 to draw a label on every tile regardless of size.
            minFontSize: 4
          },
          colorScale: {
            inverse: false,
            ranges: [],
            min: void 0,
            max: void 0,
            // Colour a tile by a SECOND metric, independent of the value that
            // sizes it (area = how big, colour = how it did). Reads
            // `datum.colorValue` unless this names another key or supplies an
            // accessor `(datum, {seriesIndex, dataPointIndex, w}) => number`.
            colorValue: void 0,
            // Continuous interpolation between colour stops. Active as soon as
            // any datum carries a colour metric; `enabled: false` opts out and
            // `true` forces it on. `ranges` is unaffected and still applies
            // wherever it is set.
            gradient: {
              enabled: void 0,
              // Domain. Defaults to the extent of the colour metric.
              min: void 0,
              max: void 0,
              // The value the middle colour is pinned to. Defaults to 0 when
              // the domain straddles zero (a diverging metric), else none.
              midpoint: void 0,
              // With a midpoint, balance the domain around it so equal moves
              // in either direction read as equally saturated.
              symmetric: true,
              // Low -> mid -> high. Two colours make a sequential ramp.
              colors: void 0,
              // Explicit `[{ value, color }]` stops; overrides colors/midpoint.
              stops: void 0
            },
            // Continuous colour legend: a gradient strip with end labels and a
            // hover indicator, in place of the categorical legend. Same options
            // as the heatmap's.
            gradientLegend: {
              enabled: false,
              width: "70%",
              height: "70%",
              thickness: 12,
              align: "center",
              stops: 16,
              showLabels: true,
              showHoverValue: true,
              labelStyle: {
                fontSize: "11px",
                fontFamily: void 0,
                colors: void 0
              },
              arrow: {
                size: 8,
                color: void 0
              },
              formatter: void 0
            }
          },
          // Arbitrary-depth treemap: a datum may carry `children`.
          nested: {
            // Parent containers appear on their own as soon as the data is
            // nested; `false` forces the flat two-level layout.
            enabled: void 0,
            // Read `drilldown: '<id>'` ids as extra levels instead of as a
            // click target for the drilldown feature. Off by default, because
            // on a treemap that id has always meant "descend on click".
            drilldownAsLevels: false
          },
          // How a parent is drawn once the data is nested. Per-level overrides
          // go in `levels` below.
          parents: {
            // 'auto' (default): on when the data carries `children`.
            show: "auto",
            // Inset between a parent's edge and the children inside it.
            padding: 4,
            fill: void 0,
            fillOpacity: 1,
            borderColor: void 0,
            borderWidth: 1,
            borderRadius: void 0,
            hover: {
              show: true,
              color: void 0,
              width: 2
            },
            header: {
              show: true,
              height: 22,
              // Skip the strip on tiles too narrow to show a name.
              minWidth: 40,
              align: "left",
              offsetX: 0,
              offsetY: 0,
              showValue: false,
              // (name, { value, depth, seriesIndex, node, w }) => string
              formatter: void 0,
              style: {
                fontSize: "12px",
                fontFamily: void 0,
                fontWeight: 600,
                color: void 0,
                background: void 0,
                cssClass: ""
              }
            },
            tooltip: {
              // ({ name, value, depth, leafCount, percentOfParent,
              //    percentOfTotal, node, w }) => html
              formatter: void 0
            }
          },
          // Per-depth overrides of `parents`, indexed from the outermost group
          // actually drawn (0 = the series, or the first authored level when a
          // single series is unwrapped).
          levels: [],
          // Click a group to fill the canvas with it; a breadcrumb goes back.
          // Ignored when the drilldown feature is active on the same chart:
          // both navigate the hierarchy, and drilldown owns the click there.
          zoom: {
            enabled: false,
            // Overrides `drilldown.breadcrumb` for this chart only. Same shape
            // (show / position / separator / rootLabel / offsetX / offsetY /
            // formatter), so a zoomed treemap and a drilled-in chart present
            // the same affordance without importing the drilldown feature.
            breadcrumb: void 0
          },
          seriesTitle: {
            show: true,
            offsetY: 1,
            offsetX: 1,
            borderColor: "#000",
            borderWidth: 1,
            borderRadius: 2,
            style: {
              background: "rgba(0, 0, 0, 0.6)",
              color: "#fff",
              fontSize: "12px",
              fontFamily: void 0,
              fontWeight: 400,
              cssClass: "",
              padding: {
                left: 6,
                right: 6,
                top: 2,
                bottom: 2
              }
            }
          }
        },
        unit: {
          // 'grouped' (each category is its own cluster, laid out in a row) |
          // 'packed' (one blob; categories coloured + sorted, minority centred) |
          // 'columns' (each category is a vertical bar built from stacked dots) |
          // 'grid' (one lattice of cells filled in category order - a waffle /
          // part-to-whole square "pie"; `chart.type:'waffle'` presets this) |
          // 'scatter' (units on real value axes: a beeswarm, or a 2D
          // value-value scatter - see the `scatter` block below) |
          // 'arc' (a semicircular fan) |
          // 'custom' (positions come from `positions` below).
          layout: "grouped",
          // `layout: 'custom'` only. The layout provider: either a function
          // `(objects, rect) => [{id, x, y, r?}]` returning plot pixels, or the
          // name of one registered with `ApexCharts.registerUnitLayout`.
          //
          // This is the whole extension point. A layout is objects in,
          // positions out; it knows nothing about animation, because the engine
          // already tweens position, radius and colour and already keeps each
          // mark's identity across a relayout. So an arrangement this file
          // cannot know about - a country silhouette, a hex grid, a timeline, a
          // projection handed over by ApexMaps - is a plugin, not a core edit.
          //
          // `objects` carries one entry per mark: {id, index, seriesIndex,
          // dataPointIndex, label, value, datum, r}. `id` is the datum's own
          // id/name when the per-unit object form supplies one, so a provider
          // can address a specific unit rather than a positional slot.
          //
          // A mark whose id the provider omits animates out; ids matching no
          // mark are ignored.
          positions: void 0,
          // Update transition, controlling which previous dot each new dot
          // tweens from. 'group' (default): keyed per category, so dots stay in
          // their group and category-level enters/exits fade. 'flow': keyed by
          // global order, so the anonymous crowd migrates across a regroup (the
          // circles-to-bars effect). 'identity': keyed by each datum's id/name,
          // so a SPECIFIC unit migrates across any regroup/relayout keeping its
          // colour and size (needs the object form with unique ids/names).
          transition: "group",
          // What ONE unit looks like. Independent of `layout`, which is where
          // the units go: `positions:'heart'` with `shape:'pictogram'` arranges
          // glyphs into a heart, and every other pairing is equally valid.
          //
          // 'circle' | 'square' | 'image' (a raster / multi-colour icon,
          // fetched) | 'pictogram' (a vector glyph, drawn - see `pictogram`).
          shape: "circle",
          // Icon used when shape:'image'. Each unit renders this icon at the
          // given size. Set `tint:true` to recolour a monochrome icon to the
          // category colour (or a per-unit fillColor) so the pictogram matches
          // the legend; leave it off for multi-colour icons that should keep
          // their own colours.
          //
          // Prefer `shape:'pictogram'` for a monochrome glyph. Tinting an
          // <image> needs an SVG filter per colour, and a filter forces an
          // offscreen surface PER ELEMENT on every paint: measured on this
          // repo's cost lab, 2000 tinted icons cost ~10x what 2000 drawn
          // glyphs cost, and the gather drops frames well before 2000.
          image: {
            src: void 0,
            width: 20,
            height: 20,
            tint: false
          },
          // `shape: 'pictogram'`. A glyph is DRAWN, not fetched: one <path> per
          // unit, filled in that unit's own colour, so it needs no request, no
          // decode and no recolour filter.
          //
          // `mark` is the glyph: the name of one registered with
          // `ApexCharts.registerUnitMark`, a `{path, viewBox?, fillRule?}`
          // object, raw path data, or an ARRAY (one per series). A single datum
          // overrides all of it with its own `mark`, exactly as `fillColor`
          // overrides the category colour - so one crowd can mix glyphs.
          //
          // There is deliberately no size here. A glyph is fitted to the box
          // the dot itself would have occupied, so `size` and `spacing` size a
          // pictogram exactly as they size a dot and swapping circle ->
          // pictogram never re-flows the chart. `fit` picks which side of the
          // glyph binds to that box, `scale` nudges glyphs that read light, and
          // `padding` (0..0.9 of the pitch) opens the lattice up.
          //
          // One caveat worth knowing: a filled glyph is hit-tested over its
          // INK, not its box, so the tooltip tracks the glyph exactly - it
          // closes in the gap between a person's legs and reopens on the next
          // glyph. Chunky glyphs therefore both read and BEHAVE better than
          // fine ones; a hairline glyph reads as flickery while sweeping a
          // crowd. There is no portable fix (`pointer-events: bounding-box` is
          // Chrome only).
          pictogram: {
            mark: void 0,
            fit: "contain",
            // 'contain' (longest side) | 'width' | 'height'
            scale: 1,
            padding: 0,
            fallback: "circle"
            // drawn when a mark cannot be resolved
          },
          // dot radius in px, or 'auto' to size dots so the largest cluster
          // fits its allotted box.
          size: "auto",
          // The 'columns' layout can size its dots independently of `size`
          // (which the circle layouts / storyboard beats often pin to a
          // constant so dots do not resize while migrating). 'inherit' uses
          // `size`; 'auto' sizes the dots to fill the plot height; a number
          // pins a columns-only size. Circle / square only (image icons keep
          // their intrinsic size).
          columns: {
            size: "inherit"
          },
          // The 'grid' (waffle) layout: one lattice of cells filled in category
          // order. `columns` = cells per row. `total` (optional) fixes the cell
          // budget - e.g. 100 for a percentage waffle - and largest-remainder
          // allocates the cells to categories; leave it undefined for one cell
          // per unit (respects unitValue / maxUnits). `fillFrom` picks the first
          // row: 'bottom' (default) or 'top'.
          //
          // `split:true` switches to SMALL MULTIPLES: one mini-waffle per
          // category, arranged in a near-square trellis (or `tileColumns` per
          // row). Each tile then has `total` cells (default 100) and fills a
          // fraction equal to the category's value over `max` (default = the
          // largest count, so the leader fills its tile; set `max:100` with
          // percentage data for true "of 100" tiles). The unfilled cells show as
          // a faint `trackColor` backdrop, and each tile gets its own label.
          grid: {
            columns: 10,
            total: void 0,
            fillFrom: "bottom",
            // small-multiple (one waffle per category) mode + its knobs:
            split: false,
            // tiles per row; undefined = auto (near-square).
            tileColumns: void 0,
            // value -> filled-cell denominator; undefined = the largest count.
            max: void 0,
            // colour of the empty "track" cells; undefined = a neutral grey.
            trackColor: void 0
          },
          // The 'scatter' layout places each unit on real value axes (needs the
          // object-form data). Two modes via `y`:
          //  - `y:'lanes'` (default): a BEESWARM. X is the per-unit value axis,
          //    Y is a category lane. `spread:'swarm'` packs dots off the centre
          //    line so equal values do not overlap; 'jitter' scatters randomly.
          //  - `y:'value'`: a 2D value-value scatter. X = each datum's `x`, Y =
          //    each datum's `y`, on two numeric axes; category = colour.
          // `sizeRange:[min,max]` turns dots into BUBBLES scaled (by area) from
          // each datum's `sizeField` (default 'z') - a bubble scatter / bubble
          // beeswarm. `tickAmount`/`xMin`/`xMax`/`xTitle`/`xFormatter` control the
          // X axis; the `y*` twins the Y axis (2D only); `laneLabelWidth` the
          // lane-label gutter (lanes mode); `gridlines` the grid.
          scatter: {
            y: "lanes",
            spread: "swarm",
            // Beeswarm orientation (1D lanes mode only): 'horizontal' lays the
            // value on the X axis with category lanes stacked on Y (default);
            // 'vertical' lays the value on the Y axis with category lanes as
            // columns across X. Ignored for the 2D value-value scatter (y:'value').
            orientation: "horizontal",
            tickAmount: 5,
            xMin: void 0,
            xMax: void 0,
            xTitle: void 0,
            // (value) => string
            xFormatter: void 0,
            yTickAmount: 5,
            yMin: void 0,
            yMax: void 0,
            yTitle: void 0,
            // (value) => string
            yFormatter: void 0,
            // bubble sizing: datum key for the size value + [minR, maxR] in px.
            sizeField: "z",
            sizeRange: void 0,
            laneLabelWidth: void 0,
            gridlines: true
          },
          // Opt-in bubble sizing: scale each dot's radius by its per-unit value
          // (needs the object-form data). Circle shape only; the lattice is
          // spaced for the largest bubble so dots never overlap.
          sizeByValue: {
            enabled: false,
            // radius (px) for the largest value, or 'auto' to fit the largest
            // bubble to the plot like uniform auto-sizing.
            maxRadius: "auto",
            // radius (px) for the smallest value; defaults to ~35% of maxRadius.
            minRadius: void 0,
            // 'area' (bubble AREA proportional to value) | 'linear'.
            scale: "area"
          },
          // packing gap factor between spiral shells (1 = dots touch).
          spacing: 1.05,
          // corner radius for shape:'square'.
          borderRadius: 0,
          // How marks move between layouts on an update, and where entering
          // marks come from.
          //
          // `motion`: 'spring' settles each mark on a damped spring, so a
          // gather interrupted by the next update carries the marks' velocity
          // into it instead of restarting them from a standstill - which is
          // what a dragged slider or a scrubbed storyboard does on almost every
          // frame. 'tween' runs the fixed-duration ease below instead. 'auto'
          // (the default) is spring, unless `easing` was set to something other
          // than the default, so an explicit curve keeps working without having
          // to set `motion` as well.
          //
          // `spring`: 'crisp' (default) | 'gentle' (softer, for large reflows)
          // | 'snappy' (faster, a hint of settle). Scaled by
          // `chart.animations.speed`, which stretches the spring in time
          // without making it bouncier.
          //
          // `easing` (tween only): 'outCubic' (default: decelerate to a stop) |
          // 'inOutCubic' (accelerate gently out of rest, weighted travel) |
          // 'outBack' (overshoot each mark past its slot and spring back - a
          // per-mark settle), with `overshoot` tuning the spring strength.
          //
          // `enter`: where a fresh / appearing mark animates FROM - 'burst'
          // (default: fly out from the cluster centre) | 'fade' (materialise in
          // place) | 'rise' (fade in while drifting gently up into the slot).
          //
          // Colour, radius and opacity always stay on the out-cubic, under
          // either motion (a back ease overshoots past 1, which would push RGB
          // channels / radii out of range; and the spring's rest thresholds are
          // absolute, so they are far too coarse for a 0..1 quantity).
          gather: {
            motion: "auto",
            spring: "crisp",
            easing: "outCubic",
            overshoot: 1.70158,
            enter: "burst"
          },
          // The 'arc' layout arranges marks as a PARLIAMENT / hemicycle: seats in
          // concentric arced rows across an annulus, filled in category order so
          // each category is a contiguous wedge (the classic seating chart). Angles
          // use the radialBar convention (0 = top, clockwise); the default sweep is
          // a top semicircle (a full circle = startAngle 0, endAngle 360).
          // `innerRadiusRatio` is the donut hole (inner radius / outer); `rows`
          // fixes the number of seat rows, or 'auto' to size the dots as large as
          // fit. Like 'packed' the legend carries the category names (no per-wedge
          // labels).
          arc: {
            startAngle: -90,
            endAngle: 90,
            innerRadiusRatio: 0.4,
            rows: "auto"
          },
          // 1 dot represents this many units of value (waffle scaling).
          unitValue: 1,
          // safety cap on total dots; counts scale down proportionally above it.
          maxUnits: 5e3,
          // packed layout: order categories smallest-first so the minority
          // group nests in the centre of the blob.
          sortByGroup: true,
          clusterLabels: {
            show: true,
            // Label placement relative to the cluster/bar: 'top' (default) or
            // 'bottom'. A 'bottom' label is always straight; the curved arc
            // (below) rides the top crown only.
            position: "top",
            curved: true,
            fontSize: "13px",
            fontFamily: void 0,
            fontWeight: 600,
            // defaults to the cluster's own colour when undefined.
            color: void 0,
            offsetY: 0,
            // (name, { seriesIndex, value, percent, w }) => string.
            // Return "\n"-separated text to split an outer label over lines.
            formatter: void 0,
            // Outer (name) labels, as pie/donut draw them: the label sits in the
            // margin beside the shape and a leader line joins it to the colour
            // band it names, so the crowd needs no legend to be read.
            //
            // `layout: 'custom'` only, and best on a silhouette whose categories
            // stack vertically (the default row ordering): those alternate down
            // the left and right gutters. A column-ordered shape sends each
            // label to the side its own band sits on.
            //
            // The margin is taken off BOTH sides so the shape stays centred,
            // which means turning this on makes the silhouette a little smaller.
            external: {
              show: false,
              connector: {
                show: true,
                width: 1.5,
                // defaults to the band's own colour when undefined.
                color: void 0,
                // air between the band's outermost dot and the line's bend.
                gap: 8,
                // length of the run out to the label.
                length: 22
              },
              offsetX: 0,
              offsetY: 0
            }
          },
          tooltip: {
            // Per-unit tooltip body. Each dot carries its category (seriesIndex)
            // and its index within that category (dataPointIndex), so the
            // formatter can look up per-unit data and return a string/HTML.
            // ({ seriesName, seriesIndex, dataPointIndex, count, unitValue,
            //    color, w }) => string
            // Default: "#<dataPointIndex+1> of <count>".
            formatter: void 0
          }
        },
        radialBar: {
          inverseOrder: false,
          startAngle: 0,
          endAngle: 360,
          offsetX: 0,
          offsetY: 0,
          // Gauge sub-shape. 'arc' (default) renders the existing filled
          // value-arc gauge; 'needle' replaces the value-arc with a rotating
          // pointer/needle. Bands and ticks are independent and work for both
          // shapes.
          shape: "arc",
          // Value-to-angle mapping. Defaults to the existing 0..100 range
          // used by radialBar. Override for gauges that need a custom domain
          // (e.g. min: 0, max: 240 for a speedometer).
          min: 0,
          max: 100,
          // Threshold bands rendered as colored arc segments along the gauge
          // arc (e.g. [{from:0,to:30,color:'#FF4560'}, ...]). Bands draw
          // behind the value-arc and tick marks. Set to [] (default) to
          // disable.
          bands: [],
          bandsStyle: {
            // % of arc radius. Slightly less than the value-arc stroke so
            // the value-arc reads on top by default.
            strokeWidth: "40%",
            // px gap between consecutive bands.
            gap: 0,
            // Hide the track when bands cover the full range; the bands
            // themselves act as the visual backdrop.
            hideTrackWhenPresent: true
          },
          // Tick marks rendered along (outside) the gauge arc.
          ticks: {
            show: false,
            major: {
              count: 11,
              length: 10,
              width: 2,
              color: "#666",
              // 'inside' draws ticks from `radius - length` to `radius`;
              // 'outside' draws from `radius` to `radius + length`.
              placement: "outside"
            },
            minor: {
              count: 4,
              // minor ticks BETWEEN each pair of major ticks
              length: 5,
              width: 1,
              color: "#999",
              placement: "outside"
            },
            labels: {
              show: false,
              offset: 6,
              fontSize: "11px",
              fontFamily: void 0,
              fontWeight: 400,
              color: "#666",
              /** @param {number} v */
              formatter(v) {
                return String(v);
              }
            }
          },
          // Needle/dial configuration. Only applies when `shape: 'needle'`.
          needle: {
            color: "#333",
            // Needle length as a % of the gauge radius (string like '85%')
            // or as an absolute px number.
            length: "85%",
            // px width of the needle line at the base.
            baseWidth: 4,
            // px width of the needle tip (tapered if smaller than baseWidth).
            tipWidth: 1,
            // px offset from the geometric arc center on Y. Positive values
            // push the needle base down (toward the chord midpoint of a
            // ∩-shape gauge); negative pushes up. The needle rotates around
            // this shifted point.
            offsetY: 0,
            // When true, also render the filled value-arc alongside the
            // needle. Default false preserves the previous needle-only
            // behavior. Useful for gauges that want a progress ring plus a
            // pointer indicator.
            showValueArc: false,
            animation: {
              enabled: true,
              duration: 800,
              easing: "ease-out"
            }
          },
          hollow: {
            margin: 5,
            size: "50%",
            background: "transparent",
            image: void 0,
            imageWidth: 150,
            imageHeight: 150,
            imageOffsetX: 0,
            imageOffsetY: 0,
            imageClipped: true,
            position: "front",
            // Optional stroke around the hollow ring. Combined with
            // `strokeDasharray` this produces a dashed indicator circle
            // around the value text — useful for gauge designs where the
            // value sits inside its own boundary.
            stroke: void 0,
            strokeWidth: 1,
            strokeDasharray: void 0,
            dropShadow: {
              enabled: false,
              top: 0,
              left: 0,
              blur: 3,
              color: "#000",
              opacity: 0.5
            }
          },
          track: {
            show: true,
            startAngle: void 0,
            endAngle: void 0,
            background: "#f2f2f2",
            strokeWidth: "97%",
            opacity: 1,
            margin: 5,
            // margin is in pixels
            dropShadow: {
              enabled: false,
              top: 0,
              left: 0,
              blur: 3,
              color: "#000",
              opacity: 0.5
            }
          },
          dataLabels: {
            show: true,
            name: {
              show: true,
              fontSize: "16px",
              fontFamily: void 0,
              fontWeight: 600,
              color: void 0,
              offsetY: 0,
              /**
               * @param {any} val
               */
              formatter(val) {
                return val;
              }
            },
            value: {
              show: true,
              fontSize: "14px",
              fontFamily: void 0,
              fontWeight: 400,
              color: void 0,
              offsetY: 16,
              /**
               * @param {any} val
               */
              formatter(val) {
                return val + "%";
              }
            },
            total: {
              show: false,
              label: "Total",
              fontSize: "16px",
              fontWeight: 600,
              fontFamily: void 0,
              color: void 0,
              /**
               * @param {import('../../types/internal').ChartStateW} w
               */
              formatter(w) {
                return (
                  /**
                   * @param {number} a
                   * @param {number} b
                   */
                  w.globals.seriesTotals.reduce((a2, b) => a2 + b, 0) / w.seriesData.series.length + "%"
                );
              }
            }
          },
          barLabels: {
            enabled: false,
            offsetX: 0,
            offsetY: 0,
            useSeriesColors: true,
            fontFamily: void 0,
            fontWeight: 600,
            fontSize: "16px",
            /**
             * @param {any} val
             */
            formatter(val) {
              return val;
            },
            onClick: void 0
          }
        },
        pie: {
          customScale: 1,
          offsetX: 0,
          offsetY: 0,
          startAngle: 0,
          endAngle: 360,
          expandOnClick: true,
          // How far a clicked slice slides out of the pie (px), measured along
          // its own mid-angle. The slice is translated, not redrawn at a bigger
          // radius, so its shape and the quantity it encodes are unchanged and
          // a gap opens between it and the rest of the pie. The inner
          // percentage label (and the outer name label, when enabled) ride
          // along with it. Ignored for polarArea, where the radius is the
          // value, and in a drilldown pie/donut, where a click navigates (the
          // slice would slide out only to be discarded by the drill, and
          // states.active takes the click feedback back over). Set 0 to keep
          // the slice in place.
          expandOffset: 10,
          // Hover outline: a translucent band traced just outside the rim of
          // the hovered slice, so the slice keeps its own colour instead of
          // being lightened. Takes the place of the states.hover filter for
          // pie / donut / polarArea, and is skipped entirely when
          // states.hover.filter.type is 'none' (that stays the way to turn all
          // hover feedback off). Applies to pie, donut and polarArea.
          hoverOutline: {
            show: true,
            size: 8,
            // band thickness (px)
            // Extra clearance between the slice rim and the band (px), ON TOP
            // of the slice stroke: the band always starts at the outer edge of
            // the stroke, never under it. Default 0, because a stroke is
            // normally present (stroke.width defaults to 2) and already reads
            // as the separation. Any gap beyond that and the band stops
            // belonging to its slice and starts reading as a ring of its own.
            gap: 0,
            opacity: 0.3,
            // band opacity, over the slice colour
            color: void 0
            // defaults to the hovered slice's colour
          },
          // Rounds the corners of each slice (in px). Applies to pie, donut and
          // polarArea (all rendered by the Pie module). 0 = sharp corners
          // (default, unchanged behavior). The value is clamped per slice so
          // opposing corner fillets never cross on thin/narrow slices.
          borderRadius: 0,
          // Gap between adjacent slices (in px). Applies to pie, donut and
          // polarArea. 0 = slices touch (default). Each slice is inset
          // symmetrically, so its mid-angle (data label + hit region) is kept.
          spacing: 0,
          dataLabels: {
            // These are the percentage values which are displayed on slice
            offset: 0,
            // offset by which labels will move outside
            minAngleToShowLabel: 10,
            // External (outer) labels: render the category/series name outside
            // the slice, joined to it by a leader (connector) line, so users
            // don't have to map legend colors back to slices. The percentage
            // keeps rendering inside the slice (governed by dataLabels.enabled).
            // Pie + donut only; ignored for polarArea (radial length already
            // encodes the value there).
            external: {
              show: false,
              // master switch for the external (outer) labels
              offsetX: 0,
              offsetY: 0,
              fontSize: void 0,
              // falls back to dataLabels.style.fontSize
              fontFamily: void 0,
              // falls back to dataLabels.style.fontFamily
              fontWeight: void 0,
              // falls back to dataLabels.style.fontWeight
              color: void 0,
              // defaults to chart.foreColor (readable text)
              /**
               * Return a string (single line) or an array of strings (stacked
               * lines, e.g. [name, percent + '%']).
               * @param {string} name
               * @param {{ seriesIndex: number, percent: number, value: number, w: any }} opts
               * @returns {string | string[]}
               */
              formatter: void 0,
              connector: {
                show: true,
                width: 1,
                color: void 0,
                // defaults to the slice color
                length: 16,
                // horizontal run after the radial elbow (px)
                gap: 6
                // radial gap from slice edge to the elbow point (px)
              }
            }
          },
          donut: {
            size: "65%",
            background: "transparent",
            labels: {
              // These are the inner labels appearing inside donut
              show: false,
              name: {
                show: true,
                fontSize: "16px",
                fontFamily: void 0,
                fontWeight: 600,
                color: void 0,
                offsetY: -10,
                /**
                 * @param {any} val
                 */
                formatter(val) {
                  return val;
                }
              },
              value: {
                show: true,
                fontSize: "20px",
                fontFamily: void 0,
                fontWeight: 400,
                color: void 0,
                offsetY: 10,
                /**
                 * @param {any} val
                 */
                formatter(val) {
                  return val;
                }
              },
              total: {
                show: false,
                showAlways: false,
                label: "Total",
                fontSize: "16px",
                fontWeight: 400,
                fontFamily: void 0,
                color: void 0,
                /**
                 * @param {import('../../types/internal').ChartStateW} w
                 */
                formatter(w) {
                  return w.globals.seriesTotals.reduce((a2, b) => a2 + b, 0);
                }
              }
            }
          }
        },
        polarArea: {
          rings: {
            strokeWidth: 1,
            strokeColor: "#e8e8e8"
          },
          spokes: {
            strokeWidth: 1,
            connectorColors: "#e8e8e8"
          }
        },
        sunburst: {
          // Sunburst / nested pie-donut (hierarchical radial). Rings go from the
          // centre hole outward, one per hierarchy level; each child arc is
          // nested inside its parent's angular wedge.
          offsetX: 0,
          offsetY: 0,
          startAngle: 0,
          endAngle: 360,
          // Centre hole radius, as a % of the max radius (like donut size).
          innerSize: "15%",
          // Corner rounding + inter-arc gap (px), same semantics as the pie
          // family (see plotOptions.pie.borderRadius / .spacing).
          borderRadius: 0,
          spacing: 1,
          // How a branch that bottoms out before the deepest level is drawn:
          // 'extend' stretches the leaf arc out to the rim (default, matches
          // d3); 'stop' leaves the outer rings empty behind it.
          leaf: "extend",
          // Angular partition of a parent's wedge among its children:
          // 'normalize' splits by each child's share of its siblings (safe for
          // any data); 'strict' expects children to sum to the parent's value.
          partition: "normalize",
          // Each depth level is tinted this much lighter than its parent colour
          // (0 = keep parent colour, 1 = white). A per-node `color` overrides.
          tint: 0.14,
          // Click a wedge to zoom into that branch (its subtree fills the
          // chart; a breadcrumb walks back). Click the focused inner ring to
          // zoom out. Set false to disable.
          zoomOnClick: true,
          dataLabels: {
            show: true,
            // Hide the label on any arc narrower than this (degrees), so tiny
            // wedges do not overflow with text.
            minAngleToShow: 8,
            style: {
              fontSize: "12px",
              fontFamily: void 0,
              fontWeight: 400,
              colors: void 0
            }
          }
        },
        radar: {
          size: void 0,
          offsetX: 0,
          offsetY: 0,
          polygons: {
            // strokeColor: '#e8e8e8', // should be deprecated in the minor version i.e 3.2
            strokeWidth: 1,
            strokeColors: "#e8e8e8",
            connectorColors: "#e8e8e8",
            fill: {
              colors: void 0
            }
          }
        }
      },
      colors: void 0,
      dataLabels: {
        enabled: true,
        enabledOnSeries: void 0,
        /**
         * @param {any} val
         */
        formatter(val) {
          return val !== null ? val : "";
        },
        textAnchor: "middle",
        distributed: false,
        offsetX: 0,
        offsetY: 0,
        style: {
          fontSize: "12px",
          fontFamily: void 0,
          fontWeight: 600,
          colors: void 0
        },
        background: {
          enabled: true,
          foreColor: "#fff",
          backgroundColor: void 0,
          borderRadius: 2,
          padding: 4,
          opacity: 0.9,
          borderWidth: 1,
          borderColor: "#fff",
          dropShadow: {
            enabled: false,
            top: 1,
            left: 1,
            blur: 1,
            color: "#000",
            opacity: 0.8
          }
        },
        dropShadow: {
          enabled: false,
          top: 1,
          left: 1,
          blur: 1,
          color: "#000",
          opacity: 0.8
        },
        // Ride data labels to their new position on a data-change update
        // instead of snapping. ON by default: the bars, the markers and the
        // axis ticks all already reflow on one clock, so a label that jumps to
        // its final slot on the first frame is the odd one out, it arrives
        // several hundred ms before the bar it belongs to. Speed/easing follow
        // chart.animations.dynamicAnimation, and a label that has not moved is
        // a per-label no-op. Bar/column only.
        animate: {
          enabled: true
        },
        // Count the numeric value up/down from its previous value on update,
        // like countUp.js. Off by default. The dataLabels.formatter runs each
        // frame, so number formatting (decimals, separators, prefixes) is
        // preserved. Bar/column only.
        countUp: {
          enabled: false
        }
      },
      fill: {
        type: "solid",
        colors: void 0,
        // array of colors
        opacity: 0.85,
        gradient: {
          shade: "dark",
          type: "horizontal",
          shadeIntensity: 0.5,
          gradientToColors: void 0,
          inverseColors: true,
          opacityFrom: 1,
          opacityTo: 1,
          stops: [0, 50, 100],
          colorStops: []
        },
        image: {
          src: [],
          width: void 0,
          // optional
          height: void 0
          // optional
        },
        pattern: {
          style: "squares",
          // String | Array of Strings
          width: 6,
          height: 6,
          strokeWidth: 2
        }
      },
      forecastDataPoints: {
        count: 0,
        fillOpacity: 0.5,
        strokeWidth: void 0,
        dashArray: 4
      },
      grid: {
        show: true,
        borderColor: "#e0e0e0",
        strokeDashArray: 0,
        position: "back",
        xaxis: {
          lines: {
            show: false
          }
        },
        yaxis: {
          lines: {
            show: true
          }
        },
        row: {
          colors: void 0,
          // takes as array which will be repeated on rows
          opacity: 0.5
        },
        column: {
          colors: void 0,
          // takes an array which will be repeated on columns
          opacity: 0.5
        },
        padding: {
          top: 0,
          right: 10,
          bottom: 0,
          left: 12
        }
      },
      labels: [],
      drilldown: {
        // Opt-in. When false, the Drilldown feature module stays inert even if
        // it was imported. Requires `import 'apexcharts/features/drilldown'`.
        enabled: false,
        // Child levels referenced by a data point's `drilldown: '<id>'` field.
        // Each: { id, name?, data, chart?, xaxis?, yaxis?, colors?, plotOptions? }
        series: [],
        breadcrumb: {
          show: true,
          position: "top-left",
          // 'top-left' | 'top-right'
          separator: " / ",
          rootLabel: "All",
          offsetX: 0,
          offsetY: 0
          // formatter: (label, { index, depth }) => label,
        },
        // Animation is delegated to the chart's update pipeline; `enabled`
        // gates whether the drill transition animates at all.
        animation: {
          enabled: true,
          // Anchor the drill transition at the clicked point: the child unfolds
          // outward from it (and settles back on drill-up) instead of the chart
          // simply re-rendering. A gentle scale layered on the SVG; opt-in.
          zoomFromPoint: false,
          // Base duration (ms) of the transition, used only when zoomFromPoint
          // is true. The fade-out phase runs a little shorter than this.
          speed: 260
        },
        // Optional async resolver, called when a drillable point has no inline
        // match in `series`. Receives ({ id, point, seriesIndex, dataPointIndex })
        // and returns a level (or a promise of one). A throw, a rejection, or a
        // resolved value without a `data` array leaves the chart exactly where
        // it was and fires `drillDownError` - a failed fetch is ordinary, not
        // a reason to strand the view.
        // onDrillDown: undefined,
        // Overlay shown while an async level resolves. `text` is optional: with
        // none, the spinner shows alone (and carries 'Loading' as its
        // accessible name), which keeps the default free of any language.
        loading: {
          show: true
          // text: 'Loading…',
        },
        // Cache levels resolved by `onDrillDown`, keyed by id, so drilling back
        // down a branch does not re-fetch it. Call `chart.drillDown` module's
        // clearCache() when the data behind an already-drilled chart changes.
        cache: true,
        // The dot that marks a drillable point on a line/area chart drawn
        // without markers. A bar, slice, tile or cell is already a visible,
        // clickable mark; a line point is not, so without this the chart would
        // give no sign that anything can be opened. Only drillable points get
        // one, which is what makes them read as openable. Set `show: false` to
        // supply your own affordance (turning `markers.size` on, for instance).
        // Omitted colours inherit the series marker defaults.
        marker: {
          show: true,
          size: 6,
          // shape: undefined,      // 'circle' | 'square' | 'rect'
          // fillColor: undefined,  // defaults to the series colour
          strokeColor: "#fff"
        }
      },
      legend: {
        show: true,
        showForSingleSeries: false,
        showForNullSeries: true,
        showForZeroSeries: true,
        floating: false,
        position: "bottom",
        // whether to position legends in 1 of 4
        // direction - top, bottom, left, right
        horizontalAlign: "center",
        // when position top/bottom, you can specify whether to align legends left, right or center
        inverseOrder: false,
        fontSize: "12px",
        fontFamily: void 0,
        fontWeight: 400,
        width: void 0,
        height: void 0,
        formatter: void 0,
        tooltipHoverFormatter: void 0,
        offsetX: -20,
        offsetY: 4,
        customLegendItems: [],
        clusterGroupedSeries: true,
        clusterGroupedSeriesOrientation: "vertical",
        labels: {
          colors: void 0,
          useSeriesColors: false
        },
        markers: {
          size: 7,
          fillColors: void 0,
          strokeWidth: 1,
          shape: void 0,
          offsetX: 0,
          offsetY: 0,
          customHTML: void 0,
          onClick: void 0
        },
        itemMargin: {
          horizontal: 5,
          vertical: 4
        },
        onItemClick: {
          toggleDataSeries: true
        },
        onItemHover: {
          highlightDataSeries: true
        }
      },
      markers: {
        discrete: [],
        size: 0,
        colors: void 0,
        strokeColors: "#fff",
        strokeWidth: 2,
        strokeOpacity: 0.9,
        strokeDashArray: 0,
        fillOpacity: 1,
        shape: "circle",
        offsetX: 0,
        offsetY: 0,
        showNullDataPoints: true,
        onClick: void 0,
        onDblClick: void 0,
        hover: {
          size: void 0,
          sizeOffset: 3
        },
        // OPT-IN (0 = off). Above this many points in a series, that series'
        // markers are drawn as ONE path element per marker size, carrying a
        // subpath per point, instead of one element per point. Each per-point
        // element costs a node, ~16 attribute writes and an appendChild, which
        // is why markers dominate a large render: 2000 of them take 15ms of an
        // 18ms render, and batched they take 1ms.
        //
        // This covers the markers `showNullDataPoints` adds implicitly, not
        // just the ones asked for: every point beside a null is isolated and
        // gets its own dot, so a 2000-point series with half its values null
        // built ~1000 elements even at markers.size 0. Batched that render goes
        // from 15ms to 3.7ms, and 5000 points from 37ms to 5.9ms. Those dots
        // are a different size from the configured ones, hence one path per
        // size rather than one per series.
        //
        // Off by default because it is NOT pixel-identical where markers
        // overlap, and above ~1000 points in a normal-width chart they always
        // do. One path is rasterized as a single region, so overlapping markers
        // lose their individual outlines: all the fills paint, then all the
        // strokes, and the seams between neighbours disappear. Dense clusters
        // read flatter (measured 1-9% of pixels, scaling with density). Sparse
        // markers that do not touch are unaffected.
        //
        // Only applies where markers are already non-interactive and uniform (a
        // plain line/area with the default sweep tooltip, no discrete markers,
        // no per-point colours, no marker click handlers, no dataPointSelection
        // handler). A batched series has no `.apexcharts-marker` nodes, so the
        // hover dot is served by the tooltip's own marker (the same one
        // markers.size: 0 charts use), the keyboard focus ring lands on that
        // marker, and the per-marker reveal / stream ride is replaced by the
        // series-level fade.
        largeDatasetThreshold: 0
      },
      noData: {
        text: void 0,
        align: "center",
        offsetX: 0,
        offsetY: 0,
        style: {
          color: void 0,
          fontSize: "14px",
          fontFamily: void 0
        }
      },
      responsive: [],
      // breakpoints should follow ascending order 400, then 700, then 1000
      series: void 0,
      states: {
        hover: {
          filter: {
            type: "lighten",
            value: 0.15
          }
        },
        active: {
          allowMultipleDataPointsSelection: false,
          filter: {
            type: "darken",
            value: 0.35
          }
        }
      },
      title: {
        text: void 0,
        align: "left",
        margin: 5,
        offsetX: 0,
        offsetY: 0,
        floating: false,
        style: {
          fontSize: "14px",
          fontWeight: 900,
          fontFamily: void 0,
          color: void 0
        }
      },
      subtitle: {
        text: void 0,
        align: "left",
        margin: 5,
        offsetX: 0,
        offsetY: 30,
        floating: false,
        style: {
          fontSize: "12px",
          fontWeight: 400,
          fontFamily: void 0,
          color: void 0
        }
      },
      stroke: {
        show: true,
        curve: "smooth",
        // "smooth" / "straight" / "monotoneCubic" / "stepline" / "linestep"
        lineCap: "butt",
        // round, butt , square
        width: 2,
        colors: void 0,
        // array of colors
        dashArray: 0,
        // single value or array of values
        fill: {
          type: "solid",
          colors: void 0,
          // array of colors
          opacity: 0.85,
          gradient: {
            shade: "dark",
            type: "horizontal",
            shadeIntensity: 0.5,
            gradientToColors: void 0,
            inverseColors: true,
            opacityFrom: 1,
            opacityTo: 1,
            stops: [0, 50, 100],
            colorStops: []
          }
        }
      },
      tooltip: {
        enabled: true,
        enabledOnSeries: void 0,
        shared: true,
        hideEmptySeries: false,
        followCursor: false,
        // when disabled, the tooltip will show on top of the series instead of mouse position
        intersect: false,
        // when enabled, tooltip will only show when user directly hovers over point
        inverseOrder: false,
        arrow: true,
        // One tight line instead of a card: the x label sits inline before
        // the value, the marker goes, the padding and font shrink. For panels
        // a normal card would cover (small multiples, sparklines, tiles). A
        // single-series chart drops the series-name label too; with several
        // series the names stay, because they are what tells the rows apart.
        compact: false,
        custom: void 0,
        fillSeriesColor: false,
        theme: "light",
        cssClass: "",
        style: {
          fontSize: "12px",
          fontFamily: void 0,
          background: void 0
        },
        onDatasetHover: {
          highlightDataSeries: false
        },
        x: {
          // x value
          show: true,
          format: "dd MMM",
          // dd/MM, dd MMM yy, dd MMM yyyy
          formatter: void 0
          // a custom user supplied formatter function
        },
        y: {
          formatter: void 0,
          title: {
            /**
             * @param {string} seriesName
             */
            formatter(seriesName) {
              return seriesName ? seriesName + ": " : "";
            }
          }
        },
        z: {
          formatter: void 0,
          title: "Size: "
        },
        marker: {
          show: true,
          fillColors: void 0
        },
        items: {
          display: "flex"
        },
        fixed: {
          enabled: false,
          position: "topRight",
          // topRight, topLeft, bottomRight, bottomLeft
          offsetX: 0,
          offsetY: 0
        }
      },
      xaxis: {
        type: "category",
        categories: [],
        convertedCatToNumeric: false,
        // internal property which should not be altered outside
        offsetX: 0,
        offsetY: 0,
        overwriteCategories: void 0,
        labels: {
          show: true,
          rotate: -45,
          rotateAlways: false,
          hideOverlappingLabels: true,
          trim: false,
          minHeight: void 0,
          maxHeight: 120,
          showDuplicates: true,
          style: {
            colors: [],
            fontSize: "12px",
            fontWeight: 400,
            fontFamily: void 0,
            cssClass: ""
          },
          offsetX: 0,
          offsetY: 0,
          format: void 0,
          formatter: void 0,
          // custom formatter function which will override format
          datetimeUTC: true,
          datetimeFormatter: {
            // Base format per interval unit. TimeScale.formatDates folds in
            // coarser context automatically when the data range spans it
            // (e.g. month-scale across years → 'MMM yyyy', hour-scale across
            // days → 'dd MMM HH:mm'). Customizing a base format that already
            // includes the higher-unit token disables the auto-expansion for
            // that level.
            year: "yyyy",
            month: "MMM",
            day: "dd MMM",
            hour: "HH:mm",
            minute: "HH:mm",
            second: "HH:mm:ss"
          }
        },
        group: {
          groups: [],
          style: {
            colors: [],
            fontSize: "12px",
            fontWeight: 400,
            fontFamily: void 0,
            cssClass: ""
          }
        },
        axisBorder: {
          show: true,
          color: "#e0e0e0",
          width: "100%",
          height: 1,
          offsetX: 0,
          offsetY: 0
        },
        axisTicks: {
          show: true,
          color: "#e0e0e0",
          height: 6,
          offsetX: 0,
          offsetY: 0
        },
        stepSize: void 0,
        tickAmount: void 0,
        tickPlacement: "on",
        min: void 0,
        max: void 0,
        range: void 0,
        floating: false,
        decimalsInFloat: void 0,
        position: "bottom",
        title: {
          text: void 0,
          offsetX: 0,
          offsetY: 0,
          style: {
            color: void 0,
            fontSize: "12px",
            fontWeight: 900,
            fontFamily: void 0,
            cssClass: ""
          }
        },
        crosshairs: {
          show: true,
          width: 1,
          // tickWidth/barWidth or an integer
          position: "back",
          opacity: 0.9,
          stroke: {
            color: "#b6b6b6",
            width: 1,
            dashArray: 3
          },
          fill: {
            type: "solid",
            // solid, gradient
            color: "#B1B9C4",
            gradient: {
              colorFrom: "#D8E3F0",
              colorTo: "#BED1E6",
              stops: [0, 100],
              opacityFrom: 0.4,
              opacityTo: 0.5
            }
          },
          dropShadow: {
            enabled: false,
            left: 0,
            top: 0,
            blur: 1,
            opacity: 0.8
          }
        },
        tooltip: {
          enabled: false,
          offsetY: 0,
          formatter: void 0,
          style: {
            fontSize: "12px",
            fontFamily: void 0
          }
        }
      },
      yaxis: this.yAxis,
      theme: {
        mode: "",
        palette: "palette1",
        // If defined, it will overwrite globals.colors variable
        // Facet (#13): read `--apx-*` CSS design tokens from the cascade
        // (accent/fore/grid/surface + series-1..N). true (default) reads any
        // present (absence is a no-op); false disables. Tokens top the
        // resolution chain below explicit config. Tokens are re-read on every
        // render; call chart.refreshTokens() to pick up a runtime CSS change
        // that does not itself trigger a render.
        tokens: true,
        // Facet (#13): 'os' follows prefers-color-scheme + prefers-contrast
        // reactively (SSR-safe, cleaned up on destroy). false disables.
        follow: false,
        // 'os' | false
        // Facet (#13): a theme registered via ApexCharts.registerTheme(name, def)
        name: "",
        // '' | registered theme name
        monochrome: {
          // monochrome allows you to select just 1 color and fill out the rest with light/dark shade (intensity can be selected)
          enabled: false,
          color: "#008FFB",
          shadeTo: "light",
          shadeIntensity: 0.65
        },
        accessibility: {
          colorBlindMode: ""
          // '' | 'deuteranopia' | 'protanopia' | 'tritanopia' | 'highContrast'
        }
      }
    };
  }
}
const TYPE_OWNED = "_apexOwnedByType";
const ownedBy = (types, fn) => {
  const marked = (
    /** @type {any} */
    fn
  );
  marked[TYPE_OWNED] = types;
  return fn;
};
const TYPE_OWNED_PATHS = [
  // What the tooltip reads and how it resolves a hover. `custom` is the sharp
  // one: each built-in reads globals only its own type fills.
  "tooltip.custom",
  "tooltip.shared",
  "tooltip.intersect",
  "tooltip.followCursor",
  // Whether values are written on the marks, and how they are phrased. A pie's
  // percentage formatter handed a treemap a category name.
  "dataLabels.enabled",
  "dataLabels.formatter",
  "plotOptions.bar.dataLabels.position",
  // A box plot's outlier markers are hit targets; a violin draws none.
  "markers.size",
  // Hover and select feedback, off by design on the types that draw their own.
  "states.hover.filter.type",
  "states.active.filter.type",
  // Axis chrome that exists to be pointed at.
  "xaxis.crosshairs.width",
  "xaxis.tickPlacement",
  "xaxis.tooltip.enabled",
  // Interaction the type either supports or does not: a violin's categories
  // cannot be range-zoomed, and an index-keyed summary animates as churn.
  "chart.zoom.enabled",
  "chart.animations.dynamicAnimation.enabled"
];
const readPath = (obj, path) => {
  let cur = (
    /** @type {any} */
    obj
  );
  for (const key of path.split(".")) {
    if (cur == null || typeof cur !== "object") return void 0;
    cur = cur[key];
  }
  return cur;
};
const writePath = (obj, path, value) => {
  const keys = path.split(".");
  const last = keys.pop();
  let cur = (
    /** @type {any} */
    obj
  );
  for (const key of keys) {
    if (cur[key] == null || typeof cur[key] !== "object") cur[key] = {};
    cur = cur[key];
  }
  if (value === void 0) delete cur[
    /** @type {string} */
    last
  ];
  else cur[
    /** @type {string} */
    last
  ] = value;
};
const TYPE_ALIASES = {
  funnel: "bar",
  pyramid: "bar",
  gauge: "radialBar",
  waffle: "unit",
  histogram: "bar"
};
const typeOpts = (type, config) => {
  var _a, _b;
  const base = (
    /** @type {Record<string, string>} */
    TYPE_ALIASES[type]
  );
  return {
    chart: {
      type: base || type,
      requestedType: base ? type : void 0,
      // Stacking belongs to the chart, not to its type, so both sides see it.
      stacked: (_a = config.chart) == null ? void 0 : _a.stacked
    },
    plotOptions: {
      bar: { isFunnel: type === "funnel" || type === "pyramid" },
      histogram: (_b = config.plotOptions) == null ? void 0 : _b.histogram
    },
    // The histogram's defaults read the series to decide whether overlaid bins
    // share a tooltip. Both sides are asked with the series the chart has now.
    series: config.series,
    yaxis: [{ title: {}, labels: {}, axisBorder: {}, axisTicks: {} }]
  };
};
const isUntouched = (current, fromDefault) => {
  if (typeof current === "function") {
    if (Array.isArray(
      /** @type {any} */
      current[TYPE_OWNED]
    )) return true;
    return typeof fromDefault === "function" && String(current) === String(fromDefault);
  }
  if (typeof fromDefault === "function") return current === void 0;
  if (current === fromDefault) return true;
  try {
    return JSON.stringify(current) === JSON.stringify(fromDefault);
  } catch (e2) {
    return false;
  }
};
const getRangeValues = ({
  isTimeline,
  seriesIndex,
  dataPointIndex,
  y1,
  y2,
  w
}) => {
  var _a;
  let start = w.rangeData.seriesRangeStart[seriesIndex][dataPointIndex];
  let end = w.rangeData.seriesRangeEnd[seriesIndex][dataPointIndex];
  let ylabel = w.labelData.labels[dataPointIndex];
  let seriesName = w.config.series[seriesIndex].name ? w.config.series[seriesIndex].name : "";
  const yLbFormatter = w.formatters.ttKeyFormatter;
  const yLbTitleFormatter = w.config.tooltip.y.title.formatter;
  const opts = {
    w,
    seriesIndex,
    dataPointIndex,
    start,
    end
  };
  if (typeof yLbTitleFormatter === "function") {
    seriesName = yLbTitleFormatter(seriesName, opts);
  }
  if ((_a = w.config.series[seriesIndex].data[dataPointIndex]) == null ? void 0 : _a.x) {
    ylabel = w.config.series[seriesIndex].data[dataPointIndex].x;
  }
  if (!isTimeline) {
    if (w.config.xaxis.type === "datetime") {
      const xFormat = new Formatters(w);
      ylabel = xFormat.xLabelFormat(
        w.formatters.ttKeyFormatter,
        ylabel,
        ylabel,
        {
          i: void 0,
          dateFormatter: new DateTime(w).formatDate,
          w
        }
      );
    }
  }
  if (typeof yLbFormatter === "function") {
    ylabel = yLbFormatter(ylabel, opts);
  }
  if (Number.isFinite(y1) && Number.isFinite(y2)) {
    start = y1;
    end = y2;
  }
  let startVal = "";
  let endVal = "";
  const color = w.globals.colors[seriesIndex];
  if (w.config.tooltip.x.formatter === void 0) {
    if (w.config.xaxis.type === "datetime") {
      const datetimeObj = new DateTime(w);
      startVal = datetimeObj.formatDate(
        datetimeObj.getDate(start),
        w.config.tooltip.x.format
      );
      endVal = datetimeObj.formatDate(
        datetimeObj.getDate(end),
        w.config.tooltip.x.format
      );
    } else {
      startVal = start;
      endVal = end;
    }
  } else {
    startVal = w.config.tooltip.x.formatter(start);
    endVal = w.config.tooltip.x.formatter(end);
  }
  return { start, end, startVal, endVal, ylabel, color, seriesName };
};
const buildRangeTooltipHTML = (opts) => {
  let { color, seriesName, ylabel, start, end, seriesIndex, dataPointIndex } = opts;
  const formatter = opts.w.globals.tooltip.tooltipLabels.getFormatters(seriesIndex);
  start = formatter.yLbFormatter(start);
  end = formatter.yLbFormatter(end);
  const val = formatter.yLbFormatter(
    opts.w.seriesData.series[seriesIndex][dataPointIndex]
  );
  let valueHTML = "";
  const rangeValues = `<span class="value start-value">
  ${start}
  </span> <span class="separator">-</span> <span class="value end-value">
  ${end}
  </span>`;
  if (opts.w.globals.comboCharts) {
    if (opts.w.config.series[seriesIndex].type === "rangeArea" || opts.w.config.series[seriesIndex].type === "rangeBar") {
      valueHTML = rangeValues;
    } else {
      valueHTML = `<span>${val}</span>`;
    }
  } else {
    valueHTML = rangeValues;
  }
  return '<div class="apexcharts-tooltip-rangebar"><div> <span class="series-name" style="color: ' + color + '">' + (seriesName ? seriesName : "") + '</span></div><div> <span class="category">' + ylabel + ": </span> " + valueHTML + " </div></div>";
};
class Defaults {
  /**
   * @param {Record<string, any>} opts
   */
  constructor(opts) {
    this.opts = opts;
  }
  /**
   * The defaults a chart type chooses for itself, which is the same pick
   * Config.init makes on the initial render. Shared with the update path so
   * that "what does type X want" has one answer and cannot drift between the
   * two. Modes layered on top of a type (brush, slope, sparkline) are not
   * included: they belong to the chart, not to its type, and a type change does
   * not disturb them.
   *
   * @param {Record<string, any>} opts a config, read for the type and for the
   *   flags that pick a variant of it
   * @returns {Record<string, any>}
   */
  static forType(opts) {
    var _a, _b;
    const defaults = new Defaults(opts);
    const chartTypes = [
      "line",
      "area",
      "bar",
      "candlestick",
      "boxPlot",
      "violin",
      "rangeBar",
      "rangeArea",
      "bubble",
      "scatter",
      "heatmap",
      "treemap",
      "unit",
      "sunburst",
      "pie",
      "polarArea",
      "donut",
      "radar",
      "radialBar"
    ];
    const requestedType = opts.chart.requestedType;
    let chartDefaults;
    if (requestedType === "funnel" || requestedType === "pyramid") {
      chartDefaults = /** @type {any} */
      defaults[requestedType]();
    } else if (requestedType === "gauge") {
      chartDefaults = defaults.gauge();
    } else if (requestedType === "histogram") {
      chartDefaults = defaults.histogram();
    } else if (chartTypes.indexOf(opts.chart.type) !== -1) {
      chartDefaults = /** @type {any} */
      defaults[opts.chart.type]();
    } else {
      chartDefaults = defaults.line();
    }
    if ((_b = (_a = opts.plotOptions) == null ? void 0 : _a.bar) == null ? void 0 : _b.isFunnel) {
      chartDefaults = defaults.funnel();
    }
    if (opts.chart.stacked && opts.chart.type === "bar") {
      chartDefaults = defaults.stackedBars();
    }
    return chartDefaults;
  }
  /**
   * Re-choose the type-owned leaves (see TYPE_OWNED_PATHS) after
   * `updateOptions({ chart: { type } })` moved the chart from one type to
   * another, so the chart behaves as the type it now is.
   *
   * A leaf is only handed over when it still holds exactly what `fromType`
   * chose for it. That single test covers every way a value can be the user's
   * instead of ours: set at construction, set by an earlier update, or set by
   * this very update. `options` is consulted too, so an explicit ask in the
   * same call wins even when it happens to equal the outgoing default.
   *
   * @param {Record<string, any>} config the merged w.config, mutated in place
   * @param {string} fromType the type (or requested alias) before this update
   * @param {Record<string, any>} [options] this update's payload
   */
  static handOverTypeDefaults(config, fromType, options2) {
    const toType = config.chart.requestedType || config.chart.type;
    if (!fromType || fromType === toType) return;
    const base = new Options().init();
    const from = Utils$1.extend(
      base,
      Defaults.forType(typeOpts(fromType, config))
    );
    const to = Utils$1.extend(base, Defaults.forType(typeOpts(toType, config)));
    for (const path of TYPE_OWNED_PATHS) {
      if (options2 && readPath(options2, path) !== void 0) continue;
      const fromDefault = readPath(from, path);
      const toDefault = readPath(to, path);
      if (fromDefault === void 0 && toDefault === void 0) continue;
      if (!isUntouched(readPath(config, path), fromDefault)) continue;
      writePath(config, path, toDefault);
    }
  }
  hideYAxis() {
    this.opts.yaxis[0].show = false;
    this.opts.yaxis[0].title.text = "";
    this.opts.yaxis[0].axisBorder.show = false;
    this.opts.yaxis[0].axisTicks.show = false;
    this.opts.yaxis[0].floating = true;
  }
  line() {
    return {
      dataLabels: {
        enabled: false
      },
      stroke: {
        width: 5,
        curve: "straight"
      },
      markers: {
        size: 0,
        hover: {
          sizeOffset: 6
        }
      },
      xaxis: {
        crosshairs: {
          width: 1
        }
      }
    };
  }
  /**
   * @param {Record<string, any>} defaults
   */
  sparkline(defaults) {
    this.hideYAxis();
    const ret = {
      grid: {
        show: false,
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      },
      legend: {
        show: false
      },
      xaxis: {
        labels: {
          show: false
        },
        tooltip: {
          enabled: false
        },
        axisBorder: {
          show: false
        },
        axisTicks: {
          show: false
        }
      },
      chart: {
        toolbar: {
          show: false
        },
        zoom: {
          enabled: false
        }
      },
      dataLabels: {
        enabled: false
      }
    };
    return Utils$1.extend(defaults, ret);
  }
  slope() {
    this.hideYAxis();
    return {
      chart: {
        toolbar: {
          show: false
        },
        zoom: {
          enabled: false
        }
      },
      dataLabels: {
        enabled: true,
        /**
         * @param {any} val
         * @param {Record<string, any>} opts
         */
        formatter(val, opts) {
          const seriesName = opts.w.config.series[opts.seriesIndex].name;
          return val !== null ? seriesName + ": " + val : "";
        },
        background: {
          enabled: false
        },
        offsetX: -5
      },
      grid: {
        xaxis: {
          lines: {
            show: true
          }
        },
        yaxis: {
          lines: {
            show: false
          }
        }
      },
      xaxis: {
        position: "top",
        labels: {
          style: {
            fontSize: 14,
            fontWeight: 900
          }
        },
        tooltip: {
          enabled: false
        },
        crosshairs: {
          show: false
        }
      },
      markers: {
        size: 8,
        hover: {
          sizeOffset: 1
        }
      },
      legend: {
        show: false
      },
      tooltip: {
        shared: false,
        intersect: true,
        followCursor: true
      },
      stroke: {
        width: 5,
        curve: "straight"
      }
    };
  }
  bar() {
    return {
      chart: {
        stacked: false
      },
      plotOptions: {
        bar: {
          dataLabels: {
            position: "center"
          }
        }
      },
      dataLabels: {
        style: {
          colors: ["#fff"]
        },
        background: {
          enabled: false
        }
      },
      stroke: {
        width: 0,
        lineCap: "square"
      },
      fill: {
        opacity: 0.85
      },
      legend: {
        markers: {
          shape: "square"
        }
      },
      tooltip: {
        shared: false,
        intersect: true
      },
      xaxis: {
        tooltip: {
          enabled: false
        },
        tickPlacement: "between",
        crosshairs: {
          width: "barWidth",
          position: "back",
          fill: {
            type: "gradient"
          },
          dropShadow: {
            enabled: false
          },
          stroke: {
            width: 0
          }
        }
      }
    };
  }
  funnel() {
    this.hideYAxis();
    return __spreadProps(__spreadValues({}, this.bar()), {
      chart: {
        animations: {
          speed: 800,
          animateGradually: {
            enabled: false
          }
        }
      },
      plotOptions: {
        bar: {
          horizontal: true,
          borderRadiusApplication: "around",
          borderRadius: 0,
          dataLabels: {
            position: "center"
          }
        }
      },
      grid: {
        show: false,
        padding: {
          left: 0,
          right: 0
        }
      },
      xaxis: {
        labels: {
          show: false
        },
        tooltip: {
          enabled: false
        },
        axisBorder: {
          show: false
        },
        axisTicks: {
          show: false
        }
      }
    });
  }
  pyramid() {
    return this.funnel();
  }
  gauge() {
    const base = this.radialBar();
    return __spreadProps(__spreadValues({}, base), {
      plotOptions: {
        radialBar: {
          startAngle: -135,
          endAngle: 135,
          hollow: {
            margin: 0,
            size: "60%"
          },
          track: {
            background: "#e7e7e7",
            strokeWidth: "100%",
            margin: 5
          },
          dataLabels: {
            name: {
              show: false
            },
            value: {
              show: true,
              fontSize: "32px",
              fontWeight: 600,
              offsetY: 8
            }
          }
        }
      }
    });
  }
  histogram() {
    var _a, _b, _c, _d;
    const overlaid = Array.isArray((_a = this.opts) == null ? void 0 : _a.series) && this.opts.series.length > 1 && ((_d = (_c = (_b = this.opts) == null ? void 0 : _b.plotOptions) == null ? void 0 : _c.histogram) == null ? void 0 : _d.overlap) !== false;
    return __spreadProps(__spreadValues({}, this.bar()), {
      chart: {
        stacked: false,
        // The bins are the summary: they are chosen once from the whole sample
        // and do NOT re-derive from the visible window, so zooming only
        // magnifies bars while hiding the rest of the distribution the shape is
        // read against. Off by default, mirroring heatmap and violin; users can
        // opt back in with chart.zoom.enabled: true.
        zoom: {
          enabled: false
        },
        animations: {
          // The bars of a histogram are one shape, not N independent
          // categories, so revealing them one by one reads as a sequence that
          // is not in the data. The distribution rises as a whole instead.
          animateGradually: {
            enabled: false
          }
        }
      },
      plotOptions: {
        bar: {
          // Bins are adjacent by definition, so the columns touch: a gap
          // between them would read as a gap in the data. Rounded corners are
          // dropped for the same reason (they shave area off each bar, and a
          // histogram's whole claim is that area is proportional to count).
          columnWidth: "100%",
          borderRadius: 0,
          dataLabels: {
            position: "top"
          }
        }
      },
      dataLabels: {
        enabled: false
      },
      fill: overlaid ? { opacity: 0.65 } : {},
      // A hairline separator keeps the bin boundaries readable once the columns
      // touch, the same treatment heatmap cells get.
      stroke: overlaid ? { show: false } : {
        show: true,
        width: 1,
        colors: ["#fff"]
      },
      xaxis: {
        type: "numeric",
        // The axis carries bin midpoints; the range is what people read, and
        // the tooltip already states it.
        tooltip: {
          enabled: false
        }
      },
      tooltip: {
        // Overlaid bars share a bin, so hovering one has to report both
        // distributions: the comparison is the whole point of stacking them on
        // one axis.
        shared: overlaid,
        intersect: false,
        x: {
          formatter: (val, opts) => {
            var _a2, _b2;
            const edges = (_b2 = (_a2 = opts == null ? void 0 : opts.w) == null ? void 0 : _a2.histogramData) == null ? void 0 : _b2.edges;
            const k = opts == null ? void 0 : opts.dataPointIndex;
            if (!Array.isArray(edges) || typeof k !== "number" || k < 0) {
              return String(val);
            }
            const lo = edges[k];
            const hi = edges[k + 1];
            if (lo === void 0 || hi === void 0) return String(val);
            const fmt = (v) => Number.isInteger(v) ? String(v) : v.toFixed(2);
            return `${fmt(lo)} to ${fmt(hi)}`;
          }
        }
      }
    });
  }
  candlestick() {
    return {
      stroke: {
        width: 1
      },
      fill: {
        opacity: 1
      },
      dataLabels: {
        enabled: false
      },
      tooltip: {
        shared: true,
        custom: ownedBy(
          ["candlestick"],
          ({ seriesIndex, dataPointIndex, w }) => {
            return this._getBoxTooltip(
              w,
              seriesIndex,
              dataPointIndex,
              ["Open", "High", "", "Low", "Close"],
              "candlestick"
            );
          }
        )
      },
      states: {
        active: {
          filter: {
            type: "none"
          }
        }
      },
      xaxis: {
        crosshairs: {
          width: 1
        }
      }
    };
  }
  boxPlot() {
    return {
      chart: {
        animations: {
          dynamicAnimation: {
            enabled: false
          }
        }
      },
      stroke: {
        width: 1,
        colors: ["#24292e"]
      },
      dataLabels: {
        enabled: false
      },
      tooltip: {
        shared: true,
        custom: ownedBy(
          ["boxPlot"],
          ({ seriesIndex, dataPointIndex, w }) => {
            return this._getBoxTooltip(
              w,
              seriesIndex,
              dataPointIndex,
              ["Minimum", "Q1", "Median", "Q3", "Maximum"],
              "boxPlot"
            );
          }
        )
      },
      markers: {
        size: 7,
        strokeWidth: 1,
        strokeColors: "#111"
      },
      xaxis: {
        crosshairs: {
          width: 1
        }
      }
    };
  }
  violin() {
    return {
      chart: {
        // Violins are a per-category distribution plot (discrete category
        // x-axis), so range zooming/panning is meaningless — off by default.
        zoom: {
          enabled: false
        },
        animations: {
          dynamicAnimation: {
            enabled: false
          }
        }
      },
      stroke: {
        width: 1,
        colors: ["#24292e"]
      },
      fill: {
        opacity: 0.7
      },
      dataLabels: {
        enabled: false
      },
      tooltip: {
        shared: true,
        custom: ownedBy(
          ["violin"],
          ({ seriesIndex, dataPointIndex, w }) => {
            return this._getViolinTooltip(w, seriesIndex, dataPointIndex);
          }
        )
      },
      states: {
        active: {
          filter: {
            type: "none"
          }
        }
      },
      xaxis: {
        crosshairs: {
          width: 1
        }
      }
    };
  }
  rangeBar() {
    const handleTimelineTooltip = (opts) => {
      const { color, seriesName, ylabel, startVal, endVal } = getRangeValues(__spreadProps(__spreadValues({}, opts), {
        isTimeline: true
      }));
      return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {
        color,
        seriesName,
        ylabel,
        start: startVal,
        end: endVal
      }));
    };
    const handleRangeColumnTooltip = (opts) => {
      const { color, seriesName, ylabel, start, end } = getRangeValues(opts);
      return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {
        color,
        seriesName,
        ylabel,
        start,
        end
      }));
    };
    return {
      chart: {
        animations: {
          animateGradually: false
        }
      },
      stroke: {
        width: 0,
        lineCap: "square"
      },
      plotOptions: {
        bar: {
          borderRadius: 0,
          dataLabels: {
            position: "center"
          }
        }
      },
      dataLabels: {
        enabled: false,
        /**
         * @param {any} val
         */
        formatter(val, { seriesIndex, dataPointIndex, w }) {
          const getVal = () => {
            const start = w.rangeData.seriesRangeStart[seriesIndex][dataPointIndex];
            const end = w.rangeData.seriesRangeEnd[seriesIndex][dataPointIndex];
            return end - start;
          };
          if (w.globals.comboCharts) {
            if (w.config.series[seriesIndex].type === "rangeBar" || w.config.series[seriesIndex].type === "rangeArea") {
              return getVal();
            } else {
              return val;
            }
          } else {
            return getVal();
          }
        },
        background: {
          enabled: false
        },
        style: {
          colors: ["#fff"]
        }
      },
      markers: {
        size: 10
      },
      tooltip: {
        shared: false,
        followCursor: true,
        custom: ownedBy(
          ["rangeBar"],
          /** @param {Record<string, any>} opts */
          (opts) => {
            if (opts.w.config.plotOptions && opts.w.config.plotOptions.bar && opts.w.config.plotOptions.bar.horizontal) {
              return handleTimelineTooltip(opts);
            } else {
              return handleRangeColumnTooltip(opts);
            }
          }
        )
      },
      xaxis: {
        tickPlacement: "between",
        tooltip: {
          enabled: false
        },
        crosshairs: {
          stroke: {
            width: 0
          }
        }
      }
    };
  }
  /**
   * @param {Record<string, any>} opts
   */
  dumbbell(opts) {
    var _a, _b;
    if (!((_a = opts.plotOptions.bar) == null ? void 0 : _a.barHeight)) {
      opts.plotOptions.bar.barHeight = 2;
    }
    if (!((_b = opts.plotOptions.bar) == null ? void 0 : _b.columnWidth)) {
      opts.plotOptions.bar.columnWidth = 2;
    }
    return opts;
  }
  area() {
    return {
      stroke: {
        width: 4,
        fill: {
          type: "solid",
          gradient: {
            inverseColors: false,
            shade: "light",
            type: "vertical",
            opacityFrom: 0.65,
            opacityTo: 0.5,
            stops: [0, 100, 100]
          }
        }
      },
      fill: {
        type: "gradient",
        gradient: {
          inverseColors: false,
          shade: "light",
          type: "vertical",
          opacityFrom: 0.65,
          opacityTo: 0.5,
          stops: [0, 100, 100]
        }
      },
      markers: {
        size: 0,
        hover: {
          sizeOffset: 6
        }
      },
      tooltip: {
        followCursor: false
      }
    };
  }
  rangeArea() {
    const handleRangeAreaTooltip = (opts) => {
      const { color, seriesName, ylabel, start, end } = getRangeValues(opts);
      return buildRangeTooltipHTML(__spreadProps(__spreadValues({}, opts), {
        color,
        seriesName,
        ylabel,
        start,
        end
      }));
    };
    return {
      stroke: {
        curve: "straight",
        width: 0
      },
      fill: {
        type: "solid",
        opacity: 0.6
      },
      markers: {
        size: 0
      },
      states: {
        hover: {
          filter: {
            type: "none"
          }
        },
        active: {
          filter: {
            type: "none"
          }
        }
      },
      tooltip: {
        intersect: false,
        shared: true,
        followCursor: true,
        custom: ownedBy(
          ["rangeArea"],
          /** @param {Record<string, any>} opts */
          (opts) => handleRangeAreaTooltip(opts)
        )
      }
    };
  }
  /**
   * @param {Record<string, any>} defaults
   */
  brush(defaults) {
    const ret = {
      chart: {
        toolbar: {
          autoSelected: "selection",
          show: false
        },
        zoom: {
          enabled: false
        }
      },
      dataLabels: {
        enabled: false
      },
      stroke: {
        width: 1
      },
      tooltip: {
        enabled: false
      },
      xaxis: {
        tooltip: {
          enabled: false
        }
      }
    };
    return Utils$1.extend(defaults, ret);
  }
  /**
   * @param {Record<string, any>} opts
   */
  stacked100(opts) {
    opts.dataLabels = opts.dataLabels || {};
    opts.dataLabels.formatter = opts.dataLabels.formatter || void 0;
    const existingDataLabelFormatter = opts.dataLabels.formatter;
    opts.yaxis.forEach((yaxe, index) => {
      opts.yaxis[index].min = 0;
      opts.yaxis[index].max = 100;
    });
    const isBar = opts.chart.type === "bar";
    if (isBar) {
      opts.dataLabels.formatter = existingDataLabelFormatter || /**
       * @param {any} val
       */
      function(val) {
        if (typeof val === "number") {
          return val ? val.toFixed(0) + "%" : val;
        }
        return val;
      };
    }
    return opts;
  }
  stackedBars() {
    const barDefaults = this.bar();
    return __spreadProps(__spreadValues({}, barDefaults), {
      plotOptions: __spreadProps(__spreadValues({}, barDefaults.plotOptions), {
        bar: __spreadProps(__spreadValues({}, barDefaults.plotOptions.bar), {
          borderRadiusApplication: "end"
        })
      })
    });
  }
  // This function removes the left and right spacing in chart for line/area/scatter if xaxis type = category for those charts by converting xaxis = numeric. Numeric/Datetime xaxis prevents the unnecessary spacing in the left/right of the chart area
  /**
   * @param {Record<string, any>} opts
   */
  convertCatToNumeric(opts) {
    opts.xaxis.convertedCatToNumeric = true;
    return opts;
  }
  /**
   * @param {Record<string, any>} opts
   * @param {any} cats
   */
  convertCatToNumericXaxis(opts, cats) {
    opts.xaxis.type = "numeric";
    opts.xaxis.labels = opts.xaxis.labels || {};
    opts.xaxis.labels.formatter = opts.xaxis.labels.formatter || /**
     * @param {any} val
     */
    function(val) {
      return Utils$1.isNumber(val) ? Math.floor(val) : val;
    };
    const defaultFormatter = opts.xaxis.labels.formatter;
    let labels = opts.xaxis.categories && opts.xaxis.categories.length ? opts.xaxis.categories : opts.labels;
    if (cats && cats.length) {
      labels = cats.map((c2) => {
        return Array.isArray(c2) ? c2 : String(c2);
      });
    }
    if (labels && labels.length) {
      opts.xaxis.labels.formatter = function(val) {
        return Utils$1.isNumber(val) ? defaultFormatter(labels[Math.floor(val) - 1]) : defaultFormatter(val);
      };
    }
    opts.xaxis.categories = [];
    opts.labels = [];
    opts.xaxis.tickAmount = opts.xaxis.tickAmount || "dataPoints";
    return opts;
  }
  bubble() {
    return {
      dataLabels: {
        style: {
          colors: ["#fff"]
        }
      },
      tooltip: {
        shared: false,
        intersect: true
      },
      xaxis: {
        crosshairs: {
          width: 0
        }
      },
      fill: {
        type: "solid",
        gradient: {
          shade: "light",
          inverse: true,
          shadeIntensity: 0.55,
          opacityFrom: 0.4,
          opacityTo: 0.8
        }
      }
    };
  }
  scatter() {
    return {
      dataLabels: {
        enabled: false
      },
      tooltip: {
        shared: false,
        intersect: true
      },
      markers: {
        size: 6,
        strokeWidth: 1,
        hover: {
          sizeOffset: 2
        }
      }
    };
  }
  heatmap() {
    return {
      chart: {
        stacked: false,
        // A heatmap is a fixed grid: zooming/panning only distorts the cells
        // and (on a datetime axis) collapses the month labels to repeats, so
        // it is off by default, mirroring treemap. Users can opt back in with
        // chart.zoom.enabled: true.
        zoom: {
          enabled: false
        }
      },
      fill: {
        opacity: 1
      },
      dataLabels: {
        style: {
          colors: ["#fff"]
        }
      },
      stroke: {
        colors: ["#fff"]
      },
      tooltip: {
        // Anchor the tooltip above the hovered cell with a downward arrow
        // (flipping below near the top edge), the same treatment horizontal
        // bars get, rather than trailing the cursor. Opt back into the old
        // behavior with tooltip.followCursor: true.
        followCursor: false,
        marker: {
          show: false
        },
        x: {
          show: false
        }
      },
      legend: {
        position: "top",
        markers: {
          shape: "square"
        }
      },
      grid: {
        padding: {
          right: 20
        }
      }
    };
  }
  treemap() {
    return {
      chart: {
        zoom: {
          enabled: false
        }
      },
      dataLabels: {
        style: {
          fontSize: 14,
          fontWeight: 600,
          colors: ["#fff"]
        }
      },
      stroke: {
        show: true,
        width: 2,
        colors: ["#fff"]
      },
      legend: {
        show: false
      },
      fill: {
        opacity: 1,
        gradient: {
          stops: [0, 100]
        }
      },
      tooltip: {
        followCursor: true,
        x: {
          show: false
        }
      },
      grid: {
        padding: {
          left: 0,
          right: 0
        }
      },
      xaxis: {
        crosshairs: {
          show: false
        },
        tooltip: {
          enabled: false
        },
        // A treemap has no x axis to read: the tiles are the whole plot, and
        // the ticks mark data-point positions that mean nothing here. One tick
        // per row is invisible at a dozen rows and a solid comb under the plot
        // at several hundred, so they are off by default. Set
        // `xaxis.axisTicks.show: true` to bring them back.
        axisTicks: {
          show: false
        }
      }
    };
  }
  unit() {
    return {
      chart: {
        toolbar: {
          show: false
        }
      },
      dataLabels: {
        enabled: false
      },
      stroke: {
        show: false,
        width: 0
      },
      fill: {
        opacity: 1
      },
      tooltip: {
        followCursor: true,
        x: {
          show: false
        }
      },
      legend: {
        show: true,
        position: "bottom"
      },
      grid: {
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      }
    };
  }
  sunburst() {
    return {
      chart: {
        toolbar: {
          show: false
        }
      },
      dataLabels: {
        style: {
          colors: ["#fff"]
        },
        dropShadow: {
          enabled: true
        }
      },
      stroke: {
        colors: ["#fff"]
      },
      fill: {
        opacity: 1
      },
      // Unlike pie, sunburst keeps the STANDARD themed tooltip (light/dark).
      // Slice-coloured tooltips (fillSeriesColor) wash out here because child
      // arcs are tinted toward white per depth; users can still opt in.
      legend: {
        position: "right"
      },
      grid: {
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      }
    };
  }
  pie() {
    return {
      chart: {
        toolbar: {
          show: false
        }
      },
      plotOptions: {
        pie: {
          donut: {
            labels: {
              show: false
            }
          }
        }
      },
      dataLabels: {
        /**
         * The share of the whole, as a percentage. Guarded because a config
         * survives a chart-type change: a pie that becomes a treemap hands
         * this same default a category NAME, and a default of ours must not
         * throw on a value it was never designed for.
         * @param {any} val
         */
        formatter(val) {
          return typeof val === "number" ? val.toFixed(1) + "%" : val;
        },
        style: {
          colors: ["#fff"]
        },
        background: {
          enabled: false
        },
        dropShadow: {
          enabled: true
        }
      },
      stroke: {
        colors: ["#fff"]
      },
      fill: {
        opacity: 1,
        gradient: {
          shade: "light",
          stops: [0, 100]
        }
      },
      tooltip: {
        theme: "dark",
        fillSeriesColor: true
      },
      legend: {
        position: "right"
      },
      grid: {
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      }
    };
  }
  donut() {
    return {
      chart: {
        toolbar: {
          show: false
        }
      },
      dataLabels: {
        /**
         * The share of the whole, as a percentage. Guarded because a config
         * survives a chart-type change: a pie that becomes a treemap hands
         * this same default a category NAME, and a default of ours must not
         * throw on a value it was never designed for.
         * @param {any} val
         */
        formatter(val) {
          return typeof val === "number" ? val.toFixed(1) + "%" : val;
        },
        style: {
          colors: ["#fff"]
        },
        background: {
          enabled: false
        },
        dropShadow: {
          enabled: true
        }
      },
      stroke: {
        colors: ["#fff"]
      },
      fill: {
        opacity: 1,
        gradient: {
          shade: "light",
          shadeIntensity: 0.35,
          stops: [80, 100],
          opacityFrom: 1,
          opacityTo: 1
        }
      },
      tooltip: {
        theme: "dark",
        fillSeriesColor: true
      },
      legend: {
        position: "right"
      },
      grid: {
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      }
    };
  }
  polarArea() {
    return {
      chart: {
        toolbar: {
          show: false
        }
      },
      dataLabels: {
        /**
         * The share of the whole, as a percentage. Guarded because a config
         * survives a chart-type change: a pie that becomes a treemap hands
         * this same default a category NAME, and a default of ours must not
         * throw on a value it was never designed for.
         * @param {any} val
         */
        formatter(val) {
          return typeof val === "number" ? val.toFixed(1) + "%" : val;
        },
        enabled: false
      },
      stroke: {
        show: true,
        width: 2
      },
      fill: {
        opacity: 0.7
      },
      tooltip: {
        theme: "dark",
        fillSeriesColor: true
      },
      legend: {
        position: "right"
      },
      grid: {
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      }
    };
  }
  radar() {
    this.opts.yaxis[0].labels.offsetY = this.opts.yaxis[0].labels.offsetY ? this.opts.yaxis[0].labels.offsetY : 6;
    return {
      dataLabels: {
        enabled: false,
        style: {
          fontSize: "11px"
        }
      },
      stroke: {
        width: 2
      },
      markers: {
        size: 5,
        strokeWidth: 1,
        strokeOpacity: 1
      },
      fill: {
        opacity: 0.2
      },
      tooltip: {
        shared: false,
        intersect: true,
        followCursor: true
      },
      grid: {
        show: false,
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      },
      xaxis: {
        labels: {
          formatter: (val) => val,
          style: {
            colors: ["#a8a8a8"],
            fontSize: "11px"
          }
        },
        tooltip: {
          enabled: false
        },
        crosshairs: {
          show: false
        }
      }
    };
  }
  radialBar() {
    return {
      chart: {
        animations: {
          dynamicAnimation: {
            enabled: true,
            speed: 800
          }
        },
        toolbar: {
          show: false
        }
      },
      stroke: {
        // Radial value arcs are stroked open arcs; square/round caps would
        // extend the stroke half a stroke-width past each endpoint, making
        // the "starting edge" visibly stick out past the geometric arc.
        // Butt cap is the only one that aligns with the arc's true angular
        // span. Without this, a chart that previously was a bar (whose
        // defaults set lineCap='square') would carry that cap across into
        // the radial render after a type morph.
        lineCap: "butt"
      },
      fill: {
        gradient: {
          shade: "dark",
          shadeIntensity: 0.4,
          inverseColors: false,
          type: "diagonal2",
          opacityFrom: 1,
          opacityTo: 1,
          stops: [70, 98, 100]
        }
      },
      legend: {
        show: false,
        position: "right"
      },
      tooltip: {
        enabled: false,
        fillSeriesColor: true
      },
      grid: {
        padding: {
          left: 0,
          right: 0,
          top: 0,
          bottom: 0
        }
      }
    };
  }
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {number} seriesIndex
   * @param {number} dataPointIndex
   * @param {any[]} labels
   * @param {string} chartType
   */
  _getBoxTooltip(w, seriesIndex, dataPointIndex, labels, chartType) {
    const o2 = w.candleData.seriesCandleO[seriesIndex][dataPointIndex];
    const h2 = w.candleData.seriesCandleH[seriesIndex][dataPointIndex];
    const m = w.candleData.seriesCandleM[seriesIndex][dataPointIndex];
    const l2 = w.candleData.seriesCandleL[seriesIndex][dataPointIndex];
    const c2 = w.candleData.seriesCandleC[seriesIndex][dataPointIndex];
    const _si = (
      /** @type {Record<string,any>} */
      w.config.series[seriesIndex]
    );
    if (_si.type && _si.type !== chartType) {
      return `<div class="apexcharts-custom-tooltip">
          ${_si.name ? _si.name : "series-" + (seriesIndex + 1)}: <strong>${w.seriesData.series[seriesIndex][dataPointIndex]}</strong>
        </div>`;
    } else {
      return `<div class="apexcharts-tooltip-box apexcharts-tooltip-${w.config.chart.type}"><div>${labels[0]}: <span class="value">` + o2 + `</span></div><div>${labels[1]}: <span class="value">` + h2 + "</span></div>" + (m ? `<div>${labels[2]}: <span class="value">` + m + "</span></div>" : "") + `<div>${labels[3]}: <span class="value">` + l2 + `</span></div><div>${labels[4]}: <span class="value">` + c2 + "</span></div></div>";
    }
  }
  /**
   * Shared tooltip for a violin: distribution value range and observation
   * count. Per-point hover is intentionally unsupported (jitter renders as a
   * single path), so the tooltip summarizes the violin as a whole.
   *
   * @param {import('../../types/internal').ChartStateW} w
   * @param {number} seriesIndex
   * @param {number} dataPointIndex
   */
  _getViolinTooltip(w, seriesIndex, dataPointIndex) {
    var _a, _b, _c;
    const minV = (_a = w.violinData.seriesViolinMin[seriesIndex]) == null ? void 0 : _a[dataPointIndex];
    const maxV = (_b = w.violinData.seriesViolinMax[seriesIndex]) == null ? void 0 : _b[dataPointIndex];
    const pts = ((_c = w.violinData.seriesViolinPoints[seriesIndex]) == null ? void 0 : _c[dataPointIndex]) || [];
    const name2 = (
      /** @type {Record<string,any>} */
      w.config.series[seriesIndex].name || "series-" + (seriesIndex + 1)
    );
    return `<div class="apexcharts-tooltip-box apexcharts-tooltip-${w.config.chart.type}"><div class="apexcharts-tooltip-violin-name">${name2}</div><div>Min: <span class="value">${minV}</span></div><div>Max: <span class="value">${maxV}</span></div><div>Observations: <span class="value">${pts.length}</span></div></div>`;
  }
}
class Config {
  /**
   * @param {Record<string, any>} opts
   */
  constructor(opts) {
    this.opts = opts;
  }
  /** @param {{responsiveOverride: any}} opts */
  init({ responsiveOverride }) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    let opts = this.opts;
    const options2 = new Options();
    const defaults = new Defaults(opts);
    opts = this.normalizeAliasedChartType(opts);
    this.chartType = opts.chart.type;
    opts = this.extendYAxis(opts);
    opts = this.extendAnnotations(opts);
    let config = options2.init();
    let newDefaults = {};
    if (opts && typeof opts === "object") {
      let chartDefaults = Defaults.forType(opts);
      if ((_a = opts.chart.brush) == null ? void 0 : _a.enabled) {
        chartDefaults = defaults.brush(chartDefaults);
      }
      if ((_c = (_b = opts.plotOptions) == null ? void 0 : _b.line) == null ? void 0 : _c.isSlopeChart) {
        chartDefaults = defaults.slope();
      }
      if (opts.chart.stacked && opts.chart.stackType === "100%") {
        opts = defaults.stacked100(opts);
      }
      if ((_e = (_d = opts.plotOptions) == null ? void 0 : _d.bar) == null ? void 0 : _e.isDumbbell) {
        opts = defaults.dumbbell(opts);
      }
      this.checkForDarkTheme(Environment.getApex());
      this.checkForDarkTheme(opts);
      opts.xaxis = opts.xaxis || Environment.getApex().xaxis || {};
      if (!responsiveOverride) {
        opts.xaxis.convertedCatToNumeric = false;
      }
      opts = this.checkForCatToNumericXAxis(this.chartType, chartDefaults, opts);
      if (((_f = opts.chart.sparkline) == null ? void 0 : _f.enabled) || ((_h = (_g = Environment.getApex().chart) == null ? void 0 : _g.sparkline) == null ? void 0 : _h.enabled)) {
        chartDefaults = defaults.sparkline(chartDefaults);
      }
      newDefaults = Utils$1.extend(config, chartDefaults);
    }
    const mergedWithDefaultConfig = Utils$1.extend(
      newDefaults,
      Environment.getApex()
    );
    config = Utils$1.extend(mergedWithDefaultConfig, opts);
    config = this.handleUserInputErrors(config);
    return config;
  }
  /**
   * Promoted chart-type aliases — `funnel`, `pyramid`, `gauge` — render via
   * the existing `bar` (with `isFunnel`) and `radialBar` pathways. To keep
   * the ~20 internal `chart.type === 'bar' | 'radialBar'` checks working
   * unchanged, we normalize `chart.type` to the base renderer name here and
   * preserve the user-facing name on `chart.requestedType` for the public
   * API and for default selection.
   *
   * @param {Record<string, any>} opts
   * @returns {Record<string, any>}
   */
  normalizeAliasedChartType(opts) {
    if (!opts || !opts.chart) return opts;
    const requested = opts.chart.type;
    if (requested !== "funnel" && requested !== "pyramid" && requested !== "gauge" && requested !== "waffle" && requested !== "histogram") {
      return opts;
    }
    opts.chart.requestedType = requested;
    if (requested === "waffle") {
      opts.plotOptions = opts.plotOptions || {};
      opts.plotOptions.unit = opts.plotOptions.unit || {};
      if (opts.plotOptions.unit.layout == null) {
        opts.plotOptions.unit.layout = "grid";
      }
      if (opts.plotOptions.unit.shape == null) {
        opts.plotOptions.unit.shape = "square";
      }
      opts.chart.type = "unit";
    } else if (requested === "funnel" || requested === "pyramid") {
      opts.plotOptions = opts.plotOptions || {};
      opts.plotOptions.bar = opts.plotOptions.bar || {};
      opts.plotOptions.bar.isFunnel = true;
      opts.plotOptions.bar.horizontal = true;
      opts.chart.type = "bar";
      if (requested === "pyramid") {
        opts.plotOptions.bar.isPyramid = true;
      } else {
        opts.plotOptions.bar.isPyramid = false;
      }
    } else if (requested === "gauge") {
      opts.chart.type = "radialBar";
    } else if (requested === "histogram") {
      opts.xaxis = opts.xaxis || {};
      if (opts.xaxis.type == null) {
        opts.xaxis.type = "numeric";
      }
      opts.chart.type = "bar";
    }
    return opts;
  }
  /**
   * @param {string} chartType
   * @param {Record<string, any>} chartDefaults
   * @param {Record<string, any>} opts
   */
  checkForCatToNumericXAxis(chartType, chartDefaults, opts) {
    var _a, _b, _c, _d, _e;
    const defaults = new Defaults(opts);
    const isBarHorizontal = (chartType === "bar" || chartType === "boxPlot" || chartType === "violin") && ((_b = (_a = opts.plotOptions) == null ? void 0 : _a.bar) == null ? void 0 : _b.horizontal);
    const unsupportedZoom = chartType === "pie" || chartType === "polarArea" || chartType === "donut" || chartType === "radar" || chartType === "radialBar" || chartType === "heatmap" || chartType === "unit" || chartType === "sunburst";
    const notNumericXAxis = opts.xaxis.type !== "datetime" && opts.xaxis.type !== "numeric";
    const isScatterJitter = (chartType === "scatter" || chartType === "bubble") && ((_e = (_d = (_c = opts.plotOptions) == null ? void 0 : _c.scatter) == null ? void 0 : _d.jitter) == null ? void 0 : _e.enabled);
    const tickPlacement = opts.xaxis.tickPlacement ? opts.xaxis.tickPlacement : chartDefaults.xaxis && chartDefaults.xaxis.tickPlacement;
    if (!isBarHorizontal && !unsupportedZoom && !isScatterJitter && notNumericXAxis && tickPlacement !== "between") {
      opts = defaults.convertCatToNumeric(opts);
    }
    return opts;
  }
  /**
   * @param {Record<string, any>} opts
   * @param {import('../../types/internal').ChartStateW} [w]
   */
  extendYAxis(opts, w) {
    const options2 = new Options();
    if (typeof opts.yaxis === "undefined" || !opts.yaxis || Array.isArray(opts.yaxis) && opts.yaxis.length === 0) {
      opts.yaxis = {};
    }
    const globalApex = Environment.getApex();
    if (opts.yaxis.constructor !== Array && globalApex.yaxis && globalApex.yaxis.constructor !== Array) {
      opts.yaxis = Utils$1.extend(opts.yaxis, globalApex.yaxis);
    }
    if (opts.yaxis.constructor !== Array) {
      opts.yaxis = [Utils$1.extend(options2.yAxis, opts.yaxis)];
    } else {
      opts.yaxis = Utils$1.extendArray(opts.yaxis, options2.yAxis);
    }
    let isLogY = false;
    opts.yaxis.forEach((y) => {
      if (y.logarithmic) {
        isLogY = true;
      }
    });
    let series = opts.series;
    if (w && !series) {
      series = w.config.series;
    }
    if (isLogY && series.length !== opts.yaxis.length && series.length) {
      opts.yaxis = series.map((s2, i2) => {
        if (!s2.name) {
          series[i2].name = `series-${i2 + 1}`;
        }
        if (opts.yaxis[i2]) {
          opts.yaxis[i2].seriesName = series[i2].name;
          return opts.yaxis[i2];
        } else {
          const newYaxis = Utils$1.extend(options2.yAxis, opts.yaxis[0]);
          newYaxis.show = false;
          return newYaxis;
        }
      });
    }
    if (isLogY && series.length > 1 && series.length !== opts.yaxis.length) {
      console.warn(
        "A multi-series logarithmic chart should have equal number of series and y-axes"
      );
    }
    return opts;
  }
  // annotations also accepts array, so we need to extend them manually
  /**
   * @param {Record<string, any>} opts
   */
  extendAnnotations(opts) {
    if (typeof opts.annotations === "undefined") {
      opts.annotations = {};
      opts.annotations.yaxis = [];
      opts.annotations.xaxis = [];
      opts.annotations.points = [];
    }
    opts = this.extendYAxisAnnotations(opts);
    opts = this.extendXAxisAnnotations(opts);
    opts = this.extendPointAnnotations(opts);
    return opts;
  }
  /**
   * @param {Record<string, any>} opts
   */
  extendYAxisAnnotations(opts) {
    const options2 = new Options();
    opts.annotations.yaxis = Utils$1.extendArray(
      typeof opts.annotations.yaxis !== "undefined" ? opts.annotations.yaxis : [],
      options2.yAxisAnnotation
    );
    return opts;
  }
  /**
   * @param {Record<string, any>} opts
   */
  extendXAxisAnnotations(opts) {
    const options2 = new Options();
    opts.annotations.xaxis = Utils$1.extendArray(
      typeof opts.annotations.xaxis !== "undefined" ? opts.annotations.xaxis : [],
      options2.xAxisAnnotation
    );
    return opts;
  }
  /**
   * @param {Record<string, any>} opts
   */
  extendPointAnnotations(opts) {
    const options2 = new Options();
    opts.annotations.points = Utils$1.extendArray(
      typeof opts.annotations.points !== "undefined" ? opts.annotations.points : [],
      options2.pointAnnotation
    );
    return opts;
  }
  /**
   * @param {Record<string, any>} opts
   */
  checkForDarkTheme(opts) {
    if (opts.theme && opts.theme.mode === "dark") {
      if (!opts.tooltip) {
        opts.tooltip = {};
      }
      if (opts.tooltip.theme !== "light") {
        opts.tooltip.theme = "dark";
      }
      if (!opts.chart.foreColor) {
        opts.chart.foreColor = "#f6f7f8";
      }
      if (!opts.theme.palette) {
        opts.theme.palette = "palette4";
      }
    }
  }
  /**
   * @param {any} opts
   */
  handleUserInputErrors(opts) {
    const config = opts;
    if (config.tooltip.shared && config.tooltip.intersect) {
      throw new Error(
        "tooltip.shared cannot be enabled when tooltip.intersect is true. Turn off any other option by setting it to false."
      );
    }
    if (config.chart.type === "bar" && config.plotOptions.bar.horizontal) {
      if (config.yaxis.length > 1) {
        throw new Error(
          "Multiple Y Axis for bars are not supported. Switch to column chart by setting plotOptions.bar.horizontal=false"
        );
      }
      if (config.yaxis[0].reversed) {
        config.yaxis[0].opposite = true;
      }
      config.xaxis.tooltip.enabled = false;
      config.yaxis[0].tooltip.enabled = false;
      config.chart.zoom.enabled = false;
    }
    if (config.chart.type === "bar" || config.chart.type === "rangeBar") {
      if (config.tooltip.shared) {
        if (config.xaxis.crosshairs.width === "barWidth" && config.series.length > 1) {
          config.xaxis.crosshairs.width = "tickWidth";
        }
      }
    }
    if (config.chart.type === "candlestick" || config.chart.type === "boxPlot") {
      if (config.yaxis[0].reversed) {
        console.warn(
          `Reversed y-axis in ${config.chart.type} chart is not supported.`
        );
        config.yaxis[0].reversed = false;
      }
    }
    return config;
  }
}
const LINE_HEIGHT_RATIO = 1.618;
const NICE_SCALE_ALLOWED_MAG_MSD = [
  [1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10],
  [1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10]
];
const NICE_SCALE_DEFAULT_TICKS = [
  1,
  2,
  4,
  4,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  6,
  12,
  12,
  12,
  12,
  12,
  12,
  12,
  12,
  12,
  24
];
class Globals {
  /**
   * @param {any} gl
   */
  initGlobalVars(gl) {
    gl.series = [];
    gl.seriesCandleO = [];
    gl.seriesCandleH = [];
    gl.seriesCandleM = [];
    gl.seriesCandleL = [];
    gl.seriesCandleC = [];
    gl.seriesRangeStart = [];
    gl.seriesRangeEnd = [];
    gl.seriesRange = [];
    gl.seriesPercent = [];
    gl.seriesGoals = [];
    gl.seriesX = [];
    gl.seriesZ = [];
    gl.seriesNames = [];
    gl.seriesTotals = [];
    gl.seriesLog = [];
    gl.seriesColors = [];
    gl.stackedSeriesTotals = [];
    gl.seriesXvalues = [];
    gl.seriesYvalues = [];
    gl.dataWasParsed = false;
    gl.originalSeries = null;
    gl.maxValsInArrayIndex = 0;
    gl.yValueDecimal = 0;
    gl.allSeriesHasEqualX = true;
    gl.hasNullValues = false;
    gl.invalidLogScale = false;
    gl.seriesRangeName = {};
    gl.labels = [];
    gl.hasXaxisGroups = false;
    gl.groups = [];
    gl.barGroups = [];
    gl.lineGroups = [];
    gl.areaGroups = [];
    gl.hasSeriesGroups = false;
    gl.seriesGroups = [];
    gl.categoryLabels = [];
    gl.timescaleLabels = [];
    gl.noLabelsProvided = false;
    gl.isXNumeric = false;
    gl.skipLastTimelinelabel = false;
    gl.skipFirstTimelinelabel = false;
    gl.isDataXYZ = false;
    gl.isMultiLineX = false;
    gl.isMultipleYAxis = false;
    gl.maxY = -Number.MAX_VALUE;
    gl.minY = Number.MIN_VALUE;
    gl.minYArr = [];
    gl.maxYArr = [];
    gl.maxX = -Number.MAX_VALUE;
    gl.minX = Number.MAX_VALUE;
    gl.initialMaxX = -Number.MAX_VALUE;
    gl.initialMinX = Number.MAX_VALUE;
    gl.maxDate = 0;
    gl.minDate = Number.MAX_VALUE;
    gl.minZ = Number.MAX_VALUE;
    gl.maxZ = -Number.MAX_VALUE;
    gl.minXDiff = Number.MAX_VALUE;
    gl.yAxisScale = [];
    gl.xAxisScale = null;
    gl.xAxisTicksPositions = [];
    gl.xRange = 0;
    gl.yRange = [];
    gl.zRange = 0;
    gl.dataPoints = 0;
    gl.xTickAmount = 0;
    gl.multiAxisTickAmount = 0;
    gl.disableZoomIn = false;
    gl.disableZoomOut = false;
    gl.yLabelsCoords = [];
    gl.yTitleCoords = [];
    gl.barPadForNumericAxis = 0;
    gl.padHorizontal = 0;
    gl.rotateXLabels = false;
    gl.overlappingXLabels = false;
    gl.radialSize = 0;
    gl.barHeight = 0;
    gl.barWidth = 0;
    gl.animationEnded = false;
    gl.isDestroyed = false;
    gl.bulkRevealScheduled = false;
    gl.resizeTimer = null;
    gl.selectionResizeTimer = null;
    gl.delayedElements = [];
    gl.pointsArray = [];
    gl.barCanvasCoords = null;
    gl.activeRenderer = null;
    gl.dataLabelsRects = [];
    gl.lastDrawnDataLabelsIndexes = [];
    gl.textRectsCache = /* @__PURE__ */ new Map();
    gl.domCache = /* @__PURE__ */ new Map();
    gl.dimensionCache = {};
    gl.cachedSelectors = {};
    if (!gl.seriesNS) {
      this._attachNamespaces(gl);
    }
  }
  /**
   * Attach domain-grouped namespace sub-objects onto gl.
   * Each sub-object is a plain object whose properties are defined as
   * getters/setters that read/write the canonical flat properties on gl.
   * This means there is exactly ONE storage location per value — no copies,
   * no sync needed.
   *
   * Namespaces:
   *   gl.series  — parsed series data and chart-type-specific arrays
   *   gl.axes    — axis bounds, scales, ranges, tick state
   *   gl.layout  — SVG/grid dimensions, translations, label sizes
   *   gl.cache   — DOM caches, timers, observers, drawing scratch space
   *
   * Note: interact state lives on w.interact (not gl) — see Base.js.
   * @param {any} gl
   */
  _attachNamespaces(gl) {
    const proxy = (ns, key, nsKey = key) => {
      Object.defineProperty(ns, nsKey, {
        get() {
          return gl[key];
        },
        set(v) {
          gl[key] = v;
        },
        enumerable: true,
        configurable: true
      });
    };
    const seriesNS = {};
    proxy(seriesNS, "series", "data");
    for (const key of [
      "seriesNames",
      "seriesX",
      "seriesZ",
      "seriesXvalues",
      "seriesYvalues",
      "seriesGoals",
      "seriesLog",
      "seriesColors",
      "seriesPercent",
      "seriesTotals",
      "stackedSeriesTotals",
      "seriesCandleO",
      "seriesCandleH",
      "seriesCandleM",
      "seriesCandleL",
      "seriesCandleC",
      "seriesRangeStart",
      "seriesRangeEnd",
      "seriesRange",
      "seriesYAxisMap",
      "seriesYAxisReverseMap",
      "seriesGroups",
      "barGroups",
      "lineGroups",
      "areaGroups",
      "originalSeries",
      "collapsedSeries",
      "collapsedSeriesIndices",
      "ancillaryCollapsedSeries",
      "ancillaryCollapsedSeriesIndices",
      "collapsingSeriesIndices",
      "allSeriesCollapsed",
      "risingSeries",
      "previousPaths",
      "ignoreYAxisIndexes",
      "labels",
      "categoryLabels",
      "timescaleLabels",
      "groups"
    ]) {
      proxy(seriesNS, key);
    }
    Object.defineProperty(gl, "seriesNS", {
      value: seriesNS,
      writable: false,
      enumerable: false,
      configurable: true
    });
    const axesNS = {};
    for (const key of [
      "minX",
      "maxX",
      "initialMinX",
      "initialMaxX",
      "minY",
      "maxY",
      "minYArr",
      "maxYArr",
      "minZ",
      "maxZ",
      "minDate",
      "maxDate",
      "minXDiff",
      "xRange",
      "yRange",
      "zRange",
      "xAxisScale",
      "yAxisScale",
      "xAxisTicksPositions",
      "xTickAmount",
      "multiAxisTickAmount",
      "dataPoints",
      "maxValsInArrayIndex",
      "isXNumeric",
      "isMultipleYAxis",
      "isMultiLineX",
      "isDataXYZ",
      "dataFormatXNumeric",
      "allSeriesHasEqualX",
      "hasNullValues",
      "dataWasParsed",
      "hasXaxisGroups",
      "hasSeriesGroups",
      "skipFirstTimelinelabel",
      "skipLastTimelinelabel",
      "yValueDecimal",
      "invalidLogScale",
      "noLabelsProvided"
    ]) {
      proxy(axesNS, key);
    }
    Object.defineProperty(gl, "axes", {
      value: axesNS,
      writable: false,
      enumerable: false,
      configurable: true
    });
    const layoutNS = {};
    for (const key of [
      "svgWidth",
      "svgHeight",
      "gridWidth",
      "gridHeight",
      "translateX",
      "translateY",
      "translateXAxisX",
      "translateXAxisY",
      "translateYAxisX",
      "xAxisLabelsHeight",
      "xAxisGroupLabelsHeight",
      "xAxisLabelsWidth",
      "yAxisLabelsWidth",
      "yAxisWidths",
      "yLabelsCoords",
      "yTitleCoords",
      "padHorizontal",
      "barPadForNumericAxis",
      "rotateXLabels",
      "scaleX",
      "scaleY",
      "radialSize",
      "defaultLabels",
      "overlappingXLabels"
    ]) {
      proxy(layoutNS, key);
    }
    Object.defineProperty(gl, "layout", {
      value: layoutNS,
      writable: false,
      enumerable: false,
      configurable: true
    });
    const cacheNS = {};
    for (const key of [
      "domCache",
      "dimensionCache",
      "cachedSelectors",
      "textRectsCache",
      "pointsArray",
      "dataLabelsRects",
      "lastDrawnDataLabelsIndexes",
      "delayedElements",
      "resizeTimer",
      "selectionResizeTimer",
      "resizeObserver"
    ]) {
      proxy(cacheNS, key);
    }
    Object.defineProperty(gl, "cache", {
      value: cacheNS,
      writable: false,
      enumerable: false,
      configurable: true
    });
  }
  /**
   * Persistent chart state — set ONCE at chart construction and intentionally NOT
   * reset by initGlobalVars.  These values must survive updateSeries / re-render.
   *
   * Rule: if a value is recalculated fresh on every render it belongs in
   * initGlobalVars instead, not here.
   * @returns {import('../../types/internal').ChartGlobals}
   * @param {Record<string, any>} config
   */
  globalVars(config) {
    const globals = {
      // ── Identity (set once, never changes) ───────────────────────────────────
      chartID: null,
      // full chart ID: "apexcharts-<cuid>"
      cuid: null,
      // random suffix only
      // ── Event registry (accumulates listeners, never reset) ───────────────────
      events: {
        beforeMount: [],
        mounted: [],
        updated: [],
        clicked: [],
        selection: [],
        dataPointSelection: [],
        zoomed: [],
        scrolled: []
      },
      // ── Theme colors (set by Theme module after config merge) ─────────────────
      colors: [],
      fill: { colors: [] },
      // ── Animation-frame handles cancellable across re-renders ─────────────────
      // The chart-type instances that own these loops (Radial needle, Unit
      // gather/exit) are recreated every render, so the handle lives here: a new
      // render cancels the previous render's loop before starting its own,
      // instead of leaving it to animate detached nodes. NOT reset per render.
      radialNeedleRAF: null,
      unitGatherRAF: null,
      unitExitRAF: null,
      stroke: { colors: [] },
      dataLabels: { style: { colors: [] } },
      radarPolygons: { fill: { colors: [] } },
      markers: {
        colors: [],
        size: config.markers.size,
        largestSize: 0,
        // Set once per render by Markers.setGlobalMarkerSize: this chart's
        // markers are drawn as one path element per series (a subpath per
        // point) rather than one element per point, so there are no
        // `.apexcharts-marker` nodes to enlarge, ride or hit-test. Everything
        // that reads per-point marker nodes has to consult this.
        batched: false
      },
      // ── Device / environment detected once at startup ─────────────────────────
      // Note: isTouchDevice lives on w.interact — see Base.js. Shim installed there.
      LINE_HEIGHT_RATIO,
      // ── Chart-type flags (derived from config, set during Core.mount) ─────────
      axisCharts: true,
      // false for pie/radial/treemap etc.
      isSlopeChart: config.plotOptions.line.isSlopeChart,
      comboCharts: false,
      // true when mixing line + column series
      // ── Config snapshots (backups for zoom-reset / updateOptions) ────────────
      initialConfig: null,
      // deep clone of the original user config
      initialSeries: [],
      // The `--apx-surface` value Theme wrote into chart.background, so a later
      // token read can tell its own value from an explicit user background and
      // update it (see Theme.applyTokenChrome). Persistent: a re-render must
      // not forget it.
      tokenSurface: void 0,
      lastXAxis: [],
      lastYAxis: [],
      // ── User interaction state (must survive re-renders) ──────────────────────
      // Note: zoomEnabled, panEnabled, selectionEnabled, zoomed, selection,
      //       visibleXRange, selectedDataPoints, mousedown, clientX, clientY,
      //       lastClientPosition, capturedSeriesIndex, capturedDataPointIndex,
      //       disableZoomIn, disableZoomOut, isTouchDevice
      //       live on w.interact — see Base.js. Backward-compat shims installed there.
      // Series collapse state (user-driven, must persist across re-renders)
      allSeriesCollapsed: false,
      collapsedSeries: [],
      collapsedSeriesIndices: [],
      ancillaryCollapsedSeries: [],
      ancillaryCollapsedSeriesIndices: [],
      // Series collapsing on THIS render only (the legend click that hid it).
      // Transient, unlike collapsedSeriesIndices it is cleared as soon as the
      // render it triggered is done, so the exit tween can keep the outgoing
      // marks painted while every later render treats the series as hidden.
      collapsingSeriesIndices: [],
      risingSeries: [],
      // series being re-shown after collapse
      ignoreYAxisIndexes: [],
      // y-axis indices excluded during series collapse
      // ── Lifecycle / update flags ──────────────────────────────────────────────
      isDirty: false,
      // true when user called an update method manually
      isExecCalled: false,
      // true when update came via exec()
      dataChanged: false,
      // true when series data was changed dynamically
      resized: false,
      // true after a container resize
      // ── Data format flags (derived from config/series, stable between renders) ─
      // Note: dataFormatXNumeric lives on w.axisFlags — see Base.js. Shim installed there.
      // hasNullValues / invalidLogScale are recomputed every render and reset in
      // initGlobalVars (they are NOT stable between renders).
      // Persistent data tracking
      columnSeries: null,
      // tracks which series are rendered as bars/columns
      yaxis: null,
      // resolved yaxis config array
      total: 0,
      // running total (used by pie/radial)
      // ── Animation control ─────────────────────────────────────────────────────
      shouldAnimate: true,
      previousPaths: [],
      // paths from previous render — source for enter animation
      // polarArea's last-drawn sector angles. Its angles are count-based, not
      // value-based, so a data-change animation cannot reconstruct them from
      // previousPaths (the previous VALUES) the way pie does; Pie.draw stashes
      // the real ones here each render.
      prevPolarAngles: null,
      // Streaming scroll: previous frame's parsed rows + pixel positions,
      // captured by Series.getPreviousPaths(). Consulted (like previousPaths)
      // only while a data-change morph renders. See StreamScroll.
      prevStreamFrame: null,
      // Set for the duration of one render when a streaming scroll is driving
      // it; see captureStreamFrame / detectStreamScroll.
      streamScrolled: false,
      // Axis-chrome snapshot (tick label texts/positions + gridline positions)
      // captured alongside prevStreamFrame; consumed once by AxisTransition
      // after a variable-length re-render mounts.
      prevChromeFrame: null,
      // ── SVG viewport (set by Dimensions, but persistent as layout anchor) ─────
      svgWidth: 0,
      svgHeight: 0,
      // Fingerprint of the container inputs that fed the last rendered size, so
      // the window-resize handler can skip a redraw (and the animation teardown
      // it causes) when a resize does not change the chart's drawing box.
      lastResizeSignature: null,
      // Note: gridWidth, gridHeight, translateX, translateY, translateXAxisX,
      // translateXAxisY, xAxisLabelsHeight, xAxisGroupLabelsHeight, xAxisLabelsWidth,
      // rotateXLabels, xAxisHeight, yLabelsCoords, yTitleCoords live on w.layout —
      // see Base.js. Backward-compat shims installed there.
      defaultLabels: false,
      // Note: formatter properties (xLabelFormatter, yLabelFormatters, etc.) live on
      // w.formatters — see Base.js. Backward-compat shims installed there.
      yAxisLabelsWidth: 0,
      scaleX: 1,
      scaleY: 1,
      translateYAxisX: [],
      yAxisWidths: [],
      // ── Instances (created once, replaced only on full re-init) ──────────────
      tooltip: null,
      resizeObserver: null,
      // ── Locale (loaded once; changes only via setLocale()) ───────────────────
      locale: {},
      // ── Method queue (deferred calls during async operations) ────────────────
      memory: {
        methodsToExec: []
      },
      // ── Scale configuration constants — imported from utils/Constants.js ──────
      niceScaleAllowedMagMsd: NICE_SCALE_ALLOWED_MAG_MSD,
      niceScaleDefaultTicks: NICE_SCALE_DEFAULT_TICKS,
      // ── Multi-axis series mapping ─────────────────────────────────────────────
      seriesYAxisMap: [],
      // yAxis index → series indices[]
      seriesYAxisReverseMap: [],
      // series index → yAxis index
      noData: false
      // true when there is nothing to render
    };
    return (
      /** @type {import('../../types/internal').ChartGlobals} */
      /** @type {unknown} */
      globals
    );
  }
  /**
   * Lazy initial-series snapshot. Capturing `initialSeries` used to deep-clone
   * the entire series on every parse and every update: the single largest CPU
   * bucket at 50k+ points (profiled at ~23ms per 50k update). The setter now
   * stores a cheap per-series shallow copy (series OBJECTS copied, data arrays
   * shared) and the deep snapshot materializes only when something actually
   * reads it (resetSeries, toolbar reset-home, tooltip same-length check).
   *
   * Why sharing the data arrays is safe: internal "mutations" of a series'
   * data are property REPLACEMENTS (`series[i].data = []` on legend collapse),
   * which cannot reach the captured copies because each series object was
   * copied at capture time. The one in-place mutator (appendData's push loop)
   * re-captures immediately after mutating, so the pending snapshot never
   * spans the mutation.
   *
   * @param {Record<string, any>} globals
   */
  defineLazyInitialSeries(globals) {
    let src = [];
    let snap = null;
    Object.defineProperty(globals, "initialSeries", {
      configurable: true,
      enumerable: true,
      get() {
        if (snap === null) {
          snap = Utils$1.clone(src);
        }
        return snap;
      },
      set(value) {
        src = Array.isArray(value) ? value.map(
          (s2) => s2 && typeof s2 === "object" && !Array.isArray(s2) ? __spreadValues({}, s2) : s2
        ) : value;
        snap = null;
        globals._initialSeriesPeek = src;
      }
    });
    globals._initialSeriesPeek = src;
  }
  /**
   * @param {Record<string, any>} config
   */
  init(config) {
    const globals = this.globalVars(config);
    this.initGlobalVars(globals);
    this.defineLazyInitialSeries(globals);
    globals.initialConfig = Utils$1.extend({}, config);
    globals.initialSeries = config.series;
    globals.lastXAxis = Utils$1.clone(
      /** @type {NonNullable<typeof globals.initialConfig>} */
      globals.initialConfig.xaxis
    );
    globals.lastYAxis = Utils$1.clone(
      /** @type {NonNullable<typeof globals.initialConfig>} */
      globals.initialConfig.yaxis
    );
    return globals;
  }
}
class Base {
  /**
   * @param {object} opts
   */
  constructor(opts) {
    this.opts = opts;
  }
  /**
   * Build and return the full chart state object `w`.
   * @returns {import('../types/internal').ChartStateW}
   */
  init() {
    const config = new Config(this.opts).init({ responsiveOverride: false });
    const globals = new Globals().init(config);
    const w = {
      config,
      globals,
      dom: {},
      // DOM node cache — lives here, not inside globals
      interact: {
        // Tool mode (derived from toolbar config at construction, updated by Toolbar)
        zoomEnabled: config.chart.toolbar.autoSelected === "zoom" && config.chart.toolbar.tools.zoom && config.chart.zoom.enabled,
        panEnabled: config.chart.toolbar.autoSelected === "pan" && config.chart.toolbar.tools.pan,
        selectionEnabled: config.chart.toolbar.autoSelected === "selection" && config.chart.toolbar.tools.selection,
        // Measure tool pre-selected via toolbar.autoSelected: 'measure'. Armed by
        // the Measure module (self-arms on mount) and the toolbar button.
        measureEnabled: config.chart.toolbar.autoSelected === "measure" && !!config.chart.toolbar.tools.measure && !!(config.chart.measure && config.chart.measure.enabled),
        // Zoom / pan state (user-driven, must persist across re-renders)
        zoomed: false,
        selection: void 0,
        visibleXRange: void 0,
        selectedDataPoints: [],
        // Mouse / pointer state
        mousedown: false,
        clientX: null,
        clientY: null,
        lastClientPosition: {},
        // Tooltip capture state
        capturedSeriesIndex: -1,
        capturedDataPointIndex: -1,
        // Timescale zoom bounds (reset per render by TimeScale)
        disableZoomIn: false,
        disableZoomOut: false,
        // Device detection (set once at construction)
        isTouchDevice: Environment.isBrowser() ? "ontouchstart" in window || navigator.maxTouchPoints > 0 : false
      },
      formatters: {
        // Populated by Formatters.setLabelFormatters() each render
        xLabelFormatter: void 0,
        yLabelFormatters: [],
        xaxisTooltipFormatter: void 0,
        ttKeyFormatter: void 0,
        ttVal: void 0,
        ttZFormatter: void 0,
        legendFormatter: void 0
      },
      // Candlestick / boxplot OHLC arrays — written by Data.handleCandleStickBoxData()
      // each render; empty for all other chart types.
      candleData: {
        seriesCandleO: [],
        seriesCandleH: [],
        seriesCandleM: [],
        seriesCandleL: [],
        seriesCandleC: [],
        // Optional raw observations per boxPlot data point ([i][j] = number[]),
        // rendered as jitter dots. Empty unless boxPlot points are supplied.
        seriesBoxPoints: []
      },
      // Range chart arrays — written by Data.handleRangeData() each render;
      // empty for all other chart types.
      rangeData: {
        seriesRangeStart: [],
        seriesRangeEnd: [],
        seriesRange: []
      },
      // Violin distribution arrays — written by Data.handleViolinData() each
      // render; empty for all other chart types.
      //   seriesViolinDensity[i][j] = { values:number[], weights:number[], maxWeight:number }
      //   seriesViolinPoints[i][j]  = number[] (raw observations, value-axis units)
      //   seriesViolinMin/Max[i][j] = number (extent of density + points — drives Range.js)
      violinData: {
        seriesViolinDensity: [],
        seriesViolinPoints: [],
        seriesViolinMin: [],
        seriesViolinMax: []
      },
      // Histogram binning — written by Data.binHistogramData() each render;
      // empty for all other chart types.
      //   edges[k]     = bin boundaries (length = binCount + 1)
      //   counts[i][k] = raw observation count per series, before normalize
      //   rule         = the rule that chose the width ('fd', 'sturges', ...)
      histogramData: {
        edges: [],
        binWidth: 0,
        counts: [],
        rule: "",
        capped: false
      },
      // Label / category data — written by Data.parseData() and TimeScale each render.
      labelData: {
        labels: [],
        categoryLabels: [],
        timescaleLabels: [],
        // written by TimeScale.calculateTimeScaleMinMax()
        hasXaxisGroups: false,
        groups: [],
        seriesGroups: []
      },
      // Axis / parsing behaviour flags — written by Data.parseData() each render.
      axisFlags: {
        isXNumeric: false,
        dataFormatXNumeric: false,
        isDataXYZ: false,
        isRangeData: false,
        isRangeBar: false,
        isMultiLineX: false,
        noLabelsProvided: false,
        dataWasParsed: false
      },
      // Parsed series data — written by Data.parseData() each render.
      // Note: initialSeries and originalSeries are intentionally excluded —
      // they are persistent (survive re-renders) and remain on w.globals.
      seriesData: {
        series: [],
        // main y-values array
        seriesNames: [],
        seriesX: [],
        seriesZ: [],
        seriesColors: [],
        seriesGoals: [],
        stackedSeriesTotals: [],
        stackedSeriesTotalsByGroups: [],
        unitData: []
        // per-unit data for the `unit` chart (see SeriesData)
      },
      // Grid / axis layout computed by Dimensions.plotCoords() each render.
      // gridWidth/gridHeight/translateX/translateY are also used as starting
      // points by Dimensions on the next render (accumulated values), so the
      // shim must be bidirectional — reads and writes both route correctly.
      layout: {
        gridHeight: 0,
        gridWidth: 0,
        translateX: 0,
        translateY: 0,
        translateXAxisX: 0,
        translateXAxisY: 0,
        rotateXLabels: false,
        xAxisHeight: 0,
        xAxisLabelsHeight: 0,
        xAxisGroupLabelsHeight: 0,
        xAxisLabelsWidth: 0,
        yLabelsCoords: [],
        yTitleCoords: [],
        gridPad: { top: 0, right: 0, bottom: 0, left: 0 }
      }
    };
    Object.defineProperty(globals, "dom", {
      get() {
        return w.dom;
      },
      set(v) {
        w.dom = v;
      },
      enumerable: false,
      configurable: true
    });
    for (const key of [
      "xLabelFormatter",
      "yLabelFormatters",
      "xaxisTooltipFormatter",
      "ttKeyFormatter",
      "ttVal",
      "ttZFormatter",
      "legendFormatter"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.formatters[key]
          );
        },
        set(v) {
          w.formatters[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "zoomEnabled",
      "panEnabled",
      "selectionEnabled",
      "zoomed",
      "selection",
      "visibleXRange",
      "selectedDataPoints",
      "mousedown",
      "clientX",
      "clientY",
      "lastClientPosition",
      "capturedSeriesIndex",
      "capturedDataPointIndex",
      "disableZoomIn",
      "disableZoomOut",
      "isTouchDevice"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.interact[key]
          );
        },
        set(v) {
          w.interact[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "gridHeight",
      "gridWidth",
      "translateX",
      "translateY",
      "translateXAxisX",
      "translateXAxisY",
      "rotateXLabels",
      "xAxisHeight",
      "xAxisLabelsHeight",
      "xAxisGroupLabelsHeight",
      "xAxisLabelsWidth",
      "yLabelsCoords",
      "yTitleCoords",
      "gridPad"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.layout[key]
          );
        },
        set(v) {
          w.layout[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "series",
      "seriesNames",
      "seriesX",
      "seriesZ",
      "seriesColors",
      "seriesGoals",
      "stackedSeriesTotals",
      "stackedSeriesTotalsByGroups"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.seriesData[key]
          );
        },
        set(v) {
          w.seriesData[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "isXNumeric",
      "dataFormatXNumeric",
      "isDataXYZ",
      "isRangeData",
      "isRangeBar",
      "isMultiLineX",
      "noLabelsProvided",
      "dataWasParsed"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.axisFlags[key]
          );
        },
        set(v) {
          w.axisFlags[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "labels",
      "categoryLabels",
      "timescaleLabels",
      "hasXaxisGroups",
      "groups",
      "seriesGroups"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.labelData[key]
          );
        },
        set(v) {
          w.labelData[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of ["seriesRangeStart", "seriesRangeEnd", "seriesRange"]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.rangeData[key]
          );
        },
        set(v) {
          w.rangeData[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "seriesCandleO",
      "seriesCandleH",
      "seriesCandleM",
      "seriesCandleL",
      "seriesCandleC"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.candleData[key]
          );
        },
        set(v) {
          w.candleData[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    for (const key of [
      "seriesViolinDensity",
      "seriesViolinPoints",
      "seriesViolinMin",
      "seriesViolinMax"
    ]) {
      Object.defineProperty(globals, key, {
        get() {
          return (
            /** @type {Record<string,any>} */
            w.violinData[key]
          );
        },
        set(v) {
          w.violinData[key] = v;
        },
        enumerable: false,
        configurable: true
      });
    }
    return (
      /** @type {import('../types/internal').ChartStateW} */
      /** @type {unknown} */
      w
    );
  }
}
class CoreUtils {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
  }
  /**
   * @param {any[]} series
   * @param {string} chartType
   */
  static checkComboSeries(series, chartType) {
    let comboCharts = false;
    let comboBarCount = 0;
    let comboCount = 0;
    if (chartType === void 0) {
      chartType = "line";
    }
    if (series.length && typeof series[0].type !== "undefined") {
      series.forEach((s2) => {
        if (s2.type === "bar" || s2.type === "column" || s2.type === "candlestick" || s2.type === "boxPlot" || s2.type === "violin") {
          comboBarCount++;
        }
        if (typeof s2.type !== "undefined" && s2.type !== chartType) {
          comboCount++;
        }
      });
    }
    if (comboCount > 0) {
      comboCharts = true;
    }
    return {
      comboBarCount,
      comboCharts
    };
  }
  /**
   * @memberof CoreUtils
   * returns the sum of all individual values in a multiple stacked series
   * Eg. w.seriesData.series = [[32,33,43,12], [2,3,5,1]]
   *  @return [34,36,48,13]
   * @param {number[]} excludedSeriesIndices
   **/
  getStackedSeriesTotals(excludedSeriesIndices = []) {
    const w = this.w;
    const total = [];
    if (w.seriesData.series.length === 0) return total;
    for (let i2 = 0; i2 < w.seriesData.series[w.globals.maxValsInArrayIndex].length; i2++) {
      let t2 = 0;
      for (let j = 0; j < w.seriesData.series.length; j++) {
        if (typeof w.seriesData.series[j][i2] !== "undefined" && excludedSeriesIndices.indexOf(j) === -1) {
          t2 += w.seriesData.series[j][i2];
        }
      }
      total.push(t2);
    }
    return total;
  }
  // get total of the all values inside all series
  /**
   * @param {number | null} [index]
   */
  getSeriesTotalByIndex(index = null) {
    if (index === null) {
      return (
        /** @type {any[]} */
        this.w.config.series.reduce(
          (acc, cur) => acc + cur,
          0
        )
      );
    } else {
      const seriesAtIndex = this.w.seriesData.series[index];
      if (!Array.isArray(seriesAtIndex)) {
        return seriesAtIndex != null ? seriesAtIndex : 0;
      }
      return seriesAtIndex.reduce(
        (acc, cur) => acc + cur,
        0
      );
    }
  }
  /**
   * @memberof CoreUtils
   * returns the sum of values in a multiple stacked grouped charts
   * Eg. w.seriesData.series = [[32,33,43,12], [2,3,5,1], [43, 23, 34, 22]]
   * series 1 and 2 are in a group, while series 3 is in another group
   *  @return [[34, 36, 48, 12], [43, 23, 34, 22]]
   **/
  getStackedSeriesTotalsByGroups() {
    const w = this.w;
    const total = [];
    w.labelData.seriesGroups.forEach((sg) => {
      const includedIndexes = [];
      w.config.series.forEach((s2, si) => {
        if (sg.indexOf(w.seriesData.seriesNames[si]) > -1) {
          includedIndexes.push(si);
        }
      });
      const excludedIndices = w.seriesData.series.map((_, fi) => includedIndexes.indexOf(fi) === -1 ? fi : -1).filter((f) => f !== -1);
      total.push(this.getStackedSeriesTotals(excludedIndices));
    });
    return total;
  }
  setSeriesYAxisMappings() {
    const gl = this.w.globals;
    const cnf = this.w.config;
    let axisSeriesMap = [];
    const seriesYAxisReverseMap = [];
    const unassignedSeriesIndices = [];
    const seriesNameArrayStyle = this.w.seriesData.series.length > cnf.yaxis.length || /**
     * @param {ApexYAxis} a
     */
    cnf.yaxis.some((a2) => Array.isArray(a2.seriesName));
    cnf.series.forEach((_s, i2) => {
      unassignedSeriesIndices.push(i2);
      seriesYAxisReverseMap.push(null);
    });
    cnf.yaxis.forEach(
      (_yaxe, yi) => {
        axisSeriesMap[yi] = [];
      }
    );
    const unassignedYAxisIndices = [];
    cnf.yaxis.forEach((yaxe, yi) => {
      let assigned = false;
      if (yaxe.seriesName) {
        let seriesNames = [];
        if (Array.isArray(yaxe.seriesName)) {
          seriesNames = yaxe.seriesName;
        } else {
          seriesNames.push(yaxe.seriesName);
        }
        seriesNames.forEach((name2) => {
          cnf.series.forEach((s2, si) => {
            if (
              /** @type {any} */
              s2.name === name2
            ) {
              let remove = si;
              if (yi === si || seriesNameArrayStyle) {
                if (!seriesNameArrayStyle || unassignedSeriesIndices.indexOf(si) > -1) {
                  axisSeriesMap[yi].push([yi, si]);
                } else {
                  console.warn(
                    "Series '" + /** @type {any} */
                    s2.name + "' referenced more than once in what looks like the new style. That is, when using either seriesName: [], or when there are more series than yaxes."
                  );
                }
              } else {
                axisSeriesMap[si].push([si, yi]);
                remove = yi;
              }
              assigned = true;
              remove = unassignedSeriesIndices.indexOf(remove);
              if (remove !== -1) {
                unassignedSeriesIndices.splice(remove, 1);
              }
            }
          });
        });
      }
      if (!assigned) {
        unassignedYAxisIndices.push(yi);
      }
    });
    axisSeriesMap = axisSeriesMap.map((yaxe) => {
      const ra = [];
      yaxe.forEach((sa) => {
        seriesYAxisReverseMap[sa[1]] = sa[0];
        ra.push(sa[1]);
      });
      return ra;
    });
    let lastUnassignedYAxis = cnf.yaxis.length - 1;
    for (let i2 = 0; i2 < unassignedYAxisIndices.length; i2++) {
      lastUnassignedYAxis = unassignedYAxisIndices[i2];
      axisSeriesMap[lastUnassignedYAxis] = [];
      if (unassignedSeriesIndices) {
        const si = unassignedSeriesIndices[0];
        unassignedSeriesIndices.shift();
        axisSeriesMap[lastUnassignedYAxis].push(si);
        seriesYAxisReverseMap[si] = lastUnassignedYAxis;
      } else {
        break;
      }
    }
    unassignedSeriesIndices.forEach((i2) => {
      axisSeriesMap[lastUnassignedYAxis].push(i2);
      seriesYAxisReverseMap[i2] = lastUnassignedYAxis;
    });
    gl.seriesYAxisMap = axisSeriesMap.map((x) => x);
    gl.seriesYAxisReverseMap = seriesYAxisReverseMap.map((x) => x);
    gl.seriesYAxisMap.forEach((axisSeries, ai) => {
      axisSeries.forEach((si) => {
        if (
          /** @type {any} */
          cnf.series[si] && /** @type {any} */
          cnf.series[si].group === void 0
        ) {
          const _series = (
            /** @type {any} */
            cnf.series[si]
          );
          _series.group = "apexcharts-axis-".concat(ai.toString());
        }
      });
    });
  }
  /**
   * @param {number | null} [index]
   */
  isSeriesNull(index = null) {
    let r2 = [];
    const series = (
      /** @type {any[]} */
      this.w.config.series
    );
    if (index === null) {
      r2 = series.filter((d) => d !== null);
    } else if (series[index] && Array.isArray(series[index].data)) {
      r2 = series[index].data.filter((d) => d !== null);
    } else {
      r2 = series[index] !== null && series[index] !== void 0 ? [series[index]] : [];
    }
    return r2.length === 0;
  }
  /**
   * @param {number} index
   */
  seriesHaveSameValues(index) {
    const seriesAtIndex = this.w.seriesData.series[index];
    if (!Array.isArray(seriesAtIndex)) {
      return true;
    }
    return seriesAtIndex.every(
      (val, i2, arr) => val === arr[0]
    );
  }
  /**
   * @param {any[]} labels
   */
  getCategoryLabels(labels) {
    const w = this.w;
    let catLabels = labels.slice();
    if (w.config.xaxis.convertedCatToNumeric) {
      catLabels = labels.map((i2) => {
        return w.config.xaxis.labels.formatter(i2 - w.globals.minX + 1);
      });
    }
    return catLabels;
  }
  // maxValsInArrayIndex is the index of series[] which has the largest number of items
  getLargestSeries() {
    const w = this.w;
    w.globals.maxValsInArrayIndex = w.seriesData.series.map((a2) => a2.length).indexOf(
      Math.max.apply(
        Math,
        /**
         * @param {number[]} a
         */
        w.seriesData.series.map((a2) => a2.length)
      )
    );
  }
  getLargestMarkerSize() {
    const w = this.w;
    let size = 0;
    w.globals.markers.size.forEach((m) => {
      size = Math.max(size, m);
    });
    if (w.config.markers.discrete && w.config.markers.discrete.length) {
      w.config.markers.discrete.forEach((m) => {
        size = Math.max(size, m.size);
      });
    }
    if (size > 0) {
      if (w.config.markers.hover.size > 0) {
        size = w.config.markers.hover.size;
      } else {
        size += w.config.markers.hover.sizeOffset;
      }
    }
    w.globals.markers.largestSize = size;
    return size;
  }
  /**
   * @memberof Core
   * returns the sum of all values in a series
   * Eg. w.seriesData.series = [[32,33,43,12], [2,3,5,1]]
   *  @return [120, 11]
   **/
  getSeriesTotals() {
    const w = this.w;
    w.globals.seriesTotals = w.seriesData.series.map((ser) => {
      let total = 0;
      if (Array.isArray(ser)) {
        for (let j = 0; j < ser.length; j++) {
          total += ser[j];
        }
      } else {
        total += ser;
      }
      return total;
    });
  }
  /**
   * @param {number} minX
   * @param {number} maxX
   */
  getSeriesTotalsXRange(minX, maxX) {
    const w = this.w;
    const seriesTotalsXRange = w.seriesData.series.map((ser, index) => {
      let total = 0;
      for (let j = 0; j < ser.length; j++) {
        if (w.seriesData.seriesX[index][j] > minX && w.seriesData.seriesX[index][j] < maxX) {
          total += ser[j];
        }
      }
      return total;
    });
    return seriesTotalsXRange;
  }
  /**
   * @memberof CoreUtils
   * returns the percentage value of all individual values which can be used in a 100% stacked series
   * Eg. w.seriesData.series = [[32, 33, 43, 12], [2, 3, 5, 1]]
   *  @return [[94.11, 91.66, 89.58, 92.30], [5.88, 8.33, 10.41, 7.7]]
   **/
  getPercentSeries() {
    const w = this.w;
    w.globals.seriesPercent = w.seriesData.series.map((ser) => {
      const seriesPercent = [];
      if (Array.isArray(ser)) {
        for (let j = 0; j < ser.length; j++) {
          const total = w.seriesData.stackedSeriesTotals[j];
          let percent = 0;
          if (total) {
            percent = 100 * ser[j] / total;
          }
          seriesPercent.push(percent);
        }
      } else {
        const total = w.globals.seriesTotals.reduce((acc, val) => acc + val, 0);
        const percent = 100 * ser / total;
        seriesPercent.push(percent);
      }
      return seriesPercent;
    });
  }
  getCalculatedRatios() {
    const w = this.w;
    const gl = w.globals;
    const yRatio = [];
    let invertedYRatio = 0;
    let xRatio = 0;
    let invertedXRatio = 0;
    let zRatio = 0;
    let baseLineY = [];
    let baseLineInvertedY = 0.1;
    let baseLineX = 0;
    gl.yRange = [];
    if (gl.isMultipleYAxis) {
      for (let i2 = 0; i2 < gl.minYArr.length; i2++) {
        gl.yRange.push(Math.abs(gl.minYArr[i2] - gl.maxYArr[i2]));
        baseLineY.push(0);
      }
    } else {
      gl.yRange.push(Math.abs(gl.minY - gl.maxY));
    }
    gl.xRange = Math.abs(gl.maxX - gl.minX);
    gl.zRange = Math.abs(gl.maxZ - gl.minZ);
    for (let i2 = 0; i2 < gl.yRange.length; i2++) {
      yRatio.push(gl.yRange[i2] / this.w.layout.gridHeight);
    }
    xRatio = gl.xRange / this.w.layout.gridWidth;
    invertedYRatio = /** @type {any} */
    gl.yRange / this.w.layout.gridWidth;
    invertedXRatio = gl.xRange / this.w.layout.gridHeight;
    zRatio = gl.zRange / this.w.layout.gridHeight * 16;
    if (!zRatio) {
      zRatio = 1;
    }
    if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
      const _hasNegsGl = (
        /** @type {any} */
        gl
      );
      _hasNegsGl.hasNegs = true;
    }
    if (w.globals.seriesYAxisReverseMap.length > 0) {
      const scaleBaseLineYScale = (y, i2) => {
        const yAxis = w.config.yaxis[w.globals.seriesYAxisReverseMap[i2]];
        if (!yAxis) return 0;
        if (yAxis.logarithmic) return 0;
        const sign = y < 0 ? -1 : 1;
        y = Math.abs(y);
        return -sign * y / yRatio[i2];
      };
      if (gl.isMultipleYAxis) {
        baseLineY = [];
        for (let i2 = 0; i2 < yRatio.length; i2++) {
          baseLineY.push(scaleBaseLineYScale(gl.minYArr[i2], i2));
        }
      } else {
        baseLineY = [];
        baseLineY.push(scaleBaseLineYScale(gl.minY, 0));
        if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
          baseLineInvertedY = -gl.minY / invertedYRatio;
          baseLineX = gl.minX / xRatio;
        }
      }
    } else {
      baseLineY = [];
      baseLineY.push(0);
      baseLineInvertedY = 0;
      baseLineX = 0;
    }
    return {
      yRatio,
      invertedYRatio,
      zRatio,
      xRatio,
      invertedXRatio,
      baseLineInvertedY,
      baseLineY,
      baseLineX
    };
  }
  /**
   * @param {any[]} series
   */
  getLogSeries(series) {
    const w = this.w;
    w.globals.seriesLog = series.map((s2, i2) => {
      const yAxisIndex = w.globals.seriesYAxisReverseMap[i2];
      if (w.config.yaxis[yAxisIndex] && w.config.yaxis[yAxisIndex].logarithmic) {
        return s2.map((d) => {
          if (d === null) return null;
          return this.getLogVal(w.config.yaxis[yAxisIndex].logBase, d, i2);
        });
      } else {
        return s2;
      }
    });
    return w.globals.invalidLogScale ? series : w.globals.seriesLog;
  }
  /**
   * @param {number} val
   * @param {number} seriesIndex
   * @returns {number}
   */
  getLogValAtSeriesIndex(val, seriesIndex) {
    if (val === null) return (
      /** @type {any} */
      null
    );
    const w = this.w;
    const yAxisIndex = w.globals.seriesYAxisReverseMap[seriesIndex];
    if (w.config.yaxis[yAxisIndex] && w.config.yaxis[yAxisIndex].logarithmic) {
      return this.getLogVal(
        w.config.yaxis[yAxisIndex].logBase,
        val,
        seriesIndex
      );
    }
    return val;
  }
  /**
   * @param {number} base
   * @param {number} value
   */
  getBaseLog(base, value) {
    return Math.log(value) / Math.log(base);
  }
  /**
   * @param {number} b
   * @param {number} d
   * @param {number} seriesIndex
   */
  getLogVal(b, d, seriesIndex) {
    if (d <= 0) {
      return 0;
    }
    const w = this.w;
    const min_log_val = w.globals.minYArr[seriesIndex] === 0 ? -1 : this.getBaseLog(b, w.globals.minYArr[seriesIndex]);
    const max_log_val = w.globals.maxYArr[seriesIndex] === 0 ? 0 : this.getBaseLog(b, w.globals.maxYArr[seriesIndex]);
    const number_of_height_levels = max_log_val - min_log_val;
    const log_height_value = this.getBaseLog(b, d) - min_log_val;
    return log_height_value / number_of_height_levels;
  }
  /**
   * @param {number[]} yRatio
   */
  getLogYRatios(yRatio) {
    const w = this.w;
    const gl = this.w.globals;
    const _gl = (
      /** @type {any} */
      gl
    );
    _gl.yLogRatio = yRatio.slice();
    _gl.logYRange = /** @type {any[]} */
    gl.yRange.map(
      (_, i2) => {
        const yAxisIndex = w.globals.seriesYAxisReverseMap[i2];
        if (w.config.yaxis[yAxisIndex] && this.w.config.yaxis[yAxisIndex].logarithmic) {
          const range = 1;
          _gl.yLogRatio[i2] = range / this.w.layout.gridHeight;
          return range;
        }
        return gl.yRange[i2];
      }
    );
    return _gl.invalidLogScale ? yRatio.slice() : _gl.yLogRatio;
  }
  // Some config objects can be array - and we need to extend them correctly
  /**
   * @param {any} configInstance
   * @param {Record<string, any>} options
   * @param {import('../types/internal').ChartStateW} w
   */
  static extendArrayProps(configInstance, options2, w) {
    var _a, _b;
    if (options2 == null ? void 0 : options2.yaxis) {
      options2 = configInstance.extendYAxis(options2, w);
    }
    if (options2 == null ? void 0 : options2.annotations) {
      if (options2.annotations.yaxis) {
        options2 = configInstance.extendYAxisAnnotations(options2);
      }
      if ((_a = options2 == null ? void 0 : options2.annotations) == null ? void 0 : _a.xaxis) {
        options2 = configInstance.extendXAxisAnnotations(options2);
      }
      if ((_b = options2 == null ? void 0 : options2.annotations) == null ? void 0 : _b.points) {
        options2 = configInstance.extendPointAnnotations(options2);
      }
    }
    return options2;
  }
  // Series of the same group and type can be stacked together distinct from
  // other series of the same type on the same axis.
  /**
   * @param {Record<string, any>} typeSeries
   * @param {string[]} typeGroups
   * @param {string} type
   * @param {string} chartClass
   */
  drawSeriesByGroup(typeSeries, typeGroups, type, chartClass) {
    const w = this.w;
    const graph = [];
    if (typeSeries.series.length > 0) {
      typeGroups.forEach((gn) => {
        const gs = [];
        const gi = [];
        typeSeries.i.forEach((i2, ii) => {
          if (
            /** @type {Record<string,any>} */
            w.config.series[i2].group === gn
          ) {
            gs.push(typeSeries.series[ii]);
            gi.push(i2);
          }
        });
        gs.length > 0 && graph.push(
          /** @type {any} */
          chartClass.draw(gs, type, gi)
        );
      });
    }
    return graph;
  }
}
const SVGNS$1 = "http://www.w3.org/2000/svg";
class Point {
  /**
   * @param {number|{x:number,y:number}} x
   * @param {number} [y]
   */
  constructor(x, y) {
    if (typeof x === "object") {
      this.x = x.x;
      this.y = x.y;
    } else {
      this.x = x || 0;
      this.y = y || 0;
    }
  }
  /**
   * @param {Matrix} matrix
   */
  transform(matrix) {
    return matrix.apply(this);
  }
  clone() {
    return new Point(this.x, this.y);
  }
}
class Matrix {
  /**
   * Defaults to the identity matrix when called with no args.
   * @param {number} [a]
   * @param {number} [b]
   * @param {number} [c]
   * @param {number} [d]
   * @param {number} [e]
   * @param {number} [f]
   */
  constructor(a2, b, c2, d, e2, f) {
    this.a = a2 != null ? a2 : 1;
    this.b = b != null ? b : 0;
    this.c = c2 != null ? c2 : 0;
    this.d = d != null ? d : 1;
    this.e = e2 != null ? e2 : 0;
    this.f = f != null ? f : 0;
  }
  /**
   * @param {number} deg
   */
  rotate(deg) {
    const rad = deg * Math.PI / 180;
    const cos = Math.cos(rad);
    const sin = Math.sin(rad);
    return this.multiply(new Matrix(cos, sin, -sin, cos, 0, 0));
  }
  /**
   * @param {number} sx
   * @param {number} sy
   */
  scale(sx, sy) {
    return this.multiply(new Matrix(sx, 0, 0, sy != null ? sy : sx, 0, 0));
  }
  /**
   * @param {Matrix} m
   */
  multiply(m) {
    return new Matrix(
      this.a * m.a + this.c * m.b,
      this.b * m.a + this.d * m.b,
      this.a * m.c + this.c * m.d,
      this.b * m.c + this.d * m.d,
      this.a * m.e + this.c * m.f + this.e,
      this.b * m.e + this.d * m.f + this.f
    );
  }
  /**
   * @param {Point} point
   */
  apply(point) {
    return new Point(
      this.a * point.x + this.c * point.y + this.e,
      this.b * point.x + this.d * point.y + this.f
    );
  }
}
class Box {
  /**
   * @param {number} x
   * @param {number} y
   * @param {number} w
   * @param {number} h
   */
  constructor(x, y, w, h2) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h2;
    this.width = w;
    this.height = h2;
    this.x2 = x + w;
    this.y2 = y + h2;
  }
}
/*!
 * Path morphing for SVG path animations
 * Based on svg.pathmorphing.js by Ulrich-Matthias Schäfer (MIT License)
 * Refactored to be standalone (no SVG.js dependency)
 *
 * Two algorithms are exported:
 *   - morphPaths()    — command-level interpolation; preserves curves but can
 *                       produce "wings/flips" when two shapes have very
 *                       different topology (e.g. bar rect → pie arc).
 *   - morphPolygons() — resamples both shapes into N evenly-spaced perimeter
 *                       points and tweens point-by-point with rotation-search
 *                       alignment; always smooth and non-self-intersecting,
 *                       at the cost of throwing away curve smoothness.
 */
function parsePath(d) {
  if (!d || typeof d !== "string") return [["M", 0, 0]];
  const commands = [];
  const re = /([MmLlHhVvCcSsQqTtAaZz])\s*/g;
  const numRe = /[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?/gi;
  let match;
  const letters = [];
  const positions = [];
  while ((match = re.exec(d)) !== null) {
    letters.push(match[1]);
    positions.push(match.index);
  }
  for (let i2 = 0; i2 < letters.length; i2++) {
    const start = positions[i2] + letters[i2].length;
    const end = i2 + 1 < positions.length ? positions[i2 + 1] : d.length;
    const paramStr = d.substring(start, end);
    const nums = [];
    let numMatch;
    numRe.lastIndex = 0;
    while ((numMatch = numRe.exec(paramStr)) !== null) {
      nums.push(parseFloat(numMatch[0]));
    }
    const cmd = letters[i2].toUpperCase();
    if (cmd === "Z") {
      commands.push(["Z"]);
    } else if (cmd === "M" || cmd === "L" || cmd === "T") {
      for (let j = 0; j < nums.length; j += 2) {
        commands.push([cmd, nums[j], nums[j + 1]]);
      }
    } else if (cmd === "H") {
      for (let j = 0; j < nums.length; j++) {
        commands.push([cmd, nums[j]]);
      }
    } else if (cmd === "V") {
      for (let j = 0; j < nums.length; j++) {
        commands.push([cmd, nums[j]]);
      }
    } else if (cmd === "C") {
      for (let j = 0; j < nums.length; j += 6) {
        commands.push([
          cmd,
          nums[j],
          nums[j + 1],
          nums[j + 2],
          nums[j + 3],
          nums[j + 4],
          nums[j + 5]
        ]);
      }
    } else if (cmd === "S" || cmd === "Q") {
      for (let j = 0; j < nums.length; j += 4) {
        commands.push([cmd, nums[j], nums[j + 1], nums[j + 2], nums[j + 3]]);
      }
    } else if (cmd === "A") {
      for (let j = 0; j < nums.length; j += 7) {
        commands.push([
          cmd,
          nums[j],
          nums[j + 1],
          nums[j + 2],
          nums[j + 3],
          nums[j + 4],
          nums[j + 5],
          nums[j + 6]
        ]);
      }
    }
  }
  if (commands.length === 0) {
    commands.push(["M", 0, 0]);
  }
  return commands;
}
function pathBbox(arr) {
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
  arr.forEach((cmd) => {
    for (let i2 = 1; i2 < cmd.length; i2 += 2) {
      if (i2 + 1 <= cmd.length) {
        const x = cmd[i2];
        const y = cmd[i2 + 1];
        if (typeof x === "number" && typeof y === "number") {
          if (x < minX) minX = x;
          if (x > maxX) maxX = x;
          if (y < minY) minY = y;
          if (y > maxY) maxY = y;
        }
      }
    }
  });
  if (minX === Infinity) {
    return { x: 0, y: 0, width: 0, height: 0 };
  }
  return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
}
function arrayToPath(arr) {
  return arr.map((cmd) => cmd.join(" ")).join(" ");
}
function simplify(val) {
  switch (val[0]) {
    case "z":
    case "Z":
      val[0] = "L";
      val[1] = this.start[0];
      val[2] = this.start[1];
      break;
    case "H":
      val[0] = "L";
      val[2] = this.pos[1];
      break;
    case "V":
      val[0] = "L";
      val[2] = val[1];
      val[1] = this.pos[0];
      break;
    case "T":
      val[0] = "Q";
      val[3] = val[1];
      val[4] = val[2];
      val[1] = this.reflection[1];
      val[2] = this.reflection[0];
      break;
    case "S":
      val[0] = "C";
      val[6] = val[4];
      val[5] = val[3];
      val[4] = val[2];
      val[3] = val[1];
      val[2] = this.reflection[1];
      val[1] = this.reflection[0];
      break;
  }
  return val;
}
function setPosAndReflection(val) {
  var len = val.length;
  this.pos = [val[len - 2], val[len - 1]];
  if ("SCQT".indexOf(val[0]) != -1) {
    this.reflection = [
      2 * this.pos[0] - val[len - 4],
      2 * this.pos[1] - val[len - 3]
    ];
  }
  return val;
}
function toBezier(val) {
  var _a;
  var retVal = [val];
  switch (val[0]) {
    case "M":
      this.pos = this.start = [val[1], val[2]];
      return retVal;
    case "L":
      val[5] = val[3] = val[1];
      val[6] = val[4] = val[2];
      val[1] = this.pos[0];
      val[2] = this.pos[1];
      break;
    case "Q":
      val[6] = val[4];
      val[5] = val[3];
      val[4] = val[4] * 1 / 3 + val[2] * 2 / 3;
      val[3] = val[3] * 1 / 3 + val[1] * 2 / 3;
      val[2] = this.pos[1] * 1 / 3 + val[2] * 2 / 3;
      val[1] = this.pos[0] * 1 / 3 + val[1] * 2 / 3;
      break;
    case "A":
      retVal = arcToBezier((_a = this.pos) != null ? _a : [], val);
      val = retVal[0];
      break;
  }
  val[0] = "C";
  this.pos = [val[5], val[6]];
  this.reflection = [2 * val[5] - val[3], 2 * val[6] - val[4]];
  return retVal;
}
function findNextM(arr, offset) {
  if (offset === false) return false;
  for (var i2 = offset, len = arr.length; i2 < len; ++i2) {
    if (arr[i2][0] == "M") return i2;
  }
  return false;
}
function arcToBezier(pos, val) {
  var rx = Math.abs(val[1]), ry = Math.abs(val[2]), xAxisRotation = val[3] % 360, largeArcFlag = val[4], sweepFlag = val[5], x = val[6], y = val[7], A = new Point(pos[0], pos[1]), B = new Point(x, y), primedCoord, lambda, mat, k, c2, cSquare, t2, O, OA, OB, tetaStart, tetaEnd, deltaTeta, nbSectors, f, arcSegPoints, angle, sinAngle, cosAngle, pt, i2, il, retVal = [], x1, y1, x2, y2;
  if (rx === 0 || ry === 0 || A.x === B.x && A.y === B.y) {
    return [["C", A.x, A.y, B.x, B.y, B.x, B.y]];
  }
  primedCoord = new Point((A.x - B.x) / 2, (A.y - B.y) / 2).transform(
    // Start with the identity matrix (no args → Matrix defaults a=d=1, others 0).
    // Passing all-zero args here would produce a degenerate zero matrix, since
    // `0 ?? 1` is `0`, not `1` — every subsequent transform then yields (0,0)
    // and the arc-to-bezier conversion crashes on a NaN cascade.
    /** @type {any} */
    new Matrix().rotate(xAxisRotation)
  );
  lambda = primedCoord.x * primedCoord.x / (rx * rx) + primedCoord.y * primedCoord.y / (ry * ry);
  if (lambda > 1) {
    lambda = Math.sqrt(lambda);
    rx = lambda * rx;
    ry = lambda * ry;
  }
  mat = /** @type {any} */
  new Matrix().rotate(xAxisRotation).scale(1 / rx, 1 / ry).rotate(-xAxisRotation);
  A = A.transform(mat);
  B = B.transform(mat);
  k = [B.x - A.x, B.y - A.y];
  cSquare = k[0] * k[0] + k[1] * k[1];
  c2 = Math.sqrt(cSquare);
  k[0] /= c2;
  k[1] /= c2;
  t2 = cSquare < 4 ? Math.sqrt(1 - cSquare / 4) : 0;
  if (largeArcFlag === sweepFlag) {
    t2 *= -1;
  }
  O = new Point((B.x + A.x) / 2 + t2 * -k[1], (B.y + A.y) / 2 + t2 * k[0]);
  OA = new Point(A.x - O.x, A.y - O.y);
  OB = new Point(B.x - O.x, B.y - O.y);
  tetaStart = Math.acos(OA.x / Math.sqrt(OA.x * OA.x + OA.y * OA.y));
  if (OA.y < 0) tetaStart *= -1;
  tetaEnd = Math.acos(OB.x / Math.sqrt(OB.x * OB.x + OB.y * OB.y));
  if (OB.y < 0) tetaEnd *= -1;
  if (sweepFlag && tetaStart > tetaEnd) {
    tetaEnd += 2 * Math.PI;
  }
  if (!sweepFlag && tetaStart < tetaEnd) {
    tetaEnd -= 2 * Math.PI;
  }
  nbSectors = Math.ceil(Math.abs(tetaStart - tetaEnd) * 2 / Math.PI);
  arcSegPoints = [];
  angle = tetaStart;
  deltaTeta = (tetaEnd - tetaStart) / nbSectors;
  f = 4 * Math.tan(deltaTeta / 4) / 3;
  for (i2 = 0; i2 <= nbSectors; i2++) {
    cosAngle = Math.cos(angle);
    sinAngle = Math.sin(angle);
    pt = new Point(O.x + cosAngle, O.y + sinAngle);
    arcSegPoints[i2] = [
      new Point(pt.x + f * sinAngle, pt.y - f * cosAngle),
      pt,
      new Point(pt.x - f * sinAngle, pt.y + f * cosAngle)
    ];
    angle += deltaTeta;
  }
  arcSegPoints[0][0] = arcSegPoints[0][1].clone();
  arcSegPoints[arcSegPoints.length - 1][2] = arcSegPoints[arcSegPoints.length - 1][1].clone();
  mat = /** @type {any} */
  new Matrix().rotate(xAxisRotation).scale(rx, ry).rotate(-xAxisRotation);
  for (i2 = 0, il = arcSegPoints.length; i2 < il; i2++) {
    arcSegPoints[i2][0] = arcSegPoints[i2][0].transform(mat);
    arcSegPoints[i2][1] = arcSegPoints[i2][1].transform(mat);
    arcSegPoints[i2][2] = arcSegPoints[i2][2].transform(mat);
  }
  for (i2 = 1, il = arcSegPoints.length; i2 < il; i2++) {
    pt = arcSegPoints[i2 - 1][2];
    x1 = pt.x;
    y1 = pt.y;
    pt = arcSegPoints[i2][0];
    x2 = pt.x;
    y2 = pt.y;
    pt = arcSegPoints[i2][1];
    x = pt.x;
    y = pt.y;
    retVal.push(["C", x1, y1, x2, y2, x, y]);
  }
  return retVal;
}
function handleBlock(startArr, startOffsetM, startOffsetNextM, destArr, destOffsetM, destOffsetNextM) {
  var startArrTemp = startArr.slice(startOffsetM, startOffsetNextM || void 0);
  var destArrTemp = destArr.slice(destOffsetM, destOffsetNextM || void 0);
  var i2 = 0, posStart = { pos: [0, 0], start: [0, 0] }, posDest = { pos: [0, 0], start: [0, 0] };
  while (true) {
    startArrTemp[i2] = simplify.call(posStart, startArrTemp[i2]);
    destArrTemp[i2] = simplify.call(posDest, destArrTemp[i2]);
    if (startArrTemp[i2][0] != destArrTemp[i2][0] || startArrTemp[i2][0] == "M" || startArrTemp[i2][0] == "A" && (startArrTemp[i2][4] != destArrTemp[i2][4] || startArrTemp[i2][5] != destArrTemp[i2][5])) {
      Array.prototype.splice.apply(
        startArrTemp,
        /** @type {[number, number, ...any[]]} */
        [i2, 1].concat(
          /** @type {any} */
          toBezier.call(posStart, startArrTemp[i2])
        )
      );
      Array.prototype.splice.apply(
        destArrTemp,
        /** @type {[number, number, ...any[]]} */
        [i2, 1].concat(
          /** @type {any} */
          toBezier.call(posDest, destArrTemp[i2])
        )
      );
    } else {
      startArrTemp[i2] = /** @type {any} */
      setPosAndReflection.call(
        posStart,
        startArrTemp[i2]
      );
      destArrTemp[i2] = /** @type {any} */
      setPosAndReflection.call(
        posDest,
        destArrTemp[i2]
      );
    }
    if (++i2 == startArrTemp.length && i2 == destArrTemp.length) break;
    if (i2 == startArrTemp.length) {
      startArrTemp.push([
        "C",
        posStart.pos[0],
        posStart.pos[1],
        posStart.pos[0],
        posStart.pos[1],
        posStart.pos[0],
        posStart.pos[1]
      ]);
    }
    if (i2 == destArrTemp.length) {
      destArrTemp.push([
        "C",
        posDest.pos[0],
        posDest.pos[1],
        posDest.pos[0],
        posDest.pos[1],
        posDest.pos[0],
        posDest.pos[1]
      ]);
    }
  }
  return { start: startArrTemp, dest: destArrTemp };
}
function synchronizePaths(fromD, toD) {
  var startArr = parsePath(fromD);
  var destArr = parsePath(toD);
  var startOffsetM = 0;
  var destOffsetM = 0;
  var startOffsetNextM = false;
  var destOffsetNextM = false;
  var result;
  while (true) {
    if (startOffsetM === false && destOffsetM === false) break;
    startOffsetNextM = findNextM(
      startArr,
      startOffsetM === false ? false : startOffsetM + 1
    );
    destOffsetNextM = findNextM(
      destArr,
      destOffsetM === false ? false : destOffsetM + 1
    );
    if (startOffsetM === false) {
      const bbox = pathBbox(
        /** @type {any} */
        result.start
      );
      if (bbox.height == 0 || bbox.width == 0) {
        startOffsetM = startArr.push(startArr[0]) - 1;
      } else {
        startOffsetM = startArr.push([
          "M",
          bbox.x + bbox.width / 2,
          bbox.y + bbox.height / 2
        ]) - 1;
      }
    }
    if (destOffsetM === false) {
      const bbox = pathBbox(
        /** @type {any} */
        result.dest
      );
      if (bbox.height == 0 || bbox.width == 0) {
        destOffsetM = destArr.push(destArr[0]) - 1;
      } else {
        destOffsetM = destArr.push([
          "M",
          bbox.x + bbox.width / 2,
          bbox.y + bbox.height / 2
        ]) - 1;
      }
    }
    result = handleBlock(
      startArr,
      startOffsetM,
      startOffsetNextM,
      destArr,
      destOffsetM,
      destOffsetNextM
    );
    startArr = startArr.slice(0, startOffsetM).concat(
      result.start,
      startOffsetNextM === false ? [] : startArr.slice(startOffsetNextM)
    );
    destArr = destArr.slice(0, destOffsetM).concat(
      result.dest,
      destOffsetNextM === false ? [] : destArr.slice(destOffsetNextM)
    );
    startOffsetM = startOffsetNextM === false ? false : startOffsetM + result.start.length;
    destOffsetM = destOffsetNextM === false ? false : destOffsetM + result.dest.length;
  }
  return { start: startArr, dest: destArr };
}
function morphPaths(fromD, toD) {
  var synced = synchronizePaths(fromD, toD);
  var startArr = synced.start;
  var destArr = synced.dest;
  return function(pos) {
    var result = startArr.map(function(from, idx) {
      return destArr[idx].map(function(to, toIdx) {
        if (toIdx === 0) return to;
        return from[toIdx] + (destArr[idx][toIdx] - from[toIdx]) * pos;
      });
    });
    return arrayToPath(result);
  };
}
let _measureSvg = null;
let _measurePath = null;
function samplePathPoints(d, n2) {
  const pts = new Array(n2);
  if (!Environment.isBrowser()) {
    const arr = parsePath(d);
    const bbox = pathBbox(arr);
    const cx = bbox.x + bbox.width / 2;
    const cy = bbox.y + bbox.height / 2;
    for (let i2 = 0; i2 < n2; i2++) pts[i2] = { x: cx, y: cy };
    return pts;
  }
  if (!_measureSvg) {
    _measureSvg = /** @type {SVGSVGElement} */
    document.createElementNS("http://www.w3.org/2000/svg", "svg");
    _measureSvg.setAttribute("width", "0");
    _measureSvg.setAttribute("height", "0");
    _measureSvg.setAttribute(
      "style",
      "position:absolute;width:0;height:0;visibility:hidden;pointer-events:none;"
    );
    _measurePath = /** @type {SVGPathElement} */
    document.createElementNS("http://www.w3.org/2000/svg", "path");
    _measureSvg.appendChild(_measurePath);
    document.body.appendChild(_measureSvg);
  }
  _measurePath.setAttribute("d", d || "M0 0");
  let len = 0;
  try {
    len = _measurePath.getTotalLength();
  } catch (e2) {
    len = 0;
  }
  if (!len || !isFinite(len)) {
    const arr = parsePath(d);
    const bbox = pathBbox(arr);
    const cx = bbox.x + bbox.width / 2;
    const cy = bbox.y + bbox.height / 2;
    for (let i2 = 0; i2 < n2; i2++) pts[i2] = { x: cx, y: cy };
    return pts;
  }
  for (let i2 = 0; i2 < n2; i2++) {
    try {
      const p = _measurePath.getPointAtLength(i2 / n2 * len);
      pts[i2] = { x: p.x, y: p.y };
    } catch (e2) {
      pts[i2] = { x: 0, y: 0 };
    }
  }
  return pts;
}
function morphPolygons(fromD, toD, n2 = 96) {
  const fromPts = samplePathPoints(fromD, n2);
  const toPts = samplePathPoints(toD, n2);
  let bestOffset = 0;
  let bestDist = Infinity;
  for (let off = 0; off < n2; off++) {
    let dist = 0;
    for (let i2 = 0; i2 < n2; i2++) {
      const a2 = fromPts[(i2 + off) % n2];
      const b = toPts[i2];
      const dx = a2.x - b.x;
      const dy = a2.y - b.y;
      dist += dx * dx + dy * dy;
      if (dist >= bestDist) break;
    }
    if (dist < bestDist) {
      bestDist = dist;
      bestOffset = off;
    }
  }
  const aligned = new Array(n2);
  for (let i2 = 0; i2 < n2; i2++) {
    aligned[i2] = fromPts[(i2 + bestOffset) % n2];
  }
  return function(pos) {
    let out = "";
    for (let i2 = 0; i2 < n2; i2++) {
      const a2 = aligned[i2];
      const b = toPts[i2];
      const x = a2.x + (b.x - a2.x) * pos;
      const y = a2.y + (b.y - a2.y) * pos;
      out += (i2 === 0 ? "M" : "L") + x.toFixed(3) + " " + y.toFixed(3) + " ";
    }
    return out + "Z";
  };
}
function easeInOut(t2) {
  return -Math.cos(t2 * Math.PI) / 2 + 0.5;
}
let _defaultEasing = easeInOut;
function setDefaultEasing(fn) {
  _defaultEasing = typeof fn === "function" ? fn : easeInOut;
}
function parseColor(str) {
  if (!str || typeof str !== "string") return null;
  if (str[0] === "#") {
    let hex = str.slice(1);
    if (hex.length === 3)
      hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
    const n2 = parseInt(hex, 16);
    return [n2 >> 16 & 255, n2 >> 8 & 255, n2 & 255, 1];
  }
  const m = str.match(
    /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/
  );
  if (m) return [+m[1], +m[2], +m[3], m[4] !== void 0 ? +m[4] : 1];
  return null;
}
function interpolateColor(from, to, pos) {
  return `rgba(${Math.round(from[0] + (to[0] - from[0]) * pos)},${Math.round(from[1] + (to[1] - from[1]) * pos)},${Math.round(from[2] + (to[2] - from[2]) * pos)},${from[3] + (to[3] - from[3]) * pos})`;
}
class SVGAnimationRunner {
  /**
   * @param {any} element
   * @param {number} duration
   * @param {number} delay
   */
  constructor(element, duration, delay) {
    this.el = element;
    this.duration = duration != null ? duration : 300;
    this.delay = delay || 0;
    this._attrTarget = null;
    this._plotTarget = null;
    this._plotSnap = null;
    this._plotAlgorithm = "commands";
    this._afterCb = null;
    this._duringCb = null;
    this._easing = null;
    this._next = null;
    this._root = null;
    this._scheduled = false;
  }
  /**
   * Override the easing for this runner (else the module default is used).
   * @param {(t:number)=>number} fn
   */
  ease(fn) {
    if (typeof fn === "function") this._easing = fn;
    this._schedule();
    return this;
  }
  /**
   * @param {Record<string, any>} to
   */
  attr(to) {
    this._attrTarget = to;
    this._schedule();
    return this;
  }
  /**
   * @param {string} d
   * @param {'commands' | 'polygons'} [algorithm] - morph engine to use for
   *   the d→d interpolation. 'commands' (default) is the legacy
   *   per-command lerp; 'polygons' resamples both paths into N evenly
   *   spaced points and tweens point-by-point (smoother for shapes with
   *   very different anchor-point counts).
   * @param {string} [snapTo] - final d to land on when it differs from the
   *   interpolation target. Used by reconciled length-change morphs: the
   *   tween runs against a padded path (extra anchors lying exactly on the
   *   final geometry) but the element must end with the renderer's clean,
   *   un-padded d so later captures and morphs stay stable.
   */
  plot(d, algorithm, snapTo) {
    this._plotTarget = d;
    if (algorithm) this._plotAlgorithm = algorithm;
    this._plotSnap = snapTo || null;
    this._schedule();
    return this;
  }
  /**
   * @param {Function} fn
   */
  after(fn) {
    this._afterCb = fn;
    this._schedule();
    return this;
  }
  /**
   * @param {Function} fn
   */
  during(fn) {
    this._duringCb = fn;
    this._schedule();
    return this;
  }
  /**
   * @param {number} duration
   * @param {number} delay
   */
  animate(duration, delay) {
    const next = new SVGAnimationRunner(this.el, duration, delay);
    this._next = next;
    next._root = this._root || this;
    return next;
  }
  _schedule() {
    const root = this._root || this;
    if (!root._scheduled) {
      root._scheduled = true;
      queueMicrotask(() => root._executeChain());
    }
  }
  _executeChain() {
    const chain = [];
    let r2 = this;
    while (r2) {
      chain.push(r2);
      r2 = r2._next;
    }
    let cumulativeDelay = 0;
    chain.forEach((runner) => {
      cumulativeDelay += runner.delay;
      runner._execute(cumulativeDelay);
      cumulativeDelay += runner.duration;
    });
  }
  /**
   * @param {number} startDelay
   */
  _execute(startDelay) {
    const el = this.el;
    const duration = this.duration;
    if (duration <= 1) {
      const apply = () => {
        if (this._attrTarget) el.attr(this._attrTarget);
        if (this._plotTarget) el.plot(this._plotSnap || this._plotTarget);
        if (this._afterCb) this._afterCb.call(el);
      };
      if (startDelay > 0) {
        setTimeout(apply, startDelay);
      } else {
        apply();
      }
      return;
    }
    const run = () => {
      const fromAttrs = (
        /** @type {Record<string, any>} */
        {}
      );
      const fromColors = (
        /** @type {Record<string, any>} */
        {}
      );
      const toColors = (
        /** @type {Record<string, any>} */
        {}
      );
      if (this._attrTarget) {
        for (const key of Object.keys(this._attrTarget)) {
          const fromVal = el.attr(key);
          fromAttrs[key] = fromVal;
          const fc = parseColor(fromVal);
          const tc = parseColor(String(this._attrTarget[key]));
          if (fc && tc) {
            fromColors[key] = fc;
            toColors[key] = tc;
          }
        }
      }
      let morphFn = null;
      if (this._plotTarget) {
        const fromPath = el.attr("d") || "";
        try {
          morphFn = this._plotAlgorithm === "polygons" ? morphPolygons(fromPath, this._plotTarget) : morphPaths(fromPath, this._plotTarget);
        } catch (e2) {
          morphFn = null;
        }
      }
      const start = performance.now();
      const easing = this._easing || _defaultEasing;
      const tick = (now) => {
        const elapsed = now - start;
        const rawPos = Math.min(elapsed / duration, 1);
        const pos = easing(rawPos);
        if (this._attrTarget) {
          if (rawPos >= 1) {
            el.attr(this._attrTarget);
          } else {
            const current = (
              /** @type {Record<string, any>} */
              {}
            );
            for (const key of Object.keys(this._attrTarget)) {
              if (fromColors[key] && toColors[key]) {
                current[key] = interpolateColor(
                  fromColors[key],
                  toColors[key],
                  pos
                );
              } else {
                const from = parseFloat(fromAttrs[key]);
                const to = parseFloat(this._attrTarget[key]);
                if (!isNaN(from) && !isNaN(to)) {
                  current[key] = from + (to - from) * pos;
                }
              }
            }
            el.attr(current);
          }
        }
        if (morphFn && rawPos < 1) {
          el.attr(
            "d",
            /** @type {any} */
            morphFn(pos)
          );
        }
        if (this._duringCb) this._duringCb(pos);
        if (rawPos < 1) {
          BrowserAPIs.requestAnimationFrame(tick);
        } else {
          if (this._plotTarget) {
            el.attr("d", this._plotSnap || this._plotTarget);
          }
          if (this._afterCb) this._afterCb.call(el);
        }
      };
      BrowserAPIs.requestAnimationFrame(tick);
    };
    if (startDelay > 0) {
      setTimeout(run, startDelay);
    } else {
      run();
    }
  }
}
function installAnimationMethods(ElementClass) {
  ElementClass.prototype.animate = function(duration, delay) {
    return new SVGAnimationRunner(this, duration, delay);
  };
}
function easeInOutSine(t2) {
  return -Math.cos(t2 * Math.PI) / 2 + 0.5;
}
function cubicBezier(x1, y1, x2, y2) {
  x1 = Math.min(Math.max(x1, 0), 1);
  x2 = Math.min(Math.max(x2, 0), 1);
  const cx = 3 * x1;
  const bx = 3 * (x2 - x1) - cx;
  const ax = 1 - cx - bx;
  const cy = 3 * y1;
  const by = 3 * (y2 - y1) - cy;
  const ay = 1 - cy - by;
  const sampleX = (t2) => ((ax * t2 + bx) * t2 + cx) * t2;
  const sampleY = (t2) => ((ay * t2 + by) * t2 + cy) * t2;
  const solveT = (x) => {
    let lo = 0;
    let hi = 1;
    let t2 = x;
    if (t2 < lo) return lo;
    if (t2 > hi) return hi;
    while (lo < hi) {
      const xt = sampleX(t2);
      if (Math.abs(xt - x) < 1e-4) return t2;
      if (x > xt) lo = t2;
      else hi = t2;
      t2 = (lo + hi) / 2;
    }
    return t2;
  };
  return (t2) => t2 <= 0 ? 0 : t2 >= 1 ? 1 : sampleY(solveT(t2));
}
const REGISTRY = /* @__PURE__ */ new Map();
const linear = (t2) => t2;
REGISTRY.set("linear", linear);
REGISTRY.set("easeInOutSine", easeInOutSine);
REGISTRY.set("easeInSine", (t2) => 1 - Math.cos(t2 * Math.PI / 2));
REGISTRY.set("easeOutSine", (t2) => Math.sin(t2 * Math.PI / 2));
REGISTRY.set("easeInQuad", (t2) => t2 * t2);
REGISTRY.set("easeOutQuad", (t2) => 1 - (1 - t2) * (1 - t2));
REGISTRY.set(
  "easeInOutQuad",
  (t2) => t2 < 0.5 ? 2 * t2 * t2 : 1 - Math.pow(-2 * t2 + 2, 2) / 2
);
REGISTRY.set("easeInCubic", (t2) => t2 * t2 * t2);
REGISTRY.set("easeOutCubic", (t2) => 1 - Math.pow(1 - t2, 3));
REGISTRY.set(
  "easeInOutCubic",
  (t2) => t2 < 0.5 ? 4 * t2 * t2 * t2 : 1 - Math.pow(-2 * t2 + 2, 3) / 2
);
REGISTRY.set("easeOutBack", (t2) => {
  const c1 = 1.70158;
  const c3 = c1 + 1;
  return 1 + c3 * Math.pow(t2 - 1, 3) + c1 * Math.pow(t2 - 1, 2);
});
REGISTRY.set("easeInOutBack", (t2) => {
  const c1 = 1.70158;
  const c2 = c1 * 1.525;
  return t2 < 0.5 ? Math.pow(2 * t2, 2) * ((c2 + 1) * 2 * t2 - c2) / 2 : (Math.pow(2 * t2 - 2, 2) * ((c2 + 1) * (t2 * 2 - 2) + c2) + 2) / 2;
});
function registerEasing(name2, fn) {
  if (typeof name2 === "string" && name2 && typeof fn === "function") {
    REGISTRY.set(name2, fn);
  }
}
function isBezierArray(v) {
  return Array.isArray(v) && v.length === 4 && v.every((n2) => typeof n2 === "number");
}
function resolveEasing(value) {
  if (typeof value === "function") return guardEasing(value);
  if (isBezierArray(value))
    return cubicBezier(value[0], value[1], value[2], value[3]);
  if (typeof value === "string" && REGISTRY.has(value)) {
    return guardEasing(
      /** @type {(t:number)=>number} */
      REGISTRY.get(value)
    );
  }
  return easeInOutSine;
}
function guardEasing(fn) {
  return (t2) => {
    const y = fn(t2);
    return typeof y === "number" && isFinite(y) ? y : t2;
  };
}
const SVGNS = "http://www.w3.org/2000/svg";
function easeOutCubic(t2) {
  return 1 - Math.pow(1 - t2, 3);
}
function easeOutBack(t2) {
  const c1 = 1.70158;
  const c3 = c1 + 1;
  return 1 + c3 * Math.pow(t2 - 1, 3) + c1 * Math.pow(t2 - 1, 2);
}
let _reducedMotionMql = null;
function prefersReducedMotion() {
  if (!Environment.isBrowser()) return false;
  try {
    if (!_reducedMotionMql) {
      _reducedMotionMql = window.matchMedia("(prefers-reduced-motion: reduce)");
    }
    return !!_reducedMotionMql.matches;
  } catch (_) {
    return false;
  }
}
function applyProgressiveReveal(el, x, w) {
  if (!Environment.isBrowser()) return false;
  if (w.globals.dataChanged || w.globals.resized) return false;
  const animCfg = w.config.chart.animations;
  if (!animCfg || animCfg.enabled === false) return false;
  const chartType = w.config.chart.type;
  if (chartType !== "line" && chartType !== "area" && chartType !== "rangeArea") {
    return false;
  }
  if (!(w.layout.gridWidth > 0)) return false;
  const drawSpeed = (animCfg.speed || 800) * 2;
  const xRatio = Math.max(0, Math.min(1, x / w.layout.gridWidth));
  const easedT = 1 - Math.cbrt(1 - xRatio);
  const revealDelay = easedT * drawSpeed;
  const node = el.node;
  const style = node.style;
  style.opacity = "0";
  let startAnchor = null;
  const tick = (now) => {
    if (startAnchor === null) startAnchor = now;
    if (now - startAnchor >= revealDelay) {
      style.opacity = "";
    } else {
      BrowserAPIs.requestAnimationFrame(tick);
    }
  };
  BrowserAPIs.requestAnimationFrame(tick);
  return true;
}
function applyAnimationPolicy(w) {
  const anim = w.config.chart.animations;
  if (!anim) return;
  if (anim.respectReducedMotion !== false && prefersReducedMotion()) {
    anim.enabled = false;
    if (anim.dynamicAnimation) anim.dynamicAnimation.enabled = false;
  }
  setDefaultEasing(resolveEasing(anim.easing));
}
function computeStagger(opts) {
  const style = opts.style;
  const index = opts.index || 0;
  const baseDelay = typeof opts.baseDelay === "number" ? opts.baseDelay : 40;
  const row = opts.row || 0;
  const col = opts.col || 0;
  const groupIndex = opts.groupIndex || 0;
  const perGroup = opts.perGroup || 1;
  const centerDistance = opts.centerDistance || 0;
  switch (style) {
    case "none":
      return 0;
    case "diagonal":
      return (row + col) * baseDelay;
    case "group":
      return groupIndex * baseDelay + index % perGroup * (baseDelay / 4);
    case "centroid":
      return centerDistance * baseDelay * (index + 1);
    case "sequential":
    default:
      return index * baseDelay;
  }
}
class Animations {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext} [ctx]
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
  }
  /**
   * @param {any} el
   * @param {Record<string, any>} from
   * @param {Record<string, any>} to
   * @param {object} speed
   */
  animateLine(el, from, to, speed) {
    el.attr(from).animate(speed).attr(to);
  }
  /*
   ** Animate radius of a circle element
   * @param {any} el
   * @param {number} speed
   * @param {string} easing
   * @param {Function} cb
   */
  /** @param {any} el @param {any} speed @param {any} easing @param {any} cb */
  animateMarker(el, speed, easing, cb) {
    el.attr({
      opacity: 0
    }).animate(speed).attr({
      opacity: 1
    }).after(() => {
      cb();
    });
  }
  /**
   * Scale-up "pop" effect for scatter/bubble markers. Animates
   * `transform: scale(0 → 1)` (with `easeOutBack` overshoot) plus opacity,
   * around the marker's own center via `transform-box: fill-box`.
   *
   * Falls back to instant render in SSR / when shouldAnimate is false.
   *
   * @param {any} el
   * @param {{ speed: number, delay?: number, onComplete?: () => void }} params
   */
  animatePop(el, { speed, delay = 0, onComplete }) {
    const w = this.w;
    if (!Environment.isBrowser() || !w.globals.shouldAnimate || speed < 1) {
      if (onComplete) onComplete();
      return;
    }
    const node = el.node;
    const style = node.style;
    style.transformBox = "fill-box";
    style.transformOrigin = "center";
    style.transform = "scale(0)";
    style.opacity = "0";
    const startAt = performance.now() + delay;
    const step = (now) => {
      if (w.globals.isDestroyed) return;
      const t2 = Math.max(0, Math.min(1, (now - startAt) / speed));
      style.transform = `scale(${easeOutBack(t2)})`;
      style.opacity = String(Math.min(1, t2 * 2));
      if (t2 < 1) {
        BrowserAPIs.requestAnimationFrame(step);
      } else {
        style.transform = "";
        style.transformOrigin = "";
        style.transformBox = "";
        style.opacity = "";
        if (onComplete) onComplete();
      }
    };
    BrowserAPIs.requestAnimationFrame(step);
  }
  /*
   ** Animate rect properties
   * @param {any} el
   * @param {any} from
   * @param {any} to
   * @param {number} speed
   * @param {Function} fn
   */
  /** @param {any} el @param {any} from @param {any} to @param {any} speed @param {any} fn @param {number} [delay] */
  animateRect(el, from, to, speed, fn, delay = 0) {
    el.attr(from).animate(speed, delay).attr(to).after(() => fn());
  }
  /**
   * @param {Record<string, any>} params
   */
  animatePathsGradually(params) {
    const {
      el,
      realIndex,
      j,
      fill,
      pathFrom,
      pathTo,
      pathToInterp,
      speed,
      delay,
      scrollMorph
    } = params;
    const me = this;
    const w = this.w;
    let delayFactor = 0;
    if (w.config.chart.animations.animateGradually.enabled) {
      delayFactor = w.config.chart.animations.animateGradually.delay;
    }
    if (w.config.chart.animations.dynamicAnimation.enabled && w.globals.dataChanged && w.config.chart.type !== "bar") {
      delayFactor = 0;
    }
    me.morphSVG(
      el,
      realIndex,
      j,
      w.config.chart.type === "line" && !w.globals.comboCharts ? "stroke" : fill,
      pathFrom,
      pathTo,
      speed,
      delay * delayFactor,
      scrollMorph,
      pathToInterp
    );
  }
  /**
   * Opacity-fade reveal (see Graphics.renderPaths `revealViaFade`): hide this
   * path immediately, then reveal the whole series in a single CSS opacity fade
   * once the synchronous draw pass has finished. Used for two cases that both
   * want to avoid per-path morphs: the large-dataset bulk render (>
   * largeDatasetThreshold) and candlestick/boxPlot data-change updates (where an
   * index-based morph would slide candles around on zoom). Every faded path is
   * pushed to delayedElements, but only the first one schedules the reveal — a
   * lone requestAnimationFrame fires after all paths are in the DOM, so N paths
   * cost one frame callback instead of N morph timelines. The guard flag is
   * reset inside the callback (and in initGlobalVars) so subsequent renders
   * re-arm it.
   * @param {any} el
   */
  revealBulk(el) {
    const w = this.w;
    el.node.classList.add("apexcharts-element-hidden");
    w.globals.delayedElements.push({ el: el.node });
    if (!Environment.isBrowser() || !w.globals.shouldAnimate) {
      this.animationCompleted(el);
      return;
    }
    if (!w.globals.bulkRevealScheduled) {
      w.globals.bulkRevealScheduled = true;
      BrowserAPIs.requestAnimationFrame(() => {
        if (w.globals.isDestroyed) return;
        w.globals.bulkRevealScheduled = false;
        this.animationCompleted(el);
      });
    }
  }
  showDelayedElements() {
    this.w.globals.delayedElements.forEach((d) => {
      if (d.holdUntilComplete && !this.w.globals.animationEnded) return;
      const ele = d.el;
      ele.classList.remove("apexcharts-element-hidden");
      ele.classList.add("apexcharts-hidden-element-shown");
    });
  }
  /**
   * @param {any} el
   */
  animationCompleted(el) {
    const w = this.w;
    if (w.globals.animationEnded) return;
    w.globals.animationEnded = true;
    this.showDelayedElements();
    if (typeof w.config.chart.events.animationEnd === "function") {
      w.config.chart.events.animationEnd(this.ctx, { el, w });
    }
  }
  /**
   * Initial-mount "pen-stroke" draw effect for line / area / rangeArea paths.
   *
   * Stroke paths animate `stroke-dashoffset` from total length → 0.
   * Fill paths animate the width of a per-series SVG `<mask>` rect from 0 → gridWidth,
   * which coexists with the existing `clip-path: gridRectMask` (mask + clip-path
   * are independent SVG attributes).
   *
   * For radar / radial shapes, pass `mask: { type: 'radial', cx, cy, r }` to
   * use a circular mask that blooms from center outward instead of the default
   * left-to-right rect wipe.
   *
   * @param {any} el            - SVG.js path element
   * @param {{realIndex: number, j?: number, isFill: boolean, isLast: boolean, speed: number, delay: number, mask?: {type: 'rect'|'radial', cx?: number, cy?: number, r?: number}}} params
   */
  animateDraw(el, { realIndex, j, isFill, isLast, speed, delay, mask: maskShape }) {
    const w = this.w;
    const me = this;
    const finalize = () => {
      if (isLast && w.globals.shouldAnimate) {
        me.animationCompleted(el);
      }
      me.showDelayedElements();
    };
    if (!Environment.isBrowser() || !w.globals.shouldAnimate || speed < 1) {
      finalize();
      return;
    }
    const node = el.node;
    const runMaskReveal = () => {
      const pad = 4;
      const isRadial = maskShape && maskShape.type === "radial";
      const targetWidth = w.layout.gridWidth + pad * 2;
      const radialCx = maskShape && maskShape.cx || 0;
      const radialCy = maskShape && maskShape.cy || 0;
      const targetRadius = (maskShape && maskShape.r || w.layout.gridWidth / 2) + pad;
      const maskId = `apexDrawMask${w.globals.cuid}-${realIndex}-${j != null ? j : 0}-${isFill ? "f" : "s"}`;
      const mask = BrowserAPIs.createElementNS(SVGNS, "mask");
      mask.setAttribute("id", maskId);
      mask.setAttribute("maskUnits", "userSpaceOnUse");
      let revealEl;
      if (isRadial) {
        const region = targetRadius;
        mask.setAttribute("x", String(radialCx - region));
        mask.setAttribute("y", String(radialCy - region));
        mask.setAttribute("width", String(region * 2));
        mask.setAttribute("height", String(region * 2));
        revealEl = BrowserAPIs.createElementNS(SVGNS, "circle");
        revealEl.setAttribute("cx", String(radialCx));
        revealEl.setAttribute("cy", String(radialCy));
        revealEl.setAttribute("r", "0");
        revealEl.setAttribute("fill", "#fff");
      } else {
        mask.setAttribute("x", String(-pad));
        mask.setAttribute("y", String(-pad));
        mask.setAttribute("width", String(targetWidth));
        mask.setAttribute("height", String(w.layout.gridHeight + pad * 2));
        revealEl = BrowserAPIs.createElementNS(SVGNS, "rect");
        revealEl.setAttribute("x", String(-pad));
        revealEl.setAttribute("y", String(-pad));
        revealEl.setAttribute("width", "0");
        revealEl.setAttribute("height", String(w.layout.gridHeight + pad * 2));
        revealEl.setAttribute("fill", "#fff");
      }
      mask.appendChild(revealEl);
      w.dom.elDefs.node.appendChild(mask);
      node.setAttribute("mask", `url(#${maskId})`);
      const startAt = performance.now() + (delay || 0);
      const step = (now) => {
        if (w.globals.isDestroyed) return;
        const t2 = Math.max(0, Math.min(1, (now - startAt) / speed));
        const eased = easeOutCubic(t2);
        if (isRadial) {
          revealEl.setAttribute("r", String(eased * targetRadius));
        } else {
          revealEl.setAttribute("width", String(eased * targetWidth));
        }
        if (t2 < 1) {
          BrowserAPIs.requestAnimationFrame(step);
        } else {
          node.removeAttribute("mask");
          if (mask.parentNode) mask.parentNode.removeChild(mask);
          finalize();
        }
      };
      BrowserAPIs.requestAnimationFrame(step);
    };
    const runStrokeDraw = (len) => {
      node.setAttribute("stroke-dasharray", String(len));
      node.setAttribute("stroke-dashoffset", String(len));
      const startAt = performance.now() + (delay || 0);
      const step = (now) => {
        if (w.globals.isDestroyed) return;
        const t2 = Math.max(0, Math.min(1, (now - startAt) / speed));
        node.setAttribute("stroke-dashoffset", String(len * (1 - easeOutCubic(t2))));
        if (t2 < 1) {
          BrowserAPIs.requestAnimationFrame(step);
        } else {
          node.removeAttribute("stroke-dasharray");
          node.removeAttribute("stroke-dashoffset");
          finalize();
        }
      };
      BrowserAPIs.requestAnimationFrame(step);
    };
    BrowserAPIs.requestAnimationFrame(() => {
      if (w.globals.isDestroyed) return;
      if (isFill) {
        runMaskReveal();
        return;
      }
      const existingDash = node.getAttribute("stroke-dasharray");
      const hasCustomDash = !!existingDash && existingDash !== "0" && existingDash !== "";
      if (hasCustomDash) {
        runMaskReveal();
        return;
      }
      let len = 0;
      try {
        if (typeof node.getTotalLength === "function") {
          len = node.getTotalLength();
        }
      } catch (_) {
        len = 0;
      }
      if (!len) {
        finalize();
        return;
      }
      runStrokeDraw(len);
    });
  }
  // SVG.js animation for morphing one path to another
  /**
   * @param {any} el
   * @param {number} realIndex
   * @param {number} j
   * @param {string} fill
   * @param {string} pathFrom
   * @param {string} pathTo
   * @param {number} speed
   * @param {number} delay
   * @param {boolean} [scrollMorph] - this morph is a streaming scroll (StreamScroll)
   * @param {string} [pathToInterp] - interpolation target that differs from the
   *   final path. Reconciled length-change morphs tween toward a padded copy of
   *   pathTo (extra anchors sitting exactly on the final geometry) and snap to
   *   the clean pathTo at the end.
   */
  morphSVG(el, realIndex, j, fill, pathFrom, pathTo, speed, delay, scrollMorph, pathToInterp) {
    var _a, _b;
    const w = this.w;
    if (!pathFrom) {
      pathFrom = el.attr("pathFrom");
    }
    if (!pathTo) {
      pathTo = el.attr("pathTo");
    }
    const disableAnimationForCorrupPath = () => {
      if (w.config.chart.type === "radar") {
        speed = 1;
      }
      return `M 0 ${w.layout.gridHeight}`;
    };
    if (!pathFrom || pathFrom.indexOf("undefined") > -1 || pathFrom.indexOf("NaN") > -1) {
      pathFrom = disableAnimationForCorrupPath();
    }
    if (!pathTo.trim() || pathTo.indexOf("undefined") > -1 || pathTo.indexOf("NaN") > -1) {
      pathTo = disableAnimationForCorrupPath();
      pathToInterp = void 0;
    }
    if (pathToInterp && (!pathToInterp.trim() || pathToInterp.indexOf("undefined") > -1 || pathToInterp.indexOf("NaN") > -1)) {
      pathToInterp = void 0;
    }
    if (!w.globals.shouldAnimate) {
      speed = 1;
    }
    const crossTypeMorph = ((_b = (_a = this.ctx) == null ? void 0 : _a.morphTypeChange) == null ? void 0 : _b.isActive()) === true;
    const morphAlgo = crossTypeMorph ? "polygons" : "commands";
    let morphEase = null;
    if (w.globals.dataChanged) {
      const dynEasing = w.config.chart.animations.dynamicAnimation.easing;
      if (dynEasing != null) {
        morphEase = resolveEasing(dynEasing);
      } else if (scrollMorph) {
        morphEase = resolveEasing("linear");
      }
    }
    const runner = el.plot(pathFrom).animate(speed, delay);
    if (morphEase) {
      runner.ease(morphEase);
    }
    runner.plot(
      pathToInterp || pathTo,
      morphAlgo,
      pathToInterp ? pathTo : void 0
    ).after(() => {
      if (Utils$1.isNumber(j)) {
        const maxSeries = w.seriesData.series[w.globals.maxValsInArrayIndex];
        if (maxSeries && j === maxSeries.length - 2 && w.globals.shouldAnimate) {
          this.animationCompleted(el);
        }
      } else if (fill !== "none" && w.globals.shouldAnimate) {
        if (!w.globals.comboCharts && realIndex === w.seriesData.series.length - 1 || w.globals.comboCharts) {
          this.animationCompleted(el);
        }
      }
      this.showDelayedElements();
    });
  }
}
const DEFAULT_INTENSITY = { lighten: 0.15, darken: 0.35 };
class Filters {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
  }
  /**
   * The three chart types drawn by the Pie module.
   * @param {any} w
   */
  static isSliceChart(w) {
    const type = w.config.chart.type;
    return type === "pie" || type === "donut" || type === "polarArea";
  }
  /**
   * True when a pie / donut slice carries the hover state itself, as the
   * outline band traced outside its rim. The band IS the hover feedback, so
   * the states.hover lighten filter must not also recolour the slice: the
   * point of the band is that a hovered slice keeps its own colour.
   * `states.hover.filter.type: 'none'` still turns every hover visual off, so
   * this only claims the state when a hover visual was wanted at all.
   * @param {any} w
   */
  static hoverOutlineOwnsHoverState(w) {
    var _a;
    return Filters.isSliceChart(w) && w.config.states.hover.filter.type !== "none" && ((_a = w.config.plotOptions.pie.hoverOutline) == null ? void 0 : _a.show) === true;
  }
  /**
   * True when a pie / donut slice carries the selected state itself, by
   * sliding out of the pie (see Pie.offsetSlice). Moving out of the pie is a
   * strong enough signal on its own, so the states.active darken filter would
   * only muddy the slice colour on top of it. polarArea is excluded: it never
   * slides (its radius is the value), so it keeps the filter as its only
   * click feedback.
   * @param {any} w
   */
  static sliceOffsetOwnsActiveState(w) {
    return Filters.isSliceChart(w) && w.config.chart.type !== "polarArea" && w.config.plotOptions.pie.expandOnClick === true && w.config.plotOptions.pie.expandOffset > 0 && !Filters.drilldownBlocksSliceOffset(w);
  }
  /**
   * A drilldown pie / donut does not slide its slices out at all: a click there
   * is navigation, so the slice would pull out and then be thrown away by the
   * drill it just triggered, which reads as a glitch rather than as motion.
   * The states.active filter comes back as the click feedback (it is instant,
   * so the re-render lands on top of it rather than fighting it).
   * @param {any} w
   */
  static drilldownBlocksSliceOffset(w) {
    var _a;
    return Filters.isSliceChart(w) && ((_a = w.config.drilldown) == null ? void 0 : _a.enabled) === true;
  }
  // create a re-usable filter which can be appended other filter effects and applied to multiple elements
  /**
   * @param {any} el
   * @param {number} i
   */
  getDefaultFilter(el, i2) {
    const w = this.w;
    if (el.unfilter) {
      el.unfilter(true);
    }
    if (w.config.chart.dropShadow.enabled) {
      this.dropShadow(el, w.config.chart.dropShadow, i2);
    }
  }
  /**
   * @param {any} el
   * @param {number} i
   * @param {string} filterType
   * @param {number} [intensity] Blend strength (0 to 1). Defaults per type.
   */
  applyFilter(el, i2, filterType, intensity) {
    var _a, _b, _c;
    const w = this.w;
    if (el.unfilter) {
      el.unfilter(true);
    }
    if (filterType === "none") {
      this.getDefaultFilter(el, i2);
      return;
    }
    const shadowAttr = w.config.chart.dropShadow;
    const fallback = filterType === "lighten" ? DEFAULT_INTENSITY.lighten : DEFAULT_INTENSITY.darken;
    const t2 = Math.max(
      0,
      Math.min(1, typeof intensity === "number" ? intensity : fallback)
    );
    const diag = 1 - t2;
    const offset = filterType === "lighten" ? t2 : 0;
    if (el.filterWith) {
      el.filterWith((add) => {
        add.colorMatrix({
          type: "matrix",
          values: `
            ${diag} 0 0 0 ${offset}
            0 ${diag} 0 0 ${offset}
            0 0 ${diag} 0 ${offset}
            0 0 0 1 0
          `,
          in: "SourceGraphic",
          result: "brightness"
        });
        if (shadowAttr.enabled) {
          this.addShadow(add, i2, shadowAttr, "brightness");
        }
      });
      if (!shadowAttr.noUserSpaceOnUse) {
        (_b = (_a = el.filterer()) == null ? void 0 : _a.node) == null ? void 0 : _b.setAttribute("filterUnits", "userSpaceOnUse");
      }
      this._scaleFilterSize((_c = el.filterer()) == null ? void 0 : _c.node);
    }
  }
  // appends dropShadow to the filter object which can be chained with other filter effects
  /**
   * @param {any} add
   * @param {number} i
   * @param {Record<string, any>} attrs
   * @param {string} source
   */
  addShadow(add, i2, attrs, source) {
    var _a;
    const w = this.w;
    let { blur, top, left, color, opacity } = attrs;
    color = Array.isArray(color) ? color[i2] : color;
    if (((_a = w.config.chart.dropShadow.enabledOnSeries) == null ? void 0 : _a.length) > 0) {
      if (w.config.chart.dropShadow.enabledOnSeries.indexOf(i2) === -1) {
        return add;
      }
    }
    add.offset({
      in: source,
      dx: left,
      dy: top,
      result: "offset"
    });
    add.gaussianBlur({
      in: "offset",
      stdDeviation: blur,
      result: "blur"
    });
    add.flood({
      "flood-color": color,
      "flood-opacity": opacity,
      result: "flood"
    });
    add.composite({
      in: "flood",
      in2: "blur",
      operator: "in",
      result: "shadow"
    });
    add.merge(["shadow", source]);
  }
  // directly adds dropShadow to the element and returns the same element.
  /**
   * @param {any} el
   * @param {Record<string, any>} attrs
   */
  dropShadow(el, attrs, i2 = 0) {
    var _a, _b, _c, _d, _e;
    const w = this.w;
    if (el.unfilter) {
      el.unfilter(true);
    }
    if (Utils$1.isMsEdge() && w.config.chart.type === "radialBar") {
      return el;
    }
    if (((_a = w.config.chart.dropShadow.enabledOnSeries) == null ? void 0 : _a.length) > 0) {
      if (((_b = w.config.chart.dropShadow.enabledOnSeries) == null ? void 0 : _b.indexOf(i2)) === -1) {
        return el;
      }
    }
    if (el.filterWith) {
      el.filterWith((add) => {
        this.addShadow(add, i2, attrs, "SourceGraphic");
      });
      if (!attrs.noUserSpaceOnUse) {
        (_d = (_c = el.filterer()) == null ? void 0 : _c.node) == null ? void 0 : _d.setAttribute("filterUnits", "userSpaceOnUse");
      }
      this._scaleFilterSize((_e = el.filterer()) == null ? void 0 : _e.node);
    }
    return el;
  }
  /**
   * @param {any} el
   * @param {number} realIndex
   * @param {number} dataPointIndex
   */
  setSelectionFilter(el, realIndex, dataPointIndex) {
    const w = this.w;
    if (typeof w.interact.selectedDataPoints[realIndex] !== "undefined") {
      if (w.interact.selectedDataPoints[realIndex].indexOf(dataPointIndex) > -1) {
        el.node.setAttribute("selected", true);
        if (Filters.sliceOffsetOwnsActiveState(w)) return;
        const activeFilter = w.config.states.active.filter;
        if (activeFilter.type !== "none") {
          this.applyFilter(el, realIndex, activeFilter.type, activeFilter.value);
        }
      }
    }
  }
  /**
   * @param {any} el
   */
  _scaleFilterSize(el) {
    if (!el) return;
    const setAttributes = (attrs) => {
      for (const key in attrs) {
        if (Object.prototype.hasOwnProperty.call(attrs, key)) {
          el.setAttribute(key, attrs[key]);
        }
      }
    };
    setAttributes({
      width: "200%",
      height: "200%",
      x: "-50%",
      y: "-50%"
    });
  }
}
class Graphics {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext | null} ctx
   */
  constructor(w, ctx = null) {
    this.w = w;
    this.ctx = ctx;
  }
  /*****************************************************************************
   *                                                                            *
   *  SVG Path Rounding Function                                                *
   *  Copyright (C) 2014 Yona Appletree                                         *
   *                                                                            *
   *  Licensed under the Apache License, Version 2.0 (the "License");           *
   *  you may not use this file except in compliance with the License.          *
   *  You may obtain a copy of the License at                                   *
   *                                                                            *
   *      http://www.apache.org/licenses/LICENSE-2.0                            *
   *                                                                            *
   *  Unless required by applicable law or agreed to in writing, software       *
   *  distributed under the License is distributed on an "AS IS" BASIS,         *
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
   *  See the License for the specific language governing permissions and       *
   *  limitations under the License.                                            *
   *                                                                            *
   *****************************************************************************/
  /**
   * SVG Path rounding function. Takes an input path string and outputs a path
   * string where all line-line corners have been rounded. Only supports absolute
   * commands at the moment.
   *
   * @param pathString The SVG input path
   * @param radius The amount to round the corners, either a value in the SVG
   *               coordinate space, or, if useFractionalRadius is true, a value
   *               from 0 to 1.
   * @returns A new SVG path string with the rounding
   * @param {string} pathString
   * @param {number} radius
   */
  roundPathCorners(pathString, radius) {
    if (pathString.indexOf("NaN") > -1) pathString = "";
    function moveTowardsLength(movingPoint, targetPoint, amount) {
      var width = targetPoint.x - movingPoint.x;
      var height = targetPoint.y - movingPoint.y;
      var distance = Math.sqrt(width * width + height * height);
      if (!distance) {
        return { x: movingPoint.x, y: movingPoint.y };
      }
      return moveTowardsFractional(
        movingPoint,
        targetPoint,
        Math.min(1, amount / distance)
      );
    }
    function moveTowardsFractional(movingPoint, targetPoint, fraction) {
      return {
        x: movingPoint.x + (targetPoint.x - movingPoint.x) * fraction,
        y: movingPoint.y + (targetPoint.y - movingPoint.y) * fraction
      };
    }
    function adjustCommand(cmd, newPoint) {
      if (cmd.length > 2) {
        cmd[cmd.length - 2] = newPoint.x;
        cmd[cmd.length - 1] = newPoint.y;
      }
    }
    function pointForCommand(cmd) {
      return {
        x: parseFloat(cmd[cmd.length - 2]),
        y: parseFloat(cmd[cmd.length - 1])
      };
    }
    var pathParts = pathString.split(/[,\s]/).reduce(function(parts, part) {
      var match = part.match(/^([a-zA-Z])(.+)/);
      if (match) {
        parts.push(match[1]);
        parts.push(match[2]);
      } else {
        parts.push(part);
      }
      return parts;
    }, []);
    var commands = pathParts.reduce(function(commands2, part) {
      if (parseFloat(part) == part && commands2.length) {
        commands2[commands2.length - 1].push(part);
      } else {
        commands2.push([part]);
      }
      return commands2;
    }, []);
    var resultCommands = [];
    if (commands.length > 1) {
      var startPoint = pointForCommand(commands[0]);
      var virtualCloseLine = null;
      if (commands[commands.length - 1][0] == "Z" && commands[0].length > 2) {
        virtualCloseLine = ["L", startPoint.x, startPoint.y];
        commands[commands.length - 1] = virtualCloseLine;
      }
      resultCommands.push(commands[0]);
      for (var cmdIndex = 1; cmdIndex < commands.length; cmdIndex++) {
        var prevCmd = resultCommands[resultCommands.length - 1];
        var curCmd = commands[cmdIndex];
        var nextCmd = curCmd == virtualCloseLine ? commands[1] : commands[cmdIndex + 1];
        if (nextCmd && prevCmd && prevCmd.length > 2 && curCmd[0] == "L" && nextCmd.length > 2 && nextCmd[0] == "L") {
          var prevPoint = pointForCommand(prevCmd);
          var curPoint = pointForCommand(curCmd);
          var nextPoint = pointForCommand(nextCmd);
          var curveStart, curveEnd;
          curveStart = moveTowardsLength(curPoint, prevPoint, radius);
          curveEnd = moveTowardsLength(curPoint, nextPoint, radius);
          adjustCommand(curCmd, curveStart);
          curCmd.origPoint = curPoint;
          resultCommands.push(curCmd);
          var startControl = moveTowardsFractional(curveStart, curPoint, 0.5);
          var endControl = moveTowardsFractional(curPoint, curveEnd, 0.5);
          var curveCmd = [
            "C",
            startControl.x,
            startControl.y,
            endControl.x,
            endControl.y,
            curveEnd.x,
            curveEnd.y
          ];
          curveCmd.origPoint = curPoint;
          resultCommands.push(curveCmd);
        } else {
          resultCommands.push(curCmd);
        }
      }
      if (virtualCloseLine) {
        var newStartPoint = pointForCommand(
          resultCommands[resultCommands.length - 1]
        );
        resultCommands.push(["Z"]);
        adjustCommand(resultCommands[0], newStartPoint);
      }
    } else {
      resultCommands = commands;
    }
    return resultCommands.reduce(function(str, c2) {
      return str + c2.join(" ") + " ";
    }, "");
  }
  /**
   * @param {number} x1
   * @param {number} y1
   * @param {number} x2
   * @param {number} y2
   * @param {number | null} [strokeWidth]
   */
  drawLine(x1, y1, x2, y2, lineColor = "#a8a8a8", dashArray = 0, strokeWidth = null, strokeLineCap = "butt") {
    const w = this.w;
    const line = w.dom.Paper.line().attr({
      x1,
      y1,
      x2,
      y2,
      stroke: lineColor,
      "stroke-dasharray": dashArray,
      "stroke-width": strokeWidth,
      "stroke-linecap": strokeLineCap
    });
    return line;
  }
  /**
   * @param {number | null} [strokeWidth]
   * @param {string | null} [strokeColor]
   */
  drawRect(x1 = 0, y1 = 0, x2 = 0, y2 = 0, radius = 0, color = "#fefefe", opacity = 1, strokeWidth = null, strokeColor = null, strokeDashArray = 0) {
    const w = this.w;
    const rect = w.dom.Paper.rect();
    rect.attr({
      x: x1,
      y: y1,
      width: x2 > 0 ? x2 : 0,
      height: y2 > 0 ? y2 : 0,
      rx: radius,
      ry: radius,
      opacity,
      "stroke-width": strokeWidth !== null ? strokeWidth : 0,
      stroke: strokeColor !== null ? strokeColor : "none",
      "stroke-dasharray": strokeDashArray
    });
    rect.node.setAttribute("fill", color);
    return rect;
  }
  /**
   * @param {string} polygonString
   */
  drawPolygon(polygonString, stroke = "#e1e1e1", strokeWidth = 1, fill = "none") {
    const w = this.w;
    const polygon = w.dom.Paper.polygon(polygonString).attr({
      fill,
      stroke,
      "stroke-width": strokeWidth
    });
    return polygon;
  }
  /**
   * @param {number} radius
   * @param {Record<string, any> | null} attrs
   */
  drawCircle(radius, attrs = null) {
    const w = this.w;
    if (radius < 0) radius = 0;
    const c2 = w.dom.Paper.circle(radius * 2);
    if (attrs !== null) {
      c2.attr(attrs);
    }
    return c2;
  }
  /** @param {{ d?: string, stroke?: string, strokeWidth?: number, fill: any, fillOpacity?: number, strokeOpacity?: number, classes?: any, strokeLinecap?: any, strokeDashArray?: number }} opts */
  drawPath({
    d = "",
    stroke = "#a8a8a8",
    strokeWidth = 1,
    fill,
    fillOpacity = 1,
    strokeOpacity = 1,
    classes,
    strokeLinecap = null,
    strokeDashArray = 0
  }) {
    const w = this.w;
    if (strokeLinecap === null) {
      strokeLinecap = w.config.stroke.lineCap;
    }
    if (d.indexOf("undefined") > -1 || d.indexOf("NaN") > -1) {
      d = `M 0 ${w.layout.gridHeight}`;
    }
    const p = w.dom.Paper.path(d).attr({
      fill,
      "fill-opacity": fillOpacity,
      stroke,
      "stroke-opacity": strokeOpacity,
      "stroke-linecap": strokeLinecap,
      "stroke-width": strokeWidth,
      "stroke-dasharray": strokeDashArray,
      class: classes
    });
    return p;
  }
  /**
   * @param {Record<string, any> | null} attrs
   */
  group(attrs = null) {
    const w = this.w;
    const g = w.dom.Paper.group();
    if (attrs !== null) {
      g.attr(attrs);
    }
    return g;
  }
  /**
   * @param {number} x
   * @param {number} y
   */
  move(x, y) {
    const move = ["M", x, y].join(" ");
    return move;
  }
  /**
   * @param {number | null} x
   * @param {number | null} y
   * @param {string | null} hORv
   * @returns {string}
   */
  line(x, y, hORv = null) {
    if (hORv === "H") return [" H", x].join(" ");
    if (hORv === "V") return [" V", y].join(" ");
    return [" L", x, y].join(" ");
  }
  /**
   * @param {number} x1
   * @param {number} y1
   * @param {number} x2
   * @param {number} y2
   * @param {number} x
   * @param {number} y
   */
  curve(x1, y1, x2, y2, x, y) {
    const curve = ["C", x1, y1, x2, y2, x, y].join(" ");
    return curve;
  }
  /**
   * @param {number} x1
   * @param {number} y1
   * @param {number} x
   * @param {number} y
   */
  quadraticCurve(x1, y1, x, y) {
    const curve = ["Q", x1, y1, x, y].join(" ");
    return curve;
  }
  /**
   * @param {number} rx
   * @param {number} ry
   * @param {number} axisRotation
   * @param {number} largeArcFlag
   * @param {number} sweepFlag
   * @param {number} x
   * @param {number} y
   */
  arc(rx, ry, axisRotation, largeArcFlag, sweepFlag, x, y, relative = false) {
    let coord = "A";
    if (relative) coord = "a";
    const arc = [
      coord,
      rx,
      ry,
      axisRotation,
      largeArcFlag,
      sweepFlag,
      x,
      y
    ].join(" ");
    return arc;
  }
  /**
   * @memberof Graphics
   * @param {Record<string, any>} opts
   *  i = series's index
   *  realIndex = realIndex is series's actual index when it was drawn time. After several redraws, the iterating "i" may change in loops, but realIndex doesn't
   *  pathFrom = existing pathFrom to animateTo
   *  pathTo = new Path to which d attr will be animated from pathFrom to pathTo
   *  stroke = line Color
   *  strokeWidth = width of path Line
   *  fill = it can be gradient, single color, pattern or image
   *  animationDelay = how much to delay when starting animation (in milliseconds)
   *  dataChangeSpeed = for dynamic animations, when data changes
   *  className = class attribute to add
   *  scrollMorph = this data-change morph is a streaming scroll (see StreamScroll);
   *                defaults the morph easing to linear so the slide is constant-velocity
   * @return {any} svg.js path object
   **/
  renderPaths({
    j,
    realIndex,
    pathFrom,
    pathTo,
    pathToInterp,
    stroke,
    strokeWidth,
    strokeLinecap,
    fill,
    animationDelay,
    initialSpeed,
    dataChangeSpeed,
    className,
    chartType,
    shouldClipToGrid = true,
    bindEventsOnPaths = true,
    drawShadow = true,
    drawMask = null,
    scrollMorph = false
  }) {
    var _a, _b, _c, _d;
    const w = this.w;
    const filters = new Filters(this.w);
    const anim = new Animations(this.w, (_a = this.ctx) != null ? _a : void 0);
    const initialAnim = this.w.config.chart.animations.enabled;
    const dynamicAnim = initialAnim && this.w.config.chart.animations.dynamicAnimation.enabled;
    if (pathFrom && pathFrom.startsWith("M 0 0 ") && pathTo) {
      const moveCommand = pathTo.match(/^M\s+[\d.-]+\s+[\d.-]+/);
      if (moveCommand) {
        pathFrom = pathFrom.replace(/^M\s+0\s+0/, moveCommand[0]);
      }
    }
    let d;
    const crossTypeMorph = ((_c = (_b = this.ctx) == null ? void 0 : _b.morphTypeChange) == null ? void 0 : _c.isActive()) === true;
    const shouldAnimate = !!(initialAnim && !w.globals.resized || dynamicAnim && w.globals.dataChanged && w.globals.shouldAnimate || crossTypeMorph && initialAnim && w.globals.shouldAnimate);
    const isDrawableSeries = typeof className === "string" && (className.indexOf("apexcharts-line") > -1 || className.indexOf("apexcharts-area") > -1 || className.indexOf("apexcharts-rangeArea") > -1 || className.indexOf("apexcharts-radar") > -1);
    const useDrawMode = !!(initialAnim && !w.globals.resized && !w.globals.dataChanged && isDrawableSeries);
    const largeThreshold = (_d = w.config.chart.animations.largeDatasetThreshold) != null ? _d : 0;
    const bulkRender = !!(shouldAnimate && !useDrawMode && largeThreshold > 0 && w.globals.dataPoints > largeThreshold);
    const isCandleOrBox = chartType === "candlestick" || chartType === "boxPlot";
    const fadeOnDataChange = !!(isCandleOrBox && shouldAnimate && !useDrawMode && w.globals.dataChanged && // ...but a cross-type morph is a deliberate one-off with marks already
    // paired, so it keeps its tween instead of fading.
    !crossTypeMorph);
    const revealViaFade = bulkRender || fadeOnDataChange;
    if (shouldAnimate && !useDrawMode && !revealViaFade) {
      d = pathFrom;
    } else {
      d = pathTo;
      if (!shouldAnimate) {
        w.globals.animationEnded = true;
      }
    }
    const strokeDashArrayOpt = w.config.stroke.dashArray;
    let strokeDashArray = 0;
    if (Array.isArray(strokeDashArrayOpt)) {
      strokeDashArray = strokeDashArrayOpt[realIndex];
    } else {
      strokeDashArray = w.config.stroke.dashArray;
    }
    const el = this.drawPath({
      d,
      stroke,
      strokeWidth,
      fill,
      fillOpacity: 1,
      classes: className,
      strokeLinecap,
      strokeDashArray
    });
    el.attr("index", realIndex);
    if (shouldClipToGrid) {
      if (chartType === "bar" && !w.globals.isBarHorizontal || w.globals.comboCharts) {
        el.attr({
          "clip-path": `url(#gridRectBarMask${w.globals.cuid})`
        });
      } else {
        el.attr({
          "clip-path": `url(#gridRectMask${w.globals.cuid})`
        });
      }
    }
    if (w.config.chart.dropShadow.enabled && drawShadow) {
      filters.dropShadow(el, w.config.chart.dropShadow, realIndex);
    }
    if (bindEventsOnPaths) {
      el.node.addEventListener("mouseenter", this.pathMouseEnter.bind(this, el));
      el.node.addEventListener("mouseleave", this.pathMouseLeave.bind(this, el));
      el.node.addEventListener("mousedown", this.pathMouseDown.bind(this, el));
    }
    el.attr({
      pathTo,
      pathFrom
    });
    const defaultAnimateOpts = {
      el,
      j,
      realIndex,
      pathFrom,
      pathTo,
      pathToInterp,
      fill,
      strokeWidth,
      delay: animationDelay,
      scrollMorph
    };
    if (initialAnim && !w.globals.resized && !w.globals.dataChanged) {
      if (useDrawMode) {
        const drawSpeed = initialSpeed * 2;
        const isFill = stroke === "none" || strokeWidth === 0;
        const seriesCount = w.seriesData.series.length;
        const isLast = w.globals.comboCharts ? true : realIndex === seriesCount - 1;
        anim.animateDraw(el, {
          realIndex,
          j,
          isFill,
          isLast,
          speed: drawSpeed,
          delay: 0,
          mask: drawMask
        });
      } else if (!revealViaFade) {
        anim.animatePathsGradually(__spreadProps(__spreadValues({}, defaultAnimateOpts), {
          speed: initialSpeed
        }));
      }
    } else {
      if ((w.globals.resized || !w.globals.dataChanged) && !revealViaFade) {
        anim.showDelayedElements();
      }
    }
    const animateOnUpdate = shouldAnimate && !revealViaFade && (w.globals.dataChanged && dynamicAnim || crossTypeMorph);
    if (animateOnUpdate) {
      anim.animatePathsGradually(__spreadProps(__spreadValues({}, defaultAnimateOpts), {
        speed: dataChangeSpeed
      }));
    }
    if (revealViaFade) {
      anim.revealBulk(el);
    }
    return el;
  }
  /**
   * @param {string} style
   * @param {number} width
   * @param {number} height
   */
  drawPattern(style, width, height, stroke = "#a8a8a8", strokeWidth = 0) {
    const w = this.w;
    const p = w.dom.Paper.pattern(width, height, (add) => {
      if (style === "horizontalLines") {
        add.line(0, 0, height, 0).stroke({ color: stroke, width: strokeWidth + 1 });
      } else if (style === "verticalLines") {
        add.line(0, 0, 0, width).stroke({ color: stroke, width: strokeWidth + 1 });
      } else if (style === "slantedLines") {
        add.line(0, 0, width, height).stroke({ color: stroke, width: strokeWidth });
      } else if (style === "squares") {
        add.rect(width, height).fill("none").stroke({ color: stroke, width: strokeWidth });
      } else if (style === "circles") {
        add.circle(width).fill("none").stroke({ color: stroke, width: strokeWidth });
      }
    });
    return p;
  }
  /**
   * @param {string} style
   * @param {string} gfrom
   * @param {string} gto
   * @param {number} opacityFrom
   * @param {number} opacityTo
   * @param {number | null} [size]
   * @param {number[] | null} stops
   * @param {any[]} colorStops
   * @param {number} [i]
   * @param {boolean} [verticalUserSpace] anchor a vertical gradient to the plot
   *   area rather than to each path's own bounding box. Needed when one series
   *   is drawn as several path elements (nulls split it into segments): with
   *   the default objectBoundingBox each segment resolves the same offset
   *   against a different bbox, so the color transition lands on a different
   *   value in every segment.
   */
  drawGradient(style, gfrom, gto, opacityFrom, opacityTo, size = null, stops = null, colorStops = [], i2 = 0, verticalUserSpace = false) {
    const w = this.w;
    let g;
    if (gfrom.length < 9 && gfrom.indexOf("#") === 0) {
      gfrom = Utils$1.hexToRgba(gfrom, opacityFrom);
    }
    if (gto.length < 9 && gto.indexOf("#") === 0) {
      gto = Utils$1.hexToRgba(gto, opacityTo);
    }
    let stop1 = 0;
    let stop2 = 1;
    let stop3 = 1;
    let stop4 = null;
    if (stops !== null) {
      stop1 = typeof stops[0] !== "undefined" ? stops[0] / 100 : 0;
      stop2 = typeof stops[1] !== "undefined" ? stops[1] / 100 : 1;
      stop3 = typeof stops[2] !== "undefined" ? stops[2] / 100 : 1;
      stop4 = typeof stops[3] !== "undefined" ? stops[3] / 100 : null;
    }
    const radial = !!(w.config.chart.type === "donut" || w.config.chart.type === "pie" || w.config.chart.type === "polarArea" || w.config.chart.type === "bubble");
    if (!colorStops || colorStops.length === 0) {
      g = w.dom.Paper.gradient(
        radial ? "radial" : "linear",
        (add) => {
          add.stop(stop1, gfrom, opacityFrom);
          add.stop(stop2, gto, opacityTo);
          add.stop(stop3, gto, opacityTo);
          if (stop4 !== null) {
            add.stop(stop4, gfrom, opacityFrom);
          }
        }
      );
    } else {
      g = w.dom.Paper.gradient(
        radial ? "radial" : "linear",
        (add) => {
          const gradientStops = Array.isArray(colorStops[i2]) ? colorStops[i2] : Array.isArray(colorStops[0]) ? colorStops[0] || [] : colorStops;
          gradientStops.forEach((s2) => {
            add.stop(s2.offset / 100, s2.color, s2.opacity);
          });
        }
      );
    }
    if (!radial) {
      if (style === "vertical") {
        if (verticalUserSpace) {
          g.attr({ gradientUnits: "userSpaceOnUse" });
          g.from(0, 0).to(0, w.layout.gridHeight);
        } else {
          g.from(0, 0).to(0, 1);
        }
      } else if (style === "diagonal") {
        g.from(0, 0).to(1, 1);
      } else if (style === "horizontal") {
        g.from(0, 1).to(1, 1);
      } else if (style === "diagonal2") {
        g.from(1, 0).to(0, 1);
      }
    } else {
      const offx = w.layout.gridWidth / 2;
      const offy = w.layout.gridHeight / 2;
      if (w.config.chart.type !== "bubble") {
        g.attr({
          gradientUnits: "userSpaceOnUse",
          cx: offx,
          cy: offy,
          r: size
        });
      } else {
        g.attr({
          cx: 0.5,
          cy: 0.5,
          r: 0.8,
          fx: 0.2,
          fy: 0.2
        });
      }
    }
    return g;
  }
  /** @param {{ text: any, maxWidth: any, fontSize: any, fontFamily?: any }} opts */
  getTextBasedOnMaxWidth({ text, maxWidth, fontSize, fontFamily }) {
    const tRects = this.getTextRects(text, fontSize, fontFamily, "");
    const wordWidth = tRects.width / text.length;
    const wordsBasedOnWidth = Math.floor(maxWidth / wordWidth);
    if (maxWidth < tRects.width) {
      return text.slice(0, wordsBasedOnWidth - 3) + "...";
    }
    return text;
  }
  /**
   * @param {{ x: any, y: any, text: any, textAnchor?: any, fontSize?: any, fontFamily?: any, fontWeight?: any, foreColor?: any, opacity?: any, maxWidth?: any, cssClass?: string, isPlainText?: boolean, dominantBaseline?: string }} opts
   */
  drawText({
    x,
    y,
    text,
    textAnchor,
    fontSize,
    fontFamily,
    fontWeight,
    foreColor,
    opacity,
    maxWidth,
    cssClass = "",
    isPlainText = true,
    dominantBaseline = "auto"
  }) {
    const w = this.w;
    if (typeof text === "undefined") text = "";
    let truncatedText = text;
    if (!textAnchor) {
      textAnchor = "start";
    }
    if (!foreColor || !foreColor.length) {
      foreColor = w.config.chart.foreColor;
    }
    fontFamily = fontFamily || w.config.chart.fontFamily;
    fontSize = fontSize || "11px";
    fontWeight = fontWeight || "regular";
    const commonProps = {
      maxWidth,
      fontSize,
      fontFamily
    };
    let elText;
    if (Array.isArray(text)) {
      elText = w.dom.Paper.text((add) => {
        for (let i2 = 0; i2 < text.length; i2++) {
          truncatedText = text[i2];
          if (maxWidth) {
            truncatedText = this.getTextBasedOnMaxWidth(__spreadValues({
              text: text[i2]
            }, commonProps));
          }
          i2 === 0 ? add.tspan(truncatedText) : add.tspan(truncatedText).newLine();
        }
      });
    } else {
      if (maxWidth) {
        truncatedText = this.getTextBasedOnMaxWidth(__spreadValues({
          text
        }, commonProps));
      }
      elText = isPlainText ? w.dom.Paper.plain(text) : (
        /**
         * @param {any} add
         */
        w.dom.Paper.text((add) => add.tspan(truncatedText))
      );
    }
    elText.attr({
      x,
      y,
      "text-anchor": textAnchor,
      "dominant-baseline": dominantBaseline,
      "font-size": fontSize,
      "font-family": fontFamily,
      "font-weight": fontWeight,
      fill: foreColor,
      class: "apexcharts-text " + cssClass
    });
    elText.node.style.fontFamily = fontFamily;
    elText.node.style.opacity = opacity;
    return elText;
  }
  /**
   * @param {number} x
   * @param {number} y
   * @param {string} type
   * @param {number} size
   */
  getMarkerPath(x, y, type, size) {
    const CROSS_SHRINK = 1.4;
    const PLUS_SHRINK = 1.12;
    const STAR_GROW = 1.15;
    const SPARKLE_SHRINK = 1.1;
    const SQUARE_SHRINK = 1.125;
    const DIAMOND_GROW = 1.05;
    const LINE_SHRINK = 1.1;
    const CIRCLE_DIAMETER = 2;
    let d = "";
    switch (type) {
      case "cross":
        size = size / CROSS_SHRINK;
        d = `M ${x - size} ${y - size} L ${x + size} ${y + size}  M ${x - size} ${y + size} L ${x + size} ${y - size}`;
        break;
      case "plus":
        size = size / PLUS_SHRINK;
        d = `M ${x - size} ${y} L ${x + size} ${y}  M ${x} ${y - size} L ${x} ${y + size}`;
        break;
      case "star":
      case "sparkle": {
        let points = 5;
        size = size * STAR_GROW;
        if (type === "sparkle") {
          size = size / SPARKLE_SHRINK;
          points = 4;
        }
        const step = Math.PI / points;
        for (let i2 = 0; i2 <= 2 * points; i2++) {
          const angle = i2 * step;
          const radius = i2 % 2 === 0 ? size : size / 2;
          const xPos = x + radius * Math.sin(angle);
          const yPos = y - radius * Math.cos(angle);
          d += (i2 === 0 ? "M" : "L") + xPos + "," + yPos;
        }
        d += "Z";
        break;
      }
      case "triangle":
        d = `M ${x} ${y - size} 
             L ${x + size} ${y + size} 
             L ${x - size} ${y + size} 
             Z`;
        break;
      case "square":
      case "rect":
        size = size / SQUARE_SHRINK;
        d = `M ${x - size} ${y - size} 
           L ${x + size} ${y - size} 
           L ${x + size} ${y + size} 
           L ${x - size} ${y + size} 
           Z`;
        break;
      case "diamond":
        size = size * DIAMOND_GROW;
        d = `M ${x} ${y - size} 
             L ${x + size} ${y} 
             L ${x} ${y + size} 
             L ${x - size} ${y} 
            Z`;
        break;
      case "line":
        size = size / LINE_SHRINK;
        d = `M ${x - size} ${y} 
           L ${x + size} ${y}`;
        break;
      case "circle":
      default:
        size = size * CIRCLE_DIAMETER;
        d = `M ${x}, ${y} 
           m -${size / 2}, 0 
           a ${size / 2},${size / 2} 0 1,0 ${size},0 
           a ${size / 2},${size / 2} 0 1,0 -${size},0`;
        break;
    }
    return d;
  }
  /**
   * @param {number} x - The x-coordinate of the marker
   * @param {number} y - The y-coordinate of the marker
   * @param {string} type - Marker shape type
   * @param {number} size - The size of the marker
   * @param {Record<string, any>} opts - The options for the marker
   * @returns {any} The created marker.
   */
  drawMarkerShape(x, y, type, size, opts) {
    const path = this.drawPath({
      d: this.getMarkerPath(x, y, type, size),
      stroke: opts.pointStrokeColor,
      strokeDashArray: opts.pointStrokeDashArray,
      strokeWidth: opts.pointStrokeWidth,
      fill: opts.pointFillColor,
      fillOpacity: opts.pointFillOpacity,
      strokeOpacity: opts.pointStrokeOpacity
    });
    path.attr({
      cx: x,
      cy: y,
      shape: opts.shape,
      class: opts.class ? opts.class : ""
    });
    return path;
  }
  /**
   * @param {number} x
   * @param {number} y
   * @param {Record<string, any>} opts
   */
  drawMarker(x, y, opts) {
    x = x || 0;
    let size = opts.pSize || 0;
    if (!Utils$1.isNumber(y)) {
      size = 0;
      y = 0;
    }
    return this.drawMarkerShape(x, y, opts == null ? void 0 : opts.shape, size, __spreadValues(__spreadValues({}, opts), opts.shape === "line" || opts.shape === "plus" || opts.shape === "cross" ? {
      pointStrokeColor: opts.pointFillColor,
      pointStrokeOpacity: opts.pointFillOpacity
    } : {}));
  }
  /**
   * @param {any} path
   * @param {Event | null} [e]
   */
  pathMouseEnter(path, e2) {
    var _a, _b;
    const w = this.w;
    const filters = new Filters(this.w);
    const i2 = parseInt((_a = path.node.getAttribute("index")) != null ? _a : "", 10);
    const j = parseInt((_b = path.node.getAttribute("j")) != null ? _b : "", 10);
    if (isNaN(i2) || isNaN(j)) return;
    if (typeof w.config.chart.events.dataPointMouseEnter === "function") {
      w.config.chart.events.dataPointMouseEnter(e2, this.ctx, {
        seriesIndex: i2,
        dataPointIndex: j,
        w
      });
    }
    Graphics._fireEvent(w, "dataPointMouseEnter", [
      e2,
      this.ctx,
      { seriesIndex: i2, dataPointIndex: j, w }
    ]);
    if (w.config.states.active.filter.type !== "none") {
      if (path.node.getAttribute("selected") === "true") {
        return;
      }
    }
    if (Filters.hoverOutlineOwnsHoverState(w)) return;
    if (w.config.states.hover.filter.type !== "none") {
      if (!w.interact.isTouchDevice) {
        const hoverFilter = w.config.states.hover.filter;
        filters.applyFilter(path, i2, hoverFilter.type, hoverFilter.value);
      }
    }
  }
  /**
   * @param {any} path
   * @param {Event | null} [e]
   */
  pathMouseLeave(path, e2) {
    var _a, _b;
    const w = this.w;
    const filters = new Filters(this.w);
    const i2 = parseInt((_a = path.node.getAttribute("index")) != null ? _a : "", 10);
    const j = parseInt((_b = path.node.getAttribute("j")) != null ? _b : "", 10);
    if (isNaN(i2) || isNaN(j)) return;
    if (typeof w.config.chart.events.dataPointMouseLeave === "function") {
      w.config.chart.events.dataPointMouseLeave(e2, this.ctx, {
        seriesIndex: i2,
        dataPointIndex: j,
        w
      });
    }
    Graphics._fireEvent(w, "dataPointMouseLeave", [
      e2,
      this.ctx,
      { seriesIndex: i2, dataPointIndex: j, w }
    ]);
    if (w.config.states.active.filter.type !== "none") {
      if (path.node.getAttribute("selected") === "true") {
        return;
      }
    }
    if (Filters.hoverOutlineOwnsHoverState(w)) return;
    if (w.config.states.hover.filter.type !== "none") {
      filters.getDefaultFilter(path, i2);
    }
  }
  /**
   * Clear every selected data point (single-select mode): reset the selection
   * array and restore the default filter on all series path/circle/rect nodes.
   * NOTE: preserves the original behavior of passing the clicked series index
   * `i` to getDefaultFilter for every element (not each element's own index).
   * @param {any} filters @param {number} i
   */
  _clearAllDataPointSelections(filters, i2) {
    const w = this.w;
    w.interact.selectedDataPoints = [];
    const elPaths = w.dom.Paper.find(
      ".apexcharts-series path:not(.apexcharts-decoration-element)"
    );
    const elCircles = w.dom.Paper.find(
      ".apexcharts-series circle:not(.apexcharts-decoration-element), .apexcharts-series rect:not(.apexcharts-decoration-element)"
    );
    const deSelect = (els) => {
      Array.prototype.forEach.call(els, (el) => {
        el.node.setAttribute("selected", "false");
        filters.getDefaultFilter(el, i2);
      });
    };
    deSelect(elPaths);
    deSelect(elCircles);
  }
  /**
   * Toggle the selected state of a single data point. Mutates
   * `w.interact.selectedDataPoints` and the path's `selected` attribute,
   * honoring single- vs multi-select mode. Returns the new selected flag.
   * @param {any} path @param {any} filters @param {number} i @param {number} j
   * @returns {'true' | 'false'}
   */
  _togglePointSelection(path, filters, i2, j) {
    const w = this.w;
    if (path.node.getAttribute("selected") === "true") {
      path.node.setAttribute("selected", "false");
      const index = w.interact.selectedDataPoints[i2].indexOf(j);
      if (index > -1) {
        w.interact.selectedDataPoints[i2].splice(index, 1);
      }
      return "false";
    }
    if (!w.config.states.active.allowMultipleDataPointsSelection && w.interact.selectedDataPoints.length > 0) {
      this._clearAllDataPointSelections(filters, i2);
    }
    path.node.setAttribute("selected", "true");
    if (typeof w.interact.selectedDataPoints[i2] === "undefined") {
      w.interact.selectedDataPoints[i2] = [];
    }
    w.interact.selectedDataPoints[i2].push(j);
    return "true";
  }
  /**
   * Apply the active / hover / default state filter after a selection toggle,
   * matching the original inline branching.
   * @param {any} path @param {any} filters @param {number} i
   * @param {'true' | 'false'} selected
   */
  _applyPointSelectionFilter(path, filters, i2, selected) {
    const w = this.w;
    if (Filters.sliceOffsetOwnsActiveState(w)) return;
    if (selected === "true") {
      const activeFilter = w.config.states.active.filter;
      if (activeFilter !== "none") {
        filters.applyFilter(path, i2, activeFilter.type, activeFilter.value);
      } else {
        if (w.config.states.hover.filter !== "none") {
          if (!w.interact.isTouchDevice) {
            const hoverFilter = w.config.states.hover.filter;
            filters.applyFilter(path, i2, hoverFilter.type, hoverFilter.value);
          }
        }
      }
    } else {
      if (w.config.states.active.filter.type !== "none") {
        if (w.config.states.hover.filter.type !== "none" && !w.interact.isTouchDevice) {
          const hoverFilter = w.config.states.hover.filter;
          filters.applyFilter(path, i2, hoverFilter.type, hoverFilter.value);
        } else {
          filters.getDefaultFilter(path, i2);
        }
      }
    }
  }
  /**
   * @param {any} path
   * @param {Event | null} e
   */
  pathMouseDown(path, e2) {
    var _a, _b;
    const w = this.w;
    const filters = new Filters(this.w);
    const i2 = parseInt((_a = path.node.getAttribute("index")) != null ? _a : "", 10);
    const j = parseInt((_b = path.node.getAttribute("j")) != null ? _b : "", 10);
    if (isNaN(i2) || isNaN(j)) return;
    const link = w.config.chart.link;
    const crossfilterClick = !!(link && (typeof link.dimension === "function" || link.enabled));
    if (!crossfilterClick) {
      const selected = this._togglePointSelection(path, filters, i2, j);
      this._applyPointSelectionFilter(path, filters, i2, selected);
    }
    if (typeof w.config.chart.events.dataPointSelection === "function") {
      w.config.chart.events.dataPointSelection(e2, this.ctx, {
        selectedDataPoints: w.interact.selectedDataPoints,
        seriesIndex: i2,
        dataPointIndex: j,
        w
      });
    }
    if (e2) {
      Graphics._fireEvent(w, "dataPointSelection", [
        e2,
        this.ctx,
        {
          selectedDataPoints: w.interact.selectedDataPoints,
          seriesIndex: i2,
          dataPointIndex: j,
          w
        }
      ]);
    }
  }
  /**
   * @param {any} el
   * @returns {{ x: number, y: number }}
   */
  rotateAroundCenter(el) {
    let coord = (
      /** @type {any} */
      {}
    );
    if (el && typeof el.getBBox === "function") {
      coord = el.getBBox();
    }
    const x = coord.x + coord.width / 2;
    const y = coord.y + coord.height / 2;
    return {
      x,
      y
    };
  }
  /**
   * Sets up event delegation on a parent group element.
   * Uses mouseover/mouseout (which bubble) to simulate mouseenter/mouseleave
   * on matching child elements, reducing per-element listener overhead.
   * @param {any} parentGroup
   * @param {string} targetSelector
   */
  setupEventDelegation(parentGroup, targetSelector) {
    let currentHovered = null;
    parentGroup.node.addEventListener("mouseover", (e2) => {
      const targetNode = Graphics._findDelegateTarget(
        e2.target,
        parentGroup.node,
        targetSelector
      );
      if (!targetNode || targetNode === currentHovered) return;
      if (currentHovered && /** @type {any} */
      currentHovered.instance) {
        this.pathMouseLeave(
          /** @type {any} */
          currentHovered.instance,
          e2
        );
      }
      currentHovered = targetNode;
      if (targetNode.instance) {
        this.pathMouseEnter(targetNode.instance, e2);
      }
    });
    parentGroup.node.addEventListener("mouseout", (e2) => {
      if (!currentHovered) return;
      const relatedNode = e2.relatedTarget ? Graphics._findDelegateTarget(
        e2.relatedTarget,
        parentGroup.node,
        targetSelector
      ) : null;
      if (relatedNode !== currentHovered) {
        if (currentHovered && /** @type {any} */
        currentHovered.instance) {
          this.pathMouseLeave(
            /** @type {any} */
            currentHovered.instance,
            e2
          );
        }
        currentHovered = null;
      }
    });
    parentGroup.node.addEventListener("mousedown", (e2) => {
      const targetNode = Graphics._findDelegateTarget(
        e2.target,
        parentGroup.node,
        targetSelector
      );
      if (targetNode && targetNode.instance) {
        this.pathMouseDown(targetNode.instance, e2);
      }
    });
  }
  // Fire a named event from w.globals.events without requiring a ctx reference.
  // Mirrors Events.fireEvent() but reads the registry directly from w so that
  // pathMouseEnter/Leave/Down work even when this.ctx is null (Graphics instances
  // created without a ctx arg for drawing-only use cases).
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {string} name
   * @param {any[]} args
   */
  static _fireEvent(w, name2, args) {
    const evs = w.globals.events;
    if (!evs || !Object.prototype.hasOwnProperty.call(evs, name2)) return;
    const handlers = (
      /** @type {Record<string,any>} */
      evs[name2]
    );
    for (let i2 = 0; i2 < handlers.length; i2++) {
      handlers[i2].apply(null, args);
    }
  }
  /**
   * @param {any} node
   * @param {Record<string, any>} boundary
   * @param {string} selector
   */
  static _findDelegateTarget(node, boundary, selector) {
    while (node && node !== boundary && node !== document) {
      if (node.matches && node.matches(selector)) return node;
      node = node.parentNode;
    }
    return null;
  }
  /**
   * @param {any} el
   * @param {Record<string, any>} attrs
   */
  static setAttrs(el, attrs) {
    for (const key in attrs) {
      if (Object.prototype.hasOwnProperty.call(attrs, key)) {
        el.setAttribute(key, attrs[key]);
      }
    }
  }
  /**
   * @param {string} text
   * @param {string} fontSize
   * @param {string | null | undefined} [fontFamily]
   * @param {string} [transform]
   * @param {boolean} [useBBox]
   * @param {string | number} [fontWeight] weight to measure at. Omit and the
   *   measurement is taken at 'regular' (drawText's default), which is only
   *   correct for text that also RENDERS at regular. Bolder text is wider, so
   *   measuring a bold label at regular under-reports its width and any
   *   fit/overflow decision made from it comes up short.
   * @returns {{ width: number, height: number }}
   */
  getTextRects(text, fontSize, fontFamily, transform, useBBox = true, fontWeight) {
    const w = this.w;
    const cacheKey = [
      text,
      fontSize,
      fontFamily,
      transform,
      useBBox,
      fontWeight
    ].join("\0");
    const cache = w.globals.textRectsCache;
    if (cache && cache.has(cacheKey)) {
      return (
        /** @type {{ width: number, height: number }} */
        cache.get(cacheKey)
      );
    }
    const virtualText = this.drawText({
      x: -200,
      y: -200,
      text,
      textAnchor: "start",
      fontSize,
      fontFamily,
      fontWeight,
      foreColor: "#fff",
      opacity: 0
    });
    if (transform) {
      virtualText.attr("transform", transform);
    }
    w.dom.Paper.add(virtualText);
    let rect = virtualText.bbox();
    const bboxY = rect.y;
    if (!useBBox) {
      rect = virtualText.node.getBoundingClientRect();
    }
    virtualText.remove();
    const result = {
      width: rect.width,
      height: rect.height,
      // Offset from the text element's `y` (alphabetic baseline) to the
      // bbox vertical center. For most fonts this is NEGATIVE (bbox center
      // sits above the baseline because the ascender is taller than the
      // descender). Use as: `text_y = desired_visual_center_y - centerOffset`.
      // Only populated when useBBox=true (the default).
      centerOffset: useBBox ? bboxY + rect.height / 2 - -200 : 0
    };
    if (cache) {
      cache.set(cacheKey, result);
    }
    return result;
  }
  /**
   * append ... to long text
   * http://stackoverflow.com/questions/9241315/trimming-text-to-a-given-pixel-width-in-svg
   * @memberof Graphics
   * @param {Record<string, any>} textObj
   * @param {string} textString
   * @param {number} width
   **/
  placeTextWithEllipsis(textObj, textString, width) {
    if (typeof textObj.getComputedTextLength !== "function") return;
    textObj.textContent = textString;
    if (textString.length > 0) {
      if (textObj.getComputedTextLength() >= width / 1.1) {
        for (let x = textString.length - 3; x > 0; x -= 3) {
          if (textObj.getSubStringLength(0, x) <= width / 1.1) {
            textObj.textContent = textString.substring(0, x) + "...";
            return;
          }
        }
        textObj.textContent = ".";
      }
    }
  }
}
class Fill {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this.opts = null;
    this.seriesIndex = 0;
    this.patternIDs = [];
  }
  /**
   * @param {Record<string, any>} params
   */
  clippedImgArea(params) {
    const w = this.w;
    const cnf = w.config;
    const svgW = parseInt(String(w.layout.gridWidth), 10);
    const svgH = parseInt(String(w.layout.gridHeight), 10);
    const size = svgW > svgH ? svgW : svgH;
    const fillImg = params.image;
    let imgWidth = 0;
    let imgHeight = 0;
    if (typeof params.width === "undefined" && typeof params.height === "undefined") {
      if (cnf.fill.image.width !== void 0 && cnf.fill.image.height !== void 0) {
        imgWidth = cnf.fill.image.width + 1;
        imgHeight = cnf.fill.image.height;
      } else {
        imgWidth = size + 1;
        imgHeight = size;
      }
    } else {
      imgWidth = params.width;
      imgHeight = params.height;
    }
    const elPattern = BrowserAPIs.createElementNS(SVGNS$1, "pattern");
    Graphics.setAttrs(elPattern, {
      id: params.patternID,
      patternUnits: params.patternUnits ? params.patternUnits : "userSpaceOnUse",
      width: imgWidth + "px",
      height: imgHeight + "px"
    });
    const elImage = BrowserAPIs.createElementNS(SVGNS$1, "image");
    elPattern.appendChild(elImage);
    const SVGLib = Environment.isBrowser() ? (
      /** @type {any} */
      window.SVG
    ) : (
      /** @type {any} */
      global.SVG
    );
    elImage.setAttributeNS(SVGLib.xlink, "href", fillImg);
    Graphics.setAttrs(elImage, {
      x: 0,
      y: 0,
      preserveAspectRatio: "none",
      width: imgWidth + "px",
      height: imgHeight + "px"
    });
    elImage.style.opacity = params.opacity;
    w.dom.elDefs.node.appendChild(elPattern);
  }
  /**
   * @param {Record<string, any>} opts
   */
  getSeriesIndex(opts) {
    const w = this.w;
    const cType = w.config.chart.type;
    if ((cType === "bar" || cType === "rangeBar") && w.config.plotOptions.bar.distributed || cType === "heatmap" || cType === "treemap") {
      this.seriesIndex = opts.seriesNumber;
    } else {
      this.seriesIndex = opts.seriesNumber % w.seriesData.series.length;
    }
    return this.seriesIndex;
  }
  /**
   * The y-axis window a series is plotted against. This is the space the
   * threshold gradient is measured in, since that gradient spans the plot area.
   *
   * @param {number} realIndex
   */
  getSeriesAxisRange(realIndex) {
    var _a, _b, _c;
    const w = this.w;
    const yaxisIndex = (_b = (_a = w.globals.seriesYAxisReverseMap) == null ? void 0 : _a[realIndex]) != null ? _b : 0;
    return {
      minY: Utils$1.isNumber(w.globals.minYArr[realIndex]) ? w.globals.minYArr[realIndex] : w.globals.minY,
      maxY: Utils$1.isNumber(w.globals.maxYArr[realIndex]) ? w.globals.maxYArr[realIndex] : w.globals.maxY,
      reversed: !!((_c = w.config.yaxis[yaxisIndex]) == null ? void 0 : _c.reversed)
    };
  }
  /**
   * Builds the two stops that split a series into an above- and a
   * below-threshold color.
   *
   * The stops are painted into a vertical gradient anchored to the plot area
   * (see Graphics.drawGradient's verticalUserSpace branch), so the boundary is
   * positioned over the *axis* range. Deriving it from the data range instead
   * puts the transition on the wrong value whenever the axis extends past the
   * data, which is the common case: an explicit yaxis.min/max, a nice scale, or
   * an axis shared with another series.
   *
   * @param {{ minY: number, maxY: number, reversed?: boolean }} axisRange
   * @param {Record<string, any>} multiColorConfig
   */
  computeColorStops(axisRange, multiColorConfig) {
    const w = this.w;
    const { threshold, colorAboveThreshold, colorBelowThreshold } = multiColorConfig;
    const { minY, maxY } = axisRange;
    const span = maxY - minY;
    let offset = span === 0 ? threshold > maxY ? 0 : 100 : (maxY - threshold) / span * 100;
    if (axisRange.reversed) {
      offset = 100 - offset;
    }
    offset = Math.max(0, Math.min(offset, 100));
    const fillOpacity = Array.isArray(w.config.fill.opacity) ? w.config.fill.opacity[this.seriesIndex] : w.config.fill.opacity;
    const above = {
      offset,
      color: colorAboveThreshold,
      opacity: fillOpacity
    };
    const below = {
      offset,
      color: colorBelowThreshold,
      opacity: fillOpacity
    };
    return axisRange.reversed ? [below, above] : [above, below];
  }
  /**
   * @param {Record<string, any>} opts
   */
  fillPath(opts) {
    var _a, _b, _c, _d;
    const w = this.w;
    this.opts = opts;
    const cnf = this.w.config;
    let pathFill;
    let patternFill, gradientFill;
    this.seriesIndex = this.getSeriesIndex(opts);
    const drawMultiColorLine = cnf.plotOptions.line.colors.colorAboveThreshold && cnf.plotOptions.line.colors.colorBelowThreshold;
    const fillColors = this.getFillColors();
    let fillColor = fillColors[this.seriesIndex];
    if (w.seriesData.seriesColors[this.seriesIndex] !== void 0) {
      fillColor = w.seriesData.seriesColors[this.seriesIndex];
    }
    if (typeof fillColor === "function") {
      fillColor = fillColor({
        seriesIndex: this.seriesIndex,
        dataPointIndex: opts.dataPointIndex,
        value: opts.value,
        w
      });
    }
    const fillType = opts.fillType ? opts.fillType : this.getFillType(this.seriesIndex);
    let fillOpacity = Array.isArray(cnf.fill.opacity) ? cnf.fill.opacity[this.seriesIndex] : cnf.fill.opacity;
    const useGradient = fillType === "gradient" || drawMultiColorLine;
    if (opts.color) {
      fillColor = opts.color;
    }
    const seriesItem = (
      /** @type {Record<string,any>} */
      w.config.series[this.seriesIndex]
    );
    if ((_b = (_a = seriesItem == null ? void 0 : seriesItem.data) == null ? void 0 : _a[opts.dataPointIndex]) == null ? void 0 : _b.fillColor) {
      fillColor = (_d = (_c = seriesItem == null ? void 0 : seriesItem.data) == null ? void 0 : _c[opts.dataPointIndex]) == null ? void 0 : _d.fillColor;
    }
    if (!fillColor) {
      fillColor = "#fff";
      console.warn("undefined color - ApexCharts");
    }
    if (opts.opacity !== void 0 && opts.opacity !== null) fillOpacity = opts.opacity;
    let defaultColor = fillColor;
    if (Utils$1.isCSSVariable(fillColor)) {
      defaultColor = Utils$1.applyOpacityToColor(fillColor, fillOpacity);
    } else if (fillColor.indexOf("rgb") === -1) {
      if (fillColor.indexOf("#") === -1) {
        defaultColor = fillColor;
      } else if (fillColor.length < 9) {
        defaultColor = Utils$1.hexToRgba(fillColor, fillOpacity);
      }
    } else {
      if (fillColor.indexOf("rgba") > -1) {
        fillOpacity = Utils$1.getOpacityFromRGBA(fillColor);
      } else {
        defaultColor = Utils$1.hexToRgba(Utils$1.rgb2hex(fillColor), fillOpacity);
      }
    }
    const resolvedFillColor = Utils$1.isCSSVariable(fillColor) ? Utils$1.getThemeColor(fillColor) : fillColor;
    if (fillType === "pattern") {
      patternFill = this.handlePatternFill({
        fillConfig: opts.fillConfig,
        patternFill,
        fillColor: resolvedFillColor,
        defaultColor
      });
    }
    if (useGradient) {
      const colorStops = cnf.fill.gradient.colorStops ? [...cnf.fill.gradient.colorStops] : [];
      let type = cnf.fill.gradient.type;
      if (drawMultiColorLine) {
        colorStops[this.seriesIndex] = this.computeColorStops(
          this.getSeriesAxisRange(this.seriesIndex),
          cnf.plotOptions.line.colors
        );
        type = "vertical";
      }
      gradientFill = this.handleGradientFill({
        type,
        fillConfig: opts.fillConfig,
        fillColor: resolvedFillColor,
        fillOpacity,
        colorStops,
        i: this.seriesIndex,
        // Threshold stops are positioned over the axis range, so the gradient
        // has to be anchored to the plot area to match. This also keeps every
        // segment of a null-split series on one shared coordinate space.
        verticalUserSpace: drawMultiColorLine
      });
    }
    if (fillType === "image") {
      const imgSrc = cnf.fill.image.src;
      const patternID = opts.patternID ? opts.patternID : "";
      const patternKey = `pattern${w.globals.cuid}${opts.seriesNumber + 1}${patternID}`;
      if (this.patternIDs.indexOf(patternKey) === -1) {
        this.clippedImgArea({
          opacity: fillOpacity,
          image: Array.isArray(imgSrc) ? opts.seriesNumber < imgSrc.length ? imgSrc[opts.seriesNumber] : imgSrc[0] : imgSrc,
          width: opts.width ? opts.width : void 0,
          height: opts.height ? opts.height : void 0,
          patternUnits: opts.patternUnits,
          patternID: patternKey
        });
        this.patternIDs.push(patternKey);
      }
      pathFill = `url(#${patternKey})`;
    } else if (useGradient) {
      pathFill = gradientFill;
    } else if (fillType === "pattern") {
      pathFill = patternFill;
    } else {
      pathFill = defaultColor;
    }
    if (opts.solid) {
      pathFill = defaultColor;
    }
    return pathFill;
  }
  /**
   * @param {number} seriesIndex
   */
  getFillType(seriesIndex) {
    const w = this.w;
    if (Array.isArray(w.config.fill.type)) {
      return w.config.fill.type[seriesIndex];
    } else {
      return w.config.fill.type;
    }
  }
  getFillColors() {
    const w = this.w;
    const cnf = w.config;
    const opts = this.opts;
    let fillColors = [];
    if (w.globals.comboCharts) {
      if (
        /** @type {Record<string,any>} */
        w.config.series[this.seriesIndex].type === "line"
      ) {
        if (Array.isArray(w.globals.stroke.colors)) {
          fillColors = w.globals.stroke.colors;
        } else {
          fillColors.push(w.globals.stroke.colors);
        }
      } else {
        if (Array.isArray(w.globals.fill.colors)) {
          fillColors = w.globals.fill.colors;
        } else {
          fillColors.push(w.globals.fill.colors);
        }
      }
    } else {
      if (cnf.chart.type === "line") {
        if (Array.isArray(w.globals.stroke.colors)) {
          fillColors = w.globals.stroke.colors;
        } else {
          fillColors.push(w.globals.stroke.colors);
        }
      } else {
        if (Array.isArray(w.globals.fill.colors)) {
          fillColors = w.globals.fill.colors;
        } else {
          fillColors.push(w.globals.fill.colors);
        }
      }
    }
    if (typeof opts.fillColors !== "undefined") {
      fillColors = [];
      if (Array.isArray(opts.fillColors)) {
        fillColors = opts.fillColors.slice();
      } else {
        fillColors.push(opts.fillColors);
      }
    }
    return fillColors;
  }
  /** @param {{fillConfig: any, patternFill: any, fillColor: any, defaultColor: any}} opts */
  handlePatternFill({ fillConfig, patternFill, fillColor, defaultColor }) {
    let fillCnf = this.w.config.fill;
    if (fillConfig) {
      fillCnf = fillConfig;
    }
    const opts = this.opts;
    const graphics = new Graphics(this.w);
    const patternStrokeWidth = Array.isArray(fillCnf.pattern.strokeWidth) ? fillCnf.pattern.strokeWidth[this.seriesIndex] : fillCnf.pattern.strokeWidth;
    const patternLineColor = fillColor;
    if (Array.isArray(fillCnf.pattern.style)) {
      if (typeof fillCnf.pattern.style[opts.seriesNumber] !== "undefined") {
        const pf = graphics.drawPattern(
          fillCnf.pattern.style[opts.seriesNumber],
          fillCnf.pattern.width,
          fillCnf.pattern.height,
          patternLineColor,
          patternStrokeWidth
        );
        patternFill = pf;
      } else {
        patternFill = defaultColor;
      }
    } else {
      patternFill = graphics.drawPattern(
        fillCnf.pattern.style,
        fillCnf.pattern.width,
        fillCnf.pattern.height,
        patternLineColor,
        patternStrokeWidth
      );
    }
    return patternFill;
  }
  handleGradientFill({
    type,
    fillColor,
    fillOpacity,
    fillConfig,
    colorStops,
    i: i2,
    verticalUserSpace = false
  }) {
    let fillCnf = this.w.config.fill;
    if (fillConfig) {
      fillCnf = __spreadValues(__spreadValues({}, fillCnf), fillConfig);
    }
    const opts = this.opts;
    const graphics = new Graphics(this.w);
    const utils = new Utils$1();
    type = type || fillCnf.gradient.type;
    let gradientFrom = fillColor;
    let gradientTo;
    let opacityFrom = fillCnf.gradient.opacityFrom === void 0 ? fillOpacity : Array.isArray(fillCnf.gradient.opacityFrom) ? fillCnf.gradient.opacityFrom[i2] : fillCnf.gradient.opacityFrom;
    if (gradientFrom.indexOf("rgba") > -1) {
      opacityFrom = Utils$1.getOpacityFromRGBA(gradientFrom);
    }
    let opacityTo = fillCnf.gradient.opacityTo === void 0 ? fillOpacity : Array.isArray(fillCnf.gradient.opacityTo) ? fillCnf.gradient.opacityTo[i2] : fillCnf.gradient.opacityTo;
    if (fillCnf.gradient.gradientToColors === void 0 || fillCnf.gradient.gradientToColors.length === 0) {
      if (fillCnf.gradient.shade === "dark") {
        gradientTo = utils.shadeColor(
          parseFloat(fillCnf.gradient.shadeIntensity) * -1,
          fillColor.indexOf("rgb") > -1 ? Utils$1.rgb2hex(fillColor) : fillColor
        );
      } else {
        gradientTo = utils.shadeColor(
          parseFloat(fillCnf.gradient.shadeIntensity),
          fillColor.indexOf("rgb") > -1 ? Utils$1.rgb2hex(fillColor) : fillColor
        );
      }
    } else {
      if (fillCnf.gradient.gradientToColors[opts.seriesNumber]) {
        const gToColor = fillCnf.gradient.gradientToColors[opts.seriesNumber];
        gradientTo = gToColor;
        if (gToColor.indexOf("rgba") > -1) {
          opacityTo = Utils$1.getOpacityFromRGBA(gToColor);
        }
      } else {
        gradientTo = fillColor;
      }
    }
    if (fillCnf.gradient.gradientFrom) {
      gradientFrom = fillCnf.gradient.gradientFrom;
    }
    if (fillCnf.gradient.gradientTo) {
      gradientTo = fillCnf.gradient.gradientTo;
    }
    if (fillCnf.gradient.inverseColors) {
      const t2 = gradientFrom;
      gradientFrom = gradientTo;
      gradientTo = t2;
    }
    if (gradientFrom.indexOf("rgb") > -1) {
      gradientFrom = Utils$1.rgb2hex(gradientFrom);
    }
    if (gradientTo.indexOf("rgb") > -1) {
      gradientTo = Utils$1.rgb2hex(gradientTo);
    }
    return graphics.drawGradient(
      type,
      gradientFrom,
      gradientTo,
      opacityFrom,
      opacityTo,
      opts.size,
      fillCnf.gradient.stops,
      colorStops,
      i2,
      verticalUserSpace
    );
  }
}
const OK_FILTER_TYPES = ["none", "lighten", "darken"];
function seriesEmitter(ctx, graphics) {
  const r2 = ctx && ctx.renderer;
  return r2 && r2.kind && r2.kind !== "svg" ? r2 : graphics;
}
function computeMarkCount(w) {
  const series = w.config.series || [];
  const type = w.config.chart.type;
  const scatterish = type === "scatter" || type === "bubble";
  const markerSize = w.config.markers && w.config.markers.size;
  const markersOn = Array.isArray(markerSize) ? markerSize.some((s2) => s2 > 0) : (markerSize || 0) > 0;
  const labelsOn = !!(w.config.dataLabels && w.config.dataLabels.enabled);
  const isHeatmap = type === "heatmap";
  let total = 0;
  let maxLen = 0;
  series.forEach((s2) => {
    const n2 = Array.isArray(s2.data) ? s2.data.length : 0;
    if (n2 > maxLen) maxLen = n2;
    if (scatterish || markersOn || isHeatmap) total += n2;
    if (labelsOn) total += n2;
  });
  const LARGE_D = 5e4;
  if (maxLen >= LARGE_D) total = Math.max(total, maxLen);
  return total;
}
function hasCanvasUnsupportedFeature(w) {
  var _a, _b;
  const fillType = w.config.fill && w.config.fill.type;
  const isUnsupportedFill = (t2) => t2 === "pattern" || t2 === "image" || t2 === "gradient";
  if (Array.isArray(fillType) ? fillType.some(isUnsupportedFill) : isUnsupportedFill(fillType)) {
    return true;
  }
  const lineColors = (_b = (_a = w.config.plotOptions) == null ? void 0 : _a.line) == null ? void 0 : _b.colors;
  if (lineColors && lineColors.colorAboveThreshold && lineColors.colorBelowThreshold) {
    return true;
  }
  const states = w.config.states || {};
  const hoverFilter = states.hover && states.hover.filter && states.hover.filter.type;
  const activeFilter = states.active && states.active.filter && states.active.filter.type;
  if (hoverFilter && !OK_FILTER_TYPES.includes(hoverFilter)) return true;
  if (activeFilter && !OK_FILTER_TYPES.includes(activeFilter)) return true;
  return false;
}
class Markers {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this._filters = new Filters(this.w);
    this._graphics = new Graphics(this.w, this.ctx);
    this._seriesWrap = null;
    this._seriesWrapIndex = -1;
    this._batch = null;
  }
  /**
   * Invalidate the cached per-series wrap group. Callers that drive
   * plotChartMarkers point-by-point (Line) must call this when a series'
   * element tree is (re)created, so a later render never appends markers to a
   * detached group from the previous pass.
   */
  resetSeriesWrapCache() {
    this._seriesWrap = null;
    this._seriesWrapIndex = -1;
    this._batch = null;
  }
  /**
   * Are this chart's markers non-interactive? True for a plain line/area with
   * the default sweep tooltip, which is exactly when `no-pointer-events` is
   * added below: markers are painted but never hit-tested, so nothing needs a
   * per-point node to receive events.
   * @param {import('../types/internal').ChartStateW} w
   */
  static markersAreInert(w) {
    const type = w.config.chart.type;
    return (type === "line" || type === "area") && !w.globals.comboCharts && !w.config.tooltip.intersect;
  }
  /**
   * Decide whether this chart draws each series' markers as ONE path element
   * (a subpath per point) instead of one element per point.
   *
   * This is deliberately all-or-nothing for the chart rather than per series.
   * The tooltip's hover indicator is chosen once for the whole chart, and a
   * chart with some batched and some per-point series would enlarge a node
   * belonging to the wrong series (`getAllMarkers` takes the first
   * `.apexcharts-marker` under each wrap), so mixed mode is not worth the
   * surface it would add.
   *
   * Every gate here is a feature that genuinely needs its own element per
   * point. Batching is skipped rather than half-supported for all of them.
   * @returns {boolean}
   */
  _shouldBatch() {
    var _a, _b, _c, _d, _e;
    const w = this.w;
    const m = w.config.markers;
    const threshold = (_a = m.largeDatasetThreshold) != null ? _a : 0;
    if (threshold <= 0) return false;
    if (((_c = (_b = this.ctx) == null ? void 0 : _b.renderer) == null ? void 0 : _c.kind) === "canvas") return false;
    if (!Markers.markersAreInert(w)) return false;
    if (m.discrete && m.discrete.length) return false;
    if (m.onClick || m.onDblClick) return false;
    if ((_d = w.config.chart.events) == null ? void 0 : _d.dataPointSelection) return false;
    const series = w.seriesData.series;
    if (!Array.isArray(series) || !series.length) return false;
    let anyOverThreshold = false;
    for (let i2 = 0; i2 < series.length; i2++) {
      if (!Array.isArray(series[i2])) return false;
      let hasNull = false;
      let perPointStyle = false;
      const data = (
        /** @type {Record<string, any>} */
        (_e = w.config.series[i2]) == null ? void 0 : _e.data
      );
      for (let j = 0; j < series[i2].length; j++) {
        if (series[i2][j] === null) hasNull = true;
        const d = Array.isArray(data) ? data[j] : null;
        if (d && (d.fillColor || d.strokeColor)) {
          perPointStyle = true;
          break;
        }
      }
      if (perPointStyle) return false;
      const drawsMarkers = w.globals.markers.size[i2] > 0 || hasNull && m.showNullDataPoints;
      if (!drawsMarkers) continue;
      if (series[i2].length > threshold) anyOverThreshold = true;
    }
    return anyOverThreshold;
  }
  setGlobalMarkerSize() {
    const w = this.w;
    w.globals.markers.size = Array.isArray(w.config.markers.size) ? w.config.markers.size : [w.config.markers.size];
    if (w.globals.markers.size.length > 0) {
      if (w.globals.markers.size.length < w.seriesData.series.length + 1) {
        for (let i2 = 0; i2 <= w.seriesData.series.length; i2++) {
          if (typeof w.globals.markers.size[i2] === "undefined") {
            w.globals.markers.size.push(w.globals.markers.size[0]);
          }
        }
      }
    } else {
      w.globals.markers.size = w.config.series.map(
        () => (
          /** @type {number} */
          w.config.markers.size
        )
      );
    }
    w.globals.markers.batched = this._shouldBatch();
  }
  /** @param {{ pointsPos?: any, seriesIndex?: any, j?: any, pSize?: any, alwaysDrawMarker?: boolean, isVirtualPoint?: boolean }} opts */
  plotChartMarkers({
    pointsPos,
    seriesIndex,
    j,
    pSize,
    alwaysDrawMarker = false,
    isVirtualPoint = false
  }) {
    const w = this.w;
    const i2 = seriesIndex;
    const p = pointsPos;
    let elMarkersWrap = null;
    const graphics = new Graphics(this.w);
    const emit = seriesEmitter(this.ctx, graphics);
    const hasDiscreteMarkers = w.config.markers.discrete && w.config.markers.discrete.length;
    if (Array.isArray(p.x)) {
      for (let q = 0; q < p.x.length; q++) {
        let markerElement;
        let dataPointIndex = j;
        let invalidMarker = !Utils$1.isNumber(p.y[q]);
        if (w.globals.markers.largestSize === 0 && w.globals.hasNullValues && w.seriesData.series[i2][j + 1] !== null && !isVirtualPoint) {
          invalidMarker = true;
        }
        if (j === 1 && q === 0) dataPointIndex = 0;
        if (j === 1 && q === 1) dataPointIndex = 1;
        let markerClasses = "apexcharts-marker";
        if (Markers.markersAreInert(w)) {
          markerClasses += " no-pointer-events";
        }
        const shouldMarkerDraw = Array.isArray(w.config.markers.size) ? w.globals.markers.size[seriesIndex] > 0 : w.config.markers.size > 0;
        const batchThisPoint = w.globals.markers.batched && (shouldMarkerDraw || alwaysDrawMarker) && !hasDiscreteMarkers && !isVirtualPoint;
        if (batchThisPoint) {
          this._batchPoint(seriesIndex, dataPointIndex, p.x[q], p.y[q], {
            invalid: invalidMarker,
            graphics,
            // alwaysDrawMarker carries an explicit size; the standard path
            // takes the series' own
            pSize: alwaysDrawMarker ? pSize : void 0,
            trackPoint: !alwaysDrawMarker
          });
          continue;
        }
        if (shouldMarkerDraw || alwaysDrawMarker || hasDiscreteMarkers) {
          if (emit.kind === "canvas") {
            if (typeof w.globals.pointsArray[seriesIndex] === "undefined") {
              w.globals.pointsArray[seriesIndex] = [];
            }
            w.globals.pointsArray[seriesIndex][dataPointIndex] = [p.x[q], p.y[q]];
          }
          if (!invalidMarker) {
            markerClasses += ` w${Utils$1.randomId()}`;
          }
          const opts = this.getMarkerConfig({
            cssClass: markerClasses,
            seriesIndex,
            dataPointIndex
          });
          const _si = (
            /** @type {Record<string,any>} */
            w.config.series[i2]
          );
          if (_si.data[dataPointIndex]) {
            if (_si.data[dataPointIndex].fillColor) {
              opts.pointFillColor = _si.data[dataPointIndex].fillColor;
            }
            if (_si.data[dataPointIndex].strokeColor) {
              opts.pointStrokeColor = _si.data[dataPointIndex].strokeColor;
            }
          }
          if (typeof pSize !== "undefined") {
            opts.pSize = pSize;
          }
          if (p.x[q] < -w.globals.markers.largestSize || p.x[q] > w.layout.gridWidth + w.globals.markers.largestSize || p.y[q] < -w.globals.markers.largestSize || p.y[q] > w.layout.gridHeight + w.globals.markers.largestSize) {
            opts.pSize = 0;
          }
          if (!invalidMarker) {
            const shouldCreateMarkerWrap = w.globals.markers.size[seriesIndex] > 0 || alwaysDrawMarker || hasDiscreteMarkers;
            if (shouldCreateMarkerWrap && !elMarkersWrap) {
              const standardWrap = !alwaysDrawMarker && !hasDiscreteMarkers;
              if (standardWrap && this._seriesWrap && this._seriesWrapIndex === seriesIndex) {
                elMarkersWrap = this._seriesWrap;
              } else {
                elMarkersWrap = emit.group({
                  class: standardWrap ? "apexcharts-series-markers" : ""
                });
                elMarkersWrap.attr(
                  "clip-path",
                  `url(#gridRectMarkerMask${w.globals.cuid})`
                );
                this.setupMarkerDelegation(elMarkersWrap);
                if (standardWrap) {
                  this._seriesWrap = elMarkersWrap;
                  this._seriesWrapIndex = seriesIndex;
                }
              }
            }
            markerElement = emit.drawMarker(p.x[q], p.y[q], opts);
            markerElement.attr("rel", dataPointIndex);
            markerElement.attr("j", dataPointIndex);
            markerElement.attr("index", seriesIndex);
            markerElement.node.setAttribute("default-marker-size", opts.pSize);
            applyProgressiveReveal(markerElement, p.x[q], w);
            this._filters.setSelectionFilter(
              markerElement,
              seriesIndex,
              dataPointIndex
            );
            if (elMarkersWrap) {
              elMarkersWrap.add(markerElement);
            }
          }
        } else {
          if (typeof w.globals.pointsArray[seriesIndex] === "undefined")
            w.globals.pointsArray[seriesIndex] = [];
          w.globals.pointsArray[seriesIndex].push([p.x[q], p.y[q]]);
        }
      }
    }
    return elMarkersWrap;
  }
  /**
   * Batched mode: record one point. Nothing touches the DOM here; each size
   * group becomes a single path in flushBatch.
   * @param {number} seriesIndex
   * @param {number} dataPointIndex
   * @param {number} x
   * @param {number} y
   * @param {{invalid: boolean, graphics: Graphics, pSize?: number,
   *          trackPoint?: boolean}} o
   */
  _batchPoint(seriesIndex, dataPointIndex, x, y, { invalid, graphics, pSize, trackPoint }) {
    const w = this.w;
    if (trackPoint) {
      if (typeof w.globals.pointsArray[seriesIndex] === "undefined") {
        w.globals.pointsArray[seriesIndex] = [];
      }
      w.globals.pointsArray[seriesIndex][dataPointIndex] = [x, y];
    }
    if (invalid) return;
    if (!this._batch || this._batch.seriesIndex !== seriesIndex) {
      this._batch = {
        seriesIndex,
        opts: this.getMarkerConfig({ cssClass: "", seriesIndex }),
        sizes: /* @__PURE__ */ new Map()
      };
    }
    const size = pSize === void 0 ? this._batch.opts.pSize : pSize;
    if (!(size > 0)) return;
    const slack = w.globals.markers.largestSize;
    if (x < -slack || x > w.layout.gridWidth + slack || y < -slack || y > w.layout.gridHeight + slack) {
      return;
    }
    let group = this._batch.sizes.get(size);
    if (!group) {
      group = [];
      this._batch.sizes.set(size, group);
    }
    group.push(graphics.getMarkerPath(x, y, this._batch.opts.shape, size));
  }
  /**
   * Emit the accumulated series as one path element per marker size and append
   * them to the series' marker wrap. Returns the elements, empty when the
   * series had nothing to batch.
   *
   * They are deliberately NOT classed `apexcharts-marker`. That class is how
   * the tooltip finds a node to enlarge (`getAllMarkers` takes the first match
   * under each wrap, `resetPointsSize` rewrites the `d` of every match), so a
   * batched path wearing it would have its entire subpath list replaced by a
   * single hover dot on the first mouseover.
   * @param {any} elPointsMain
   * @param {number} seriesIndex
   * @returns {any[]}
   */
  flushBatch(elPointsMain, seriesIndex) {
    const b = this._batch;
    this._batch = null;
    if (!b || b.seriesIndex !== seriesIndex || !b.sizes.size) return [];
    const w = this.w;
    const graphics = new Graphics(this.w);
    const opts = b.opts;
    const strokeShape = opts.shape === "line" || opts.shape === "plus" || opts.shape === "cross";
    const stroke = strokeShape ? opts.pointFillColor : opts.pointStrokeColor;
    const strokeOpacity = strokeShape ? opts.pointFillOpacity : opts.pointStrokeOpacity;
    const els = [];
    b.sizes.forEach((subpaths, size) => {
      if (!subpaths.length) return;
      const el = graphics.drawPath({
        d: subpaths.join(" "),
        fill: opts.pointFillColor,
        fillOpacity: opts.pointFillOpacity,
        stroke,
        strokeOpacity,
        strokeWidth: opts.pointStrokeWidth,
        strokeDashArray: opts.pointStrokeDashArray
      });
      el.attr({
        class: `apexcharts-marker-batch${Markers.markersAreInert(w) ? " no-pointer-events" : ""}`,
        "clip-path": `url(#gridRectMarkerMask${w.globals.cuid})`,
        shape: opts.shape,
        index: seriesIndex,
        "default-marker-size": size
      });
      elPointsMain.add(el);
      els.push(el);
    });
    return els;
  }
  /** @param {{cssClass: any, seriesIndex: any, dataPointIndex?: any, radius?: any, size?: any, strokeWidth?: any}} opts */
  getMarkerConfig({
    cssClass,
    seriesIndex,
    dataPointIndex = null,
    radius = null,
    size = null,
    strokeWidth = null
  }) {
    const w = this.w;
    const pStyle = this.getMarkerStyle(seriesIndex);
    let pSize = size === null ? w.globals.markers.size[seriesIndex] : size;
    const m = w.config.markers;
    if (dataPointIndex !== null && m.discrete.length) {
      m.discrete.map((marker) => {
        if (marker.seriesIndex === seriesIndex && marker.dataPointIndex === dataPointIndex) {
          if (marker.strokeColor !== void 0) {
            pStyle.pointStrokeColor = marker.strokeColor;
          }
          if (marker.fillColor !== void 0) {
            pStyle.pointFillColor = marker.fillColor;
          }
          if (marker.size !== void 0) pSize = marker.size;
          if (marker.shape !== void 0) pStyle.pointShape = marker.shape;
        }
      });
    }
    return {
      pSize: radius === null ? pSize : radius,
      pRadius: radius !== null ? radius : m.radius,
      pointStrokeWidth: strokeWidth !== null ? strokeWidth : Array.isArray(m.strokeWidth) ? m.strokeWidth[seriesIndex] : m.strokeWidth,
      pointStrokeColor: pStyle.pointStrokeColor,
      pointFillColor: pStyle.pointFillColor,
      shape: pStyle.pointShape || (Array.isArray(m.shape) ? m.shape[seriesIndex] : m.shape),
      class: cssClass,
      pointStrokeOpacity: Array.isArray(m.strokeOpacity) ? m.strokeOpacity[seriesIndex] : m.strokeOpacity,
      pointStrokeDashArray: Array.isArray(m.strokeDashArray) ? m.strokeDashArray[seriesIndex] : m.strokeDashArray,
      pointFillOpacity: Array.isArray(m.fillOpacity) ? m.fillOpacity[seriesIndex] : m.fillOpacity,
      seriesIndex
    };
  }
  /**
   * @param {any} parentGroup
   */
  setupMarkerDelegation(parentGroup) {
    const w = this.w;
    const selector = ".apexcharts-marker";
    this._graphics.setupEventDelegation(parentGroup, selector);
    parentGroup.node.addEventListener("click", (e2) => {
      if (w.config.markers.onClick) {
        const targetNode = Graphics._findDelegateTarget(
          e2.target,
          parentGroup.node,
          selector
        );
        if (targetNode) w.config.markers.onClick(e2);
      }
    });
    parentGroup.node.addEventListener("dblclick", (e2) => {
      if (w.config.markers.onDblClick) {
        const targetNode = Graphics._findDelegateTarget(
          e2.target,
          parentGroup.node,
          selector
        );
        if (targetNode) w.config.markers.onDblClick(e2);
      }
    });
    parentGroup.node.addEventListener(
      "touchstart",
      (e2) => {
        const targetNode = Graphics._findDelegateTarget(
          e2.target,
          parentGroup.node,
          selector
        );
        if (targetNode && targetNode.instance) {
          this._graphics.pathMouseDown(targetNode.instance, e2);
        }
      },
      { passive: true }
    );
  }
  /**
   * @returns {any}
   * @param {number} seriesIndex
   */
  getMarkerStyle(seriesIndex) {
    const w = this.w;
    const colors = w.globals.markers.colors;
    const strokeColors = w.config.markers.strokeColor || w.config.markers.strokeColors;
    const pointStrokeColor = Array.isArray(strokeColors) ? strokeColors[seriesIndex] : strokeColors;
    const pointFillColor = Array.isArray(colors) ? colors[seriesIndex] : colors;
    return {
      pointStrokeColor,
      pointFillColor
    };
  }
}
class Scatter {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.ctx = ctx;
    this.w = w;
    this.initialAnim = this.w.config.chart.animations.enabled;
    this.anim = new Animations(this.w);
    this.filters = new Filters(this.w);
    this.fill = new Fill(this.w);
    this.markers = new Markers(this.w, this.ctx);
    this.graphics = new Graphics(this.w);
    this._elPointsWrap = null;
    this._elPointsWrapParent = null;
    this._perSeries = null;
  }
  /**
   * @param {Element} elSeries
   * @param {number} j
   * @param {Record<string, any>} opts
   */
  draw(elSeries, j, opts) {
    const w = this.w;
    const graphics = this.graphics;
    const emit = seriesEmitter(this.ctx, graphics);
    const realIndex = opts.realIndex;
    const pointsPos = opts.pointsPos;
    const zRatio = opts.zRatio;
    const elPointsMain = opts.elParent;
    let elPointsWrap = this._elPointsWrap;
    if (!elPointsWrap || this._elPointsWrapParent !== elPointsMain) {
      elPointsWrap = emit.group({
        class: `apexcharts-series-markers apexcharts-series-${w.config.chart.type}`
      });
      elPointsWrap.attr(
        "clip-path",
        `url(#gridRectMarkerMask${w.globals.cuid})`
      );
      this.markers.setupMarkerDelegation(elPointsWrap);
      elPointsMain.add(elPointsWrap);
      this._elPointsWrap = elPointsWrap;
      this._elPointsWrapParent = elPointsMain;
      this._perSeries = this._buildPerSeriesCache(realIndex, emit);
    }
    if (Array.isArray(pointsPos.x)) {
      for (let q = 0; q < pointsPos.x.length; q++) {
        let dataPointIndex = j + 1;
        let shouldDraw = true;
        if (j === 0 && q === 0) dataPointIndex = 0;
        if (j === 0 && q === 1) dataPointIndex = 1;
        let radius = w.globals.markers.size[realIndex];
        if (zRatio !== Infinity) {
          const bubble = w.config.plotOptions.bubble;
          radius = w.seriesData.seriesZ[realIndex][dataPointIndex];
          if (bubble.zScaling) {
            radius /= zRatio;
          }
          if (bubble.minBubbleRadius && radius < bubble.minBubbleRadius) {
            radius = bubble.minBubbleRadius;
          }
          if (bubble.maxBubbleRadius && radius > bubble.maxBubbleRadius) {
            radius = bubble.maxBubbleRadius;
          }
        }
        const x = pointsPos.x[q];
        const y = pointsPos.y[q];
        radius = radius || 0;
        if (y === null || typeof w.seriesData.series[realIndex][dataPointIndex] === "undefined") {
          shouldDraw = false;
        }
        if (shouldDraw) {
          const point = this.drawPoint(
            x,
            y,
            radius,
            realIndex,
            dataPointIndex,
            j
          );
          elPointsWrap.add(point);
          if (emit.kind === "canvas") {
            if (typeof w.globals.pointsArray[realIndex] === "undefined") {
              w.globals.pointsArray[realIndex] = [];
            }
            w.globals.pointsArray[realIndex][dataPointIndex] = [x, y];
          }
        }
      }
    }
  }
  /**
   * Per-series constants for drawPoint's hot path. Everything here is uniform
   * across the points of one series; computing or allocating it per point is
   * measurable overhead at 20k-50k points.
   * @param {number} realIndex
   * @param {any} emit
   */
  _buildPerSeriesCache(realIndex, emit) {
    var _a;
    const w = this.w;
    return {
      realIndex,
      emit,
      isBubble: w.config.chart.type === "bubble" || w.globals.comboCharts && w.config.series[realIndex] && /** @type {Record<string,any>} */
      w.config.series[realIndex].type === "bubble",
      // discrete markers vary per point; they disable both caches below
      canCacheConfig: !w.config.markers.discrete.length,
      /** @type {any} lazily built shared marker config (first point) */
      markerConfig: null,
      /** @type {boolean|undefined} lazily resolved on the first fillPath call */
      fillCacheable: void 0,
      /** @type {any} cached fillPath result (undefined = not cached yet) */
      fillCircle: void 0,
      dropShadowEnabled: w.config.chart.dropShadow.enabled,
      doInitialAnim: this.initialAnim && !w.globals.dataChanged && !w.globals.resized,
      jitter: (_a = w.config.plotOptions.scatter) == null ? void 0 : _a.jitter,
      /** @type {any} lazily built pop-animation constants */
      anim: null
    };
  }
  /**
   * @param {number} x
   * @param {number} y
   * @param {number} radius
   * @param {number} realIndex
   * @param {number} dataPointIndex
   * @param {number} j
   */
  drawPoint(x, y, radius, realIndex, dataPointIndex, j) {
    var _a;
    const w = this.w;
    const i2 = realIndex;
    const anim = this.anim;
    const filters = this.filters;
    const fill = this.fill;
    const markers = this.markers;
    let ps = this._perSeries;
    if (!ps || ps.realIndex !== realIndex) {
      ps = this._perSeries = this._buildPerSeriesCache(
        realIndex,
        seriesEmitter(this.ctx, this.graphics)
      );
    }
    const emit = ps.emit;
    let markerConfig;
    if (ps.canCacheConfig) {
      if (!ps.markerConfig) {
        ps.markerConfig = markers.getMarkerConfig({
          cssClass: "apexcharts-marker",
          seriesIndex: i2,
          dataPointIndex,
          radius: ps.isBubble ? radius : null
        });
      }
      markerConfig = ps.markerConfig;
      if (ps.isBubble) {
        markerConfig.pSize = radius;
        markerConfig.pRadius = radius;
      }
    } else {
      markerConfig = markers.getMarkerConfig({
        cssClass: "apexcharts-marker",
        seriesIndex: i2,
        dataPointIndex,
        radius: ps.isBubble ? radius : null
      });
    }
    const _si = (
      /** @type {Record<string,any>} */
      w.config.series[i2]
    );
    const dataItem = _si.data[dataPointIndex];
    let pathFillCircle;
    if (ps.fillCircle !== void 0) {
      pathFillCircle = ps.fillCircle;
    } else {
      pathFillCircle = fill.fillPath({
        seriesNumber: realIndex,
        dataPointIndex,
        color: markerConfig.pointFillColor,
        patternUnits: "objectBoundingBox",
        value: w.seriesData.series[realIndex][j]
      });
      if (ps.fillCacheable === void 0) {
        ps.fillCacheable = ps.canCacheConfig && fill.getFillType(realIndex) === "solid" && typeof markerConfig.pointFillColor === "string" && !!markerConfig.pointFillColor;
      }
      if (ps.fillCacheable && !(dataItem == null ? void 0 : dataItem.fillColor)) {
        ps.fillCircle = pathFillCircle;
      }
    }
    const el = emit.drawMarker(x, y, markerConfig);
    if (dataItem == null ? void 0 : dataItem.fillColor) {
      pathFillCircle = dataItem.fillColor;
    }
    const jt = ps.jitter;
    if ((jt == null ? void 0 : jt.enabled) && jt.distributed && w.globals.colors.length) {
      const bandIdx = Math.round(
        (_a = w.seriesData.seriesX[realIndex]) == null ? void 0 : _a[dataPointIndex]
      );
      if (!isNaN(bandIdx)) {
        pathFillCircle = w.globals.colors[bandIdx % w.globals.colors.length];
      }
    }
    el.attr({
      fill: pathFillCircle
    });
    if (ps.dropShadowEnabled) {
      const dropShadow = w.config.chart.dropShadow;
      filters.dropShadow(el, dropShadow, realIndex);
    }
    if (ps.doInitialAnim) {
      if (!ps.anim) {
        const animCfg = w.config.chart.animations;
        const totalPoints = w.globals.dataPoints || 1;
        const gradCfg = animCfg.animateGradually;
        const gradEnabled = gradCfg && gradCfg.enabled !== false;
        ps.anim = {
          popSpeed: animCfg.speed,
          baseDelay: gradEnabled ? Math.min(20, animCfg.speed * 0.5 / Math.max(1, totalPoints)) : 0
        };
      }
      const delay = computeStagger({
        style: ps.anim.baseDelay > 0 ? "sequential" : "none",
        index: dataPointIndex,
        baseDelay: ps.anim.baseDelay
      });
      anim.animatePop(el, {
        speed: ps.anim.popSpeed,
        delay,
        onComplete: () => anim.animationCompleted(el)
      });
    } else {
      w.globals.animationEnded = true;
    }
    el.attr({
      rel: dataPointIndex,
      j: dataPointIndex,
      index: realIndex,
      "default-marker-size": markerConfig.pSize
    });
    filters.setSelectionFilter(el, realIndex, dataPointIndex);
    return el;
  }
  /**
   * @param {number} y
   */
  centerTextInBubble(y) {
    const w = this.w;
    y = y + parseInt(w.config.dataLabels.style.fontSize, 10) / 4;
    return {
      y
    };
  }
}
const resolveDataLabelOffset = (value, w, seriesIndex, dataPointIndex) => {
  if (typeof value !== "function") return value;
  const resolved = value({
    series: w.seriesData.series,
    seriesIndex,
    dataPointIndex,
    w
  });
  return Number.isFinite(resolved) ? resolved : 0;
};
class DataLabels {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext | null} ctx
   */
  constructor(w, ctx = null) {
    this.w = w;
    this.ctx = ctx;
  }
  // When there are many datalabels to be printed, and some of them overlaps each other in the same series, this method will take care of that
  // Also, when datalabels exceeds the drawable area and get clipped off, we need to adjust and move some pixels to make them visible again
  /**
   * @param {number} x
   * @param {number} y
   * @param {any} val
   * @param {number} i
   * @param {number} dataPointIndex
   * @param {boolean} alwaysDrawDataLabel
   * @param {string} fontSize
   */
  dataLabelsCorrection(x, y, val, i2, dataPointIndex, alwaysDrawDataLabel, fontSize) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    let drawnextLabel = false;
    const textRects = (
      /** @type {any} */
      graphics.getTextRects(val, fontSize)
    );
    const width = textRects.width;
    const height = textRects.height;
    if (y < 0) y = 0;
    if (y > w.layout.gridHeight + height) y = w.layout.gridHeight + height / 2;
    if (typeof /** @type {any} */
    w.globals.dataLabelsRects[i2] === "undefined") {
      w.globals.dataLabelsRects[i2] = [];
    }
    w.globals.dataLabelsRects[i2].push({
      x,
      y,
      width,
      height
    });
    const len = (
      /** @type {any} */
      w.globals.dataLabelsRects[i2].length - 2
    );
    const lastDrawnIndex = typeof w.globals.lastDrawnDataLabelsIndexes[i2] !== "undefined" ? w.globals.lastDrawnDataLabelsIndexes[i2][w.globals.lastDrawnDataLabelsIndexes[i2].length - 1] : 0;
    if (typeof /** @type {any} */
    w.globals.dataLabelsRects[i2][len] !== "undefined") {
      const lastDataLabelRect = (
        /** @type {any} */
        w.globals.dataLabelsRects[i2][lastDrawnIndex]
      );
      if (
        // next label forward and x not intersecting
        x > lastDataLabelRect.x + lastDataLabelRect.width || y > lastDataLabelRect.y + lastDataLabelRect.height || y + height < lastDataLabelRect.y || x + width < lastDataLabelRect.x
      ) {
        drawnextLabel = true;
      }
    }
    if (dataPointIndex === 0 || alwaysDrawDataLabel) {
      drawnextLabel = true;
    }
    return {
      x,
      y,
      textRects,
      drawnextLabel
    };
  }
  /** @param {{type: any, pos: any, i: any, j: any, isRangeStart: any, strokeWidth?: any}} opts */
  drawDataLabel({ type, pos, i: i2, j, isRangeStart, strokeWidth = 2 }) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const dataLabelsConfig = w.config.dataLabels;
    let x = 0;
    let y = 0;
    let dataPointIndex = j;
    let elDataLabelsWrap = null;
    const seriesCollapsed = w.globals.collapsedSeriesIndices.indexOf(i2) !== -1;
    if (seriesCollapsed || !dataLabelsConfig.enabled || !Array.isArray(pos.x)) {
      return elDataLabelsWrap;
    }
    elDataLabelsWrap = graphics.group({
      class: "apexcharts-data-labels"
    });
    for (let q = 0; q < pos.x.length; q++) {
      if (j === 1 && q === 0) dataPointIndex = 0;
      if (j === 1 && q === 1) dataPointIndex = 1;
      x = pos.x[q] + resolveDataLabelOffset(dataLabelsConfig.offsetX, w, i2, dataPointIndex);
      y = pos.y[q] + resolveDataLabelOffset(dataLabelsConfig.offsetY, w, i2, dataPointIndex) + strokeWidth;
      if (!isNaN(x)) {
        let val = w.seriesData.series[i2][dataPointIndex];
        if (type === "rangeArea") {
          if (isRangeStart) {
            val = w.rangeData.seriesRangeStart[i2][dataPointIndex];
          } else {
            val = w.rangeData.seriesRangeEnd[i2][dataPointIndex];
          }
        }
        let text = "";
        const getText = (v) => {
          return w.config.dataLabels.formatter(v, {
            seriesIndex: i2,
            dataPointIndex,
            w
          });
        };
        if (w.config.chart.type === "bubble") {
          val = w.seriesData.seriesZ[i2][dataPointIndex];
          text = getText(val);
          y = pos.y[q];
          const scatter = new Scatter(
            this.w,
            /** @type {import('../types/internal').ChartContext} */
            this.ctx
          );
          const centerTextInBubbleCoords = scatter.centerTextInBubble(y);
          y = centerTextInBubbleCoords.y;
        } else {
          if (typeof val !== "undefined") {
            text = getText(val);
          }
        }
        let textAnchor = w.config.dataLabels.textAnchor;
        if (w.globals.isSlopeChart) {
          if (dataPointIndex === 0) {
            textAnchor = "end";
          } else if (dataPointIndex === /** @type {Record<string,any>} */
          w.config.series[i2].data.length - 1) {
            textAnchor = "start";
          } else {
            textAnchor = "middle";
          }
        }
        this.plotDataLabelsText({
          x,
          y,
          text,
          i: i2,
          j: dataPointIndex,
          parent: elDataLabelsWrap,
          offsetCorrection: true,
          dataLabelsConfig: w.config.dataLabels,
          textAnchor
        });
      }
    }
    return elDataLabelsWrap;
  }
  /**
   * @param {Record<string, any>} opts
   */
  plotDataLabelsText(opts) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    let {
      x,
      y,
      i: i2,
      j,
      text,
      textAnchor,
      fontSize,
      parent,
      dataLabelsConfig,
      color,
      alwaysDrawDataLabel,
      offsetCorrection,
      className,
      // some callers (radar) reuse `j` for something other than the data point
      // index, so per-point offsets take these explicit indices when supplied
      seriesIndex = i2,
      dataPointIndex = j
    } = opts;
    let dataLabelText = null;
    if (Array.isArray(w.config.dataLabels.enabledOnSeries)) {
      if (w.config.dataLabels.enabledOnSeries.indexOf(i2) < 0) {
        return dataLabelText;
      }
    }
    let correctedLabels = {
      x,
      y,
      drawnextLabel: true,
      textRects: null
    };
    if (offsetCorrection) {
      correctedLabels = this.dataLabelsCorrection(
        x,
        y,
        text,
        i2,
        j,
        alwaysDrawDataLabel,
        parseInt(
          /** @type {any} */
          dataLabelsConfig.style.fontSize,
          10
        ).toString()
      );
    }
    if (!w.interact.zoomed) {
      x = correctedLabels.x;
      y = correctedLabels.y;
    }
    if (correctedLabels.textRects) {
      const barPad = w.globals.barPadForNumericAxis || 0;
      if (x < -(barPad + 20) - /** @type {any} */
      correctedLabels.textRects.width || x > w.layout.gridWidth + /** @type {any} */
      correctedLabels.textRects.width + barPad + 30) {
        text = "";
      }
    }
    let dataLabelColor = w.globals.dataLabels.style.colors[i2];
    if ((w.config.chart.type === "bar" || w.config.chart.type === "rangeBar") && w.config.plotOptions.bar.distributed || w.config.dataLabels.distributed) {
      dataLabelColor = w.globals.dataLabels.style.colors[j];
    }
    if (typeof dataLabelColor === "function") {
      dataLabelColor = /** @type {any} */
      dataLabelColor({
        series: w.seriesData.series,
        seriesIndex: i2,
        dataPointIndex: j,
        w
      });
    }
    if (color) {
      dataLabelColor = color;
    }
    const offsetsHandledElsewhere = w.config.chart.type === "bar" || w.config.chart.type === "rangeBar";
    const resolvedOffX = offsetsHandledElsewhere ? 0 : resolveDataLabelOffset(
      dataLabelsConfig.offsetX,
      w,
      seriesIndex,
      dataPointIndex
    );
    const resolvedOffY = offsetsHandledElsewhere ? 0 : resolveDataLabelOffset(
      dataLabelsConfig.offsetY,
      w,
      seriesIndex,
      dataPointIndex
    );
    let offX = resolvedOffX;
    const offY = resolvedOffY;
    if (w.globals.isSlopeChart) {
      if (j !== 0) {
        offX = resolvedOffX * -2 + 5;
      }
      if (j !== 0 && j !== /** @type {Record<string,any>} */
      w.config.series[i2].data.length - 1) {
        offX = 0;
      }
    }
    if (correctedLabels.drawnextLabel) {
      if (textAnchor === "middle") {
        if (x === w.layout.gridWidth) {
          textAnchor = "end";
        }
      }
      dataLabelText = graphics.drawText({
        x: x + offX,
        y: y + offY,
        foreColor: dataLabelColor,
        textAnchor: textAnchor || dataLabelsConfig.textAnchor,
        text,
        fontSize: fontSize || dataLabelsConfig.style.fontSize,
        fontFamily: dataLabelsConfig.style.fontFamily,
        fontWeight: dataLabelsConfig.style.fontWeight || "normal"
      });
      dataLabelText.attr({
        class: className || "apexcharts-datalabel",
        cx: x,
        cy: y
      });
      if (dataLabelsConfig.dropShadow.enabled) {
        const textShadow = dataLabelsConfig.dropShadow;
        const filters = new Filters(this.w);
        filters.dropShadow(dataLabelText, textShadow);
      }
      parent.add(dataLabelText);
      applyProgressiveReveal(dataLabelText, x, w);
      if (typeof w.globals.lastDrawnDataLabelsIndexes[i2] === "undefined") {
        w.globals.lastDrawnDataLabelsIndexes[i2] = [];
      }
      w.globals.lastDrawnDataLabelsIndexes[i2].push(j);
    }
    return dataLabelText;
  }
  /**
   * @param {Element} el
   * @param {{x: number, y: number, width: number, height: number}} coords
   */
  addBackgroundToDataLabel(el, coords) {
    const w = this.w;
    const bCnf = w.config.dataLabels.background;
    const paddingH = bCnf.padding;
    const paddingV = bCnf.padding / 2;
    const width = coords.width;
    const height = coords.height;
    const graphics = new Graphics(this.w);
    const elRect = graphics.drawRect(
      coords.x - paddingH,
      coords.y - paddingV / 2,
      width + paddingH * 2,
      height + paddingV,
      bCnf.borderRadius,
      w.config.chart.background === "transparent" || !w.config.chart.background ? "#fff" : w.config.chart.background,
      bCnf.opacity,
      bCnf.borderWidth,
      bCnf.borderColor
    );
    if (bCnf.dropShadow.enabled) {
      const filters = new Filters(this.w);
      filters.dropShadow(elRect, bCnf.dropShadow);
    }
    return elRect;
  }
  dataLabelsBackground() {
    var _a;
    const w = this.w;
    if (w.config.chart.type === "bubble") return;
    const elDataLabels = w.dom.baseEl.querySelectorAll(
      ".apexcharts-datalabels text"
    );
    for (let i2 = 0; i2 < elDataLabels.length; i2++) {
      const el = elDataLabels[i2];
      const coords = (
        /** @type {SVGGraphicsElement} */
        el.getBBox()
      );
      let elRect = null;
      if (coords.width && coords.height) {
        elRect = this.addBackgroundToDataLabel(el, coords);
      }
      if (elRect) {
        (_a = el.parentNode) == null ? void 0 : _a.insertBefore(elRect.node, el);
        const background = w.config.dataLabels.background.backgroundColor || el.getAttribute("fill");
        const shouldAnim = w.config.chart.animations.enabled && !w.globals.resized && !w.globals.dataChanged;
        if (shouldAnim) {
          elRect.animate().attr({ fill: background });
        } else {
          elRect.attr({ fill: background });
        }
        el.setAttribute("fill", w.config.dataLabels.background.foreColor);
        const cxAttr = el.getAttribute("cx");
        if (cxAttr !== null) {
          applyProgressiveReveal(elRect, parseFloat(cxAttr), w);
        }
      }
    }
  }
  bringForward() {
    const w = this.w;
    const elDataLabelsNodes = w.dom.baseEl.querySelectorAll(
      ".apexcharts-datalabels"
    );
    const elSeries = w.dom.baseEl.querySelector(
      ".apexcharts-plot-series:last-child"
    );
    for (let i2 = 0; i2 < elDataLabelsNodes.length; i2++) {
      if (elSeries) {
        elSeries.insertBefore(elDataLabelsNodes[i2], elSeries.nextSibling);
      }
    }
  }
}
class PerformanceCache {
  /**
   * Invalidate all caches
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   */
  static invalidateAll(w) {
    if (!w || !w.globals) return;
    if (w.globals.cachedSelectors) {
      w.globals.cachedSelectors = {};
    }
    if (w.globals.domCache) {
      w.globals.domCache.clear();
    }
    w.globals.dimensionCache = {};
  }
  /**
   * Invalidate dimension cache only
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   */
  static invalidateDimensions(w) {
    if (!w || !w.globals) return;
    w.globals.dimensionCache = {};
  }
  /**
   * Invalidate selector cache only
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   */
  static invalidateSelectors(w) {
    if (!w || !w.globals) return;
    if (w.globals.cachedSelectors) {
      w.globals.cachedSelectors = {};
    }
  }
  /**
   * Get cached selector result or compute and cache it
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   * @param {string} key - Cache key
   * @param {Function} queryFn - Function to execute if not cached
   * @returns {*} Cached or newly computed result
   */
  static getCachedSelector(w, key, queryFn) {
    if (!w || !w.globals) return queryFn();
    if (!w.globals.cachedSelectors) {
      w.globals.cachedSelectors = {};
    }
    if (!w.globals.cachedSelectors[key]) {
      w.globals.cachedSelectors[key] = queryFn();
    }
    return w.globals.cachedSelectors[key];
  }
  /**
   * Get cached dimension or compute and cache it
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   * @param {string} key - Cache key
   * @param {Function} computeFn - Function to compute dimensions
   * @param {number} maxAge - Maximum cache age in milliseconds (default: 1000ms)
   * @returns {*} Cached or newly computed dimensions
   */
  static getCachedDimension(w, key, computeFn, maxAge = 1e3) {
    if (!w || !w.globals) return computeFn();
    if (!w.globals.dimensionCache) {
      w.globals.dimensionCache = {};
    }
    const cache = w.globals.dimensionCache[key];
    const now = Date.now();
    if (cache && cache.lastUpdate && now - cache.lastUpdate < maxAge) {
      return cache.value;
    }
    const value = computeFn();
    w.globals.dimensionCache[key] = {
      value,
      lastUpdate: now
    };
    return value;
  }
  /**
   * Cache a DOM element reference
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   * @param {string} key - Cache key
   * @param {Element} element - DOM element to cache
   */
  static cacheDOMElement(w, key, element) {
    if (!w || !w.globals) return;
    if (!w.globals.domCache) {
      w.globals.domCache = /* @__PURE__ */ new Map();
    }
    w.globals.domCache.set(key, element);
  }
  /**
   * Get cached DOM element
   * @param {import('../types/internal').ChartStateW} w - ApexCharts state object
   * @param {string} key - Cache key
   * @returns {Element|null} Cached element or null
   */
  static getCachedDOMElement(w, key) {
    if (!w || !w.globals || !w.globals.domCache) return null;
    return w.globals.domCache.get(key) || null;
  }
}
class AxesUtils {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   */
  constructor(w, { theme = null, timeScale = null } = {}) {
    this.w = w;
    this.theme = theme;
    this.timeScale = timeScale;
  }
  // Based on the formatter function, get the label text and position
  /**
   * @param {any[]} labels
   * @param {Array<Record<string, any>>} timescaleLabels
   * @param {number} x
   * @param {number} i
   * @param {any[]} drawnLabels
   */
  getLabel(labels, timescaleLabels, x, i2, drawnLabels = [], fontSize = "12px", isLeafGroup = true) {
    const w = this.w;
    const rawLabel = typeof labels[i2] === "undefined" ? "" : labels[i2];
    let label = rawLabel;
    const xlbFormatter = w.formatters.xLabelFormatter;
    const customFormatter = w.config.xaxis.labels.formatter;
    const xFormat = new Formatters(this.w);
    const timestamp = rawLabel;
    if (isLeafGroup) {
      label = /** @type {any} */
      xFormat.xLabelFormat(
        xlbFormatter,
        rawLabel,
        timestamp,
        {
          i: i2,
          dateFormatter: new DateTime(this.w).formatDate,
          w
        }
      );
      if (customFormatter !== void 0) {
        label = customFormatter(rawLabel, labels[i2], {
          i: i2,
          dateFormatter: new DateTime(this.w).formatDate,
          w
        });
      }
    }
    if (timescaleLabels.length > 0) {
      x = timescaleLabels[i2].position;
      label = timescaleLabels[i2].value;
    } else {
      if (w.config.xaxis.type === "datetime" && customFormatter === void 0) {
        label = "";
      }
    }
    if (typeof label === "undefined") label = "";
    label = Array.isArray(label) ? label : label.toString();
    const graphics = new Graphics(this.w);
    let textRect = {};
    if (w.layout.rotateXLabels && isLeafGroup) {
      textRect = graphics.getTextRects(
        label,
        parseInt(fontSize, 10).toString(),
        null,
        `rotate(${w.config.xaxis.labels.rotate} 0 0)`,
        false
      );
    } else {
      textRect = graphics.getTextRects(label, parseInt(fontSize, 10).toString());
    }
    const allowDuplicatesInTimeScale = !w.config.xaxis.labels.showDuplicates && this.timeScale;
    if (!Array.isArray(label) && (String(label) === "NaN" || drawnLabels.indexOf(label) >= 0 && allowDuplicatesInTimeScale)) {
      label = "";
    }
    return {
      x,
      text: label,
      textRect
    };
  }
  /**
   * @param {number} i
   * @param {any} label
   * @param {number} labelsLen
   */
  checkLabelBasedOnTickamount(i2, label, labelsLen) {
    const w = this.w;
    let ticks = w.config.xaxis.tickAmount;
    if (ticks === "dataPoints") ticks = Math.round(w.layout.gridWidth / 120);
    if (ticks > labelsLen) return label;
    const tickMultiple = Math.round(labelsLen / (ticks + 1));
    if (i2 % tickMultiple === 0) {
      return label;
    } else {
      label.text = "";
    }
    return label;
  }
  /**
   * @param {number} i
   * @param {any} label
   * @param {number} labelsLen
   * @param {any[]} drawnLabels
   * @param {Array<Record<string, any>>} drawnLabelsRects
   */
  checkForOverflowingLabels(i2, label, labelsLen, drawnLabels, drawnLabelsRects) {
    const w = this.w;
    if (i2 === 0) {
      if (w.globals.skipFirstTimelinelabel) {
        label.text = "";
      }
    }
    if (i2 === labelsLen - 1) {
      if (w.globals.skipLastTimelinelabel) {
        label.text = "";
      }
    }
    if (w.config.xaxis.labels.hideOverlappingLabels && drawnLabels.length > 0) {
      const prev = drawnLabelsRects[drawnLabelsRects.length - 1];
      if (w.config.xaxis.labels.trim && w.config.xaxis.type !== "datetime") {
        return label;
      }
      if (
        /** @type {any} */
        label.x < prev.textRect.width / (w.layout.rotateXLabels ? (
          // Floor the rotation at 1deg: rotateAlways:true forces
          // rotateXLabels even with rotate:0, and a 0 divisor here makes the
          // spread Infinity, blanking every label after the first.
          Math.max(Math.abs(w.config.xaxis.labels.rotate), 1) / 12
        ) : 1.01) + prev.x
      ) {
        label.text = "";
      }
    }
    return label;
  }
  /**
   * @param {number} i
   * @param {any[]} labels
   */
  checkForReversedLabels(i2, labels) {
    const w = this.w;
    if (w.config.yaxis[i2] && w.config.yaxis[i2].reversed) {
      labels.reverse();
    }
    return labels;
  }
  /**
   * @param {number} index
   */
  yAxisAllSeriesCollapsed(index) {
    const gl = this.w.globals;
    return !gl.seriesYAxisMap[index].some((si) => {
      return gl.collapsedSeriesIndices.indexOf(si) === -1;
    });
  }
  // Method to translate annotation.yAxisIndex values from
  // seriesName-as-a-string values to seriesName-as-an-array values (old style
  // series mapping to new style).
  /**
   * @param {number} index
   */
  translateYAxisIndex(index) {
    const w = this.w;
    const gl = w.globals;
    const yaxis = w.config.yaxis;
    const newStyle = w.seriesData.series.length > yaxis.length || /**
     * @param {Record<string, any>} a
     */
    yaxis.some((a2) => Array.isArray(a2.seriesName));
    if (newStyle) {
      return index;
    } else {
      return gl.seriesYAxisReverseMap[index];
    }
  }
  /**
   * @param {number} index
   */
  isYAxisHidden(index) {
    const w = this.w;
    const yaxis = w.config.yaxis[index];
    if (!yaxis.show || this.yAxisAllSeriesCollapsed(index)) {
      return true;
    }
    if (!yaxis.showForNullSeries) {
      const seriesIndices = w.globals.seriesYAxisMap[index];
      const coreUtils = new CoreUtils(this.w);
      return seriesIndices.every((si) => coreUtils.isSeriesNull(si));
    }
    return false;
  }
  // get the label color for y-axis
  // realIndex is the actual series index, while i is the tick Index
  /**
   * @param {string[]} yColors
   * @param {number} realIndex
   */
  getYAxisForeColor(yColors, realIndex) {
    var _a;
    const w = this.w;
    if (Array.isArray(yColors) && w.globals.yAxisScale[realIndex]) {
      (_a = this.theme) == null ? void 0 : _a.pushExtraColors(
        yColors,
        w.globals.yAxisScale[realIndex].result.length,
        false
      );
    }
    return yColors;
  }
  /**
   * @param {number} x
   * @param {number} tickAmount
   * @param {Record<string, any>} axisBorder
   * @param {Record<string, any>} axisTicks
   * @param {number} realIndex
   * @param {any} labelsDivider
   * @param {any} elYaxis
   */
  drawYAxisTicks(x, tickAmount, axisBorder, axisTicks, realIndex, labelsDivider, elYaxis) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    let tY = w.layout.translateY + w.config.yaxis[realIndex].labels.offsetY;
    if (w.globals.isBarHorizontal) {
      tY = 0;
    } else if (w.config.chart.type === "heatmap") {
      tY += labelsDivider / 2;
    }
    if (axisTicks.show && tickAmount > 0) {
      if (w.config.yaxis[realIndex].opposite === true) x = x + axisTicks.width;
      for (let i2 = tickAmount; i2 >= 0; i2--) {
        const elTick = graphics.drawLine(
          x + axisBorder.offsetX - axisTicks.width + axisTicks.offsetX,
          tY + axisTicks.offsetY,
          x + axisBorder.offsetX + axisTicks.offsetX,
          tY + axisTicks.offsetY,
          axisTicks.color
        );
        elYaxis.add(elTick);
        tY += labelsDivider;
      }
    }
  }
}
class XAxis {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {import('../../types/internal').ChartContext} ctx
   * @param {any} [elgrid]
   */
  constructor(w, ctx, elgrid) {
    this.w = w;
    this.ctx = ctx;
    this.elgrid = elgrid;
    this.axesUtils = new AxesUtils(w, {
      theme: ctx.theme,
      timeScale: ctx.timeScale
    });
    this.xaxisLabels = w.labelData.labels.slice();
    if (w.labelData.timescaleLabels.length > 0 && !w.globals.isBarHorizontal) {
      this.xaxisLabels = w.labelData.timescaleLabels.slice();
    }
    if (w.config.xaxis.overwriteCategories) {
      this.xaxisLabels = w.config.xaxis.overwriteCategories;
    }
    this.drawnLabels = [];
    this.drawnLabelsRects = [];
    if (w.config.xaxis.position === "top") {
      this.offY = 0;
    } else {
      this.offY = w.layout.gridHeight;
    }
    this.offY = this.offY + w.config.xaxis.axisBorder.offsetY;
    this.isCategoryBarHorizontal = w.config.chart.type === "bar" && w.config.plotOptions.bar.horizontal;
    this.xaxisFontSize = w.config.xaxis.labels.style.fontSize;
    this.xaxisFontFamily = w.config.xaxis.labels.style.fontFamily;
    this.xaxisForeColors = w.config.xaxis.labels.style.colors;
    this.xaxisBorderWidth = w.config.xaxis.axisBorder.width;
    if (this.isCategoryBarHorizontal) {
      this.xaxisBorderWidth = w.config.yaxis[0].axisBorder.width.toString();
    }
    if (String(this.xaxisBorderWidth).indexOf("%") > -1) {
      this.xaxisBorderWidth = w.layout.gridWidth * parseInt(this.xaxisBorderWidth, 10) / 100;
    } else {
      this.xaxisBorderWidth = parseInt(this.xaxisBorderWidth, 10);
    }
    this.xaxisBorderHeight = w.config.xaxis.axisBorder.height;
    this.yaxis = w.config.yaxis[0];
  }
  drawXaxis() {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const elXaxis = graphics.group({
      class: "apexcharts-xaxis",
      transform: `translate(${w.config.xaxis.offsetX}, ${w.config.xaxis.offsetY})`
    });
    const elXaxisTexts = graphics.group({
      class: "apexcharts-xaxis-texts-g",
      transform: `translate(${w.layout.translateXAxisX}, ${w.layout.translateXAxisY})`
    });
    elXaxis.add(elXaxisTexts);
    let labels = [];
    for (let i2 = 0; i2 < this.xaxisLabels.length; i2++) {
      labels.push(this.xaxisLabels[i2]);
    }
    this.drawXAxisLabelAndGroup(
      true,
      graphics,
      elXaxisTexts,
      labels,
      w.axisFlags.isXNumeric,
      (i2, colWidth) => colWidth
    );
    if (w.labelData.hasXaxisGroups) {
      const labelsGroup = w.labelData.groups;
      labels = [];
      for (let i2 = 0; i2 < labelsGroup.length; i2++) {
        labels.push(labelsGroup[i2].title);
      }
      const overwriteStyles = (
        /** @type {any} */
        {}
      );
      if (w.config.xaxis.group.style) {
        overwriteStyles.xaxisFontSize = w.config.xaxis.group.style.fontSize;
        overwriteStyles.xaxisFontFamily = w.config.xaxis.group.style.fontFamily;
        overwriteStyles.xaxisForeColors = w.config.xaxis.group.style.colors;
        overwriteStyles.fontWeight = w.config.xaxis.group.style.fontWeight;
        overwriteStyles.cssClass = w.config.xaxis.group.style.cssClass;
      }
      this.drawXAxisLabelAndGroup(
        false,
        graphics,
        elXaxisTexts,
        labels,
        false,
        (i2, colWidth) => labelsGroup[i2].cols * colWidth,
        overwriteStyles
      );
    }
    if (w.config.xaxis.title.text !== void 0) {
      const elXaxisTitle = graphics.group({
        class: "apexcharts-xaxis-title"
      });
      const elXAxisTitleText = graphics.drawText({
        x: w.layout.gridWidth / 2 + w.config.xaxis.title.offsetX,
        y: this.offY + parseFloat(this.xaxisFontSize) + (w.config.xaxis.position === "bottom" ? w.layout.xAxisLabelsHeight : -w.layout.xAxisLabelsHeight - 10) + w.config.xaxis.title.offsetY,
        text: w.config.xaxis.title.text,
        textAnchor: "middle",
        fontSize: w.config.xaxis.title.style.fontSize,
        fontFamily: w.config.xaxis.title.style.fontFamily,
        fontWeight: w.config.xaxis.title.style.fontWeight,
        foreColor: w.config.xaxis.title.style.color,
        cssClass: "apexcharts-xaxis-title-text " + w.config.xaxis.title.style.cssClass
      });
      elXaxisTitle.add(elXAxisTitleText);
      elXaxis.add(elXaxisTitle);
    }
    if (w.config.xaxis.axisBorder.show) {
      const offX = w.globals.barPadForNumericAxis;
      const elHorzLine = graphics.drawLine(
        w.globals.padHorizontal + w.config.xaxis.axisBorder.offsetX - offX,
        this.offY,
        this.xaxisBorderWidth + offX,
        this.offY,
        w.config.xaxis.axisBorder.color,
        0,
        this.xaxisBorderHeight
      );
      if (this.elgrid && this.elgrid.elGridBorders && w.config.grid.show) {
        this.elgrid.elGridBorders.add(elHorzLine);
      } else {
        elXaxis.add(elHorzLine);
      }
    }
    return elXaxis;
  }
  /**
   * @param {Record<string, any>} [overwriteStyles]
   * @param {boolean} isLeafGroup
   * @param {import('../Graphics').default} graphics
   * @param {any} elXaxisTexts
   * @param {any[]} labels
   * @param {boolean} isXNumeric
   * @param {any} colWidthCb
   */
  drawXAxisLabelAndGroup(isLeafGroup, graphics, elXaxisTexts, labels, isXNumeric, colWidthCb, overwriteStyles = {}) {
    var _a, _b;
    const drawnLabels = [];
    const drawnLabelsRects = [];
    const w = this.w;
    const xaxisFontSize = overwriteStyles.xaxisFontSize || this.xaxisFontSize;
    const xaxisFontFamily = overwriteStyles.xaxisFontFamily || this.xaxisFontFamily;
    const xaxisForeColors = overwriteStyles.xaxisForeColors || this.xaxisForeColors;
    const fontWeight = overwriteStyles.fontWeight || w.config.xaxis.labels.style.fontWeight;
    const cssClass = overwriteStyles.cssClass || w.config.xaxis.labels.style.cssClass;
    let colWidth;
    let xPos = w.globals.padHorizontal;
    const labelsLen = labels.length;
    let dataPoints = w.config.xaxis.type === "category" ? w.globals.dataPoints : labelsLen;
    if (dataPoints === 0 && labelsLen > dataPoints) dataPoints = labelsLen;
    if (isXNumeric) {
      const len = Math.max(
        Number(w.config.xaxis.tickAmount) || 1,
        dataPoints > 1 ? dataPoints - 1 : dataPoints
      );
      colWidth = w.layout.gridWidth / Math.min(len, labelsLen - 1);
      xPos = xPos + colWidthCb(0, colWidth) / 2 + w.config.xaxis.labels.offsetX;
    } else {
      colWidth = w.layout.gridWidth / dataPoints;
      xPos = xPos + colWidthCb(0, colWidth) + w.config.xaxis.labels.offsetX;
    }
    for (let i2 = 0; i2 <= labelsLen - 1; i2++) {
      let x = xPos - colWidthCb(i2, colWidth) / 2 + w.config.xaxis.labels.offsetX;
      if (i2 === 0 && labelsLen === 1 && colWidth / 2 === xPos && dataPoints === 1) {
        x = w.layout.gridWidth / 2;
      }
      let label = this.axesUtils.getLabel(
        labels,
        w.labelData.timescaleLabels,
        x,
        i2,
        drawnLabels,
        xaxisFontSize,
        isLeafGroup
      );
      let offsetYCorrection = 28;
      if (w.layout.rotateXLabels && isLeafGroup) {
        offsetYCorrection = 22;
      }
      if (w.config.xaxis.title.text && w.config.xaxis.position === "top") {
        offsetYCorrection += parseFloat(w.config.xaxis.title.style.fontSize) + 2;
      }
      if (!isLeafGroup) {
        offsetYCorrection = offsetYCorrection + parseFloat(xaxisFontSize) + (w.layout.xAxisLabelsHeight - w.layout.xAxisGroupLabelsHeight) + (w.layout.rotateXLabels ? 10 : 0);
      }
      const isCategoryTickAmounts = typeof w.config.xaxis.tickAmount !== "undefined" && w.config.xaxis.tickAmount !== "dataPoints" && w.config.xaxis.type !== "datetime";
      if (isCategoryTickAmounts) {
        label = this.axesUtils.checkLabelBasedOnTickamount(i2, label, labelsLen);
      } else {
        label = this.axesUtils.checkForOverflowingLabels(
          i2,
          label,
          labelsLen,
          drawnLabels,
          drawnLabelsRects
        );
      }
      const getCatForeColor = () => {
        return isLeafGroup && w.config.xaxis.convertedCatToNumeric ? xaxisForeColors[w.globals.minX + i2 - 1] : xaxisForeColors[i2];
      };
      const labelRectWidth = (
        /** @type {any} */
        (_b = (_a = label.textRect) == null ? void 0 : _a.width) != null ? _b : 0
      );
      const halfWidth = labelRectWidth / 2;
      const fullyOutsideGrid = label.x + halfWidth < 0;
      if (w.config.xaxis.labels.show && !fullyOutsideGrid) {
        const elText = graphics.drawText({
          x: label.x,
          y: this.offY + w.config.xaxis.labels.offsetY + offsetYCorrection - (w.config.xaxis.position === "top" ? w.layout.xAxisHeight + w.config.xaxis.axisTicks.height - 2 : 0),
          text: label.text,
          textAnchor: "middle",
          fontWeight,
          fontSize: xaxisFontSize,
          fontFamily: xaxisFontFamily,
          foreColor: Array.isArray(xaxisForeColors) ? getCatForeColor() : xaxisForeColors,
          isPlainText: false,
          cssClass: (isLeafGroup ? "apexcharts-xaxis-label " : "apexcharts-xaxis-group-label ") + cssClass
        });
        elXaxisTexts.add(elText);
        elText.on("click", (e2) => {
          if (typeof w.config.chart.events.xAxisLabelClick === "function") {
            const opts = Object.assign({}, w, {
              labelIndex: i2
            });
            w.config.chart.events.xAxisLabelClick(e2, this.ctx, opts);
          }
        });
        if (isLeafGroup) {
          const elTooltipTitle = BrowserAPIs.createElementNS(SVGNS$1, "title");
          elTooltipTitle.textContent = Array.isArray(label.text) ? label.text.join(" ") : label.text;
          elText.node.appendChild(elTooltipTitle);
          if (label.text !== "") {
            drawnLabels.push(label.text);
            drawnLabelsRects.push(label);
          }
        }
      }
      if (i2 < labelsLen - 1) {
        xPos = xPos + colWidthCb(i2 + 1, colWidth);
      }
    }
  }
  // this actually becomes the vertical axis (for bar charts)
  /**
   * @param {number} realIndex
   */
  drawXaxisInversed(realIndex) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const translateYAxisX = w.config.yaxis[0].opposite ? w.globals.translateYAxisX[realIndex] : 0;
    const elYaxis = graphics.group({
      class: "apexcharts-yaxis apexcharts-xaxis-inversed",
      rel: realIndex
    });
    const elYaxisTexts = graphics.group({
      class: "apexcharts-yaxis-texts-g apexcharts-xaxis-inversed-texts-g",
      transform: "translate(" + translateYAxisX + ", 0)"
    });
    elYaxis.add(elYaxisTexts);
    const labels = [];
    if (w.config.yaxis[realIndex].show) {
      for (let i2 = 0; i2 < this.xaxisLabels.length; i2++) {
        labels.push(this.xaxisLabels[i2]);
      }
    }
    const colHeight = w.layout.gridHeight / labels.length;
    let yPos = -(colHeight / 2.2);
    const lbFormatter = w.formatters.yLabelFormatters[0];
    const ylabels = w.config.yaxis[0].labels;
    if (ylabels.show) {
      for (let i2 = 0; i2 <= labels.length - 1; i2++) {
        let label = typeof labels[i2] === "undefined" ? "" : labels[i2];
        label = lbFormatter(label, {
          seriesIndex: realIndex,
          dataPointIndex: i2,
          w
        });
        const yColors = this.axesUtils.getYAxisForeColor(
          ylabels.style.colors,
          realIndex
        );
        const getForeColor = () => {
          return Array.isArray(yColors) ? yColors[i2] : yColors;
        };
        let multiY = 0;
        if (Array.isArray(label)) {
          multiY = label.length / 2 * parseInt(ylabels.style.fontSize, 10);
        }
        let offsetX = ylabels.offsetX - 15;
        let textAnchor = "end";
        if (this.yaxis.opposite) {
          textAnchor = "start";
        }
        if (w.config.yaxis[0].labels.align === "left") {
          offsetX = ylabels.offsetX;
          textAnchor = "start";
        } else if (w.config.yaxis[0].labels.align === "center") {
          offsetX = ylabels.offsetX;
          textAnchor = "middle";
        } else if (w.config.yaxis[0].labels.align === "right") {
          textAnchor = "end";
        }
        const elLabel = graphics.drawText({
          x: offsetX,
          y: yPos + colHeight + ylabels.offsetY - multiY,
          text: label,
          textAnchor,
          foreColor: getForeColor(),
          fontSize: ylabels.style.fontSize,
          fontFamily: ylabels.style.fontFamily,
          fontWeight: ylabels.style.fontWeight,
          isPlainText: false,
          cssClass: "apexcharts-yaxis-label " + ylabels.style.cssClass,
          maxWidth: ylabels.maxWidth
        });
        elYaxisTexts.add(elLabel);
        elLabel.on("click", (e2) => {
          if (typeof w.config.chart.events.xAxisLabelClick === "function") {
            const opts = Object.assign({}, w, {
              labelIndex: i2
            });
            w.config.chart.events.xAxisLabelClick(e2, this.ctx, opts);
          }
        });
        const elTooltipTitle = BrowserAPIs.createElementNS(SVGNS$1, "title");
        elTooltipTitle.textContent = Array.isArray(label) ? label.join(" ") : label;
        elLabel.node.appendChild(elTooltipTitle);
        if (w.config.yaxis[realIndex].labels.rotate !== 0) {
          const labelRotatingCenter = graphics.rotateAroundCenter(elLabel.node);
          elLabel.node.setAttribute(
            "transform",
            `rotate(${w.config.yaxis[realIndex].labels.rotate} 0 ${labelRotatingCenter.y})`
          );
        }
        yPos = yPos + colHeight;
      }
    }
    if (w.config.yaxis[0].title.text !== void 0) {
      const elXaxisTitle = graphics.group({
        class: "apexcharts-yaxis-title apexcharts-xaxis-title-inversed",
        transform: "translate(" + translateYAxisX + ", 0)"
      });
      const elXAxisTitleText = graphics.drawText({
        x: w.config.yaxis[0].title.offsetX,
        y: w.layout.gridHeight / 2 + w.config.yaxis[0].title.offsetY,
        text: w.config.yaxis[0].title.text,
        textAnchor: "middle",
        foreColor: w.config.yaxis[0].title.style.color,
        fontSize: w.config.yaxis[0].title.style.fontSize,
        fontWeight: w.config.yaxis[0].title.style.fontWeight,
        fontFamily: w.config.yaxis[0].title.style.fontFamily,
        cssClass: "apexcharts-yaxis-title-text " + w.config.yaxis[0].title.style.cssClass
      });
      elXaxisTitle.add(elXAxisTitleText);
      elYaxis.add(elXaxisTitle);
    }
    let offX = 0;
    if (this.isCategoryBarHorizontal && w.config.yaxis[0].opposite) {
      offX = w.layout.gridWidth;
    }
    const axisBorder = w.config.xaxis.axisBorder;
    if (axisBorder.show) {
      const elVerticalLine = graphics.drawLine(
        w.globals.padHorizontal + axisBorder.offsetX + offX,
        1 + axisBorder.offsetY,
        w.globals.padHorizontal + axisBorder.offsetX + offX,
        w.layout.gridHeight + axisBorder.offsetY,
        axisBorder.color,
        0
      );
      if (this.elgrid && this.elgrid.elGridBorders && w.config.grid.show) {
        this.elgrid.elGridBorders.add(elVerticalLine);
      } else {
        elYaxis.add(elVerticalLine);
      }
    }
    if (w.config.yaxis[0].axisTicks.show) {
      this.axesUtils.drawYAxisTicks(
        offX,
        labels.length,
        w.config.yaxis[0].axisBorder,
        w.config.yaxis[0].axisTicks,
        0,
        colHeight,
        elYaxis
      );
    }
    return elYaxis;
  }
  /**
   * @param {number} x1
   * @param {number} y2
   * @param {any} appendToElement
   */
  drawXaxisTicks(x1, y2, appendToElement) {
    const w = this.w;
    const x2 = x1;
    if (x1 < 0 || x1 - 2 > w.layout.gridWidth) return;
    const y1 = this.offY + w.config.xaxis.axisTicks.offsetY;
    y2 = y2 + y1 + w.config.xaxis.axisTicks.height;
    if (w.config.xaxis.position === "top") {
      y2 = y1 - w.config.xaxis.axisTicks.height;
    }
    if (w.config.xaxis.axisTicks.show) {
      const graphics = new Graphics(this.w);
      const line = graphics.drawLine(
        x1 + w.config.xaxis.axisTicks.offsetX,
        y1 + w.config.xaxis.offsetY,
        x2 + w.config.xaxis.axisTicks.offsetX,
        y2 + w.config.xaxis.offsetY,
        w.config.xaxis.axisTicks.color
      );
      appendToElement.add(line);
      line.node.classList.add("apexcharts-xaxis-tick");
    }
  }
  getXAxisTicksPositions() {
    const w = this.w;
    const xAxisTicksPositions = [];
    const xCount = this.xaxisLabels.length;
    let x1 = w.globals.padHorizontal;
    if (w.labelData.timescaleLabels.length > 0) {
      for (let i2 = 0; i2 < xCount; i2++) {
        x1 = this.xaxisLabels[i2].position;
        xAxisTicksPositions.push(x1);
      }
    } else {
      const xCountForCategoryCharts = xCount;
      for (let i2 = 0; i2 < xCountForCategoryCharts; i2++) {
        let x1Count = xCountForCategoryCharts;
        if (w.axisFlags.isXNumeric && w.config.chart.type !== "bar") {
          x1Count -= 1;
        }
        x1 = x1 + w.layout.gridWidth / x1Count;
        xAxisTicksPositions.push(x1);
      }
    }
    return xAxisTicksPositions;
  }
  // to rotate x-axis labels or to put ... for longer text in xaxis
  xAxisLabelCorrections() {
    var _a, _b, _c;
    const w = this.w;
    const graphics = new Graphics(this.w);
    const xAxis = w.dom.baseEl.querySelector(".apexcharts-xaxis-texts-g");
    const xAxisTexts = w.dom.baseEl.querySelectorAll(
      ".apexcharts-xaxis-texts-g text:not(.apexcharts-xaxis-group-label)"
    );
    const yAxisTextsInversed = w.dom.baseEl.querySelectorAll(
      ".apexcharts-yaxis-inversed text"
    );
    const xAxisTextsInversed = w.dom.baseEl.querySelectorAll(
      ".apexcharts-xaxis-inversed-texts-g text tspan"
    );
    if (w.layout.rotateXLabels || w.config.xaxis.labels.rotateAlways) {
      for (let xat = 0; xat < xAxisTexts.length; xat++) {
        const textRotatingCenter = graphics.rotateAroundCenter(xAxisTexts[xat]);
        textRotatingCenter.y = textRotatingCenter.y - 1;
        textRotatingCenter.x = textRotatingCenter.x + 1;
        xAxisTexts[xat].setAttribute(
          "transform",
          `rotate(${w.config.xaxis.labels.rotate} ${textRotatingCenter.x} ${textRotatingCenter.y})`
        );
        xAxisTexts[xat].setAttribute("text-anchor", `end`);
        xAxis == null ? void 0 : xAxis.setAttribute("transform", `translate(0, ${-10})`);
        const tSpan = xAxisTexts[xat].childNodes;
        if (w.config.xaxis.labels.trim) {
          Array.prototype.forEach.call(tSpan, (ts) => {
            graphics.placeTextWithEllipsis(
              ts,
              ts.textContent,
              w.layout.xAxisLabelsHeight - (w.config.legend.position === "bottom" ? 20 : 10)
            );
          });
        }
      }
    } else {
      const width = w.layout.gridWidth / (w.labelData.labels.length + 1);
      for (let xat = 0; xat < xAxisTexts.length; xat++) {
        const tSpan = xAxisTexts[xat].childNodes;
        if (w.config.xaxis.labels.trim && w.config.xaxis.type !== "datetime") {
          Array.prototype.forEach.call(tSpan, (ts) => {
            graphics.placeTextWithEllipsis(ts, ts.textContent, width);
          });
        }
      }
    }
    if (yAxisTextsInversed.length > 0) {
      const firstLabelPosX = (
        /** @type {SVGGraphicsElement} */
        yAxisTextsInversed[yAxisTextsInversed.length - 1].getBBox()
      );
      const lastLabelPosX = (
        /** @type {SVGGraphicsElement} */
        yAxisTextsInversed[0].getBBox()
      );
      if (firstLabelPosX.x < -20) {
        (_a = yAxisTextsInversed[yAxisTextsInversed.length - 1].parentNode) == null ? void 0 : _a.removeChild(
          yAxisTextsInversed[yAxisTextsInversed.length - 1]
        );
      }
      if (lastLabelPosX.x + lastLabelPosX.width > w.layout.gridWidth && !w.globals.isBarHorizontal) {
        (_b = yAxisTextsInversed[0].parentNode) == null ? void 0 : _b.removeChild(yAxisTextsInversed[0]);
      }
      for (let xat = 0; xat < xAxisTextsInversed.length; xat++) {
        graphics.placeTextWithEllipsis(
          xAxisTextsInversed[xat],
          (_c = xAxisTextsInversed[xat].textContent) != null ? _c : "",
          w.config.yaxis[0].labels.maxWidth - (w.config.yaxis[0].title.text ? parseFloat(w.config.yaxis[0].title.style.fontSize) * 2 : 0) - 15
        );
      }
    }
  }
  // renderXAxisBands() {
  //   let w = this.w;
  //   let plotBand = document.createElementNS(SVGNS, 'rect')
  //   w.dom.elGraphical.add(plotBand)
  // }
}
class Grid {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.xaxisLabels = w.labelData.labels.slice();
    this.axesUtils = new AxesUtils(ctx.w, {
      theme: ctx.theme,
      timeScale: ctx.timeScale
    });
    this.isRangeBar = w.rangeData.seriesRange.length && w.globals.isBarHorizontal;
    if (w.labelData.timescaleLabels.length > 0) {
      this.xaxisLabels = w.labelData.timescaleLabels.slice();
    }
  }
  /**
   * @param {any} elGrid
   */
  drawGridArea(elGrid = null) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    if (!elGrid) {
      elGrid = graphics.group({ class: "apexcharts-grid" });
    }
    const elVerticalLine = graphics.drawLine(
      w.globals.padHorizontal,
      1,
      w.globals.padHorizontal,
      w.layout.gridHeight,
      "transparent"
    );
    const elHorzLine = graphics.drawLine(
      w.globals.padHorizontal,
      w.layout.gridHeight,
      w.layout.gridWidth,
      w.layout.gridHeight,
      "transparent"
    );
    elGrid.add(elHorzLine);
    elGrid.add(elVerticalLine);
    return elGrid;
  }
  drawGrid() {
    const gl = this.w.globals;
    if (gl.axisCharts) {
      const elgrid = this.renderGrid();
      this.drawGridArea(elgrid.el);
      return elgrid;
    }
    return null;
  }
  createGridMask() {
    const w = this.w;
    const gl = w.globals;
    const graphics = new Graphics(this.w);
    const strokeSize = Array.isArray(w.config.stroke.width) ? Math.max(...w.config.stroke.width) : w.config.stroke.width;
    const createClipPath = (id) => {
      const clipPath = BrowserAPIs.createElementNS(SVGNS$1, "clipPath");
      clipPath.setAttribute("id", id);
      return clipPath;
    };
    w.dom.elGridRectMask = createClipPath(`gridRectMask${gl.cuid}`);
    w.dom.elGridRectBarMask = createClipPath(`gridRectBarMask${gl.cuid}`);
    w.dom.elGridRectMarkerMask = createClipPath(`gridRectMarkerMask${gl.cuid}`);
    w.dom.elForecastMask = createClipPath(`forecastMask${gl.cuid}`);
    w.dom.elNonForecastMask = createClipPath(`nonForecastMask${gl.cuid}`);
    const hasBar = ["bar", "rangeBar", "candlestick", "boxPlot", "violin"].includes(
      w.config.chart.type
    ) || w.globals.comboBarCount > 0;
    let barWidthLeft = 0;
    let barWidthRight = 0;
    if (hasBar && w.axisFlags.isXNumeric && !w.globals.isBarHorizontal) {
      barWidthLeft = Math.max(w.layout.gridPad.left, gl.barPadForNumericAxis);
      barWidthRight = Math.max(w.layout.gridPad.right, gl.barPadForNumericAxis);
    }
    w.dom.elGridRect = graphics.drawRect(
      -strokeSize / 2 - 2,
      -strokeSize / 2 - 2,
      w.layout.gridWidth + strokeSize + 4,
      w.layout.gridHeight + strokeSize + 4,
      0,
      "#fff"
    );
    w.dom.elGridRectBar = graphics.drawRect(
      -strokeSize / 2 - barWidthLeft - 2,
      -strokeSize / 2 - 2,
      w.layout.gridWidth + strokeSize + barWidthRight + barWidthLeft + 4,
      w.layout.gridHeight + strokeSize + 4,
      0,
      "#fff"
    );
    const markerSize = w.globals.markers.largestSize;
    w.dom.elGridRectMarker = graphics.drawRect(
      Math.min(-strokeSize / 2 - barWidthLeft - 2, -markerSize),
      -markerSize,
      w.layout.gridWidth + Math.max(strokeSize + barWidthRight + barWidthLeft + 4, markerSize * 2),
      w.layout.gridHeight + markerSize * 2,
      0,
      "#fff"
    );
    w.dom.elGridRectMask.appendChild(w.dom.elGridRect.node);
    w.dom.elGridRectBarMask.appendChild(w.dom.elGridRectBar.node);
    w.dom.elGridRectMarkerMask.appendChild(w.dom.elGridRectMarker.node);
    const defs = w.dom.elDefs.node;
    defs.appendChild(w.dom.elGridRectMask);
    defs.appendChild(w.dom.elGridRectBarMask);
    defs.appendChild(w.dom.elGridRectMarkerMask);
    defs.appendChild(w.dom.elForecastMask);
    defs.appendChild(w.dom.elNonForecastMask);
  }
  /** @param {{i: any, x1: any, y1: any, x2: any, y2: any, xCount: any, parent: any}} opts */
  _drawGridLines({ i: i2, x1, y1, x2, y2, xCount, parent }) {
    const w = this.w;
    const shouldDraw = () => {
      if (i2 === 0 && w.globals.skipFirstTimelinelabel) return false;
      if (i2 === xCount - 1 && w.globals.skipLastTimelinelabel && !w.config.xaxis.labels.formatter)
        return false;
      if (w.config.chart.type === "radar") return false;
      return true;
    };
    if (shouldDraw()) {
      if (w.config.grid.xaxis.lines.show) {
        this._drawGridLine({ i: i2, x1, y1, x2, y2, xCount, parent });
      }
      let y_2 = 0;
      if (w.labelData.hasXaxisGroups && w.config.xaxis.tickPlacement === "between") {
        const groups = w.labelData.groups;
        if (groups) {
          let gacc = 0;
          for (let gi = 0; gacc < i2 && gi < groups.length; gi++) {
            gacc += groups[gi].cols;
          }
          if (gacc === i2) {
            y_2 = w.layout.xAxisLabelsHeight * 0.6;
          }
        }
      }
      const xAxis = new XAxis(this.w, this.ctx);
      xAxis.drawXaxisTicks(x1, y_2, w.dom.elGraphical);
    }
  }
  /** @param {{i: any, x1: any, y1: any, x2: any, y2: any, xCount: any, parent: any}} opts */
  _drawGridLine({ i: i2, x1, y1, x2, y2, xCount, parent }) {
    const w = this.w;
    const isHorzLine = parent.node.classList.contains(
      "apexcharts-gridlines-horizontal"
    );
    const offX = w.globals.barPadForNumericAxis;
    const excludeBorders = y1 === 0 && y2 === 0 || x1 === 0 && x2 === 0 || y1 === w.layout.gridHeight && y2 === w.layout.gridHeight || w.globals.isBarHorizontal && (i2 === 0 || i2 === xCount - 1);
    const graphics = new Graphics(this.w);
    const line = graphics.drawLine(
      x1 - (isHorzLine ? offX : 0),
      y1,
      x2 + (isHorzLine ? offX : 0),
      y2,
      w.config.grid.borderColor,
      w.config.grid.strokeDashArray
    );
    line.node.classList.add("apexcharts-gridline");
    if (excludeBorders && w.config.grid.show) {
      this.elGridBorders.add(line);
    } else {
      parent.add(line);
    }
  }
  /** @param {{c: any, x1: any, y1: any, x2: any, y2: any, type: any}} opts */
  _drawGridBandRect({ c: c2, x1, y1, x2, y2, type }) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const offX = w.globals.barPadForNumericAxis;
    const color = w.config.grid[type].colors[c2];
    const rect = graphics.drawRect(
      x1 - (type === "row" ? offX : 0),
      y1,
      x2 + (type === "row" ? offX * 2 : 0),
      y2,
      0,
      color,
      w.config.grid[type].opacity
    );
    this.elg.add(rect);
    rect.attr("clip-path", `url(#gridRectMask${w.globals.cuid})`);
    rect.node.classList.add(`apexcharts-grid-${type}`);
  }
  /** @param {{xCount: any, tickAmount: any}} opts */
  _drawXYLines({ xCount, tickAmount }) {
    var _a;
    const w = this.w;
    const datetimeLines = ({ xC, x1, y1, x2, y2 }) => {
      for (let i2 = 0; i2 < xC; i2++) {
        x1 = /** @type {any} */
        this.xaxisLabels[i2].position;
        x2 = /** @type {any} */
        this.xaxisLabels[i2].position;
        if (x1 < 0 || x1 - 2 > w.layout.gridWidth) continue;
        this._drawGridLines({
          i: i2,
          x1,
          y1,
          x2,
          y2,
          xCount,
          parent: this.elgridLinesV
        });
      }
    };
    const categoryLines = ({ xC, x1, y1, x2, y2 }) => {
      for (let i2 = 0; i2 < xC + (w.axisFlags.isXNumeric ? 0 : 1); i2++) {
        if (i2 === 0 && xC === 1 && w.globals.dataPoints === 1) {
          x1 = w.layout.gridWidth / 2;
          x2 = x1;
        }
        this._drawGridLines({
          i: i2,
          x1,
          y1,
          x2,
          y2,
          xCount,
          parent: this.elgridLinesV
        });
        x1 += w.layout.gridWidth / (w.axisFlags.isXNumeric ? xC - 1 : xC);
        x2 = x1;
      }
    };
    if (w.config.grid.xaxis.lines.show || w.config.xaxis.axisTicks.show) {
      const x1 = w.globals.padHorizontal;
      const y1 = 0;
      let x2;
      const y2 = w.layout.gridHeight;
      if (w.labelData.timescaleLabels.length) {
        datetimeLines({ xC: xCount, x1, y1, x2, y2 });
      } else {
        if (w.axisFlags.isXNumeric) {
          xCount = (_a = w.globals.xAxisScale) == null ? void 0 : _a.result.length;
        }
        categoryLines({ xC: xCount, x1, y1, x2, y2 });
      }
    }
    if (w.config.grid.yaxis.lines.show) {
      const x1 = 0;
      let y1 = 0;
      let y2 = 0;
      const x2 = w.layout.gridWidth;
      let tA = tickAmount + 1;
      if (this.isRangeBar) {
        tA = w.labelData.labels.length;
      }
      for (let i2 = 0; i2 < tA + (this.isRangeBar ? 1 : 0); i2++) {
        this._drawGridLine({
          i: i2,
          xCount: tA + (this.isRangeBar ? 1 : 0),
          x1,
          y1,
          x2,
          y2,
          parent: this.elgridLinesH
        });
        y1 += w.layout.gridHeight / (this.isRangeBar ? tA : tickAmount);
        y2 = y1;
      }
    }
  }
  /** @param {{ xCount?: any, tickAmount?: any }} opts */
  _drawInvertedXYLines({ xCount }) {
    const w = this.w;
    if (w.config.grid.xaxis.lines.show || w.config.xaxis.axisTicks.show) {
      let x1 = w.globals.padHorizontal;
      const y1 = 0;
      let x2;
      const y2 = w.layout.gridHeight;
      for (let i2 = 0; i2 < xCount + 1; i2++) {
        if (w.config.grid.xaxis.lines.show) {
          this._drawGridLine({
            i: i2,
            xCount: xCount + 1,
            x1,
            y1,
            x2,
            y2,
            parent: this.elgridLinesV
          });
        }
        const xAxis = new XAxis(this.w, this.ctx);
        xAxis.drawXaxisTicks(x1, 0, w.dom.elGraphical);
        x1 += w.layout.gridWidth / xCount;
        x2 = x1;
      }
    }
    if (w.config.grid.yaxis.lines.show) {
      const x1 = 0;
      let y1 = 0;
      let y2 = 0;
      const x2 = w.layout.gridWidth;
      for (let i2 = 0; i2 < w.globals.dataPoints + 1; i2++) {
        this._drawGridLine({
          i: i2,
          xCount: w.globals.dataPoints + 1,
          x1,
          y1,
          x2,
          y2,
          parent: this.elgridLinesH
        });
        y1 += w.layout.gridHeight / w.globals.dataPoints;
        y2 = y1;
      }
    }
  }
  renderGrid() {
    var _a, _b, _c;
    const w = this.w;
    const gl = w.globals;
    const graphics = new Graphics(this.w);
    this.elg = graphics.group({ class: "apexcharts-grid" });
    this.elgridLinesH = graphics.group({
      class: "apexcharts-gridlines-horizontal"
    });
    this.elgridLinesV = graphics.group({
      class: "apexcharts-gridlines-vertical"
    });
    this.elGridBorders = graphics.group({ class: "apexcharts-grid-borders" });
    this.elg.add(this.elgridLinesH);
    this.elg.add(this.elgridLinesV);
    if (!w.config.grid.show) {
      this.elgridLinesV.hide();
      this.elgridLinesH.hide();
      this.elGridBorders.hide();
    }
    let gridAxisIndex = 0;
    while (gridAxisIndex < gl.seriesYAxisMap.length && gl.ignoreYAxisIndexes.includes(gridAxisIndex)) {
      gridAxisIndex++;
    }
    if (gridAxisIndex === gl.seriesYAxisMap.length) {
      gridAxisIndex = 0;
    }
    let yTickAmount = gl.yAxisScale[gridAxisIndex].result.length - 1;
    let xCount;
    if (!gl.isBarHorizontal || this.isRangeBar) {
      xCount = this.xaxisLabels.length;
      if (this.isRangeBar) {
        yTickAmount = w.labelData.labels.length;
        if (w.config.xaxis.tickAmount && w.config.xaxis.labels.formatter) {
          xCount = w.config.xaxis.tickAmount;
        }
        if (((_c = (_b = (_a = gl.yAxisScale) == null ? void 0 : _a[gridAxisIndex]) == null ? void 0 : _b.result) == null ? void 0 : _c.length) > 0 && w.config.xaxis.type !== "datetime") {
          xCount = gl.yAxisScale[gridAxisIndex].result.length - 1;
        }
      }
      this._drawXYLines({ xCount, tickAmount: yTickAmount });
    } else {
      xCount = yTickAmount;
      yTickAmount = gl.xTickAmount;
      this._drawInvertedXYLines({ xCount, tickAmount: yTickAmount });
    }
    this.drawGridBands(xCount, yTickAmount);
    return {
      el: this.elg,
      elGridBorders: this.elGridBorders,
      xAxisTickWidth: w.layout.gridWidth / xCount
    };
  }
  /**
   * @param {number} xCount
   * @param {number} tickAmount
   */
  drawGridBands(xCount, tickAmount) {
    var _a, _b, _c, _d, _e;
    const w = this.w;
    const drawBands = (type, count, x1, y1, x2, y2) => {
      for (let i2 = 0, c2 = 0; i2 < count; i2++, c2++) {
        if (c2 >= w.config.grid[type].colors.length) {
          c2 = 0;
        }
        this._drawGridBandRect({ c: c2, x1, y1, x2, y2, type });
        y1 += w.layout.gridHeight / tickAmount;
      }
    };
    if (((_a = w.config.grid.row.colors) == null ? void 0 : _a.length) > 0) {
      drawBands(
        "row",
        tickAmount,
        0,
        0,
        w.layout.gridWidth,
        w.layout.gridHeight / tickAmount
      );
    }
    if (((_b = w.config.grid.column.colors) == null ? void 0 : _b.length) > 0) {
      let xc = !w.globals.isBarHorizontal && w.config.xaxis.tickPlacement === "on" && (w.config.xaxis.type === "category" || w.config.xaxis.convertedCatToNumeric) ? xCount - 1 : xCount;
      if (w.axisFlags.isXNumeric) {
        xc = ((_d = (_c = w.globals.xAxisScale) == null ? void 0 : _c.result.length) != null ? _d : 1) - 1;
      }
      let x1 = w.globals.padHorizontal;
      const y1 = 0;
      let x2 = w.globals.padHorizontal + w.layout.gridWidth / xc;
      const y2 = w.layout.gridHeight;
      for (let i2 = 0, c2 = 0; i2 < xCount; i2++, c2++) {
        if (c2 >= w.config.grid.column.colors.length) {
          c2 = 0;
        }
        if (w.config.xaxis.type === "datetime") {
          x1 = /** @type {any} */
          this.xaxisLabels[i2].position;
          x2 = /** @type {any} */
          (((_e = this.xaxisLabels[i2 + 1]) == null ? void 0 : _e.position) || w.layout.gridWidth) - /** @type {any} */
          this.xaxisLabels[i2].position;
        }
        this._drawGridBandRect({ c: c2, x1, y1, x2, y2, type: "column" });
        x1 += w.layout.gridWidth / xc;
      }
    }
  }
}
class Scales {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this.coreUtils = new CoreUtils(this.w);
  }
  // http://stackoverflow.com/questions/326679/choosing-an-attractive-linear-scale-for-a-graphs-y-axis
  // This routine creates the Y axis values for a graph.
  /**
   * @param {number} yMin
   * @param {number} yMax
   */
  niceScale(yMin, yMax, index = 0) {
    const jsPrecision = 1e-11;
    const w = this.w;
    const gl = w.globals;
    let axisCnf;
    let maxTicks;
    let gotMin;
    let gotMax;
    if (gl.isBarHorizontal) {
      axisCnf = w.config.xaxis;
      maxTicks = Math.max((gl.svgWidth - 100) / 25, 2);
    } else {
      axisCnf = w.config.yaxis[index];
      maxTicks = Math.max((gl.svgHeight - 100) / 15, 2);
    }
    if (!Utils$1.isNumber(maxTicks)) {
      maxTicks = 10;
    }
    gotMin = axisCnf.min !== void 0 && axisCnf.min !== null;
    gotMax = axisCnf.max !== void 0 && axisCnf.max !== null;
    let gotStepSize = axisCnf.stepSize !== void 0 && axisCnf.stepSize !== null;
    let gotTickAmount = axisCnf.tickAmount !== void 0 && axisCnf.tickAmount !== null;
    let ticks = gotTickAmount ? axisCnf.tickAmount : NICE_SCALE_DEFAULT_TICKS[Math.min(
      Math.round(maxTicks / 2),
      NICE_SCALE_DEFAULT_TICKS.length - 1
    )];
    if (gl.isMultipleYAxis && !gotTickAmount && gl.multiAxisTickAmount > 0) {
      ticks = gl.multiAxisTickAmount;
      gotTickAmount = true;
    }
    if (ticks === "dataPoints") {
      ticks = gl.dataPoints - 1;
    } else {
      ticks = Math.abs(Math.round(ticks));
    }
    if (yMin === Number.MIN_VALUE && yMax === 0 || !Utils$1.isNumber(yMin) && !Utils$1.isNumber(yMax) || yMin === Number.MIN_VALUE && yMax === -Number.MAX_VALUE) {
      yMin = Utils$1.isNumber(axisCnf.min) ? axisCnf.min : 0;
      yMax = Utils$1.isNumber(axisCnf.max) ? axisCnf.max : yMin + ticks;
      gl.allSeriesCollapsed = false;
    }
    if (yMin > yMax) {
      console.warn(
        "axis.min cannot be greater than axis.max: swapping min and max"
      );
      const temp = yMax;
      yMax = yMin;
      yMin = temp;
    } else if (yMin === yMax) {
      yMin = yMin === 0 ? 0 : yMin - 1;
      yMax = yMax === 0 ? 2 : yMax + 1;
    }
    const result = [];
    if (ticks < 1) {
      ticks = 1;
    }
    let tiks = ticks;
    let range = Math.abs(yMax - yMin);
    const proximityRatio = 0.15;
    if (!gotMin && yMin > 0 && yMin / range < proximityRatio) {
      yMin = 0;
      gotMin = true;
    }
    if (!gotMax && yMax < 0 && -yMax / range < proximityRatio) {
      yMax = 0;
      gotMax = true;
    }
    range = Math.abs(yMax - yMin);
    let stepSize = range / tiks;
    let niceStep = stepSize;
    const mag = Math.floor(Math.log10(niceStep));
    const magPow = Math.pow(10, mag);
    let magMsd = Math.ceil(niceStep / magPow);
    magMsd = NICE_SCALE_ALLOWED_MAG_MSD[gl.yValueDecimal === 0 ? 0 : 1][magMsd];
    niceStep = magMsd * magPow;
    stepSize = niceStep;
    if (gl.isBarHorizontal && axisCnf.stepSize && axisCnf.type !== "datetime") {
      stepSize = axisCnf.stepSize;
      gotStepSize = true;
    } else if (gotStepSize) {
      stepSize = axisCnf.stepSize;
    }
    if (gotStepSize) {
      if (axisCnf.forceNiceScale) {
        const stepMag = Math.floor(Math.log10(stepSize));
        stepSize *= Math.pow(10, mag - stepMag);
      }
    }
    if (gotMin && gotMax) {
      let crudeStep = range / tiks;
      if (gotTickAmount) {
        if (gotStepSize) {
          if (Utils$1.mod(range, stepSize) != 0) {
            const gcdStep = Utils$1.getGCD(stepSize, crudeStep);
            if (crudeStep / gcdStep < 10) {
              stepSize = gcdStep;
            } else {
              stepSize = crudeStep;
            }
          } else {
            if (Utils$1.mod(stepSize, crudeStep) == 0) {
              stepSize = crudeStep;
            } else {
              crudeStep = stepSize;
              gotTickAmount = false;
            }
          }
        } else {
          stepSize = crudeStep;
        }
      } else {
        if (gotStepSize) {
          if (Utils$1.mod(range, stepSize) == 0) {
            crudeStep = stepSize;
          } else {
            stepSize = crudeStep;
          }
        } else {
          if (Utils$1.mod(range, stepSize) == 0) {
            crudeStep = stepSize;
          } else {
            tiks = Math.ceil(range / stepSize);
            crudeStep = range / tiks;
            const gcdStep = Utils$1.getGCD(range, stepSize);
            if (range / gcdStep < maxTicks) {
              crudeStep = gcdStep;
            }
            stepSize = crudeStep;
          }
        }
      }
      tiks = Math.round(range / stepSize);
    } else {
      if (!gotMin && !gotMax) {
        if (gl.isMultipleYAxis && gotTickAmount) {
          const tMin = stepSize * Math.floor(yMin / stepSize);
          let tMax = tMin + stepSize * tiks;
          if (tMax < yMax) {
            stepSize *= 2;
          }
          yMin = tMin;
          tMax = yMax;
          yMax = yMin + stepSize * tiks;
          range = Math.abs(yMax - yMin);
          if (yMin > 0 && yMin < Math.abs(tMax - yMax)) {
            yMin = 0;
            yMax = stepSize * tiks;
          }
          if (yMax < 0 && -yMax < Math.abs(tMin - yMin)) {
            yMax = 0;
            yMin = -stepSize * tiks;
          }
        } else {
          yMin = stepSize * Math.floor(yMin / stepSize);
          yMax = stepSize * Math.ceil(yMax / stepSize);
        }
      } else if (gotMax) {
        if (gotTickAmount) {
          yMin = yMax - stepSize * tiks;
        } else {
          const yMinPrev = yMin;
          yMin = stepSize * Math.floor(yMin / stepSize);
          if (Math.abs(yMax - yMin) / Utils$1.getGCD(range, stepSize) > maxTicks) {
            yMin = yMax - stepSize * ticks;
            yMin += stepSize * Math.floor((yMinPrev - yMin) / stepSize);
          }
        }
      } else if (gotMin) {
        if (gotTickAmount) {
          yMax = yMin + stepSize * tiks;
        } else {
          const yMaxPrev = yMax;
          yMax = stepSize * Math.ceil(yMax / stepSize);
          if (Math.abs(yMax - yMin) / Utils$1.getGCD(range, stepSize) > maxTicks) {
            yMax = yMin + stepSize * ticks;
            yMax += stepSize * Math.ceil((yMaxPrev - yMax) / stepSize);
          }
        }
      }
      range = Math.abs(yMax - yMin);
      stepSize = Utils$1.getGCD(range, stepSize);
      tiks = Math.round(range / stepSize);
    }
    if (!gotTickAmount && !(gotMin || gotMax)) {
      tiks = Math.ceil((range - jsPrecision) / (stepSize + jsPrecision));
      if (tiks > 16 && Utils$1.getPrimeFactors(tiks).length < 2) {
        tiks++;
      }
    }
    if (!gotTickAmount && axisCnf.forceNiceScale && gl.yValueDecimal === 0 && tiks > range) {
      tiks = range;
      stepSize = Math.round(range / tiks);
    }
    if (tiks > maxTicks && (!(gotTickAmount || gotStepSize) || axisCnf.forceNiceScale)) {
      const pf = Utils$1.getPrimeFactors(tiks);
      const last = pf.length - 1;
      let tt = tiks;
      reduceLoop: for (var xFactors = 0; xFactors < last; xFactors++) {
        for (var lowest = 0; lowest <= last - xFactors; lowest++) {
          const stop = Math.min(lowest + xFactors, last);
          let t2 = tt;
          let div = 1;
          for (var next = lowest; next <= stop; next++) {
            div *= pf[next];
          }
          t2 /= div;
          if (t2 < maxTicks) {
            tt = t2;
            break reduceLoop;
          }
        }
      }
      if (tt === tiks) {
        stepSize = range;
      } else {
        stepSize = range / tt;
      }
      tiks = Math.round(range / stepSize);
    }
    if (gl.isMultipleYAxis && gl.multiAxisTickAmount == 0 && gl.ignoreYAxisIndexes.indexOf(index) < 0) {
      gl.multiAxisTickAmount = tiks;
    }
    let val = yMin - stepSize;
    const err = stepSize * jsPrecision;
    do {
      val += stepSize;
      result.push(Utils$1.stripNumber(val, 7));
    } while (yMax - val > err);
    return {
      result,
      niceMin: result[0],
      niceMax: result[result.length - 1]
    };
  }
  /** @param {number} yMin @param {number} yMax @param {number|string} ticks @param {number} index @param {number|undefined} step */
  linearScale(yMin, yMax, ticks = 10, index = 0, step = void 0) {
    const range = Math.abs(yMax - yMin);
    let result = [];
    if (yMin === yMax) {
      result = [yMin];
      return {
        result,
        niceMin: result[0],
        niceMax: result[result.length - 1]
      };
    }
    ticks = this._adjustTicksForSmallRange(ticks, index, range);
    if (
      /** @type {any} */
      ticks === "dataPoints"
    ) {
      ticks = this.w.globals.dataPoints - 1;
    }
    const ticksNum = (
      /** @type {number} */
      ticks
    );
    if (!step) {
      step = range / ticksNum;
    }
    const MIN_PRECISION = 2;
    if (step !== 0 && isFinite(step)) {
      const magnitude = Math.floor(Math.log10(Math.abs(step)));
      const precision = Math.max(MIN_PRECISION, -magnitude + MIN_PRECISION);
      const multiplier = Math.pow(10, precision);
      step = Math.round((step + Number.EPSILON) * multiplier) / multiplier;
    }
    let tickCount = ticks === Number.MAX_VALUE ? 5 : ticksNum;
    if (ticks === Number.MAX_VALUE) {
      step = 1;
    }
    let v = yMin;
    while (tickCount >= 0) {
      result.push(v);
      v = Utils$1.preciseAddition(v, step);
      tickCount -= 1;
    }
    return {
      result,
      niceMin: result[0],
      niceMax: result[result.length - 1]
    };
  }
  /**
   * Resolve an axis' tickAmount into a numeric interval count, or null when the
   * axis does not constrain it. Matches niceScale: tickAmount counts INTERVALS,
   * so N yields N + 1 labels.
   * @param {any} axisCnf
   * @returns {number | null}
   */
  _resolveLogTickAmount(axisCnf) {
    let ta = axisCnf.tickAmount;
    if (ta === "dataPoints") ta = this.w.globals.dataPoints - 1;
    return Utils$1.isNumber(ta) && ta >= 1 ? Number(ta) : null;
  }
  /**
   * Drop ticks from an evenly spaced list until it holds at most
   * `tickAmount + 1` of them, keeping both endpoints and even spacing.
   * @param {number[]} values
   * @param {number | null} tickAmount
   * @returns {number[]}
   */
  _thinToTickAmount(values, tickAmount) {
    if (tickAmount === null || !Utils$1.isNumber(tickAmount) || tickAmount < 1) {
      return values;
    }
    const want = tickAmount + 1;
    if (values.length <= want) return values;
    const intervals = values.length - 1;
    let best = null;
    for (let stride = 1; stride <= intervals; stride++) {
      if (intervals % stride !== 0) continue;
      const count = intervals / stride + 1;
      if (count > want) continue;
      if (best === null || count > best.count) best = { stride, count };
    }
    if (!best) return [values[0], values[values.length - 1]];
    const out = [];
    for (let i2 = 0; i2 < values.length; i2 += best.stride) out.push(values[i2]);
    return out;
  }
  /**
   * @param {number} yMin
   * @param {number} yMax
   * @param {number} base
   * @param {number | null} [tickAmount]
   */
  logarithmicScaleNice(yMin, yMax, base, tickAmount = null) {
    if (yMax <= 0) yMax = Math.max(yMin, base);
    if (yMin <= 0) yMin = Math.min(yMax, base);
    const logs = [];
    const logMax = Math.ceil(Math.log(yMax) / Math.log(base) + 1);
    const logMin = Math.floor(Math.log(yMin) / Math.log(base));
    for (let i2 = logMin; i2 < logMax; i2++) {
      logs.push(Math.pow(base, i2));
    }
    const result = this._thinToTickAmount(logs, tickAmount);
    return {
      result,
      niceMin: result[0],
      niceMax: result[result.length - 1]
    };
  }
  /**
   * How many full multiples of `base` the domain spans. Used to decide whether
   * a log scale is meaningful at all, independent of the domain's magnitude.
   * @param {number} yMin
   * @param {number} yMax
   * @param {number} base
   * @returns {number}
   */
  _logDomainSpan(yMin, yMax, base) {
    if (!base) base = 10;
    if (base <= 1) return 0;
    if (yMax <= 0) yMax = Math.max(yMin, base);
    if (yMin <= 0) yMin = Math.min(yMax, base);
    if (yMin <= 0 || yMax <= 0) return 0;
    return Math.abs(
      Math.log(yMax) / Math.log(base) - Math.log(yMin) / Math.log(base)
    );
  }
  /**
   * @param {number} yMin
   * @param {number} yMax
   * @param {number} base
   * @param {number | null} [tickAmount]
   */
  logarithmicScale(yMin, yMax, base, tickAmount = null) {
    if (yMax <= 0) yMax = Math.max(yMin, base);
    if (yMin <= 0) yMin = Math.min(yMax, base);
    const logs = [];
    const logMax = Math.log(yMax) / Math.log(base);
    const logMin = Math.log(yMin) / Math.log(base);
    const logRange = logMax - logMin;
    const ticks = tickAmount !== null ? tickAmount : Math.max(1, Math.round(logRange));
    const logTickSpacing = logRange / ticks;
    for (let i2 = 0, logTick = logMin; i2 < ticks; i2++, logTick += logTickSpacing) {
      logs.push(Math.pow(base, logTick));
    }
    logs.push(Math.pow(base, logMax));
    return {
      result: logs,
      niceMin: yMin,
      niceMax: yMax
    };
  }
  /**
   * @param {number | string} ticks
   * @param {number} index
   * @param {number} range
   */
  _adjustTicksForSmallRange(ticks, index, range) {
    let newTicks = ticks;
    if (typeof index !== "undefined" && this.w.config.yaxis[index].labels.formatter && this.w.config.yaxis[index].tickAmount === void 0) {
      const formattedVal = Number(
        this.w.config.yaxis[index].labels.formatter(1)
      );
      if (Utils$1.isNumber(formattedVal) && this.w.globals.yValueDecimal === 0) {
        newTicks = Math.ceil(range);
      }
    }
    return newTicks < ticks ? newTicks : ticks;
  }
  /**
   * @param {number} index
   * @param {number} minY
   * @param {number} maxY
   */
  setYScaleForIndex(index, minY, maxY) {
    const gl = this.w.globals;
    const cnf = this.w.config;
    const y = gl.isBarHorizontal ? cnf.xaxis : cnf.yaxis[index];
    if (typeof gl.yAxisScale[index] === "undefined") {
      gl.yAxisScale[index] = [];
    }
    const range = Math.abs(maxY - minY);
    const spansABase = y.logarithmic && this._logDomainSpan(minY, maxY, y.logBase) >= 1;
    const validLogScale = y.logarithmic && (spansABase || range > 5);
    if (y.logarithmic && !validLogScale) {
      gl.invalidLogScale = true;
    }
    if (validLogScale) {
      gl.allSeriesCollapsed = false;
      const logTickAmount = this._resolveLogTickAmount(y);
      gl.yAxisScale[index] = y.forceNiceScale ? this.logarithmicScaleNice(minY, maxY, y.logBase, logTickAmount) : this.logarithmicScale(minY, maxY, y.logBase, logTickAmount);
    } else {
      if (maxY === -Number.MAX_VALUE || !Utils$1.isNumber(maxY) || minY === Number.MAX_VALUE || !Utils$1.isNumber(minY)) {
        gl.yAxisScale[index] = this.niceScale(
          Number.MIN_VALUE,
          0,
          index
        );
      } else {
        gl.allSeriesCollapsed = false;
        gl.yAxisScale[index] = this.niceScale(
          minY,
          maxY,
          index
        );
      }
    }
  }
  /**
   * @param {number} minX
   * @param {number} maxX
   */
  setXScale(minX, maxX) {
    const w = this.w;
    const gl = w.globals;
    if (maxX === -Number.MAX_VALUE || !Utils$1.isNumber(maxX)) {
      gl.xAxisScale = this.linearScale(0, 10, 10);
    } else {
      const ticks = gl.xTickAmount;
      gl.xAxisScale = this.linearScale(
        minX,
        maxX,
        ticks,
        0,
        w.config.xaxis.max === void 0 ? w.config.xaxis.stepSize : void 0
      );
    }
    return gl.xAxisScale;
  }
  scaleMultipleYAxes() {
    const cnf = this.w.config;
    const gl = this.w.globals;
    this.coreUtils.setSeriesYAxisMappings();
    const axisSeriesMap = gl.seriesYAxisMap;
    const minYArr = gl.minYArr;
    const maxYArr = gl.maxYArr;
    const alignZeroParticipants = [];
    const canAlignZero = !gl.isBarHorizontal;
    gl.allSeriesCollapsed = true;
    gl.barGroups = [];
    axisSeriesMap.forEach((axisSeries, ai) => {
      const groupNames = [];
      axisSeries.forEach((as) => {
        var _a;
        const group = (
          /** @type {Record<string,any>} */
          (_a = cnf.series[as]) == null ? void 0 : _a.group
        );
        if (groupNames.indexOf(group) < 0) {
          groupNames.push(group);
        }
      });
      if (axisSeries.length > 0) {
        let minY = Number.MAX_VALUE;
        let maxY = -Number.MAX_VALUE;
        let lowestY = minY;
        let highestY = maxY;
        let seriesType;
        let seriesGroupName;
        if (cnf.chart.stacked) {
          const mapSeries = new Array(gl.dataPoints).fill(0);
          const sumSeries = [];
          const posSeries = [];
          const negSeries = [];
          groupNames.forEach(() => {
            sumSeries.push(mapSeries.map(() => Number.MIN_VALUE));
            posSeries.push(mapSeries.map(() => Number.MIN_VALUE));
            negSeries.push(mapSeries.map(() => Number.MIN_VALUE));
          });
          for (let i2 = 0; i2 < axisSeries.length; i2++) {
            if (!seriesType && /** @type {Record<string,any>} */
            cnf.series[axisSeries[i2]].type) {
              seriesType = /** @type {Record<string,any>} */
              cnf.series[axisSeries[i2]].type;
            }
            const si = axisSeries[i2];
            if (
              /** @type {Record<string,any>} */
              cnf.series[si].group
            ) {
              seriesGroupName = /** @type {Record<string,any>} */
              cnf.series[si].group;
            } else {
              seriesGroupName = "axis-".concat(ai.toString());
            }
            const collapsed = !(gl.collapsedSeriesIndices.indexOf(si) < 0 && gl.ancillaryCollapsedSeriesIndices.indexOf(si) < 0);
            if (!collapsed) {
              gl.allSeriesCollapsed = false;
              groupNames.forEach((gn, gni) => {
                if (
                  /** @type {Record<string,any>} */
                  cnf.series[si].group === gn
                ) {
                  for (let j = 0; j < this.w.seriesData.series[si].length; j++) {
                    const val = this.w.seriesData.series[si][j];
                    if (val >= 0) {
                      posSeries[gni][j] += val;
                    } else {
                      negSeries[gni][j] += val;
                    }
                    sumSeries[gni][j] += val;
                    lowestY = Math.min(lowestY, val);
                    highestY = Math.max(highestY, val);
                  }
                }
              });
            }
            if (seriesType === "bar" || seriesType === "column") {
              gl.barGroups.push(seriesGroupName);
            }
          }
          if (!seriesType) {
            seriesType = cnf.chart.type;
          }
          if (seriesType === "bar" || seriesType === "column") {
            groupNames.forEach((gn, gni) => {
              minY = Math.min(minY, Math.min.apply(null, negSeries[gni]));
              maxY = Math.max(maxY, Math.max.apply(null, posSeries[gni]));
            });
          } else {
            groupNames.forEach((gn, gni) => {
              lowestY = Math.min(lowestY, Math.min.apply(null, sumSeries[gni]));
              highestY = Math.max(
                highestY,
                Math.max.apply(null, sumSeries[gni])
              );
            });
            minY = lowestY;
            maxY = highestY;
          }
          if (minY === Number.MIN_VALUE && maxY === Number.MIN_VALUE) {
            maxY = -Number.MAX_VALUE;
          }
        } else {
          for (let i2 = 0; i2 < axisSeries.length; i2++) {
            const si = axisSeries[i2];
            minY = Math.min(minY, minYArr[si]);
            maxY = Math.max(maxY, maxYArr[si]);
            const collapsed = !(gl.collapsedSeriesIndices.indexOf(si) < 0 && gl.ancillaryCollapsedSeriesIndices.indexOf(si) < 0);
            if (!collapsed) {
              gl.allSeriesCollapsed = false;
            }
          }
        }
        if (cnf.yaxis[ai].min !== void 0) {
          if (typeof cnf.yaxis[ai].min === "function") {
            minY = cnf.yaxis[ai].min(minY);
          } else {
            minY = cnf.yaxis[ai].min;
          }
        }
        if (cnf.yaxis[ai].max !== void 0) {
          if (typeof cnf.yaxis[ai].max === "function") {
            maxY = cnf.yaxis[ai].max(maxY);
          } else {
            maxY = cnf.yaxis[ai].max;
          }
        }
        gl.barGroups = gl.barGroups.filter((v, i2, a2) => a2.indexOf(v) === i2);
        const yaxe = cnf.yaxis[ai];
        const participates = canAlignZero && yaxe.alignZero === true && !yaxe.logarithmic && yaxe.min === void 0 && yaxe.max === void 0 && gl.ignoreYAxisIndexes.indexOf(ai) < 0 && Utils$1.isNumber(minY) && Utils$1.isNumber(maxY);
        if (participates) {
          alignZeroParticipants.push({ ai, minY, maxY });
        } else {
          this.setYScaleForIndex(ai, minY, maxY);
          axisSeries.forEach((si) => {
            minYArr[si] = gl.yAxisScale[ai].niceMin;
            maxYArr[si] = gl.yAxisScale[ai].niceMax;
          });
        }
      } else {
        this.setYScaleForIndex(ai, 0, -Number.MAX_VALUE);
      }
    });
    if (alignZeroParticipants.length >= 2) {
      alignZeroParticipants.forEach((p) => {
        this.setYScaleForIndex(p.ai, p.minY, p.maxY);
        axisSeriesMap[p.ai].forEach((si) => {
          minYArr[si] = gl.yAxisScale[p.ai].niceMin;
          maxYArr[si] = gl.yAxisScale[p.ai].niceMax;
        });
      });
      let targetRatio = 0;
      alignZeroParticipants.forEach((p) => {
        const scale = gl.yAxisScale[p.ai];
        const range = scale.niceMax - scale.niceMin;
        if (range > 0) {
          const r2 = -scale.niceMin / range;
          if (r2 > targetRatio) targetRatio = r2;
        }
      });
      if (targetRatio > 1) targetRatio = 1;
      if (targetRatio < 0) targetRatio = 0;
      const niceRoundUp = (raw) => {
        if (raw <= 0) return 1;
        const mag = Math.floor(Math.log10(raw));
        const magPow = Math.pow(10, mag);
        const msd = raw / magPow;
        let mult;
        if (msd <= 1 + 1e-9) mult = 1;
        else if (msd <= 2 + 1e-9) mult = 2;
        else if (msd <= 2.5 + 1e-9) mult = 2.5;
        else if (msd <= 5 + 1e-9) mult = 5;
        else mult = 10;
        return mult * magPow;
      };
      alignZeroParticipants.forEach((p) => {
        const scale = gl.yAxisScale[p.ai];
        if (!scale.result || scale.result.length < 2) return;
        const range = scale.niceMax - scale.niceMin;
        if (range <= 0) return;
        const r2 = -scale.niceMin / range;
        if (Math.abs(r2 - targetRatio) <= 1e-9) return;
        const extendMin = r2 < targetRatio && targetRatio < 1 - 1e-9;
        const extendMaxOnly = !extendMin && r2 > targetRatio && targetRatio > 1e-9;
        if (!extendMin && !extendMaxOnly) return;
        const targetNiceMin = extendMin ? -targetRatio * scale.niceMax / (1 - targetRatio) : scale.niceMin;
        const targetNiceMax = extendMaxOnly ? -scale.niceMin * (1 - targetRatio) / targetRatio : scale.niceMax;
        const newRange = targetNiceMax - targetNiceMin;
        if (newRange <= 0) return;
        const desiredTicks = Math.max(scale.result.length, 5);
        const newStep = niceRoundUp(newRange / Math.max(desiredTicks - 1, 1));
        if (newStep <= 0) return;
        let newNiceMin;
        let newNiceMax;
        if (extendMin) {
          newNiceMin = Math.floor(targetNiceMin / newStep + 1e-9) * newStep;
          const requiredMax = targetRatio > 1e-9 ? newNiceMin * (targetRatio - 1) / targetRatio : scale.niceMax;
          const maxNeeded = Math.max(requiredMax, scale.niceMax);
          newNiceMax = Math.ceil(maxNeeded / newStep - 1e-9) * newStep;
        } else {
          newNiceMax = Math.ceil(targetNiceMax / newStep - 1e-9) * newStep;
          const requiredMin = targetRatio < 1 - 1e-9 ? -targetRatio * newNiceMax / (1 - targetRatio) : scale.niceMin;
          const minNeeded = Math.min(requiredMin, scale.niceMin);
          newNiceMin = Math.floor(minNeeded / newStep + 1e-9) * newStep;
        }
        scale.result = [];
        for (let v = newNiceMin; v <= newNiceMax + newStep * 1e-9; v = Utils$1.preciseAddition(v, newStep)) {
          scale.result.push(Utils$1.stripNumber(v, 7));
        }
        scale.niceMin = newNiceMin;
        scale.niceMax = newNiceMax;
        axisSeriesMap[p.ai].forEach((si) => {
          minYArr[si] = scale.niceMin;
          maxYArr[si] = scale.niceMax;
        });
      });
    } else if (alignZeroParticipants.length === 1) {
      const p = alignZeroParticipants[0];
      this.setYScaleForIndex(p.ai, p.minY, p.maxY);
      axisSeriesMap[p.ai].forEach((si) => {
        minYArr[si] = gl.yAxisScale[p.ai].niceMin;
        maxYArr[si] = gl.yAxisScale[p.ai].niceMax;
      });
    }
  }
}
class Range {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this.scales = new Scales(this.w);
  }
  init() {
    this.setYRange();
    this.setXRange();
    this.setZRange();
  }
  /**
   * One rendered x-pixel expressed in data units, used to widen the
   * autoScaleYaxis window so a boundary point that is still drawn inside the
   * plot survives a sub-pixel rounding error in `xaxis.min`/`xaxis.max`.
   *
   * The window is taken from the configured bounds (that is what maps onto the
   * grid) and falls back to the series' own x-extent for whichever bound is
   * unset. Returns 0 when there is nothing to scale against: `gridWidth` is
   * still 0 before the first `plotCoords()` run, and a first render has no
   * pixel round-trip to compensate for anyway.
   *
   * @param {number[] | undefined} seriesX
   * @returns {number}
   */
  _xPixelTolerance(seriesX) {
    const gridWidth = this.w.layout.gridWidth;
    if (!gridWidth || !seriesX || !seriesX.length) return 0;
    const cnfX = this.w.config.xaxis;
    const lo = typeof cnfX.min === "number" ? cnfX.min : seriesX[0];
    const hi = typeof cnfX.max === "number" ? cnfX.max : seriesX[seriesX.length - 1];
    if (!(hi > lo)) return 0;
    return (hi - lo) / gridWidth;
  }
  /**
   * @param {number} startingSeriesIndex
   * @param {number | null} [endingSeriesIndex]
   */
  getMinYMaxY(startingSeriesIndex, lowestY = Number.MAX_VALUE, highestY = -Number.MAX_VALUE, endingSeriesIndex = null) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i;
    const cnf = this.w.config;
    const gl = this.w.globals;
    let maxY = -Number.MAX_VALUE;
    let minY = Number.MIN_VALUE;
    if (endingSeriesIndex === null) {
      endingSeriesIndex = startingSeriesIndex + 1;
    }
    const series = this.w.seriesData.series;
    let seriesMin = series;
    let seriesMax = series;
    if (cnf.chart.type === "candlestick") {
      seriesMin = this.w.candleData.seriesCandleL;
      seriesMax = this.w.candleData.seriesCandleH;
    } else if (cnf.chart.type === "boxPlot") {
      seriesMin = this.w.candleData.seriesCandleO;
      seriesMax = this.w.candleData.seriesCandleC;
    } else if (cnf.chart.type === "violin") {
      seriesMin = this.w.violinData.seriesViolinMin;
      seriesMax = this.w.violinData.seriesViolinMax;
    } else if (this.w.axisFlags.isRangeData) {
      seriesMin = this.w.rangeData.seriesRangeStart;
      seriesMax = this.w.rangeData.seriesRangeEnd;
    }
    let autoScaleYaxis = false;
    if (this.w.seriesData.seriesX.length >= endingSeriesIndex) {
      const brush = (
        /** @type {any} */
        (_a = gl.brushSource) == null ? void 0 : _a.w.config.chart.brush
      );
      if (cnf.chart.zoom.enabled && cnf.chart.zoom.autoScaleYaxis || (brush == null ? void 0 : brush.enabled) && (brush == null ? void 0 : brush.autoScaleYaxis)) {
        autoScaleYaxis = true;
      }
    }
    for (let i2 = startingSeriesIndex; i2 < endingSeriesIndex; i2++) {
      gl.dataPoints = Math.max(gl.dataPoints, series[i2].length);
      const seriesType = (
        /** @type {Record<string,any>} */
        cnf.series[i2].type
      );
      if (this.w.labelData.categoryLabels.length) {
        gl.dataPoints = this.w.labelData.categoryLabels.filter(
          (label) => typeof label !== "undefined"
        ).length;
      }
      if (this.w.labelData.labels.length && cnf.xaxis.type !== "datetime" && /**
       * @param {number} a
       * @param {number[]} c
       */
      this.w.seriesData.series.reduce((a2, c2) => a2 + c2.length, 0) !== 0) {
        gl.dataPoints = Math.max(gl.dataPoints, this.w.labelData.labels.length);
      }
      let firstXIndex = 0;
      let lastXIndex = series[i2].length - 1;
      if (autoScaleYaxis) {
        const xTolerance = this._xPixelTolerance(this.w.seriesData.seriesX[i2]);
        if (cnf.xaxis.min) {
          const lowerBound = cnf.xaxis.min - xTolerance;
          for (; firstXIndex < lastXIndex && this.w.seriesData.seriesX[i2][firstXIndex] < lowerBound; firstXIndex++) {
          }
        }
        if (cnf.xaxis.max) {
          const upperBound = cnf.xaxis.max + xTolerance;
          for (; lastXIndex > firstXIndex && this.w.seriesData.seriesX[i2][lastXIndex] > upperBound; lastXIndex--) {
          }
        }
      }
      const plainNumeric = seriesMin === series && seriesMax === series && cnf.chart.type !== "boxPlot" && seriesType !== "candlestick" && seriesType !== "boxPlot" && seriesType !== "violin" && seriesType !== "rangeArea" && seriesType !== "rangeBar" && !(this.w.seriesData.seriesGoals[i2] && this.w.seriesData.seriesGoals[i2].length);
      if (plainNumeric) {
        const arr = series[i2];
        const jEnd = Math.min(lastXIndex, arr.length - 1);
        const pe = (_b = this.w.seriesData._parsedExtrema) == null ? void 0 : _b[i2];
        if (pe && pe.ref === arr && pe.len === arr.length && firstXIndex === 0 && jEnd === arr.length - 1) {
          if (pe.maxY > maxY) maxY = pe.maxY;
          if (pe.lowestY < lowestY) lowestY = pe.lowestY;
          if (pe.negMinY < 0 && pe.negMinY < minY) minY = pe.negMinY;
          if (pe.yDec > gl.yValueDecimal) gl.yValueDecimal = pe.yDec;
          if (pe.hasNulls) gl.hasNullValues = true;
        } else {
          let yDec = gl.yValueDecimal;
          let hasNulls = false;
          for (let j = firstXIndex; j <= jEnd; j++) {
            const val = arr[j];
            if (val !== null && typeof val === "number" && val === val && val !== Infinity && val !== -Infinity) {
              if (val > maxY) maxY = val;
              if (val < lowestY) lowestY = val;
              if (minY > val && val < 0) minY = val;
              if (!Number.isInteger(val)) {
                const av = val < 0 ? -val : val;
                if (av >= 1e-6 && av < 1e21) {
                  const str = "" + val;
                  const dot = str.indexOf(".");
                  const dec = dot === -1 ? 0 : str.length - dot - 1;
                  if (dec > yDec) yDec = dec;
                } else {
                  const nv = Utils$1.noExponents(val);
                  if (Utils$1.isFloat(nv)) {
                    yDec = Math.max(yDec, nv.toString().split(".")[1].length);
                  }
                }
              }
            } else {
              hasNulls = true;
            }
          }
          gl.yValueDecimal = yDec;
          if (hasNulls) gl.hasNullValues = true;
        }
        highestY = maxY;
        if (seriesType === "bar" || seriesType === "column") {
          if (minY < 0 && maxY < 0) {
            maxY = 0;
            highestY = Math.max(highestY, 0);
          }
          if (minY === Number.MIN_VALUE) {
            minY = 0;
            lowestY = Math.min(lowestY, 0);
          }
        }
        continue;
      }
      for (let j = firstXIndex; j <= lastXIndex && j < this.w.seriesData.series[i2].length; j++) {
        let val = series[i2][j];
        if (val !== null && Utils$1.isNumber(val)) {
          if (typeof ((_c = seriesMax[i2]) == null ? void 0 : _c[j]) !== "undefined") {
            maxY = Math.max(maxY, seriesMax[i2][j]);
            lowestY = Math.min(lowestY, seriesMax[i2][j]);
          }
          if (typeof ((_d = seriesMin[i2]) == null ? void 0 : _d[j]) !== "undefined") {
            lowestY = Math.min(lowestY, seriesMin[i2][j]);
            highestY = Math.max(highestY, seriesMin[i2][j]);
          }
          switch (seriesType) {
            case "candlestick":
              {
                if (typeof this.w.candleData.seriesCandleC[i2][j] !== "undefined") {
                  maxY = Math.max(maxY, this.w.candleData.seriesCandleH[i2][j]);
                  lowestY = Math.min(
                    lowestY,
                    this.w.candleData.seriesCandleL[i2][j]
                  );
                }
              }
              break;
            case "boxPlot":
              {
                if (typeof this.w.candleData.seriesCandleC[i2][j] !== "undefined") {
                  maxY = Math.max(maxY, this.w.candleData.seriesCandleC[i2][j]);
                  lowestY = Math.min(
                    lowestY,
                    this.w.candleData.seriesCandleO[i2][j]
                  );
                }
              }
              break;
            case "violin":
              {
                if (typeof ((_e = this.w.violinData.seriesViolinMax[i2]) == null ? void 0 : _e[j]) !== "undefined") {
                  maxY = Math.max(maxY, this.w.violinData.seriesViolinMax[i2][j]);
                  lowestY = Math.min(
                    lowestY,
                    this.w.violinData.seriesViolinMin[i2][j]
                  );
                }
              }
              break;
          }
          if (seriesType && seriesType !== "candlestick" && seriesType !== "boxPlot" && seriesType !== "violin" && seriesType !== "rangeArea" && seriesType !== "rangeBar") {
            maxY = Math.max(maxY, this.w.seriesData.series[i2][j]);
            lowestY = Math.min(lowestY, this.w.seriesData.series[i2][j]);
          }
          if (this.w.seriesData.seriesGoals[i2] && this.w.seriesData.seriesGoals[i2][j] && Array.isArray(this.w.seriesData.seriesGoals[i2][j])) {
            this.w.seriesData.seriesGoals[i2][j].forEach(
              (g) => {
                maxY = Math.max(maxY, g.value);
                lowestY = Math.min(lowestY, g.value);
              }
            );
          }
          if (this.w.config.chart.type === "boxPlot" || seriesType === "boxPlot") {
            const boxPts = (_g = (_f = this.w.candleData.seriesBoxPoints) == null ? void 0 : _f[i2]) == null ? void 0 : _g[j];
            if (boxPts) {
              for (let p = 0; p < boxPts.length; p++) {
                const pv = boxPts[p];
                if (typeof pv === "number") {
                  maxY = Math.max(maxY, pv);
                  lowestY = Math.min(lowestY, pv);
                }
              }
            }
          }
          highestY = maxY;
          val = Utils$1.noExponents(val);
          if (Utils$1.isFloat(val)) {
            gl.yValueDecimal = Math.max(
              gl.yValueDecimal,
              val.toString().split(".")[1].length
            );
          }
          if (minY > ((_h = seriesMin[i2]) == null ? void 0 : _h[j]) && ((_i = seriesMin[i2]) == null ? void 0 : _i[j]) < 0) {
            minY = seriesMin[i2][j];
          }
        } else {
          gl.hasNullValues = true;
        }
      }
      if (seriesType === "bar" || seriesType === "column") {
        if (minY < 0 && maxY < 0) {
          maxY = 0;
          highestY = Math.max(highestY, 0);
        }
        if (minY === Number.MIN_VALUE) {
          minY = 0;
          lowestY = Math.min(lowestY, 0);
        }
      }
    }
    if (cnf.chart.type === "rangeBar" && this.w.rangeData.seriesRangeStart.length && gl.isBarHorizontal) {
      minY = lowestY;
    }
    if (cnf.chart.type === "bar") {
      if (minY < 0 && maxY < 0) {
        maxY = 0;
      }
      if (minY === Number.MIN_VALUE) {
        minY = 0;
      }
    }
    return {
      minY,
      maxY,
      lowestY,
      highestY
    };
  }
  setYRange() {
    const gl = this.w.globals;
    const cnf = this.w.config;
    gl.maxY = -Number.MAX_VALUE;
    gl.minY = Number.MIN_VALUE;
    let lowestYInAllSeries = Number.MAX_VALUE;
    let minYMaxY;
    if (gl.isMultipleYAxis) {
      lowestYInAllSeries = Number.MAX_VALUE;
      for (let i2 = 0; i2 < this.w.seriesData.series.length; i2++) {
        minYMaxY = this.getMinYMaxY(i2);
        gl.minYArr[i2] = minYMaxY.lowestY;
        gl.maxYArr[i2] = minYMaxY.highestY;
        lowestYInAllSeries = Math.min(lowestYInAllSeries, minYMaxY.lowestY);
      }
    }
    minYMaxY = this.getMinYMaxY(
      0,
      lowestYInAllSeries,
      void 0,
      this.w.seriesData.series.length
    );
    if (cnf.chart.type === "bar") {
      gl.minY = minYMaxY.minY;
      gl.maxY = minYMaxY.maxY;
    } else {
      gl.minY = minYMaxY.lowestY;
      gl.maxY = minYMaxY.highestY;
    }
    lowestYInAllSeries = minYMaxY.lowestY;
    if (cnf.chart.stacked) {
      this._setStackedMinMax();
    }
    if (cnf.chart.type === "line" || cnf.chart.type === "area" || cnf.chart.type === "scatter" || cnf.chart.type === "candlestick" || cnf.chart.type === "boxPlot" || cnf.chart.type === "violin" || cnf.chart.type === "rangeBar" && !gl.isBarHorizontal) {
      if (gl.minY === Number.MIN_VALUE && lowestYInAllSeries !== -Number.MAX_VALUE && lowestYInAllSeries !== gl.maxY) {
        gl.minY = lowestYInAllSeries;
      }
    } else {
      gl.minY = gl.minY !== Number.MIN_VALUE ? Math.min(minYMaxY.minY, gl.minY) : minYMaxY.minY;
    }
    cnf.yaxis.forEach((yaxe, index) => {
      if (yaxe.max !== void 0) {
        if (typeof yaxe.max === "number") {
          gl.maxYArr[index] = yaxe.max;
        } else if (typeof yaxe.max === "function") {
          gl.maxYArr[index] = yaxe.max(
            gl.isMultipleYAxis ? gl.maxYArr[index] : gl.maxY
          );
        }
        gl.maxY = gl.maxYArr[index];
      }
      if (yaxe.min !== void 0) {
        if (typeof yaxe.min === "number") {
          gl.minYArr[index] = yaxe.min;
        } else if (typeof yaxe.min === "function") {
          gl.minYArr[index] = yaxe.min(
            gl.isMultipleYAxis ? gl.minYArr[index] === Number.MIN_VALUE ? 0 : gl.minYArr[index] : gl.minY
          );
        }
        gl.minY = gl.minYArr[index];
      }
    });
    if (gl.isBarHorizontal) {
      const minmax = ["min", "max"];
      minmax.forEach((m) => {
        if (cnf.xaxis[m] !== void 0 && typeof cnf.xaxis[m] === "number") {
          m === "min" ? gl.minY = cnf.xaxis[m] : gl.maxY = cnf.xaxis[m];
        }
      });
    }
    if (gl.isMultipleYAxis) {
      this.scales.scaleMultipleYAxes();
      gl.minY = lowestYInAllSeries;
    } else {
      this.scales.setYScaleForIndex(0, gl.minY, gl.maxY);
      gl.minY = gl.yAxisScale[0].niceMin;
      gl.maxY = gl.yAxisScale[0].niceMax;
      gl.minYArr[0] = gl.minY;
      gl.maxYArr[0] = gl.maxY;
    }
    gl.barGroups = [];
    gl.lineGroups = [];
    gl.areaGroups = [];
    cnf.series.forEach((s2) => {
      const _s = (
        /** @type {any} */
        s2
      );
      const type = _s.type || cnf.chart.type;
      switch (type) {
        case "bar":
        case "column":
          gl.barGroups.push(_s.group);
          break;
        case "line":
          gl.lineGroups.push(_s.group);
          break;
        case "area":
          gl.areaGroups.push(_s.group);
          break;
      }
    });
    gl.barGroups = gl.barGroups.filter((v, i2, a2) => a2.indexOf(v) === i2);
    gl.lineGroups = gl.lineGroups.filter((v, i2, a2) => a2.indexOf(v) === i2);
    gl.areaGroups = gl.areaGroups.filter((v, i2, a2) => a2.indexOf(v) === i2);
    return {
      minY: gl.minY,
      maxY: gl.maxY,
      minYArr: gl.minYArr,
      maxYArr: gl.maxYArr,
      yAxisScale: gl.yAxisScale
    };
  }
  setXRange() {
    const gl = this.w.globals;
    const cnf = this.w.config;
    const isXNumeric = cnf.xaxis.type === "numeric" || cnf.xaxis.type === "datetime" || cnf.xaxis.type === "category" && !this.w.axisFlags.noLabelsProvided || this.w.axisFlags.noLabelsProvided || this.w.axisFlags.isXNumeric;
    const getInitialMinXMaxX = () => {
      var _a;
      let minX = gl.minX;
      let maxX = gl.maxX;
      for (let i2 = 0; i2 < this.w.seriesData.series.length; i2++) {
        const lbls = (
          /** @type {any} */
          this.w.labelData.labels[i2]
        );
        if (!lbls) continue;
        const pe = (_a = this.w.seriesData._parsedExtrema) == null ? void 0 : _a[i2];
        if (pe && pe.xNumeric && pe.xref === lbls && pe.len === lbls.length) {
          if (pe.maxX > maxX) maxX = pe.maxX;
          if (pe.minX < minX) minX = pe.minX;
          continue;
        }
        for (let j = 0; j < lbls.length; j++) {
          const v = lbls[j];
          if (v !== null && typeof v === "number" && v === v) {
            if (v > maxX) maxX = v;
            if (v < minX) minX = v;
          }
        }
      }
      gl.maxX = maxX;
      gl.initialMaxX = maxX;
      gl.minX = minX;
      gl.initialMinX = minX;
    };
    if (this.w.axisFlags.isXNumeric) {
      getInitialMinXMaxX();
    }
    if (this.w.axisFlags.noLabelsProvided) {
      if (cnf.xaxis.categories.length === 0) {
        gl.maxX = /** @type {any} */
        this.w.labelData.labels[this.w.labelData.labels.length - 1];
        gl.initialMaxX = /** @type {any} */
        this.w.labelData.labels[this.w.labelData.labels.length - 1];
        gl.minX = 1;
        gl.initialMinX = 1;
      }
    }
    if (this.w.axisFlags.isXNumeric || this.w.axisFlags.noLabelsProvided || this.w.axisFlags.dataFormatXNumeric) {
      let ticks = 10;
      if (cnf.xaxis.tickAmount === void 0) {
        ticks = Math.round(gl.svgWidth / 150);
        if (cnf.xaxis.type === "numeric" && gl.dataPoints < 30) {
          ticks = gl.dataPoints - 1;
        }
        if (ticks > gl.dataPoints && gl.dataPoints !== 0) {
          ticks = gl.dataPoints - 1;
        }
      } else if (cnf.xaxis.tickAmount === "dataPoints") {
        if (this.w.seriesData.series.length > 1) {
          ticks = this.w.seriesData.series[gl.maxValsInArrayIndex].length - 1;
        }
        if (this.w.axisFlags.isXNumeric) {
          const diff = Math.round(gl.maxX - gl.minX);
          if (diff < 30) {
            ticks = diff;
          }
        }
      } else {
        ticks = cnf.xaxis.tickAmount;
      }
      gl.xTickAmount = ticks;
      if (cnf.xaxis.max !== void 0 && typeof cnf.xaxis.max === "number") {
        gl.maxX = cnf.xaxis.max;
      }
      if (cnf.xaxis.min !== void 0 && typeof cnf.xaxis.min === "number") {
        gl.minX = cnf.xaxis.min;
      }
      if (cnf.xaxis.range !== void 0) {
        gl.minX = gl.maxX - cnf.xaxis.range;
      }
      if (gl.minX !== Number.MAX_VALUE && gl.maxX !== -Number.MAX_VALUE) {
        if (cnf.xaxis.convertedCatToNumeric && !this.w.axisFlags.dataFormatXNumeric) {
          const catScale = [];
          for (let i2 = gl.minX - 1; i2 < gl.maxX; i2++) {
            catScale.push(i2 + 1);
          }
          gl.xAxisScale = {
            result: catScale,
            niceMin: catScale[0],
            niceMax: catScale[catScale.length - 1]
          };
        } else {
          gl.xAxisScale = this.scales.setXScale(gl.minX, gl.maxX);
        }
      } else {
        gl.xAxisScale = this.scales.linearScale(
          0,
          ticks,
          ticks,
          0,
          cnf.xaxis.stepSize
        );
        if (this.w.axisFlags.noLabelsProvided && this.w.labelData.labels.length > 0) {
          gl.xAxisScale = this.scales.linearScale(
            1,
            this.w.labelData.labels.length,
            ticks - 1,
            0,
            cnf.xaxis.stepSize
          );
          this.w.seriesData.seriesX = /** @type {any} */
          this.w.labelData.labels.slice();
        }
      }
      if (isXNumeric) {
        this.w.labelData.labels = /** @type {any} */
        gl.xAxisScale.result.slice();
      }
    }
    if (gl.isBarHorizontal && this.w.labelData.labels.length) {
      gl.xTickAmount = this.w.labelData.labels.length;
    }
    this._handleSingleDataPoint();
    this._getMinXDiff();
    return {
      minX: gl.minX,
      maxX: gl.maxX
    };
  }
  setZRange() {
    var _a;
    const gl = this.w.globals;
    if (!this.w.axisFlags.isDataXYZ) return;
    for (let i2 = 0; i2 < this.w.seriesData.series.length; i2++) {
      if (typeof this.w.seriesData.seriesZ[i2] !== "undefined") {
        for (let j = 0; j < this.w.seriesData.seriesZ[i2].length; j++) {
          if (this.w.seriesData.seriesZ[i2][j] !== null && Utils$1.isNumber(this.w.seriesData.seriesZ[i2][j])) {
            gl.maxZ = Math.max(gl.maxZ, this.w.seriesData.seriesZ[i2][j]);
            gl.minZ = Math.min(gl.minZ, this.w.seriesData.seriesZ[i2][j]);
          }
        }
      }
    }
    const bubbleCfg = ((_a = this.w.config.plotOptions) == null ? void 0 : _a.bubble) || {};
    if (Utils$1.isNumber(bubbleCfg.minZ) && bubbleCfg.minZ < gl.minZ) {
      gl.minZ = bubbleCfg.minZ;
    }
    if (Utils$1.isNumber(bubbleCfg.maxZ) && bubbleCfg.maxZ > gl.maxZ) {
      gl.maxZ = bubbleCfg.maxZ;
    }
  }
  _handleSingleDataPoint() {
    const gl = this.w.globals;
    const cnf = this.w.config;
    if (gl.minX === gl.maxX) {
      const datetimeObj = new DateTime(this.w);
      if (cnf.xaxis.type === "datetime") {
        const newMinX = datetimeObj.getDate(gl.minX);
        if (cnf.xaxis.labels.datetimeUTC) {
          newMinX.setUTCDate(newMinX.getUTCDate() - 2);
        } else {
          newMinX.setDate(newMinX.getDate() - 2);
        }
        gl.minX = new Date(newMinX).getTime();
        const newMaxX = datetimeObj.getDate(gl.maxX);
        if (cnf.xaxis.labels.datetimeUTC) {
          newMaxX.setUTCDate(newMaxX.getUTCDate() + 2);
        } else {
          newMaxX.setDate(newMaxX.getDate() + 2);
        }
        gl.maxX = new Date(newMaxX).getTime();
      } else if (cnf.xaxis.type === "numeric" || cnf.xaxis.type === "category" && !this.w.axisFlags.noLabelsProvided) {
        gl.minX = gl.minX - 2;
        gl.initialMinX = gl.minX;
        gl.maxX = gl.maxX + 2;
        gl.initialMaxX = gl.maxX;
      }
    }
  }
  _getMinXDiff() {
    const gl = this.w.globals;
    if (this.w.axisFlags.isXNumeric) {
      this.w.seriesData.seriesX.forEach((sX, si) => {
        var _a;
        if (sX.length) {
          if (sX.length === 1) {
            sX.push(
              this.w.seriesData.seriesX[gl.maxValsInArrayIndex][this.w.seriesData.seriesX[gl.maxValsInArrayIndex].length - 1]
            );
          }
          const pe = (_a = this.w.seriesData._parsedExtrema) == null ? void 0 : _a[si];
          if (pe && pe.xNumeric && pe.xSorted && pe.xref === sX && pe.len === sX.length) {
            if (pe.minXDiff < gl.minXDiff) gl.minXDiff = pe.minXDiff;
            if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
              gl.minXDiff = 0.5;
            }
            return;
          }
          let presorted = true;
          let minDiff = gl.minXDiff;
          for (let j = 1; j < sX.length; j++) {
            const d = sX[j] - sX[j - 1];
            if (d > 0) {
              if (d < minDiff) minDiff = d;
            } else if (d < 0) {
              presorted = false;
              break;
            }
          }
          if (presorted) {
            gl.minXDiff = minDiff;
            if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
              gl.minXDiff = 0.5;
            }
            return;
          }
          const seriesX = sX.slice();
          seriesX.sort((a2, b) => a2 - b);
          seriesX.forEach((s2, j) => {
            if (j > 0) {
              const xDiff = s2 - seriesX[j - 1];
              if (xDiff > 0) {
                gl.minXDiff = Math.min(xDiff, gl.minXDiff);
              }
            }
          });
          if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
            gl.minXDiff = 0.5;
          }
        }
      });
    }
  }
  _setStackedMinMax() {
    const gl = this.w.globals;
    if (!this.w.seriesData.series.length) return;
    let seriesGroups = this.w.labelData.seriesGroups;
    if (!seriesGroups.length) {
      seriesGroups = [this.w.seriesData.seriesNames.map((name2) => name2)];
    }
    const stackedPoss = {};
    const stackedNegs = {};
    seriesGroups.forEach((group) => {
      stackedPoss[group] = [];
      stackedNegs[group] = [];
      const indicesOfSeriesInGroup = this.w.config.series.map(
        (serie, si) => group.indexOf(this.w.seriesData.seriesNames[si]) > -1 ? si : null
      ).filter((f) => f !== null);
      indicesOfSeriesInGroup.forEach((i2) => {
        var _a, _b, _c, _d;
        for (let j = 0; j < this.w.seriesData.series[gl.maxValsInArrayIndex].length; j++) {
          if (typeof stackedPoss[group][j] === "undefined") {
            stackedPoss[group][j] = 0;
            stackedNegs[group][j] = 0;
          }
          const stackSeries = this.w.config.chart.stacked && !gl.comboCharts || this.w.config.chart.stacked && gl.comboCharts && (!this.w.config.chart.stackOnlyBar || /** @type {Record<string,any>} */
          ((_b = (_a = this.w.config.series) == null ? void 0 : _a[i2]) == null ? void 0 : _b.type) === "bar" || /** @type {Record<string,any>} */
          ((_d = (_c = this.w.config.series) == null ? void 0 : _c[i2]) == null ? void 0 : _d.type) === "column");
          if (stackSeries) {
            if (this.w.seriesData.series[i2][j] !== null && Utils$1.isNumber(this.w.seriesData.series[i2][j])) {
              this.w.seriesData.series[i2][j] > 0 ? stackedPoss[group][j] += parseFloat(String(this.w.seriesData.series[i2][j])) + 1e-4 : stackedNegs[group][j] += parseFloat(
                String(this.w.seriesData.series[i2][j])
              );
            }
          }
        }
      });
    });
    Object.entries(stackedPoss).forEach(([key]) => {
      stackedPoss[key].forEach(
        (_, stgi) => {
          gl.maxY = Math.max(gl.maxY, stackedPoss[key][stgi]);
          gl.minY = Math.min(gl.minY, stackedNegs[key][stgi]);
        }
      );
    });
  }
}
function getThemePalettes() {
  return {
    // All colours pass WCAG 1.4.11 non-text contrast (≥ 3:1) against the
    // default light (#fff) and dark (#293450) theme backgrounds.
    palette1: ["#008FFB", "#00A86F", "#CA8501", "#FF4560", "#846DD5"],
    palette2: ["#6978CB", "#039DE2", "#49A84D", "#B39105", "#D68000"],
    palette3: ["#209FCC", "#648291", "#D4526E", "#0FA783", "#A19285"],
    palette4: ["#2FA59D", "#73A20B", "#099DE1", "#FD5D5D", "#648291"],
    palette5: ["#2B908F", "#F56566", "#2EAB16", "#FA4443", "#1EA2BD"],
    palette6: ["#449DD1", "#F86624", "#EA3A4A", "#9C63D1", "#899E2A"],
    palette7: ["#DF475B", "#1B998B", "#7E75B7", "#F46036", "#B1911B"],
    palette8: ["#9C63D1", "#F86624", "#B38F04", "#EA3A4A", "#2FA2B3"],
    palette9: ["#98776F", "#A19285", "#A8705E", "#BA6560", "#A0927F"],
    palette10: ["#C91EFF", "#A94BFD", "#6C6AFE", "#2983FF", "#009ED8"],
    // CVD-safe palettes (Wong 2011 / IBM design)
    cvdDeuteranopia: [
      "#0072B2",
      "#E69F00",
      "#56B4E9",
      "#009E73",
      "#F0E442",
      "#D55E00",
      "#CC79A7"
    ],
    cvdProtanopia: [
      "#0077BB",
      "#EE7733",
      "#009988",
      "#EE3377",
      "#BBBBBB",
      "#33BBEE",
      "#CC3311"
    ],
    cvdTritanopia: [
      "#CC3311",
      "#009988",
      "#EE7733",
      "#0077BB",
      "#EE3377",
      "#BBBBBB",
      "#33BBEE"
    ],
    highContrast: [
      "#005A9C",
      "#C00000",
      "#007A33",
      "#6C3483",
      "#7B3F00",
      "#0097A7",
      "#4A235A"
    ]
  };
}
class YAxis {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {any} [elgrid]
   */
  constructor(w, { theme = null, timeScale = null } = {}, elgrid) {
    this.w = w;
    this.elgrid = elgrid;
    this.xaxisFontSize = w.config.xaxis.labels.style.fontSize;
    this.axisFontFamily = w.config.xaxis.labels.style.fontFamily;
    this.xaxisForeColors = w.config.xaxis.labels.style.colors;
    this.isCategoryBarHorizontal = w.config.chart.type === "bar" && w.config.plotOptions.bar.horizontal;
    this.xAxisoffX = w.config.xaxis.position === "bottom" ? w.layout.gridHeight : 0;
    this.drawnLabels = [];
    this.axesUtils = new AxesUtils(w, { theme, timeScale });
  }
  /**
   * @param {number} realIndex
   */
  drawYaxis(realIndex) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const yaxisStyle = w.config.yaxis[realIndex].labels.style;
    const {
      fontSize: yaxisFontSize,
      fontFamily: yaxisFontFamily,
      fontWeight: yaxisFontWeight
    } = yaxisStyle;
    const elYaxis = graphics.group({
      class: "apexcharts-yaxis",
      rel: realIndex,
      transform: `translate(${w.globals.translateYAxisX[realIndex]}, 0)`
    });
    if (this.axesUtils.isYAxisHidden(realIndex)) return elYaxis;
    const elYaxisTexts = graphics.group({ class: "apexcharts-yaxis-texts-g" });
    elYaxis.add(elYaxisTexts);
    const tickAmount = w.globals.yAxisScale[realIndex].result.length - 1;
    const labelsDivider = w.layout.gridHeight / tickAmount;
    const lbFormatter = w.formatters.yLabelFormatters[realIndex];
    const labels = this.axesUtils.checkForReversedLabels(
      realIndex,
      w.globals.yAxisScale[realIndex].result.slice()
    );
    let labelStep = 1;
    if (w.config.chart.type === "heatmap" && !w.config.yaxis[realIndex].labels.formatter) {
      const fs = parseInt(yaxisFontSize, 10) || 11;
      const maxLabels = Math.max(1, Math.floor(w.layout.gridHeight / (fs * 1.4)));
      const count = tickAmount + 1;
      if (count > maxLabels) labelStep = Math.ceil(count / maxLabels);
    }
    if (w.config.yaxis[realIndex].labels.show) {
      let lY = w.layout.translateY + w.config.yaxis[realIndex].labels.offsetY;
      if (w.globals.isBarHorizontal) lY = 0;
      else if (w.config.chart.type === "heatmap") lY -= labelsDivider / 2;
      lY += parseInt(yaxisFontSize, 10) / 3;
      let firstLabel = null;
      for (let i2 = tickAmount; i2 >= 0; i2--) {
        const thinned = labelStep > 1 && i2 % labelStep !== 0;
        const val = thinned ? "" : lbFormatter(labels[i2], i2, w);
        let xPad = w.config.yaxis[realIndex].labels.padding;
        if (w.config.yaxis[realIndex].opposite && w.config.yaxis.length !== 0)
          xPad *= -1;
        const textAnchor = this.getTextAnchor(
          w.config.yaxis[realIndex].labels.align,
          w.config.yaxis[realIndex].opposite
        );
        const yColors = this.axesUtils.getYAxisForeColor(
          yaxisStyle.colors,
          realIndex
        );
        const foreColor = Array.isArray(yColors) ? yColors[i2] : yColors;
        const existingYLabels = Array.from(
          w.dom.baseEl.querySelectorAll(
            `.apexcharts-yaxis[rel='${realIndex}'] .apexcharts-yaxis-label tspan`
          )
        ).map((label2) => label2.textContent);
        const label = graphics.drawText({
          x: xPad,
          y: lY,
          text: existingYLabels.includes(val) && !w.config.yaxis[realIndex].labels.showDuplicates ? "" : val,
          textAnchor,
          fontSize: yaxisFontSize,
          fontFamily: yaxisFontFamily,
          fontWeight: yaxisFontWeight,
          maxWidth: w.config.yaxis[realIndex].labels.maxWidth,
          foreColor,
          isPlainText: false,
          cssClass: `apexcharts-yaxis-label ${yaxisStyle.cssClass}`
        });
        elYaxisTexts.add(label);
        this.addTooltip(label, val);
        if (firstLabel === null) {
          firstLabel = label;
        }
        if (w.config.yaxis[realIndex].labels.rotate !== 0) {
          this.rotateLabel(
            graphics,
            label,
            firstLabel,
            w.config.yaxis[realIndex].labels.rotate
          );
        }
        lY += labelsDivider;
      }
    }
    this.addYAxisTitle(graphics, elYaxis, realIndex);
    this.addAxisBorder(graphics, elYaxis, realIndex, tickAmount, labelsDivider);
    return elYaxis;
  }
  /**
   * @param {string} align
   * @param {boolean} opposite
   */
  getTextAnchor(align, opposite) {
    if (align === "left") return "start";
    if (align === "center") return "middle";
    if (align === "right") return "end";
    return opposite ? "start" : "end";
  }
  /**
   * @param {any} label
   * @param {any} val
   */
  addTooltip(label, val) {
    const elTooltipTitle = BrowserAPIs.createElementNS(SVGNS$1, "title");
    elTooltipTitle.textContent = Array.isArray(val) ? val.join(" ") : val;
    label.node.appendChild(elTooltipTitle);
  }
  /**
   * @param {import('../Graphics').default} graphics
   * @param {any} label
   * @param {any} firstLabel
   * @param {number} rotate
   */
  rotateLabel(graphics, label, firstLabel, rotate) {
    const firstLabelCenter = graphics.rotateAroundCenter(firstLabel.node);
    const labelCenter = graphics.rotateAroundCenter(label.node);
    label.node.setAttribute(
      "transform",
      `rotate(${rotate} ${firstLabelCenter.x} ${labelCenter.y})`
    );
  }
  /**
   * @param {import('../Graphics').default} graphics
   * @param {any} elYaxis
   * @param {number} realIndex
   */
  addYAxisTitle(graphics, elYaxis, realIndex) {
    const w = this.w;
    if (w.config.yaxis[realIndex].title.text !== void 0) {
      const elYaxisTitle = graphics.group({ class: "apexcharts-yaxis-title" });
      const x = w.config.yaxis[realIndex].opposite ? w.globals.translateYAxisX[realIndex] : 0;
      const elYAxisTitleText = graphics.drawText({
        x,
        y: w.layout.gridHeight / 2 + w.layout.translateY + w.config.yaxis[realIndex].title.offsetY,
        text: w.config.yaxis[realIndex].title.text,
        textAnchor: "end",
        foreColor: w.config.yaxis[realIndex].title.style.color,
        fontSize: w.config.yaxis[realIndex].title.style.fontSize,
        fontWeight: w.config.yaxis[realIndex].title.style.fontWeight,
        fontFamily: w.config.yaxis[realIndex].title.style.fontFamily,
        cssClass: `apexcharts-yaxis-title-text ${w.config.yaxis[realIndex].title.style.cssClass}`
      });
      elYaxisTitle.add(elYAxisTitleText);
      elYaxis.add(elYaxisTitle);
    }
  }
  /**
   * @param {import('../Graphics').default} graphics
   * @param {any} elYaxis
   * @param {number} realIndex
   * @param {number} tickAmount
   * @param {number} labelsDivider
   */
  addAxisBorder(graphics, elYaxis, realIndex, tickAmount, labelsDivider) {
    const w = this.w;
    const axisBorder = w.config.yaxis[realIndex].axisBorder;
    let x = 31 + axisBorder.offsetX;
    if (w.config.yaxis[realIndex].opposite) x = -31 - axisBorder.offsetX;
    if (axisBorder.show) {
      const elVerticalLine = graphics.drawLine(
        x,
        w.layout.translateY + axisBorder.offsetY - 2,
        x,
        w.layout.gridHeight + w.layout.translateY + axisBorder.offsetY + 2,
        axisBorder.color,
        0,
        axisBorder.width
      );
      elYaxis.add(elVerticalLine);
    }
    if (w.config.yaxis[realIndex].axisTicks.show) {
      this.axesUtils.drawYAxisTicks(
        x,
        tickAmount,
        axisBorder,
        w.config.yaxis[realIndex].axisTicks,
        realIndex,
        labelsDivider,
        elYaxis
      );
    }
  }
  /**
   * @param {number} realIndex
   */
  drawYaxisInversed(realIndex) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const elXaxis = graphics.group({
      class: "apexcharts-xaxis apexcharts-yaxis-inversed"
    });
    const elXaxisTexts = graphics.group({
      class: "apexcharts-xaxis-texts-g",
      transform: `translate(${w.layout.translateXAxisX}, ${w.layout.translateXAxisY})`
    });
    elXaxis.add(elXaxisTexts);
    let tickAmount = w.globals.yAxisScale[realIndex].result.length - 1;
    const labelsDivider = w.layout.gridWidth / tickAmount + 0.1;
    let l2 = labelsDivider + w.config.xaxis.labels.offsetX;
    const lbFormatter = w.formatters.xLabelFormatter;
    let labels = this.axesUtils.checkForReversedLabels(
      realIndex,
      w.globals.yAxisScale[realIndex].result.slice()
    );
    const timescaleLabels = w.labelData.timescaleLabels;
    if (timescaleLabels.length > 0) {
      this.xaxisLabels = timescaleLabels.slice();
      labels = timescaleLabels.slice();
      tickAmount = labels.length;
    }
    if (w.config.xaxis.labels.show) {
      for (let i2 = timescaleLabels.length ? 0 : tickAmount; timescaleLabels.length ? i2 < timescaleLabels.length : i2 >= 0; timescaleLabels.length ? i2++ : i2--) {
        let val = lbFormatter == null ? void 0 : lbFormatter(labels[i2], i2, w);
        let x = w.layout.gridWidth + w.globals.padHorizontal - (l2 - labelsDivider + w.config.xaxis.labels.offsetX);
        if (timescaleLabels.length) {
          const label = this.axesUtils.getLabel(
            labels,
            timescaleLabels,
            x,
            i2,
            this.drawnLabels,
            this.xaxisFontSize
          );
          x = label.x;
          val = label.text;
          this.drawnLabels.push(label.text);
          if (i2 === 0 && w.globals.skipFirstTimelinelabel) val = "";
          if (i2 === labels.length - 1 && w.globals.skipLastTimelinelabel)
            val = "";
        }
        const elTick = graphics.drawText({
          x,
          y: this.xAxisoffX + w.config.xaxis.labels.offsetY + 30 - (w.config.xaxis.position === "top" ? w.layout.xAxisHeight + w.config.xaxis.axisTicks.height - 2 : 0),
          text: val,
          textAnchor: "middle",
          foreColor: Array.isArray(this.xaxisForeColors) ? this.xaxisForeColors[realIndex] : this.xaxisForeColors,
          fontSize: this.xaxisFontSize,
          fontFamily: this.axisFontFamily,
          fontWeight: w.config.xaxis.labels.style.fontWeight,
          isPlainText: false,
          cssClass: `apexcharts-xaxis-label ${w.config.xaxis.labels.style.cssClass}`
        });
        elXaxisTexts.add(elTick);
        this.addTooltip(elTick, val);
        l2 += labelsDivider;
      }
    }
    this.inversedYAxisTitleText(elXaxis);
    this.inversedYAxisBorder(elXaxis);
    return elXaxis;
  }
  /**
   * @param {any} parent
   */
  inversedYAxisBorder(parent) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const axisBorder = w.config.xaxis.axisBorder;
    if (axisBorder.show) {
      let lineCorrection = 0;
      if (w.config.chart.type === "bar" && w.axisFlags.isXNumeric)
        lineCorrection -= 15;
      const elHorzLine = graphics.drawLine(
        w.globals.padHorizontal + lineCorrection + axisBorder.offsetX,
        this.xAxisoffX,
        w.layout.gridWidth,
        this.xAxisoffX,
        axisBorder.color,
        0,
        axisBorder.height
      );
      if (this.elgrid && this.elgrid.elGridBorders && w.config.grid.show) {
        this.elgrid.elGridBorders.add(elHorzLine);
      } else {
        parent.add(elHorzLine);
      }
    }
  }
  /**
   * @param {any} parent
   */
  inversedYAxisTitleText(parent) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    if (w.config.xaxis.title.text !== void 0) {
      const elYaxisTitle = graphics.group({
        class: "apexcharts-xaxis-title apexcharts-yaxis-title-inversed"
      });
      const elYAxisTitleText = graphics.drawText({
        x: w.layout.gridWidth / 2 + w.config.xaxis.title.offsetX,
        y: this.xAxisoffX + parseFloat(this.xaxisFontSize) + parseFloat(w.config.xaxis.title.style.fontSize) + w.config.xaxis.title.offsetY + 20,
        text: w.config.xaxis.title.text,
        textAnchor: "middle",
        fontSize: w.config.xaxis.title.style.fontSize,
        fontFamily: w.config.xaxis.title.style.fontFamily,
        fontWeight: w.config.xaxis.title.style.fontWeight,
        foreColor: w.config.xaxis.title.style.color,
        cssClass: `apexcharts-xaxis-title-text ${w.config.xaxis.title.style.cssClass}`
      });
      elYaxisTitle.add(elYAxisTitleText);
      parent.add(elYaxisTitle);
    }
  }
  /**
   * @param {number} realIndex
   * @param {boolean} yAxisOpposite
   */
  yAxisTitleRotate(realIndex, yAxisOpposite) {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const elYAxisLabelsWrap = w.dom.baseEl.querySelector(
      `.apexcharts-yaxis[rel='${realIndex}'] .apexcharts-yaxis-texts-g`
    );
    const yAxisLabelsCoord = elYAxisLabelsWrap ? elYAxisLabelsWrap.getBoundingClientRect() : { width: 0, height: 0 };
    const yAxisTitle = w.dom.baseEl.querySelector(
      `.apexcharts-yaxis[rel='${realIndex}'] .apexcharts-yaxis-title text`
    );
    const yAxisTitleCoord = yAxisTitle ? yAxisTitle.getBoundingClientRect() : { width: 0, height: 0 };
    if (yAxisTitle) {
      const x = this.xPaddingForYAxisTitle(
        realIndex,
        yAxisLabelsCoord,
        yAxisTitleCoord,
        yAxisOpposite
      );
      yAxisTitle.setAttribute("x", String(x.xPos - (yAxisOpposite ? 10 : 0)));
      const titleRotatingCenter = graphics.rotateAroundCenter(yAxisTitle);
      yAxisTitle.setAttribute(
        "transform",
        `rotate(${yAxisOpposite ? w.config.yaxis[realIndex].title.rotate * -1 : w.config.yaxis[realIndex].title.rotate} ${titleRotatingCenter.x} ${titleRotatingCenter.y})`
      );
    }
  }
  /**
   * @param {number} realIndex
   * @param {{width: number, height: number}} yAxisLabelsCoord
   * @param {{width: number, height: number}} yAxisTitleCoord
   * @param {boolean} yAxisOpposite
   */
  xPaddingForYAxisTitle(realIndex, yAxisLabelsCoord, yAxisTitleCoord, yAxisOpposite) {
    const w = this.w;
    let x = 0;
    let padd = 10;
    if (w.config.yaxis[realIndex].title.text === void 0 || realIndex < 0) {
      return { xPos: x, padd: 0 };
    }
    if (yAxisOpposite) {
      x = yAxisLabelsCoord.width + w.config.yaxis[realIndex].title.offsetX + yAxisTitleCoord.width / 2 + padd / 2;
    } else {
      x = yAxisLabelsCoord.width * -1 + w.config.yaxis[realIndex].title.offsetX + padd / 2 + yAxisTitleCoord.width / 2;
      if (w.globals.isBarHorizontal) {
        padd = 25;
        x = yAxisLabelsCoord.width * -1 - w.config.yaxis[realIndex].title.offsetX - padd;
      }
    }
    return { xPos: x, padd };
  }
  /**
   * @param {Array<{width: number, height: number}>} yaxisLabelCoords
   * @param {Array<{width: number, height: number}>} yTitleCoords
   */
  setYAxisXPosition(yaxisLabelCoords, yTitleCoords) {
    const w = this.w;
    let xLeft = 0;
    let xRight = 0;
    let leftOffsetX = 18;
    let rightOffsetX = 1;
    if (w.config.yaxis.length > 1) this.multipleYs = true;
    w.config.yaxis.forEach((yaxe, index) => {
      const shouldNotDrawAxis = w.globals.ignoreYAxisIndexes.includes(index) || !yaxe.show || yaxe.floating || yaxisLabelCoords[index].width === 0;
      const axisWidth = yaxisLabelCoords[index].width + yTitleCoords[index].width;
      if (!yaxe.opposite) {
        xLeft = w.layout.translateX - leftOffsetX;
        if (!shouldNotDrawAxis) leftOffsetX += axisWidth + 20;
        w.globals.translateYAxisX[index] = xLeft + yaxe.labels.offsetX;
      } else {
        if (w.globals.isBarHorizontal) {
          xRight = w.layout.gridWidth + w.layout.translateX - 1;
          w.globals.translateYAxisX[index] = xRight - yaxe.labels.offsetX;
        } else {
          xRight = w.layout.gridWidth + w.layout.translateX + rightOffsetX;
          if (!shouldNotDrawAxis) rightOffsetX += axisWidth + 20;
          w.globals.translateYAxisX[index] = xRight - yaxe.labels.offsetX + 20;
        }
      }
    });
  }
  setYAxisTextAlignments() {
    const w = this.w;
    const yaxis = Array.from(
      w.dom.baseEl.getElementsByClassName("apexcharts-yaxis")
    );
    yaxis.forEach((y, index) => {
      const yaxe = w.config.yaxis[index];
      if (yaxe && !yaxe.floating && yaxe.labels.align !== void 0) {
        const yAxisInner = w.dom.baseEl.querySelector(
          `.apexcharts-yaxis[rel='${index}'] .apexcharts-yaxis-texts-g`
        );
        const yAxisTexts = Array.from(
          w.dom.baseEl.querySelectorAll(
            `.apexcharts-yaxis[rel='${index}'] .apexcharts-yaxis-label`
          )
        );
        const rect = (
          /** @type {Element} */
          yAxisInner.getBoundingClientRect()
        );
        yAxisTexts.forEach((label) => {
          label.setAttribute("text-anchor", yaxe.labels.align);
        });
        if (yaxe.labels.align === "left" && !yaxe.opposite) {
          yAxisInner.setAttribute(
            "transform",
            `translate(-${rect.width}, 0)`
          );
        } else if (yaxe.labels.align === "center") {
          yAxisInner.setAttribute(
            "transform",
            `translate(${rect.width / 2 * (!yaxe.opposite ? -1 : 1)}, 0)`
          );
        } else if (yaxe.labels.align === "right" && yaxe.opposite) {
          yAxisInner.setAttribute(
            "transform",
            `translate(${rect.width}, 0)`
          );
        }
      }
    });
  }
}
class Events {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.documentEvent = this.documentEvent.bind(this);
  }
  /**
   * @param {string} name
   * @param {Function} handler
   */
  addEventListener(name2, handler) {
    const w = this.w;
    if (Object.prototype.hasOwnProperty.call(w.globals.events, name2)) {
      w.globals.events[name2].push(handler);
    } else {
      w.globals.events[name2] = [handler];
    }
  }
  /**
   * @param {string} name
   * @param {Function} handler
   */
  removeEventListener(name2, handler) {
    const w = this.w;
    if (!Object.prototype.hasOwnProperty.call(w.globals.events, name2)) {
      return;
    }
    const index = (
      /** @type {Record<string,any>} */
      w.globals.events[name2].indexOf(handler)
    );
    if (index !== -1) {
      w.globals.events[name2].splice(
        index,
        1
      );
    }
  }
  /**
   * @param {string} name
   * @param {any[]} args
   */
  fireEvent(name2, args) {
    const w = this.w;
    if (!Object.prototype.hasOwnProperty.call(w.globals.events, name2)) {
      return;
    }
    if (!args || !args.length) {
      args = [];
    }
    const evs = (
      /** @type {Record<string,any>} */
      w.globals.events[name2]
    );
    const l2 = evs.length;
    for (let i2 = 0; i2 < l2; i2++) {
      evs[i2].apply(null, args);
    }
  }
  setupEventHandlers() {
    const w = this.w;
    const me = this.ctx;
    const clickableArea = w.dom.baseEl.querySelector(w.globals.chartClass);
    this.ctx.eventList.forEach((event) => {
      clickableArea == null ? void 0 : clickableArea.addEventListener(
        event,
        (e2) => {
          const capturedSeriesIndex = e2.target.getAttribute("i") === null && w.interact.capturedSeriesIndex !== -1 ? w.interact.capturedSeriesIndex : e2.target.getAttribute("i");
          const capturedDataPointIndex = e2.target.getAttribute("j") === null && w.interact.capturedDataPointIndex !== -1 ? w.interact.capturedDataPointIndex : e2.target.getAttribute("j");
          const opts = Object.assign({}, w, {
            seriesIndex: w.globals.axisCharts ? capturedSeriesIndex : 0,
            dataPointIndex: capturedDataPointIndex
          });
          if (e2.type === "keydown") {
            if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.keyboard.enabled) {
              if (me.ctx.keyboardNavigation) {
                me.ctx.keyboardNavigation.handleKey(e2);
              }
              if (typeof w.config.chart.events.keyDown === "function") {
                w.config.chart.events.keyDown(e2, me, opts);
              }
              me.ctx.events.fireEvent("keydown", [e2, me, opts]);
            }
          } else if (e2.type === "keyup") {
            if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.keyboard.enabled) {
              if (typeof w.config.chart.events.keyUp === "function") {
                w.config.chart.events.keyUp(e2, me, opts);
              }
              me.ctx.events.fireEvent("keyup", [e2, me, opts]);
            }
          } else if (e2.type === "mousemove" || e2.type === "touchmove") {
            if (typeof w.config.chart.events.mouseMove === "function") {
              w.config.chart.events.mouseMove(e2, me, opts);
            }
          } else if (e2.type === "mouseleave" || e2.type === "touchleave") {
            if (typeof w.config.chart.events.mouseLeave === "function") {
              w.config.chart.events.mouseLeave(e2, me, opts);
            }
          } else if (e2.type === "mouseup" && e2.which === 1 || e2.type === "touchend") {
            if (typeof w.config.chart.events.click === "function") {
              w.config.chart.events.click(e2, me, opts);
            }
            me.ctx.events.fireEvent("click", [e2, me, opts]);
          }
        },
        { capture: false, passive: true }
      );
    });
    this.ctx.eventList.forEach((event) => {
      w.dom.baseEl.addEventListener(event, this.documentEvent, {
        passive: true
      });
    });
    this.ctx.core.setupBrushHandler();
  }
  /**
   * @param {any} e
   */
  documentEvent(e2) {
    const w = this.w;
    const target = e2.target.className;
    if (e2.type === "click") {
      const elMenu = w.dom.baseEl.querySelector(".apexcharts-menu");
      if (elMenu && elMenu.classList.contains("apexcharts-menu-open") && target !== "apexcharts-menu-icon") {
        elMenu.classList.remove("apexcharts-menu-open");
      }
    }
    w.interact.clientX = e2.type === "touchmove" ? e2.touches[0].clientX : e2.clientX;
    w.interact.clientY = e2.type === "touchmove" ? e2.touches[0].clientY : e2.clientY;
  }
}
class Localization {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
  }
  /**
   * @param {string} localeName
   */
  setCurrentLocaleValues(localeName) {
    let locales = this.w.config.chart.locales;
    const globalApex = Environment.getApex();
    if (globalApex.chart && globalApex.chart.locales && globalApex.chart.locales.length > 0) {
      locales = this.w.config.chart.locales.concat(globalApex.chart.locales);
    }
    const selectedLocale = locales.filter(
      (c2) => c2.name === localeName
    )[0];
    if (selectedLocale) {
      const ret = Utils$1.extend(en, selectedLocale);
      this.w.globals.locale = ret.options;
    } else {
      throw new Error(
        "Wrong locale name provided. Please make sure you set the correct locale name in options"
      );
    }
  }
}
class Axes {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
  }
  /**
   * @param {string} type
   * @param {any} elgrid
   */
  drawAxis(type, elgrid) {
    const gl = this.w.globals;
    const cnf = this.w.config;
    const xAxis = new XAxis(this.w, this.ctx, elgrid);
    const yAxis = new YAxis(this.w, { theme: this.ctx.theme, timeScale: this.ctx.timeScale }, elgrid);
    if (gl.axisCharts && type !== "radar") {
      let elXaxis, elYaxis;
      if (gl.isBarHorizontal) {
        elYaxis = yAxis.drawYaxisInversed(0);
        elXaxis = xAxis.drawXaxisInversed(0);
        this.w.dom.elGraphical.add(elXaxis);
        this.w.dom.elGraphical.add(elYaxis);
      } else {
        elXaxis = xAxis.drawXaxis();
        this.w.dom.elGraphical.add(elXaxis);
        cnf.yaxis.map((yaxe, index) => {
          if (gl.ignoreYAxisIndexes.indexOf(index) === -1) {
            elYaxis = yAxis.drawYaxis(index);
            this.w.dom.Paper.add(elYaxis);
            if (this.w.config.grid.position === "back") {
              const inner = this.w.dom.Paper.children()[1];
              if (inner) {
                inner.remove();
                this.w.dom.Paper.add(inner);
              }
            }
          }
        });
      }
    }
  }
}
class Crosshairs {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
  }
  drawXCrosshairs() {
    const w = this.w;
    w.dom.elGraphical.node.querySelectorAll(":scope > .apexcharts-xcrosshairs").forEach((el) => el.remove());
    const graphics = new Graphics(this.w);
    const filters = new Filters(this.w);
    const crosshairGradient = w.config.xaxis.crosshairs.fill.gradient;
    const crosshairShadow = w.config.xaxis.crosshairs.dropShadow;
    const fillType = w.config.xaxis.crosshairs.fill.type;
    const gradientFrom = crosshairGradient.colorFrom;
    const gradientTo = crosshairGradient.colorTo;
    const opacityFrom = crosshairGradient.opacityFrom;
    const opacityTo = crosshairGradient.opacityTo;
    const stops = crosshairGradient.stops;
    const shadow = "none";
    const dropShadow = crosshairShadow.enabled;
    const shadowLeft = crosshairShadow.left;
    const shadowTop = crosshairShadow.top;
    const shadowBlur = crosshairShadow.blur;
    const shadowColor = crosshairShadow.color;
    const shadowOpacity = crosshairShadow.opacity;
    let xcrosshairsFill = w.config.xaxis.crosshairs.fill.color;
    if (w.config.xaxis.crosshairs.show) {
      if (fillType === "gradient") {
        xcrosshairsFill = graphics.drawGradient(
          "vertical",
          gradientFrom,
          gradientTo,
          opacityFrom,
          opacityTo,
          null,
          stops,
          []
        );
      }
      let xcrosshairs = w.config.xaxis.crosshairs.width === 1 ? graphics.drawLine(0, 0, 0, 0) : graphics.drawRect();
      let gridHeight = w.layout.gridHeight;
      if (!Utils$1.isNumber(gridHeight) || gridHeight < 0) {
        gridHeight = 0;
      }
      let crosshairsWidth = w.config.xaxis.crosshairs.width;
      if (!Utils$1.isNumber(crosshairsWidth) || Number(crosshairsWidth) < 0) {
        crosshairsWidth = 0;
      }
      xcrosshairs.attr({
        class: "apexcharts-xcrosshairs",
        x: 0,
        y: 0,
        y2: gridHeight,
        width: crosshairsWidth,
        height: gridHeight,
        fill: xcrosshairsFill,
        filter: shadow,
        "fill-opacity": w.config.xaxis.crosshairs.opacity,
        stroke: w.config.xaxis.crosshairs.stroke.color,
        "stroke-width": w.config.xaxis.crosshairs.stroke.width,
        "stroke-dasharray": w.config.xaxis.crosshairs.stroke.dashArray
      });
      if (dropShadow) {
        xcrosshairs = filters.dropShadow(xcrosshairs, {
          left: shadowLeft,
          top: shadowTop,
          blur: shadowBlur,
          color: shadowColor,
          opacity: shadowOpacity
        });
      }
      w.dom.elGraphical.add(xcrosshairs);
    }
  }
  drawYCrosshairs() {
    const w = this.w;
    w.dom.elGraphical.node.querySelectorAll(
      ":scope > .apexcharts-ycrosshairs, :scope > .apexcharts-ycrosshairs-hidden"
    ).forEach((el) => el.remove());
    const graphics = new Graphics(this.w);
    const crosshair = (
      /** @type {any[]} */
      w.config.yaxis[0].crosshairs
    );
    const offX = w.globals.barPadForNumericAxis;
    if (
      /** @type {any[]} */
      w.config.yaxis[0].crosshairs.show
    ) {
      const ycrosshairs = graphics.drawLine(
        -offX,
        0,
        w.layout.gridWidth + offX,
        0,
        crosshair.stroke.color,
        crosshair.stroke.dashArray,
        crosshair.stroke.width
      );
      ycrosshairs.attr({
        class: "apexcharts-ycrosshairs"
      });
      w.dom.elGraphical.add(ycrosshairs);
    }
    const ycrosshairsHidden = graphics.drawLine(
      -offX,
      0,
      w.layout.gridWidth + offX,
      0,
      crosshair.stroke.color,
      0,
      0
    );
    ycrosshairsHidden.attr({
      class: "apexcharts-ycrosshairs-hidden"
    });
    w.dom.elGraphical.add(ycrosshairsHidden);
  }
}
function mergeYaxisOverride(base, override) {
  if (!Utils$1.isObject(base) || !Utils$1.isObject(override)) {
    return override !== void 0 ? override : base;
  }
  const out = __spreadValues({}, base);
  for (const key of Object.keys(override)) {
    const v = override[key];
    if (v === void 0) continue;
    if (Utils$1.isObject(v) && Utils$1.isObject(base[key])) {
      out[key] = mergeYaxisOverride(base[key], v);
    } else {
      out[key] = v;
    }
  }
  return out;
}
class Responsive {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this._activeBreakpoint = null;
  }
  // the opts parameter if not null has to be set overriding everything
  // as the opts is set by user externally
  /**
   * @param {object} opts
   */
  checkResponsiveConfig(opts) {
    const w = this.w;
    const cnf = w.config;
    if (cnf.responsive.length === 0) return;
    const res = cnf.responsive.slice();
    res.sort(
      (a2, b) => a2.breakpoint > b.breakpoint ? 1 : b.breakpoint > a2.breakpoint ? -1 : 0
    ).reverse();
    const config = new Config({});
    const iterateResponsiveOptions = (newOptions = {}) => {
      var _a;
      const largestBreakpoint = res[0].breakpoint;
      const width = Environment.isBrowser() ? window.innerWidth > 0 ? window.innerWidth : screen.width : 0;
      if (width > largestBreakpoint) {
        if (this._activeBreakpoint !== null) {
          if (!w.globals.initialConfig) return;
          const initialConfig = Utils$1.clone(w.globals.initialConfig);
          initialConfig.series = Utils$1.clone(w.config.series);
          const options2 = CoreUtils.extendArrayProps(config, initialConfig, w);
          newOptions = Utils$1.extend(options2, newOptions);
          this.overrideResponsiveOptions(newOptions);
          this._activeBreakpoint = null;
        }
      } else {
        for (let i2 = 0; i2 < res.length; i2++) {
          if (width < res[i2].breakpoint) {
            const originalUserYaxis = ((_a = res[i2].options) == null ? void 0 : _a.yaxis) ? Utils$1.clone(res[i2].options.yaxis) : null;
            newOptions = CoreUtils.extendArrayProps(config, res[i2].options, w);
            newOptions = Utils$1.extend(w.config, newOptions);
            if (Array.isArray(w.config.yaxis) && originalUserYaxis) {
              const userYaxis = Array.isArray(originalUserYaxis) ? originalUserYaxis : [originalUserYaxis];
              newOptions = __spreadProps(__spreadValues({}, newOptions), {
                yaxis: w.config.yaxis.map(
                  (baseAxis, idx) => mergeYaxisOverride(baseAxis, userYaxis[idx])
                )
              });
            }
            this.overrideResponsiveOptions(newOptions);
            this._activeBreakpoint = res[i2].breakpoint;
          }
        }
      }
    };
    if (opts) {
      let options2 = CoreUtils.extendArrayProps(config, opts, w);
      options2 = Utils$1.extend(w.config, options2);
      options2 = Utils$1.extend(options2, opts);
      iterateResponsiveOptions(options2);
    } else {
      iterateResponsiveOptions({});
    }
  }
  /**
   * @param {Record<string, any>} newOptions
   */
  overrideResponsiveOptions(newOptions) {
    const newConfig = new Config(newOptions).init({ responsiveOverride: true });
    this.w.config = /** @type {any} */
    newConfig;
  }
}
function captureStreamFrame(w) {
  var _a, _b, _c;
  const gl = w.globals;
  gl.streamScrolled = false;
  if (!gl.axisCharts || !w.seriesData || !Array.isArray(w.seriesData.series) || w.seriesData.series.length === 0) {
    gl.prevStreamFrame = null;
    return;
  }
  const rPixels = [];
  if ((_b = (_a = w.dom) == null ? void 0 : _a.baseEl) == null ? void 0 : _b.querySelectorAll) {
    w.dom.baseEl.querySelectorAll(".apexcharts-marker").forEach((node) => {
      var _a2, _b2, _c2, _d, _e;
      const ri = parseInt((_a2 = node.getAttribute("index")) != null ? _a2 : "", 10);
      const j = parseInt(
        (_c2 = (_b2 = node.getAttribute("j")) != null ? _b2 : node.getAttribute("rel")) != null ? _c2 : "",
        10
      );
      const r2 = parseFloat(
        (_e = (_d = node.getAttribute("r")) != null ? _d : node.getAttribute("default-marker-size")) != null ? _e : ""
      );
      if (isFinite(ri) && isFinite(j) && isFinite(r2)) {
        (rPixels[ri] = rPixels[ri] || [])[j] = r2;
      }
    });
  }
  gl.prevStreamFrame = {
    seriesX: (w.seriesData.seriesX || []).slice(),
    seriesY: w.seriesData.series.slice(),
    xPixels: (gl.seriesXvalues || []).slice(),
    yPixels: (gl.seriesYvalues || []).slice(),
    rPixels,
    labels: (gl.labels || []).slice(),
    isXNumeric: !!((_c = w.axisFlags) == null ? void 0 : _c.isXNumeric)
  };
}
function trimStreamingSeries(newSeries, w) {
  const cfg = w.config.chart.streaming;
  if (!cfg || !cfg.enabled) return;
  const maxPoints = cfg.maxPoints;
  const range = w.config.xaxis.range;
  const xOf = (p) => {
    if (p == null) return null;
    if (Array.isArray(p)) return typeof p[0] === "number" ? p[0] : null;
    if (typeof p === "object") return typeof p.x === "number" ? p.x : null;
    return null;
  };
  newSeries.forEach((s2) => {
    var _a;
    const data = s2 == null ? void 0 : s2.data;
    if (!Array.isArray(data) || data.length < 2) return;
    if (typeof maxPoints === "number" && maxPoints > 0) {
      if (data.length > maxPoints) s2.data = data.slice(data.length - maxPoints);
      return;
    }
    if (!range) return;
    const lastX = xOf(data[data.length - 1]);
    const firstX = xOf(data[0]);
    if (lastX == null || firstX == null || lastX <= firstX) return;
    const avgSpacing = (lastX - firstX) / (data.length - 1);
    const cutoff = lastX - range - 2 * avgSpacing;
    let idx = 0;
    while (idx < data.length && ((_a = xOf(data[idx])) != null ? _a : cutoff) < cutoff) idx++;
    if (idx > 0) s2.data = data.slice(idx);
  });
}
function lengthTransitionEnabled(w) {
  var _a;
  const anim = w.config.chart.animations;
  if (!anim || anim.enabled === false) return false;
  if (!anim.dynamicAnimation || anim.dynamicAnimation.enabled === false) {
    return false;
  }
  const largeThreshold = (_a = anim.largeDatasetThreshold) != null ? _a : 0;
  if (largeThreshold > 0 && w.globals.dataPoints > largeThreshold) return false;
  return !!(Environment.isBrowser() && w.globals.dataChanged && w.globals.shouldAnimate);
}
function datumKey(w, realIndex, j) {
  var _a, _b, _c, _d;
  if ((_a = w.axisFlags) == null ? void 0 : _a.isXNumeric) {
    const sx = (_c = (_b = w.seriesData) == null ? void 0 : _b.seriesX) == null ? void 0 : _c[realIndex];
    if (sx && sx.length && sx[j] != null) return "x:" + sx[j];
  }
  const lbl = (_d = w.globals.labels) == null ? void 0 : _d[j];
  if (lbl != null && String(lbl) !== "") {
    return "c:" + (Array.isArray(lbl) ? lbl.join(" ") : String(lbl));
  }
  return "j:" + j;
}
function frameDatumKey(frame, realIndex, j) {
  var _a, _b;
  if (frame.isXNumeric) {
    const sx = (_a = frame.seriesX) == null ? void 0 : _a[realIndex];
    if (sx && sx.length && sx[j] != null) return "x:" + sx[j];
  }
  const lbl = (_b = frame.labels) == null ? void 0 : _b[j];
  if (lbl != null && String(lbl) !== "") {
    return "c:" + (Array.isArray(lbl) ? lbl.join(" ") : String(lbl));
  }
  return "j:" + j;
}
function joinKeys(oldKeys, newKeys) {
  const oldIndex = /* @__PURE__ */ new Map();
  oldKeys.forEach((k, i2) => {
    if (!oldIndex.has(k)) oldIndex.set(k, i2);
  });
  const toOld = new Array(newKeys.length);
  const usedOld = /* @__PURE__ */ new Set();
  let prev = -1;
  let ordered = true;
  let identity = oldKeys.length === newKeys.length;
  newKeys.forEach((k, i2) => {
    const oi = oldIndex.has(k) && !usedOld.has(oldIndex.get(k)) ? oldIndex.get(k) : -1;
    toOld[i2] = oi;
    if (oi !== -1) {
      usedOld.add(oi);
      if (oi < prev) ordered = false;
      prev = oi;
    }
    if (oi !== i2) identity = false;
  });
  const exits = [];
  for (let i2 = 0; i2 < oldKeys.length; i2++) {
    if (!usedOld.has(i2)) exits.push(i2);
  }
  return { toOld, exits, ordered, changed: !identity };
}
function uniquifyKeys(keys) {
  const seen = /* @__PURE__ */ new Map();
  return keys.map((k) => {
    const count = seen.get(k) || 0;
    seen.set(k, count + 1);
    return count === 0 ? k : `${k}#${count}`;
  });
}
function seriesJoin(w, realIndex, includeIdentity = false, allowReorder = false) {
  var _a, _b;
  if (!lengthTransitionEnabled(w)) return null;
  const frame = w.globals.prevStreamFrame;
  if (!frame) return null;
  const oldY = (_a = frame.seriesY) == null ? void 0 : _a[realIndex];
  const newY = (_b = w.seriesData.series) == null ? void 0 : _b[realIndex];
  if (!Array.isArray(oldY) || !Array.isArray(newY)) return null;
  if (!oldY.length || !newY.length) return null;
  const oldKeys = uniquifyKeys(
    oldY.map((_, j) => frameDatumKey(frame, realIndex, j))
  );
  const newKeys = uniquifyKeys(newY.map((_, j) => datumKey(w, realIndex, j)));
  const join = joinKeys(oldKeys, newKeys);
  if (!join.ordered && !allowReorder) return null;
  if (!join.changed && !includeIdentity) return null;
  return { join, oldKeys, newKeys };
}
function morphEasing(w) {
  var _a, _b;
  const anim = w.config.chart.animations;
  return resolveEasing((_b = (_a = anim.dynamicAnimation) == null ? void 0 : _a.easing) != null ? _b : anim.easing);
}
function rafTween(w, duration, ease, onFrame, onDone) {
  const startAt = performance.now();
  const step = (now) => {
    if (w.globals.isDestroyed) return;
    const raw = Math.max(0, Math.min(1, (now - startAt) / duration));
    onFrame(ease(raw), raw);
    if (raw < 1) {
      BrowserAPIs.requestAnimationFrame(step);
    } else if (onDone) {
      onDone();
    }
  };
  BrowserAPIs.requestAnimationFrame(step);
}
function grabLabels(root, sel, posAttr) {
  return [...root.querySelectorAll(sel)].map((el) => {
    var _a, _b, _c;
    return {
      // `text` is the matching KEY (textContent, which doubles tspan + title
      // but does so consistently on both sides); `display` is the visible
      // string, used when rendering an exit ghost.
      text: el.textContent || "",
      display: (_c = (_b = (_a = el.querySelector("tspan")) == null ? void 0 : _a.textContent) != null ? _b : el.textContent) != null ? _c : "",
      pos: parseFloat(el.getAttribute(posAttr) || ""),
      transform: el.getAttribute("transform")
    };
  });
}
function grabLines(root, sel, posAttr) {
  return [...root.querySelectorAll(sel)].map(
    (el) => parseFloat(el.getAttribute(posAttr) || "")
  );
}
const NO_GHOST = ":not(.apexcharts-tick-ghost)";
const X_LABELS_SEL = `.apexcharts-xaxis-texts-g text:not(.apexcharts-xaxis-group-label)${NO_GHOST}`;
const Y_LABELS_SEL = `.apexcharts-yaxis-texts-g text${NO_GHOST}`;
const V_GRID_SEL = `.apexcharts-gridlines-vertical line${NO_GHOST}`;
const H_GRID_SEL = `.apexcharts-gridlines-horizontal line${NO_GHOST}`;
function currentXScale(w) {
  var _a, _b;
  const gl = w.globals;
  if (!((_a = w.axisFlags) == null ? void 0 : _a.isXNumeric) || gl.isBarHorizontal) return null;
  if ((_b = w.config.xaxis) == null ? void 0 : _b.reversed) return null;
  const min = gl.minX;
  const max = gl.maxX;
  const width = w.layout.gridWidth;
  if (!isFinite(min) || !isFinite(max) || !(max > min) || !(width > 0)) {
    return null;
  }
  return { min, max, width };
}
function currentYAnchors(w, labels) {
  var _a;
  const gl = w.globals;
  if (gl.isBarHorizontal) return null;
  if (!Array.isArray(w.config.yaxis) || w.config.yaxis.length !== 1) return null;
  if ((_a = w.config.yaxis[0]) == null ? void 0 : _a.logarithmic) return null;
  const min = gl.minY;
  const max = gl.maxY;
  if (!isFinite(min) || !isFinite(max) || !(max > min)) return null;
  const ps = labels.map((l2) => l2.pos).filter((p) => isFinite(p));
  if (ps.length < 2) return null;
  return { min, max, pLo: Math.max(...ps), pHi: Math.min(...ps) };
}
function composeXMap(o2, n2) {
  if (!o2 || !n2) return null;
  const os = o2.max - o2.min;
  const ns = n2.max - n2.min;
  if (!(os > 0) || !(ns > 0) || !(o2.width > 0) || !(n2.width > 0)) return null;
  return {
    toNew: (p) => (o2.min + p / o2.width * os - n2.min) / ns * n2.width,
    toOld: (p) => (n2.min + p / n2.width * ns - o2.min) / os * o2.width
  };
}
function composeYMap(o2, n2) {
  if (!o2 || !n2) return null;
  const oSpanP = o2.pHi - o2.pLo;
  const nSpanP = n2.pHi - n2.pLo;
  const oSpanV = o2.max - o2.min;
  const nSpanV = n2.max - n2.min;
  if (!oSpanP || !nSpanP || !(oSpanV > 0) || !(nSpanV > 0)) return null;
  const oldVal = (p) => o2.min + (p - o2.pLo) / oSpanP * oSpanV;
  const newVal = (p) => n2.min + (p - n2.pLo) / nSpanP * nSpanV;
  return {
    toNew: (p) => n2.pLo + (oldVal(p) - n2.min) / nSpanV * nSpanP,
    toOld: (p) => o2.pLo + (newVal(p) - o2.min) / oSpanV * oSpanP
  };
}
function captureAxisChrome(w) {
  const gl = w.globals;
  gl.prevChromeFrame = null;
  if (!gl.axisCharts || !Environment.isBrowser()) return;
  const root = w.dom.baseEl;
  if (!Utils$1.elementExists(root)) return;
  try {
    const yLabels = grabLabels(root, Y_LABELS_SEL, "y");
    gl.prevChromeFrame = {
      xLabels: grabLabels(root, X_LABELS_SEL, "x"),
      yLabels,
      vGrid: grabLines(root, V_GRID_SEL, "x1"),
      hGrid: grabLines(root, H_GRID_SEL, "y1"),
      // Value scales of the outgoing render, so ticks whose TEXT has no
      // counterpart (e.g. a zoom across datetime granularities) can still be
      // re-projected: new ticks slide in from where their value sat, old
      // ticks ghost out to where their value lands.
      xScale: currentXScale(w),
      yAnchors: currentYAnchors(w, yLabels)
    };
  } catch (_) {
    gl.prevChromeFrame = null;
  }
}
function fadeIn$1(w, node, duration, ease) {
  const style = (
    /** @type {any} */
    node.style
  );
  style.opacity = "0";
  rafTween(
    w,
    duration,
    ease,
    (eased) => {
      style.opacity = String(eased);
    },
    () => {
      style.opacity = "";
    }
  );
}
function tweenPos(w, node, attrs, from, to, duration, ease) {
  attrs.forEach((a2) => node.setAttribute(a2, String(from)));
  rafTween(
    w,
    duration,
    ease,
    (eased) => {
      const v = String(from + (to - from) * eased);
      attrs.forEach((a2) => node.setAttribute(a2, v));
    },
    () => {
      attrs.forEach((a2) => node.setAttribute(a2, String(to)));
    }
  );
}
function spawnGhost(w, { template, display, attrs, from, to, duration, ease }) {
  const parent = template.parentNode;
  if (!parent) return;
  const ghost = (
    /** @type {Element} */
    template.cloneNode(true)
  );
  ghost.classList.add("apexcharts-tick-ghost");
  ghost.setAttribute("pointer-events", "none");
  ghost.removeAttribute("id");
  if (display !== void 0) {
    const tspan = ghost.querySelector("tspan");
    if (tspan) tspan.textContent = display;
    else ghost.textContent = display;
    const title = ghost.querySelector("title");
    if (title) title.textContent = display;
  }
  attrs.forEach((a2) => ghost.setAttribute(a2, String(from)));
  const style = (
    /** @type {any} */
    ghost.style
  );
  style.opacity = "1";
  parent.appendChild(ghost);
  rafTween(
    w,
    duration,
    ease,
    (eased) => {
      const v = String(from + (to - from) * eased);
      attrs.forEach((a2) => ghost.setAttribute(a2, v));
      style.opacity = String(1 - eased);
    },
    () => {
      if (ghost.parentNode) ghost.parentNode.removeChild(ghost);
    }
  );
}
const MAX_GHOSTS = 20;
function transitionAxis(w, {
  newLabels,
  oldLabels,
  posAttr,
  newLines,
  oldLines,
  lineAttrs,
  duration,
  ease,
  project
}) {
  const oldByText = /* @__PURE__ */ new Map();
  oldLabels.forEach((l2, i2) => {
    if (!oldByText.has(l2.text)) oldByText.set(l2.text, __spreadProps(__spreadValues({}, l2), { i: i2 }));
  });
  const matchedOld = /* @__PURE__ */ new Set();
  const newLinesAligned = newLines.length === newLabels.length;
  const oldLinesAligned = oldLines.length === oldLabels.length;
  const spanPs = oldLabels.map((l2) => l2.pos).concat(
    newLabels.map((l2) => parseFloat(l2.getAttribute(posAttr) || ""))
  ).filter((p) => isFinite(p));
  const spanLo = Math.min(...spanPs);
  const spanHi = Math.max(...spanPs);
  const margin = Math.max(40, (spanHi - spanLo) * 0.25);
  const clamp = (p) => Math.max(spanLo - margin, Math.min(spanHi + margin, p));
  const tweenPairedLine = (line, old) => {
    if (!line) return;
    const lineTo = parseFloat(line.getAttribute(lineAttrs[0]) || "");
    const lineFrom = oldLines[old.i];
    if (isFinite(lineTo) && isFinite(lineFrom)) {
      tweenPos(w, line, lineAttrs, lineFrom, lineTo, duration, ease);
    }
  };
  newLabels.forEach((label, i2) => {
    const to = parseFloat(label.getAttribute(posAttr) || "");
    const old = oldByText.get(label.textContent || "");
    const line = newLinesAligned ? newLines[i2] : null;
    if (old) matchedOld.add(old.i);
    const labelTransform = label.getAttribute("transform");
    if (!old || !isFinite(old.pos)) {
      if (!old) {
        if (project && isFinite(to) && !labelTransform) {
          const from = isFinite(project.toOld(to)) ? clamp(project.toOld(to)) : NaN;
          if (isFinite(from) && Math.abs(from - to) > 0.5) {
            tweenPos(w, label, [posAttr], from, to, duration, ease);
            if (line) tweenPos(w, line, lineAttrs, from, to, duration, ease);
          }
        }
        fadeIn$1(w, label, duration, ease);
        if (line) fadeIn$1(w, line, duration, ease);
      }
      return;
    }
    if (!isFinite(to) || Math.abs(old.pos - to) < 0.5) return;
    if (labelTransform || old.transform) {
      const delta = old.pos - to;
      if (isFinite(delta)) {
        const base = labelTransform || "";
        rafTween(
          w,
          duration,
          ease,
          (eased) => {
            const v = delta * (1 - eased);
            const t2 = posAttr === "x" ? `translate(${v} 0)` : `translate(0 ${v})`;
            label.setAttribute("transform", `${t2} ${base}`.trim());
          },
          () => {
            if (base) label.setAttribute("transform", base);
            else label.removeAttribute("transform");
          }
        );
      }
      tweenPairedLine(line, old);
      return;
    }
    tweenPos(w, label, [posAttr], old.pos, to, duration, ease);
    tweenPairedLine(line, old);
  });
  if (!project || !newLabels.length) return;
  let ghosts = 0;
  oldLabels.forEach((old, i2) => {
    if (matchedOld.has(i2)) return;
    if (!isFinite(old.pos) || old.transform) return;
    if (ghosts >= MAX_GHOSTS) return;
    const rawTo = project.toNew(old.pos);
    if (!isFinite(rawTo) || Math.abs(rawTo - old.pos) < 0.5) return;
    ghosts++;
    spawnGhost(w, {
      template: newLabels[0],
      display: old.display,
      attrs: [posAttr],
      from: old.pos,
      to: clamp(rawTo),
      duration,
      ease
    });
    if (oldLinesAligned && newLines.length && isFinite(oldLines[i2])) {
      spawnGhost(w, {
        template: newLines[0],
        attrs: lineAttrs,
        from: oldLines[i2],
        to: clamp(project.toNew(oldLines[i2])),
        duration,
        ease
      });
    }
  });
}
function applyAxisTransition(w) {
  const gl = w.globals;
  const chrome = gl.prevChromeFrame;
  gl.prevChromeFrame = null;
  if (!chrome || !gl.axisCharts || !Environment.isBrowser()) return;
  if (!lengthTransitionEnabled(w)) return;
  const anyMotion = (w.seriesData.series || []).some(
    (_, i2) => seriesJoin(w, i2, true, true) !== null
  );
  if (!anyMotion) return;
  const root = w.dom.baseEl;
  if (!Utils$1.elementExists(root)) return;
  const duration = Math.max(1, w.config.chart.animations.dynamicAnimation.speed || 1);
  const ease = morphEasing(w);
  try {
    const newYLabels = [...root.querySelectorAll(Y_LABELS_SEL)];
    const projX = composeXMap(chrome.xScale, currentXScale(w));
    const projY = composeYMap(
      chrome.yAnchors,
      currentYAnchors(
        w,
        newYLabels.map((el) => ({
          pos: parseFloat(el.getAttribute("y") || "")
        }))
      )
    );
    transitionAxis(w, {
      newLabels: [...root.querySelectorAll(X_LABELS_SEL)],
      oldLabels: chrome.xLabels,
      posAttr: "x",
      newLines: [...root.querySelectorAll(V_GRID_SEL)],
      oldLines: chrome.vGrid,
      lineAttrs: ["x1", "x2"],
      duration,
      ease,
      project: projX
    });
    transitionAxis(w, {
      newLabels: newYLabels,
      oldLabels: chrome.yLabels,
      posAttr: "y",
      newLines: [...root.querySelectorAll(H_GRID_SEL)],
      oldLines: chrome.hGrid,
      lineAttrs: ["y1", "y2"],
      duration,
      ease,
      project: projY
    });
  } catch (_) {
  }
}
const DL_GROUP_SEL = ".apexcharts-data-labels[data\\:dlKey]";
const DL_TEXT_SEL = ".apexcharts-datalabel";
const DL_TOTAL_SEL = ".apexcharts-datalabel-total[data\\:dlTotalKey]";
function dataLabelMotionEnabled(w) {
  var _a, _b;
  const dl = w.config.dataLabels;
  return !!(((_a = dl == null ? void 0 : dl.animate) == null ? void 0 : _a.enabled) || ((_b = dl == null ? void 0 : dl.countUp) == null ? void 0 : _b.enabled));
}
function decimalsOf(n2) {
  if (!isFinite(n2)) return 0;
  const s2 = String(Math.abs(n2));
  const e2 = s2.indexOf("e");
  if (e2 !== -1) {
    const mantissa = s2.slice(0, e2);
    const exp = parseInt(s2.slice(e2 + 1), 10);
    const dot2 = mantissa.indexOf(".");
    const mantissaDec = dot2 === -1 ? 0 : mantissa.length - dot2 - 1;
    return Math.min(6, Math.max(0, mantissaDec - exp));
  }
  const dot = s2.indexOf(".");
  return dot === -1 ? 0 : Math.min(6, s2.length - dot - 1);
}
function writeLabel(textEl, s2) {
  const tspan = textEl.querySelector("tspan");
  if (tspan) tspan.textContent = s2;
  else textEl.textContent = s2;
}
function captureDataLabels(w) {
  const gl = w.globals;
  gl.prevDataLabels = null;
  if (!gl.axisCharts || !Environment.isBrowser()) return;
  if (!dataLabelMotionEnabled(w)) return;
  const root = w.dom.baseEl;
  if (!Utils$1.elementExists(root)) return;
  try {
    const map = /* @__PURE__ */ new Map();
    root.querySelectorAll(DL_GROUP_SEL).forEach((group) => {
      const key = group.getAttribute("data:dlKey");
      if (!key) return;
      const textEl = group.querySelector(DL_TEXT_SEL);
      if (!textEl) return;
      map.set(key, {
        cx: parseFloat(textEl.getAttribute("cx") || ""),
        cy: parseFloat(textEl.getAttribute("cy") || ""),
        val: parseFloat(group.getAttribute("data:dlVal") || "")
      });
    });
    root.querySelectorAll(DL_TOTAL_SEL).forEach((el) => {
      const key = el.getAttribute("data:dlTotalKey");
      if (!key) return;
      map.set(`total::${key}`, {
        cx: parseFloat(el.getAttribute("cx") || ""),
        cy: parseFloat(el.getAttribute("cy") || ""),
        val: parseFloat(el.getAttribute("data:dlTotalVal") || "")
      });
    });
    gl.prevDataLabels = map.size ? map : null;
  } catch (_) {
    gl.prevDataLabels = null;
  }
}
function fadeIn(w, node, duration, ease) {
  const style = (
    /** @type {any} */
    node.style
  );
  style.opacity = "0";
  rafTween(
    w,
    duration,
    ease,
    (eased) => {
      style.opacity = String(eased);
    },
    () => {
      style.opacity = "";
    }
  );
}
function rideTo(w, { el, oldCx, oldCy, duration, ease, delay = 0 }) {
  const anchor = el.hasAttribute("cx") ? el : el.querySelector(DL_TEXT_SEL);
  if (!anchor) return;
  const dx = oldCx - parseFloat(anchor.getAttribute("cx") || "");
  const dy = oldCy - parseFloat(anchor.getAttribute("cy") || "");
  if (!isFinite(dx) || !isFinite(dy)) return;
  if (Math.abs(dx) + Math.abs(dy) <= 0.5) return;
  const base = el.getAttribute("transform") || "";
  const start = () => rafTween(
    w,
    duration,
    ease,
    (eased) => {
      const t2 = 1 - eased;
      el.setAttribute("transform", `translate(${dx * t2} ${dy * t2}) ${base}`.trim());
    },
    () => {
      if (base) el.setAttribute("transform", base);
      else el.removeAttribute("transform");
    }
  );
  if (delay > 0) {
    el.setAttribute("transform", `translate(${dx} ${dy}) ${base}`.trim());
    setTimeout(() => {
      if (w.globals.isDestroyed) return;
      start();
    }, delay);
  } else {
    start();
  }
}
function countUpText(w, { el, from, to, formatter, fmtOpts, duration, ease, delay = 0 }) {
  if (!isFinite(from) || !isFinite(to)) return;
  if (Math.abs(to - from) <= 1e-9) return;
  const dec = Math.max(decimalsOf(from), decimalsOf(to));
  const format = (v) => {
    const rounded = Number(v.toFixed(dec));
    let out = rounded;
    if (typeof formatter === "function") {
      try {
        out = formatter(rounded, fmtOpts);
      } catch (_) {
        out = rounded;
      }
    }
    return String(out);
  };
  const start = () => rafTween(
    w,
    duration,
    ease,
    (eased) => {
      writeLabel(el, format(from + (to - from) * eased));
    },
    () => {
      writeLabel(el, format(to));
    }
  );
  if (delay > 0) {
    writeLabel(el, format(from));
    setTimeout(() => {
      if (w.globals.isDestroyed) return;
      start();
    }, delay);
  } else {
    start();
  }
}
function applyDataLabelTransition(w) {
  var _a, _b;
  const gl = w.globals;
  const prev = gl.prevDataLabels;
  gl.prevDataLabels = null;
  if (!prev || !gl.axisCharts || !Environment.isBrowser()) return;
  if (!dataLabelMotionEnabled(w)) return;
  if (!lengthTransitionEnabled(w)) return;
  const root = w.dom.baseEl;
  if (!Utils$1.elementExists(root)) return;
  const dl = w.config.dataLabels;
  const ride = !!((_a = dl.animate) == null ? void 0 : _a.enabled);
  const countUp = !!((_b = dl.countUp) == null ? void 0 : _b.enabled);
  const formatter = dl.formatter;
  const duration = Math.max(1, w.config.chart.animations.dynamicAnimation.speed || 1);
  const ease = morphEasing(w);
  try {
    root.querySelectorAll(DL_GROUP_SEL).forEach((group) => {
      const key = group.getAttribute("data:dlKey");
      if (!key) return;
      const textEl = group.querySelector(DL_TEXT_SEL);
      if (!textEl) return;
      const old = prev.get(key);
      const delay = parseInt(group.getAttribute("data:dlDelay") || "0", 10) || 0;
      if (ride) {
        if (old && isFinite(old.cx) && isFinite(old.cy)) {
          rideTo(w, {
            el: group,
            oldCx: old.cx,
            oldCy: old.cy,
            duration,
            ease,
            delay
          });
        } else if (!old) {
          fadeIn(w, group, duration, ease);
        }
      }
      if (countUp && old) {
        const realIndex = parseInt(key, 10);
        const j = parseInt(group.getAttribute("data:dlJ") || "", 10);
        countUpText(w, {
          el: textEl,
          from: old.val,
          to: parseFloat(group.getAttribute("data:dlVal") || ""),
          formatter,
          // The formatter opts don't change between tween frames (only the
          // value does), so build them once per label instead of spreading all
          // of `w` on every frame. Same shape the bar formatter gets.
          fmtOpts: __spreadProps(__spreadValues({}, w), {
            seriesIndex: realIndex,
            dataPointIndex: isFinite(j) ? j : 0,
            w
          }),
          duration,
          ease,
          delay
        });
      }
    });
    const totalFormatter = w.config.plotOptions.bar.dataLabels.total.formatter || formatter;
    root.querySelectorAll(DL_TOTAL_SEL).forEach((el) => {
      const key = el.getAttribute("data:dlTotalKey");
      if (!key) return;
      const old = prev.get(`total::${key}`);
      if (!old) return;
      const delay = parseInt(el.getAttribute("data:dlDelay") || "0", 10) || 0;
      if (ride && isFinite(old.cx) && isFinite(old.cy)) {
        rideTo(w, { el, oldCx: old.cx, oldCy: old.cy, duration, ease, delay });
      }
      if (countUp) {
        const realIndex = parseInt(
          el.getAttribute("data:dlTotalSeries") || key,
          10
        );
        countUpText(w, {
          el,
          from: old.val,
          to: parseFloat(el.getAttribute("data:dlTotalVal") || ""),
          formatter: totalFormatter,
          fmtOpts: __spreadProps(__spreadValues({}, w), { seriesIndex: realIndex, dataPointIndex: 0, w }),
          duration,
          ease,
          delay
        });
      }
    });
  } catch (_) {
  }
}
class Series {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {{ toggleDataSeries?: Function, revertDefaultAxisMinMax?: Function, updateSeries?: Function }} [callbacks]
   */
  constructor(w, {
    toggleDataSeries = void 0,
    revertDefaultAxisMinMax = void 0,
    updateSeries = void 0
  } = {}) {
    this.w = w;
    this._toggleDataSeries = toggleDataSeries || null;
    this._revertDefaultAxisMinMax = revertDefaultAxisMinMax || null;
    this._updateSeries = updateSeries || null;
    this.legendInactiveClass = "legend-mouseover-inactive";
  }
  clearSeriesCache() {
    const w = this.w;
    if (w.globals.cachedSelectors) {
      delete w.globals.cachedSelectors.allSeriesEls;
      delete w.globals.cachedSelectors.highlightSeriesEls;
    }
  }
  getAllSeriesEls() {
    const w = this.w;
    const cacheKey = "allSeriesEls";
    if (!w.globals.cachedSelectors[cacheKey]) {
      w.globals.cachedSelectors[cacheKey] = /** @type {any} */
      w.dom.baseEl.getElementsByClassName(`apexcharts-series`);
    }
    return w.globals.cachedSelectors[cacheKey];
  }
  /**
   * @param {string} seriesName
   */
  getSeriesByName(seriesName) {
    return this.w.dom.baseEl.querySelector(
      `.apexcharts-inner .apexcharts-series[seriesName='${Utils$1.escapeString(
        seriesName
      )}']`
    );
  }
  /**
   * @param {string} seriesName
   */
  isSeriesHidden(seriesName) {
    var _a;
    const targetElement = this.getSeriesByName(seriesName);
    const el = (
      /** @type {Element} */
      targetElement
    );
    const realIndex = parseInt((_a = el.getAttribute("data:realIndex")) != null ? _a : "0", 10);
    const isHidden = el.classList.contains("apexcharts-series-collapsed");
    return { isHidden, realIndex };
  }
  /**
   * @param {any} elSeries
   * @param {number} index
   */
  addCollapsedClassToSeries(elSeries, index) {
    Series.addCollapsedClassToSeries(this.w, elSeries, index);
  }
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {any} elSeries
   * @param {number} index
   */
  static addCollapsedClassToSeries(w, elSeries, index) {
    let collapsed = false;
    function iterateOnAllCollapsedSeries(series) {
      for (let cs = 0; cs < series.length; cs++) {
        if (series[cs].index === index) {
          elSeries.node.classList.add("apexcharts-series-collapsed");
          collapsed = true;
        }
      }
    }
    iterateOnAllCollapsedSeries(w.globals.collapsedSeries);
    iterateOnAllCollapsedSeries(w.globals.ancillaryCollapsedSeries);
    if (!collapsed) return;
    if ((w.globals.collapsingSeriesIndices || []).indexOf(index) === -1) return;
    elSeries.node.classList.add("apexcharts-series-collapsing");
    if (!Environment.isBrowser()) return;
    const anim = w.config.chart.animations;
    const hold = (anim.dynamicAnimation.speed || 0) + (anim.speed || 0) + 100;
    setTimeout(() => {
      if (w.globals.isDestroyed) return;
      elSeries.node.classList.remove("apexcharts-series-collapsing");
    }, hold);
  }
  /**
   * @param {string} seriesName
   */
  toggleSeries(seriesName) {
    var _a;
    const isSeriesHidden = this.isSeriesHidden(seriesName);
    (_a = this._toggleDataSeries) == null ? void 0 : _a.call(this, isSeriesHidden.realIndex, isSeriesHidden.isHidden);
    return isSeriesHidden.isHidden;
  }
  /**
   * @param {string} seriesName
   */
  showSeries(seriesName) {
    var _a;
    const isSeriesHidden = this.isSeriesHidden(seriesName);
    if (isSeriesHidden.isHidden) {
      (_a = this._toggleDataSeries) == null ? void 0 : _a.call(this, isSeriesHidden.realIndex, true);
    }
  }
  /**
   * @param {string} seriesName
   */
  hideSeries(seriesName) {
    var _a;
    const isSeriesHidden = this.isSeriesHidden(seriesName);
    if (!isSeriesHidden.isHidden) {
      (_a = this._toggleDataSeries) == null ? void 0 : _a.call(this, isSeriesHidden.realIndex, false);
    }
  }
  /**
   * Cheap pre-update reset for the data-replacement paths (updateSeries /
   * appendSeries). Clears the same bookkeeping resetSeries() clears (series
   * cache, previous paths, collapsed-series state) WITHOUT restoring
   * config.series from the initialSeries snapshot: the caller is about to
   * replace the series anyway (parseData assigns config.series = newSeries),
   * so materializing and cloning the snapshot per update is pure waste (two
   * O(n) deep clones per streaming tick at 50k points).
   */
  prepareDataUpdate() {
    const w = this.w;
    this.clearSeriesCache();
    w.globals.previousPaths = [];
    w.globals.collapsedSeries = [];
    w.globals.ancillaryCollapsedSeries = [];
    w.globals.collapsedSeriesIndices = [];
    w.globals.ancillaryCollapsedSeriesIndices = [];
  }
  resetSeries(shouldUpdateChart = true, shouldResetZoom = true, shouldResetCollapsed = true) {
    var _a, _b;
    const w = this.w;
    this.clearSeriesCache();
    let series = Utils$1.clone(w.globals.initialSeries);
    if (!Array.isArray(series)) {
      series = Utils$1.clone(w.config.series) || [];
    }
    w.globals.previousPaths = [];
    if (shouldResetCollapsed) {
      w.globals.collapsedSeries = [];
      w.globals.ancillaryCollapsedSeries = [];
      w.globals.collapsedSeriesIndices = [];
      w.globals.ancillaryCollapsedSeriesIndices = [];
    } else {
      series = this.emptyCollapsedSeries(series);
    }
    w.config.series = series;
    if (shouldUpdateChart) {
      if (shouldResetZoom) {
        w.interact.zoomed = false;
        (_a = this._revertDefaultAxisMinMax) == null ? void 0 : _a.call(this);
      }
      (_b = this._updateSeries) == null ? void 0 : _b.call(
        this,
        series,
        w.config.chart.animations.dynamicAnimation.enabled
      );
    }
  }
  /**
   * @param {any[]} series
   */
  emptyCollapsedSeries(series) {
    const w = this.w;
    if (!Array.isArray(series)) return series;
    for (let i2 = 0; i2 < series.length; i2++) {
      if (w.globals.collapsedSeriesIndices.indexOf(i2) > -1) {
        if (series[i2] && typeof series[i2] === "object") {
          series[i2].data = [];
        } else {
          series[i2] = 0;
        }
      }
    }
    return series;
  }
  /**
   * Series display names for the CURRENT `w.config` (post-merge), derived the
   * same way the parser does: an object series' own `name`, else the matching
   * `labels` entry (non-axis / pie / unit), else a generated `series-N`.
   * @returns {string[]}
   */
  _deriveSeriesNames() {
    const w = this.w;
    const series = w.config.series || [];
    const labels = w.config.labels || [];
    return series.map((s2, i2) => {
      if (s2 && typeof s2 === "object" && s2.name != null) return String(s2.name);
      return labels[i2] != null ? String(labels[i2]) : `series-${i2 + 1}`;
    });
  }
  /**
   * Re-apply legend-hidden (collapsed) series to a freshly-updated
   * `w.config.series`, matching BY CATEGORY NAME rather than index. This keeps a
   * hide alive across a data update that reorders or regroups categories - most
   * visibly a storyboard beat that supplies new series each scroll:
   *   - a category still present stays hidden (at its possibly-new index);
   *   - a category the update dropped/regrouped away is un-hidden (it no longer
   *     exists, so it must reappear as part of the new grouping).
   * Records without a stored name (older collapses) fall back to their index.
   */
  reconcileCollapsedByName() {
    const w = this.w;
    const gl = w.globals;
    const newNames = this._deriveSeriesNames();
    const reconcile = (records) => {
      const nextRecords = [];
      const nextIndices = [];
      records.forEach((rec) => {
        const j = rec && rec.name != null ? newNames.indexOf(rec.name) : rec.index;
        if (j == null || j < 0 || j >= w.config.series.length) return;
        const s2 = (
          /** @type {any} */
          w.config.series[j]
        );
        rec.index = j;
        rec.data = gl.axisCharts ? s2 && s2.data ? s2.data.slice() : [] : s2;
        nextRecords.push(rec);
        nextIndices.push(j);
      });
      return { records: nextRecords, indices: nextIndices };
    };
    const main = reconcile(gl.collapsedSeries);
    gl.collapsedSeries = main.records;
    gl.collapsedSeriesIndices = main.indices;
    const anc = reconcile(gl.ancillaryCollapsedSeries);
    gl.ancillaryCollapsedSeries = anc.records;
    gl.ancillaryCollapsedSeriesIndices = anc.indices;
    gl.allSeriesCollapsed = gl.collapsedSeries.length + gl.ancillaryCollapsedSeries.length === w.config.series.length;
    this.emptyCollapsedSeries(w.config.series);
  }
  /**
   * @param {string} seriesName
   */
  /**
   * Bridge SVG series-dim state to the canvas renderer: SVG opacity classes
   * (legend-mouseover-inactive) don't touch the painted canvas series layer, so
   * repaint it with a matching per-series opacity. No-op unless the canvas
   * renderer is active. The renderer is mirrored on globals by RendererController
   * (Series has no ctx handle).
   * @param {{active:number, opacity:number}|null} dim
   */
  canvasRestyle(dim) {
    const r2 = this.w.globals.activeRenderer;
    if (r2 && r2.kind === "canvas" && typeof r2.restyle === "function") {
      r2.restyle(dim);
    }
  }
  /**
   * @param {string} seriesName
   */
  highlightSeries(seriesName) {
    var _a;
    const w = this.w;
    const targetElement = this.getSeriesByName(seriesName);
    const realIndex = parseInt(
      (_a = targetElement == null ? void 0 : targetElement.getAttribute("data:realIndex")) != null ? _a : "",
      10
    );
    const cacheKey = "highlightSeriesEls";
    let allSeriesEls = w.globals.cachedSelectors[cacheKey];
    if (!allSeriesEls) {
      allSeriesEls = w.dom.baseEl.querySelectorAll(
        `.apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis`
      );
      w.globals.cachedSelectors[cacheKey] = allSeriesEls;
    }
    let seriesEl = null;
    let dataLabelEl = null;
    let yaxisEl = null;
    if (w.globals.axisCharts || w.config.chart.type === "radialBar") {
      if (w.globals.axisCharts) {
        seriesEl = w.dom.baseEl.querySelector(
          `.apexcharts-series[data\\:realIndex='${realIndex}']`
        );
        dataLabelEl = w.dom.baseEl.querySelector(
          `.apexcharts-datalabels[data\\:realIndex='${realIndex}']`
        );
        const yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex];
        yaxisEl = w.dom.baseEl.querySelector(
          `.apexcharts-yaxis[rel='${yaxisIndex}']`
        );
      } else {
        seriesEl = w.dom.baseEl.querySelector(
          `.apexcharts-series[rel='${realIndex + 1}']`
        );
      }
    } else {
      seriesEl = w.dom.baseEl.querySelector(
        `.apexcharts-series[rel='${realIndex + 1}'] path`
      );
    }
    for (let se = 0; se < allSeriesEls.length; se++) {
      const serEl = (
        /** @type {Element} */
        allSeriesEls[se]
      );
      serEl.classList.add(this.legendInactiveClass);
    }
    if (seriesEl) {
      if (!w.globals.axisCharts) {
        const parentEl = (
          /** @type {Element} */
          seriesEl.parentNode
        );
        parentEl == null ? void 0 : parentEl.classList.remove(this.legendInactiveClass);
      }
      seriesEl.classList.remove(this.legendInactiveClass);
      if (dataLabelEl !== null) {
        dataLabelEl.classList.remove(this.legendInactiveClass);
      }
      if (yaxisEl !== null) {
        yaxisEl.classList.remove(this.legendInactiveClass);
      }
    } else {
      for (let se = 0; se < allSeriesEls.length; se++) {
        const serEl = (
          /** @type {Element} */
          allSeriesEls[se]
        );
        serEl.classList.remove(this.legendInactiveClass);
      }
    }
    this.canvasRestyle(
      seriesEl && !Number.isNaN(realIndex) ? { active: realIndex, opacity: 0.2 } : null
    );
  }
  /**
   * @param {Event} e
   * @param {any} targetElement
   */
  toggleSeriesOnHover(e2, targetElement) {
    const w = this.w;
    if (!targetElement) targetElement = e2.target;
    const allSeriesEls = w.dom.baseEl.querySelectorAll(
      `.apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis`
    );
    if (e2.type === "mousemove") {
      const realIndex = parseInt(targetElement.getAttribute("rel"), 10) - 1;
      this.highlightSeries(w.seriesData.seriesNames[realIndex]);
    } else if (e2.type === "mouseout") {
      for (let se = 0; se < allSeriesEls.length; se++) {
        allSeriesEls[se].classList.remove(this.legendInactiveClass);
      }
      this.canvasRestyle(null);
    }
  }
  /**
   * Dim every heatmap cell except those whose value falls inside the color
   * range at `rangeIndex`. Shared by the categorical legend (hover a legend
   * item) and the gradient legend (hover a band) — both supply an index into
   * `colorScale.ranges` plus an action, decoupling the highlight from any
   * particular DOM element / event shape.
   *
   * @param {number} rangeIndex index into `colorScale.ranges`
   * @param {'highlight'|'reset'} action
   */
  highlightRangeInSeries(rangeIndex, action) {
    const w = this.w;
    const allHeatMapElements = w.dom.baseEl.getElementsByClassName(
      "apexcharts-heatmap-rect"
    );
    const toggleAllInactive = (op) => {
      for (let i2 = 0; i2 < allHeatMapElements.length; i2++) {
        const classList = (
          /** @type {any} */
          allHeatMapElements[i2].classList
        );
        if (typeof classList[op] === "function") {
          classList[op](this.legendInactiveClass);
        }
      }
    };
    if (action === "reset") {
      toggleAllInactive("remove");
      return;
    }
    const ranges = w.config.plotOptions.heatmap.colorScale.ranges;
    const range = ranges && ranges[rangeIndex];
    if (!range) return;
    toggleAllInactive("add");
    for (let i2 = 0; i2 < allHeatMapElements.length; i2++) {
      const val = Number(allHeatMapElements[i2].getAttribute("val"));
      if (val >= range.from && val <= range.to) {
        allHeatMapElements[i2].classList.remove(this.legendInactiveClass);
      }
    }
  }
  /**
   * @param {string[]} chartTypes
   */
  getActiveConfigSeriesIndex(order = "asc", chartTypes = []) {
    const w = this.w;
    let activeIndex = 0;
    if (w.config.series.length > 1) {
      const activeSeriesIndex = w.config.series.map((s2, index) => {
        const checkChartType = () => {
          if (w.globals.comboCharts) {
            return chartTypes.length === 0 || chartTypes.length && chartTypes.indexOf(
              /** @type {Record<string,any>} */
              w.config.series[index].type
            ) > -1;
          }
          return true;
        };
        const hasData = (
          /** @type {any} */
          s2.data && /** @type {any} */
          s2.data.length > 0 && w.globals.collapsedSeriesIndices.indexOf(index) === -1
        );
        return hasData && checkChartType() ? index : -1;
      });
      for (let a2 = order === "asc" ? 0 : activeSeriesIndex.length - 1; order === "asc" ? a2 < activeSeriesIndex.length : a2 >= 0; order === "asc" ? a2++ : a2--) {
        if (activeSeriesIndex[a2] !== -1) {
          activeIndex = activeSeriesIndex[a2];
          break;
        }
      }
    }
    return activeIndex;
  }
  /**
   * The highest active series index inside each series group, as an array
   * parallel to `w.labelData.seriesGroups`. Entries are -1 for a group whose
   * every series is collapsed or empty.
   *
   * Same activity test as `getActiveConfigSeriesIndex` (has data and is not
   * legend-collapsed), applied per group so grouped stacked bars can ask which
   * series caps each individual stack rather than the chart as a whole.
   * @param {string[]} chartTypes
   * @returns {number[]}
   */
  getActiveConfigSeriesIndexByGroup(chartTypes = []) {
    const w = this.w;
    const groups = w.labelData.seriesGroups || [];
    return groups.map((group) => {
      let last = -1;
      w.config.series.forEach((s2, i2) => {
        if (group.indexOf(w.seriesData.seriesNames[i2]) === -1) return;
        if (w.globals.comboCharts && chartTypes.length && chartTypes.indexOf(s2.type) === -1) {
          return;
        }
        const hasData = s2.data && s2.data.length > 0 && w.globals.collapsedSeriesIndices.indexOf(i2) === -1;
        if (hasData) last = i2;
      });
      return last;
    });
  }
  getBarSeriesIndices() {
    const w = this.w;
    if (w.globals.comboCharts) {
      return this.w.config.series.map((s2, i2) => {
        return s2.type === "bar" || s2.type === "column" ? i2 : -1;
      }).filter((i2) => {
        return i2 !== -1;
      });
    }
    return this.w.config.series.map((s2, i2) => {
      return i2;
    });
  }
  getPreviousPaths() {
    var _a, _b, _c, _d;
    const w = this.w;
    captureStreamFrame(w);
    captureAxisChrome(w);
    captureDataLabels(w);
    if (!w.globals.axisCharts) {
      w.globals.previousPaths = w.seriesData.series;
      return;
    }
    if (!Utils$1.elementExists(w.dom.baseEl)) {
      w.globals.previousPaths = [];
      return;
    }
    w.globals.previousPaths = [];
    function pushPaths(seriesEls, i2, type) {
      const paths = seriesEls[i2].childNodes;
      const dArr = {
        type,
        paths: (
          /** @type {any[]} */
          []
        ),
        realIndex: seriesEls[i2].getAttribute("data:realIndex")
      };
      for (let j = 0; j < paths.length; j++) {
        if (paths[j].hasAttribute("pathTo")) {
          const d = paths[j].getAttribute("pathTo");
          dArr.paths.push({
            d,
            key: paths[j].getAttribute("data:pathKey"),
            fill: paths[j].getAttribute("fill"),
            flip: paths[j].classList.contains("apexcharts-flip-y") || paths[j].classList.contains("apexcharts-flip-x")
          });
        }
      }
      w.globals.previousPaths.push(dArr);
    }
    const getPaths = (chartType) => {
      return w.dom.baseEl.querySelectorAll(
        `.apexcharts-${chartType}-series .apexcharts-series`
      );
    };
    const chartTypes = [
      "line",
      "area",
      "bar",
      "rangebar",
      "rangeArea",
      "candlestick",
      "radar"
    ];
    chartTypes.forEach((type) => {
      const paths = getPaths(type);
      for (let p = 0; p < paths.length; p++) {
        pushPaths(paths, p, type);
      }
    });
    const heatTreeSeries = w.dom.baseEl.querySelectorAll(
      `.apexcharts-${w.config.chart.type} .apexcharts-series`
    );
    if (heatTreeSeries.length > 0) {
      for (let h2 = 0; h2 < heatTreeSeries.length; h2++) {
        const seriesEls = w.dom.baseEl.querySelectorAll(
          `.apexcharts-${w.config.chart.type} .apexcharts-series[data\\:realIndex='${h2}'] rect`
        );
        const dArr = [];
        for (let i2 = 0; i2 < seriesEls.length; i2++) {
          const getAttr = (x) => {
            return (
              /** @type {Element} */
              seriesEls[i2].getAttribute(x)
            );
          };
          const rect = {
            x: parseFloat((_a = getAttr("x")) != null ? _a : "0"),
            y: parseFloat((_b = getAttr("y")) != null ? _b : "0"),
            width: parseFloat((_c = getAttr("width")) != null ? _c : "0"),
            height: parseFloat((_d = getAttr("height")) != null ? _d : "0")
          };
          dArr.push({
            rect,
            color: seriesEls[i2].getAttribute("color")
          });
        }
        w.globals.previousPaths.push(dArr);
      }
    }
  }
  clearPreviousPaths() {
    const w = this.w;
    w.globals.previousPaths = [];
    w.globals.allSeriesCollapsed = false;
  }
  handleNoData() {
    const w = this.w;
    const me = this;
    const noDataOpts = w.config.noData;
    const graphics = new Graphics(me.w);
    let x = w.globals.svgWidth / 2;
    let y = w.globals.svgHeight / 2;
    let textAnchor = "middle";
    w.globals.noData = true;
    w.globals.animationEnded = true;
    if (noDataOpts.align === "left") {
      x = 10;
      textAnchor = "start";
    } else if (noDataOpts.align === "right") {
      x = w.globals.svgWidth - 10;
      textAnchor = "end";
    }
    if (noDataOpts.verticalAlign === "top") {
      y = 50;
    } else if (noDataOpts.verticalAlign === "bottom") {
      y = w.globals.svgHeight - 50;
    }
    x = x + noDataOpts.offsetX;
    y = y + parseInt(noDataOpts.style.fontSize, 10) + 2 + noDataOpts.offsetY;
    if (noDataOpts.text !== void 0 && noDataOpts.text !== "") {
      const titleText = graphics.drawText({
        x,
        y,
        text: noDataOpts.text,
        textAnchor,
        fontSize: noDataOpts.style.fontSize,
        fontFamily: noDataOpts.style.fontFamily,
        foreColor: noDataOpts.style.color,
        opacity: 1,
        cssClass: "apexcharts-text-nodata"
      });
      w.dom.Paper.add(titleText);
    }
  }
  // When user clicks on legends, the collapsed series is filled with [0,0,0,...,0]
  // This is because we don't want to alter the series' length as it is used at many places
  /**
   * @param {any[]} series
   */
  setNullSeriesToZeroValues(series) {
    const w = this.w;
    for (let sl = 0; sl < series.length; sl++) {
      if (series[sl].length === 0) {
        for (let j = 0; j < series[w.globals.maxValsInArrayIndex].length; j++) {
          series[sl].push(0);
        }
      }
    }
    return series;
  }
  hasAllSeriesEqualX() {
    let equalLen = true;
    const w = this.w;
    const filteredSerX = this.filteredSeriesX();
    for (let i2 = 0; i2 < filteredSerX.length - 1; i2++) {
      if (filteredSerX[i2][0] !== filteredSerX[i2 + 1][0]) {
        equalLen = false;
        break;
      }
    }
    w.globals.allSeriesHasEqualX = equalLen;
    return equalLen;
  }
  filteredSeriesX() {
    const w = this.w;
    const filteredSeriesX = w.seriesData.seriesX.map(
      (ser) => ser.length > 0 ? ser : []
    );
    return filteredSeriesX;
  }
}
const TOKEN_MAP = {
  accent: "--apx-accent",
  fore: "--apx-fore",
  grid: "--apx-grid",
  surface: "--apx-surface"
};
const MAX_SERIES_TOKENS = 24;
function readTokens(w) {
  if (!Environment.isBrowser()) return {};
  const el = w.dom && (w.dom.elWrap || w.dom.baseEl) || null;
  if (!el) return {};
  const cs = BrowserAPIs.getComputedStyle(el);
  if (!cs || typeof /** @type {any} */
  cs.getPropertyValue !== "function") {
    return {};
  }
  const read = (name2) => {
    const v = (
      /** @type {any} */
      cs.getPropertyValue(name2)
    );
    return v ? String(v).trim() : "";
  };
  const out = {};
  for (const key in TOKEN_MAP) {
    const v = read(
      /** @type {any} */
      TOKEN_MAP[key]
    );
    if (v) out[key] = v;
  }
  const series = [];
  for (let i2 = 1; i2 <= MAX_SERIES_TOKENS; i2++) {
    const v = read(`--apx-series-${i2}`);
    if (!v) break;
    series.push(v);
  }
  if (series.length) out.series = series;
  return out;
}
const THEME_KEY = "__apexcharts_themes__";
if (!/** @type {any} */
globalThis[THEME_KEY]) {
  globalThis[THEME_KEY] = {};
}
function getThemes() {
  return (
    /** @type {any} */
    globalThis[THEME_KEY]
  );
}
function registerTheme(name2, def) {
  if (!name2 || typeof name2 !== "string") {
    console.warn("ApexCharts: registerTheme requires a non-empty name.");
    return;
  }
  if (def != null && (typeof def !== "object" || Array.isArray(def))) {
    console.warn(
      `ApexCharts: registerTheme("${name2}") expects an object like { mode, palette, tokens, monochrome, accessibility }.`
    );
    return;
  }
  getThemes()[name2] = def || {};
}
function getTheme(name2) {
  if (!name2) return null;
  return getThemes()[name2] || null;
}
function unregisterTheme(name2) {
  if (!name2) return;
  delete getThemes()[name2];
}
const DEFAULT_FORECOLOR_LIGHT = "#373d3f";
const DEFAULT_FORECOLOR_DARK = "#f6f7f8";
const DEFAULT_AXIS_GRID = "#e0e0e0";
class Theme {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
    this.colors = [];
    this.isColorFn = false;
    this.isHeatmapDistributed = this.checkHeatmapDistributed();
    this.isBarDistributed = this.checkBarDistributed();
    this._tokens = {};
    this._namedTheme = null;
  }
  checkHeatmapDistributed() {
    const { chart, plotOptions } = this.w.config;
    return chart.type === "treemap" && plotOptions.treemap && plotOptions.treemap.distributed || chart.type === "heatmap" && plotOptions.heatmap && plotOptions.heatmap.distributed;
  }
  checkBarDistributed() {
    const { chart, plotOptions } = this.w.config;
    return plotOptions.bar && plotOptions.bar.distributed && (chart.type === "bar" || chart.type === "rangeBar");
  }
  init() {
    this.setDefaultColors();
  }
  setDefaultColors() {
    var _a;
    const w = this.w;
    const utils = new Utils$1();
    this._namedTheme = getTheme(w.config.theme.name);
    this._applyNamedThemeMode();
    w.dom.elWrap.classList.add(
      `apexcharts-theme-${w.config.theme.mode || "light"}`
    );
    this._applyModeDefaults();
    this._tokens = this._resolveTokens();
    this.applyTokenChrome(this._tokens);
    const colorBlindMode = (_a = w.config.theme.accessibility) == null ? void 0 : _a.colorBlindMode;
    if (colorBlindMode) {
      w.globals.colors = this.getColorBlindColors(colorBlindMode);
      this.applySeriesColors(w.seriesData.seriesColors, w.globals.colors);
      const defaultColors2 = w.globals.colors.slice();
      this.pushExtraColors(w.globals.colors);
      this.applyColorTypes(["fill", "stroke"], defaultColors2);
      this.applyDataLabelsColors(defaultColors2);
      this.applyRadarPolygonsColors();
      this.applyMarkersColors(defaultColors2);
      if (colorBlindMode === "highContrast") {
        w.dom.elWrap.classList.add("apexcharts-high-contrast");
      }
      return;
    }
    const configColors = [...w.config.colors || w.config.fill.colors || []];
    w.globals.colors = this.getColors(configColors);
    this.applySeriesColors(w.seriesData.seriesColors, w.globals.colors);
    if (w.config.theme.monochrome.enabled) {
      w.globals.colors = this.getMonochromeColors(
        w.config.theme.monochrome,
        w.seriesData.series,
        utils
      );
    }
    const defaultColors = w.globals.colors.slice();
    this.pushExtraColors(w.globals.colors);
    this.applyColorTypes(["fill", "stroke"], defaultColors);
    this.applyDataLabelsColors(defaultColors);
    this.applyRadarPolygonsColors();
    this.applyMarkersColors(defaultColors);
  }
  /**
   * Facet (#13): normalize the mode's concrete defaults (foreColor + palette +
   * tooltip theme) at render time. Only overwrites a value still at its
   * opposite-mode default sentinel, so an explicit user value or a value
   * already normalized by checkForDarkTheme/updateThemeOptions is untouched.
   */
  _applyModeDefaults() {
    const w = this.w;
    const mode = w.config.theme.mode;
    if (mode === "dark") {
      if (w.config.chart.foreColor === DEFAULT_FORECOLOR_LIGHT) {
        w.config.chart.foreColor = DEFAULT_FORECOLOR_DARK;
      }
      if (w.config.theme.palette === "palette1") {
        w.config.theme.palette = "palette4";
      }
      if (w.config.tooltip && w.config.tooltip.theme !== "light") {
        w.config.tooltip.theme = "dark";
      }
    } else if (mode === "light") {
      if (w.config.chart.foreColor === DEFAULT_FORECOLOR_DARK) {
        w.config.chart.foreColor = DEFAULT_FORECOLOR_LIGHT;
      }
      if (w.config.theme.palette === "palette4") {
        w.config.theme.palette = "palette1";
      }
    }
  }
  /**
   * Facet (#13): apply a registered named theme's mode / accessibility /
   * monochrome, each only when the user (or the OS watcher) has not set it, so
   * explicit config and `follow:'os'` both win over the named theme.
   */
  _applyNamedThemeMode() {
    const named = this._namedTheme;
    if (!named) return;
    const theme = this.w.config.theme;
    if (named.mode && !theme.mode) {
      theme.mode = named.mode;
    }
    if (named.accessibility && named.accessibility.colorBlindMode && !(theme.accessibility && theme.accessibility.colorBlindMode)) {
      theme.accessibility = theme.accessibility || {};
      theme.accessibility.colorBlindMode = named.accessibility.colorBlindMode;
    }
    if (named.monochrome && named.monochrome.enabled && !theme.monochrome.enabled) {
      theme.monochrome = __spreadValues(__spreadValues({}, theme.monochrome), named.monochrome);
    }
  }
  /**
   * Facet (#13): the effective token set. CSS `--apx-*` tokens (when enabled)
   * layer over the named theme's `tokens`, so a page-level token overrides a
   * registered brand default.
   * @returns {{accent?:string, fore?:string, grid?:string, surface?:string, series?:string[]}}
   */
  _resolveTokens() {
    const named = this._namedTheme && this._namedTheme.tokens || {};
    const css = this._shouldUseTokens() ? readTokens(this.w) : {};
    return __spreadValues(__spreadValues({}, named), css);
  }
  /**
   * Facet (#13): tokens are on unless explicitly disabled (`theme.tokens:false`).
   * `true` is the default (the legacy `'auto'` value is accepted and means the
   * same); `readTokens` returns only the tokens actually present, so absence
   * is a no-op.
   * @returns {boolean}
   */
  _shouldUseTokens() {
    return this.w.config.theme.tokens !== false;
  }
  /**
   * Facet (#13): overwrite chrome defaults with `--apx-*` tokens, but only where
   * the value still equals its built-in default (so explicit config wins).
   * @param {{fore?:string, grid?:string, surface?:string}} tokens
   */
  applyTokenChrome(tokens) {
    if (!tokens) return;
    const w = this.w;
    if (tokens.fore && (w.config.chart.foreColor === DEFAULT_FORECOLOR_LIGHT || w.config.chart.foreColor === DEFAULT_FORECOLOR_DARK)) {
      w.config.chart.foreColor = tokens.fore;
    }
    if (tokens.grid) {
      if (w.config.grid.borderColor === DEFAULT_AXIS_GRID) {
        w.config.grid.borderColor = tokens.grid;
      }
      const applyAxis = (axis) => {
        if (!axis) return;
        if (axis.axisBorder && axis.axisBorder.color === DEFAULT_AXIS_GRID) {
          axis.axisBorder.color = tokens.grid;
        }
        if (axis.axisTicks && axis.axisTicks.color === DEFAULT_AXIS_GRID) {
          axis.axisTicks.color = tokens.grid;
        }
      };
      applyAxis(w.config.xaxis);
      if (Array.isArray(w.config.yaxis)) {
        w.config.yaxis.forEach(applyAxis);
      } else {
        applyAxis(w.config.yaxis);
      }
    }
    const appliedSurface = w.globals.tokenSurface;
    const currentBg = w.config.chart.background;
    const isOurs = !currentBg || currentBg === appliedSurface;
    if (tokens.surface) {
      if (isOurs) {
        w.config.chart.background = tokens.surface;
        w.globals.tokenSurface = tokens.surface;
        const paperNode = w.dom.Paper && w.dom.Paper.node;
        if (paperNode && paperNode.style) {
          paperNode.style.background = tokens.surface;
        }
      }
    } else if (appliedSurface && currentBg === appliedSurface) {
      w.config.chart.background = "";
      w.globals.tokenSurface = void 0;
      const paperNode = w.dom.Paper && w.dom.Paper.node;
      if (paperNode && paperNode.style) {
        paperNode.style.background = "";
      }
    }
  }
  /**
   * @param {any[]} configColors
   */
  getColors(configColors) {
    const w = this.w;
    if (!configColors || configColors.length === 0) {
      return this.predefined();
    }
    if (Array.isArray(configColors) && configColors.length > 0 && typeof configColors[0] === "function") {
      this.isColorFn = true;
      return w.config.series.map((s2, i2) => {
        const c2 = configColors[i2] || configColors[0];
        return typeof c2 === "function" ? c2({
          value: w.globals.axisCharts ? w.seriesData.series[i2][0] || 0 : w.seriesData.series[i2],
          seriesIndex: i2,
          dataPointIndex: i2,
          w: this.w
        }) : c2;
      });
    }
    return configColors;
  }
  /**
   * @param {any[]} seriesColors
   * @param {any[]} globalsColors
   */
  applySeriesColors(seriesColors, globalsColors) {
    seriesColors.forEach((c2, i2) => {
      if (c2) {
        globalsColors[i2] = c2;
      }
    });
  }
  /**
   * @param {Record<string, any>} monochrome
   * @param {any[]} series
   * @param {any} utils
   */
  getMonochromeColors(monochrome, series, utils) {
    const { color, shadeIntensity, shadeTo } = monochrome;
    const glsCnt = this.isBarDistributed || this.isHeatmapDistributed ? series[0].length * series.length : series.length;
    const part = 1 / (glsCnt / shadeIntensity);
    let percent = 0;
    return Array.from({ length: glsCnt }, () => {
      const newColor = shadeTo === "dark" ? utils.shadeColor(percent * -1, color) : utils.shadeColor(percent, color);
      percent += part;
      return newColor;
    });
  }
  /**
   * @param {string[]} colorTypes
   * @param {string[]} defaultColors
   */
  applyColorTypes(colorTypes, defaultColors) {
    const w = this.w;
    colorTypes.forEach((c2) => {
      w.globals[c2].colors = w.config[c2].colors === void 0 ? this.isColorFn ? w.config.colors : defaultColors : w.config[c2].colors.slice();
      this.pushExtraColors(
        /** @type {Record<string,any>} */
        w.globals[c2].colors
      );
    });
  }
  /**
   * @param {string[]} defaultColors
   */
  applyDataLabelsColors(defaultColors) {
    const w = this.w;
    w.globals.dataLabels.style.colors = w.config.dataLabels.style.colors === void 0 ? defaultColors : w.config.dataLabels.style.colors.slice();
    this.pushExtraColors(w.globals.dataLabels.style.colors, 50);
  }
  applyRadarPolygonsColors() {
    const w = this.w;
    w.globals.radarPolygons.fill.colors = w.config.plotOptions.radar.polygons.fill.colors === void 0 ? [w.config.theme.mode === "dark" ? "#343A3F" : "none"] : w.config.plotOptions.radar.polygons.fill.colors.slice();
    this.pushExtraColors(w.globals.radarPolygons.fill.colors, 20);
  }
  /**
   * @param {string[]} defaultColors
   */
  applyMarkersColors(defaultColors) {
    const w = this.w;
    w.globals.markers.colors = w.config.markers.colors === void 0 ? defaultColors : w.config.markers.colors.slice();
    this.pushExtraColors(w.globals.markers.colors);
  }
  /**
   * @param {any} colorSeries
   * @param {number} [length]
   * @param {boolean | null} [distributed]
   */
  pushExtraColors(colorSeries, length, distributed = null) {
    const w = this.w;
    let len = length || w.seriesData.series.length;
    if (distributed === null) {
      distributed = this.isBarDistributed || this.isHeatmapDistributed || w.config.chart.type === "heatmap" && w.config.plotOptions.heatmap && w.config.plotOptions.heatmap.colorScale.inverse;
    }
    if (distributed && w.seriesData.series.length) {
      len = w.seriesData.series[w.globals.maxValsInArrayIndex].length * w.seriesData.series.length;
    }
    if (colorSeries.length < len) {
      const diff = len - colorSeries.length;
      for (let i2 = 0; i2 < diff; i2++) {
        colorSeries.push(colorSeries[i2]);
      }
    }
  }
  /**
   * @param {'light' | 'dark'} mode
   */
  getColorBlindColors(mode) {
    const palettes = getThemePalettes();
    const map = {
      deuteranopia: palettes.cvdDeuteranopia,
      protanopia: palettes.cvdProtanopia,
      tritanopia: palettes.cvdTritanopia,
      highContrast: palettes.highContrast
    };
    return (
      /** @type {Record<string,any>} */
      /** @type {any} */
      (map[mode] || palettes.palette1).slice()
    );
  }
  /**
   * @param {Record<string, any>} options
   */
  updateThemeOptions(options2) {
    options2.chart = options2.chart || {};
    options2.tooltip = options2.tooltip || {};
    const mode = options2.theme.mode;
    const palette = mode === "dark" ? "palette4" : mode === "light" ? "palette1" : options2.theme.palette || "palette1";
    const foreColor = mode === "dark" ? "#f6f7f8" : mode === "light" ? "#373d3f" : options2.chart.foreColor || "#373d3f";
    options2.tooltip.theme = mode || "light";
    options2.chart.foreColor = foreColor;
    options2.theme.palette = palette;
    return options2;
  }
  predefined() {
    const palette = this.w.config.theme.palette;
    const palettes = getThemePalettes();
    const builtin = (
      /** @type {Record<string,any>} */
      palettes[palette] || palettes.palette1
    );
    const tokens = this._tokens || {};
    if (Array.isArray(tokens.series) && tokens.series.length) {
      return tokens.series.slice();
    }
    if (tokens.accent) {
      return [tokens.accent, ...builtin];
    }
    const named = this._namedTheme;
    if (named && Array.isArray(named.palette) && named.palette.length) {
      return named.palette.slice();
    }
    return builtin;
  }
}
class TitleSubtitle {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w) {
    this.w = w;
  }
  draw() {
    this.drawTitleSubtitle("title");
    this.drawTitleSubtitle("subtitle");
  }
  /**
   * @param {'title' | 'subtitle'} type
   */
  drawTitleSubtitle(type) {
    const w = this.w;
    const tsConfig = type === "title" ? w.config.title : w.config.subtitle;
    let x = w.globals.svgWidth / 2;
    let y = tsConfig.offsetY;
    let textAnchor = "middle";
    if (tsConfig.align === "left") {
      x = 10;
      textAnchor = "start";
    } else if (tsConfig.align === "right") {
      x = w.globals.svgWidth - 10;
      textAnchor = "end";
    }
    x = x + tsConfig.offsetX;
    y = y + parseInt(tsConfig.style.fontSize, 10) + tsConfig.margin / 2;
    if (tsConfig.text !== void 0) {
      const graphics = new Graphics(this.w);
      const titleText = graphics.drawText({
        x,
        y,
        text: tsConfig.text,
        textAnchor,
        fontSize: tsConfig.style.fontSize,
        fontFamily: tsConfig.style.fontFamily,
        fontWeight: tsConfig.style.fontWeight,
        foreColor: tsConfig.style.color,
        opacity: 1
      });
      titleText.node.setAttribute("class", `apexcharts-${type}-text`);
      w.dom.Paper.add(titleText);
    }
  }
}
class Helpers {
  /**
   * @param {import('./Dimensions').default} dCtx
   */
  constructor(dCtx) {
    this.w = dCtx.w;
    this.dCtx = dCtx;
  }
  /**
   * Get Chart Title/Subtitle Dimensions
   * @memberof Dimensions
   * @return {{width: number, height: number}}
   * @param {string} type
   **/
  getTitleSubtitleCoords(type) {
    const w = this.w;
    let width = 0;
    let height = 0;
    const floating = type === "title" ? w.config.title.floating : w.config.subtitle.floating;
    const el = w.dom.baseEl.querySelector(`.apexcharts-${type}-text`);
    if (el !== null && !floating) {
      const coord = el.getBoundingClientRect();
      width = coord.width;
      height = w.globals.axisCharts ? coord.height + 5 : coord.height;
    }
    return {
      width,
      height
    };
  }
  getLegendsRect() {
    const w = this.w;
    const elLegendWrap = w.dom.elLegendWrap;
    if (!w.config.legend.height && (w.config.legend.position === "top" || w.config.legend.position === "bottom")) {
      if (elLegendWrap)
        elLegendWrap.style.maxHeight = w.globals.svgHeight / 2 + "px";
    }
    const lgRect = (
      /** @type {any} */
      Object.assign({}, Utils$1.getBoundingClientRect(elLegendWrap))
    );
    if (elLegendWrap !== null && !w.config.legend.floating && w.config.legend.show) {
      this.dCtx.lgRect = {
        x: lgRect.x,
        y: lgRect.y,
        height: lgRect.height,
        width: lgRect.height === 0 ? 0 : lgRect.width
      };
    } else {
      this.dCtx.lgRect = {
        x: 0,
        y: 0,
        height: 0,
        width: 0
      };
    }
    if (w.config.legend.position === "left" || w.config.legend.position === "right") {
      if (this.dCtx.lgRect.width * 1.5 > w.globals.svgWidth) {
        this.dCtx.lgRect.width = w.globals.svgWidth / 1.5;
      }
    }
    return this.dCtx.lgRect;
  }
  /**
   * Get Y Axis Dimensions
   * @memberof Dimensions
   * @return {{width: number, height: number}}
   **/
  getDatalabelsRect() {
    const w = this.w;
    const allLabels = [];
    w.config.series.forEach(
      (serie, seriesIndex) => {
        serie.data.forEach(
          (datum, dataPointIndex) => {
            const getText = (v) => {
              return w.config.dataLabels.formatter(v, {
                seriesIndex,
                dataPointIndex,
                w
              });
            };
            const labelText = getText(
              w.seriesData.series[seriesIndex][dataPointIndex]
            );
            allLabels.push(labelText);
          }
        );
      }
    );
    const val = Utils$1.getLargestStringFromArr(allLabels);
    const graphics = new Graphics(this.w);
    const dataLabelsStyle = w.config.dataLabels.style;
    const labelrect = graphics.getTextRects(
      val,
      parseInt(dataLabelsStyle.fontSize).toString(),
      dataLabelsStyle.fontFamily
    );
    return {
      width: labelrect.width * 1.05,
      height: labelrect.height
    };
  }
  /**
   * @param {any} val
   * @param {any[]} arr
   */
  getLargestStringFromMultiArr(val, arr) {
    const w = this.w;
    let valArr = val;
    if (w.axisFlags.isMultiLineX) {
      const maxArrs = arr.map((xl) => {
        return Array.isArray(xl) ? xl.length : 1;
      });
      const maxArrLen = Math.max(...maxArrs);
      const maxArrIndex = maxArrs.indexOf(maxArrLen);
      valArr = arr[maxArrIndex];
    }
    return valArr;
  }
  /**
   * Vertical space a sparkline has to keep free inside its SVG so the series
   * stroke isn't clipped at the top / bottom edge.
   *
   * A stroke is centred on its path, so half of it hangs outside the plot
   * wherever the path runs along an edge. Reserving that half unconditionally
   * lifts the whole plot away from the SVG edges even when nothing is drawn
   * there, which shows up as a strip of empty space under an area fill or a
   * bar base (#5137). So reserve only what the ink can't absorb itself: where
   * the stroke traces the data points, the distance between the extreme datum
   * and the axis extreme already swallows part or all of the overhang. Fills
   * need nothing: area fills are drawn unstroked (see Line.js renderPaths).
   *
   * @returns {{ top: number, bottom: number }}
   **/
  getSparklineStrokeInset() {
    const w = this.w;
    const maxStrokeWidth = Array.isArray(w.config.stroke.width) ? Math.max(...w.config.stroke.width) : w.config.stroke.width;
    const half = maxStrokeWidth / 2;
    if (!w.config.stroke.show || !(half > 0)) {
      return { top: 0, bottom: 0 };
    }
    const yRange = w.globals.maxY - w.globals.minY;
    const extremes = this._getSeriesYExtremes();
    if (!this._strokeTracesDataPoints() || !(yRange > 0) || !extremes) {
      return { top: half, bottom: half };
    }
    const plotHeight = Math.max(w.globals.svgHeight - maxStrokeWidth, 0);
    const roomAbove = plotHeight * (w.globals.maxY - extremes.max) / yRange;
    const roomBelow = plotHeight * (extremes.min - w.globals.minY) / yRange;
    return {
      top: Math.min(Math.max(half - roomAbove, 0), half),
      bottom: Math.min(Math.max(half - roomBelow, 0), half)
    };
  }
  /**
   * Whether every drawn series is one whose stroke follows the data points, so
   * the extreme datum marks the outermost ink. False for anything that strokes
   * to the baseline or fills the plot (bar, heatmap, ...) and for stacked
   * charts, where the ink is the cumulative total rather than the raw values.
   * @returns {boolean}
   **/
  _strokeTracesDataPoints() {
    const w = this.w;
    if (!w.globals.axisCharts || w.config.chart.stacked) return false;
    const tracesPoints = ["line", "area", "scatter"];
    return (
      /** @type {any[]} */
      w.config.series.every(
        (s2) => tracesPoints.includes(s2.type || w.config.chart.type)
      )
    );
  }
  /**
   * Min / max across every plotted y value, or null when nothing is plottable.
   * @returns {{ min: number, max: number } | null}
   **/
  _getSeriesYExtremes() {
    let min = Infinity;
    let max = -Infinity;
    this.w.seriesData.series.forEach((data) => {
      if (!Array.isArray(data)) return;
      data.forEach((val) => {
        if (!Number.isFinite(val)) return;
        if (val < min) min = val;
        if (val > max) max = val;
      });
    });
    return min === Infinity ? null : { min, max };
  }
}
class DimXAxis {
  /**
   * @param {import('./Dimensions').default} dCtx
   */
  constructor(dCtx) {
    this.w = dCtx.w;
    this.dCtx = dCtx;
  }
  /**
   * Get X Axis Dimensions
   * @memberof Dimensions
   * @return {{width: number, height: number}}
   **/
  getxAxisLabelsCoords() {
    const w = this.w;
    let xaxisLabels = w.labelData.labels.slice();
    if (w.config.xaxis.convertedCatToNumeric && xaxisLabels.length === 0) {
      xaxisLabels = w.labelData.categoryLabels;
    }
    let rect;
    if (w.labelData.timescaleLabels.length > 0) {
      const coords = this.getxAxisTimeScaleLabelsCoords();
      rect = {
        width: coords.width,
        height: coords.height
      };
      w.layout.rotateXLabels = false;
    } else {
      this.dCtx.lgWidthForSideLegends = (w.config.legend.position === "left" || w.config.legend.position === "right") && !w.config.legend.floating ? this.dCtx.lgRect.width : 0;
      const xlbFormatter = w.formatters.xLabelFormatter;
      let val = Utils$1.getLargestStringFromArr(xaxisLabels);
      let valArr = this.dCtx.dimHelpers.getLargestStringFromMultiArr(
        val,
        xaxisLabels
      );
      if (w.globals.isBarHorizontal) {
        val = w.globals.yAxisScale[0].result.reduce(
          (a2, b) => a2.length > b.length ? a2 : b,
          0
        );
        valArr = val;
      }
      const xFormat = new Formatters(this.w);
      const timestamp = val;
      val = xFormat.xLabelFormat(
        /** @type {Function} */
        xlbFormatter,
        val,
        timestamp,
        {
          i: void 0,
          dateFormatter: new DateTime(this.w).formatDate,
          w
        }
      );
      valArr = xFormat.xLabelFormat(
        /** @type {Function} */
        xlbFormatter,
        valArr,
        timestamp,
        {
          i: void 0,
          dateFormatter: new DateTime(this.w).formatDate,
          w
        }
      );
      if (w.config.xaxis.convertedCatToNumeric && typeof val === "undefined" || String(val).trim() === "") {
        val = "1";
        valArr = val;
      }
      const graphics = new Graphics(this.w);
      let xLabelrect = graphics.getTextRects(
        val,
        w.config.xaxis.labels.style.fontSize
      );
      let xArrLabelrect = xLabelrect;
      if (val !== valArr) {
        xArrLabelrect = graphics.getTextRects(
          valArr,
          w.config.xaxis.labels.style.fontSize
        );
      }
      rect = {
        width: xLabelrect.width >= xArrLabelrect.width ? xLabelrect.width : xArrLabelrect.width,
        height: xLabelrect.height >= xArrLabelrect.height ? xLabelrect.height : xArrLabelrect.height
      };
      if (rect.width * xaxisLabels.length > w.globals.svgWidth - this.dCtx.lgWidthForSideLegends - this.dCtx.yAxisWidth - this.dCtx.gridPad.left - this.dCtx.gridPad.right && w.config.xaxis.labels.rotate !== 0 || w.config.xaxis.labels.rotateAlways) {
        if (!w.globals.isBarHorizontal) {
          w.layout.rotateXLabels = true;
          const getRotatedTextRects = (text) => {
            return graphics.getTextRects(
              text,
              w.config.xaxis.labels.style.fontSize,
              w.config.xaxis.labels.style.fontFamily,
              `rotate(${w.config.xaxis.labels.rotate} 0 0)`,
              false
            );
          };
          xLabelrect = getRotatedTextRects(val);
          if (val !== valArr) {
            xArrLabelrect = getRotatedTextRects(valArr);
          }
          rect.height = (xLabelrect.height > xArrLabelrect.height ? xLabelrect.height : xArrLabelrect.height) / 1.5;
          rect.width = xLabelrect.width > xArrLabelrect.width ? xLabelrect.width : xArrLabelrect.width;
        }
      } else {
        w.layout.rotateXLabels = false;
      }
    }
    if (!w.config.xaxis.labels.show) {
      rect = {
        width: 0,
        height: 0
      };
    }
    return {
      width: rect.width,
      height: rect.height
    };
  }
  /**
   * Get X Axis Label Group height
   * @memberof Dimensions
   * @return {{width: number, height: number}}
   */
  getxAxisGroupLabelsCoords() {
    var _a;
    const w = this.w;
    if (!w.labelData.hasXaxisGroups) {
      return { width: 0, height: 0 };
    }
    const fontSize = ((_a = w.config.xaxis.group.style) == null ? void 0 : _a.fontSize) || w.config.xaxis.labels.style.fontSize;
    const xaxisLabels = w.labelData.groups.map(
      (g) => g.title
    );
    let rect;
    const val = Utils$1.getLargestStringFromArr(xaxisLabels);
    const valArr = this.dCtx.dimHelpers.getLargestStringFromMultiArr(
      val,
      xaxisLabels
    );
    const graphics = new Graphics(this.w);
    const xLabelrect = graphics.getTextRects(val, fontSize);
    let xArrLabelrect = xLabelrect;
    if (val !== valArr) {
      xArrLabelrect = graphics.getTextRects(valArr, fontSize);
    }
    rect = {
      width: xLabelrect.width >= xArrLabelrect.width ? xLabelrect.width : xArrLabelrect.width,
      height: xLabelrect.height >= xArrLabelrect.height ? xLabelrect.height : xArrLabelrect.height
    };
    if (!w.config.xaxis.labels.show) {
      rect = {
        width: 0,
        height: 0
      };
    }
    return {
      width: rect.width,
      height: rect.height
    };
  }
  /**
   * Get X Axis Title Dimensions
   * @memberof Dimensions
   * @return {{width: number, height: number}}
   **/
  getxAxisTitleCoords() {
    const w = this.w;
    let width = 0;
    let height = 0;
    if (w.config.xaxis.title.text !== void 0) {
      const graphics = new Graphics(this.w);
      const rect = graphics.getTextRects(
        w.config.xaxis.title.text,
        w.config.xaxis.title.style.fontSize
      );
      width = rect.width;
      height = rect.height;
    }
    return {
      width,
      height
    };
  }
  getxAxisTimeScaleLabelsCoords() {
    const w = this.w;
    this.dCtx.timescaleLabels = w.labelData.timescaleLabels.slice();
    const labels = this.dCtx.timescaleLabels.map(
      (label) => label.value
    );
    const val = labels.reduce((a2, b) => {
      if (typeof a2 === "undefined") {
        console.error(
          "You have possibly supplied invalid Date format. Please supply a valid JavaScript Date"
        );
        return 0;
      } else {
        return a2.length > b.length ? a2 : b;
      }
    }, 0);
    const graphics = new Graphics(this.w);
    const rect = graphics.getTextRects(
      val,
      w.config.xaxis.labels.style.fontSize
    );
    const totalWidthRotated = rect.width * 1.05 * labels.length;
    if (totalWidthRotated > w.layout.gridWidth && w.config.xaxis.labels.rotate !== 0) {
      w.globals.overlappingXLabels = true;
    }
    return rect;
  }
  // In certain cases, the last labels gets cropped in xaxis.
  // Hence, we add some additional padding based on the label length to avoid the last label being cropped or we don't draw it at all
  /**
   * @param {Record<string, any>} xaxisLabelCoords
   */
  additionalPaddingXLabels(xaxisLabelCoords) {
    const w = this.w;
    const gl = w.globals;
    const cnf = w.config;
    const xtype = cnf.xaxis.type;
    const lbWidth = xaxisLabelCoords.width;
    gl.skipLastTimelinelabel = false;
    gl.skipFirstTimelinelabel = false;
    const isBarOpposite = w.config.yaxis[0].opposite && w.globals.isBarHorizontal;
    const isCollapsed = (i2) => gl.collapsedSeriesIndices.indexOf(i2) !== -1;
    const rightPad = (yaxe) => {
      if (this.dCtx.timescaleLabels && this.dCtx.timescaleLabels.length) {
        const firstimescaleLabel = this.dCtx.timescaleLabels[0];
        const lastTimescaleLabel = this.dCtx.timescaleLabels[this.dCtx.timescaleLabels.length - 1];
        const lastLabelPosition = lastTimescaleLabel.position + lbWidth / 1.75 - this.dCtx.yAxisWidthRight;
        const firstLabelPosition = firstimescaleLabel.position - lbWidth / 1.75 + this.dCtx.yAxisWidthLeft;
        const lgRightRectWidth = w.config.legend.position === "right" && this.dCtx.lgRect.width > 0 ? this.dCtx.lgRect.width : 0;
        if (lastLabelPosition > gl.svgWidth - w.layout.translateX - lgRightRectWidth) {
          gl.skipLastTimelinelabel = true;
        }
        if (firstLabelPosition < -((!yaxe.show || yaxe.floating) && (cnf.chart.type === "bar" || cnf.chart.type === "candlestick" || cnf.chart.type === "rangeBar" || cnf.chart.type === "boxPlot" || cnf.chart.type === "violin") ? lbWidth / 1.75 : 10)) {
          gl.skipFirstTimelinelabel = true;
        }
      } else if (xtype === "datetime") {
        if (this.dCtx.gridPad.right < lbWidth && !w.layout.rotateXLabels) {
          gl.skipLastTimelinelabel = true;
        }
      } else if (xtype !== "datetime") {
        if (this.dCtx.gridPad.right < lbWidth / 2 - this.dCtx.yAxisWidthRight && !w.layout.rotateXLabels && !w.config.xaxis.labels.trim) {
          this.dCtx.xPadRight = lbWidth / 2 + 1;
        }
      }
    };
    const padYAxe = (yaxe, i2) => {
      if (cnf.yaxis.length > 1 && isCollapsed(i2)) return;
      rightPad(yaxe);
    };
    cnf.yaxis.forEach((yaxe, i2) => {
      if (isBarOpposite) {
        if (this.dCtx.gridPad.left < lbWidth) {
          this.dCtx.xPadLeft = lbWidth / 2 + 1;
        }
        this.dCtx.xPadRight = lbWidth / 2 + 1;
      } else {
        padYAxe(yaxe, i2);
      }
    });
  }
}
class DimYAxis {
  /**
   * @param {import('./Dimensions').default} dCtx
   */
  constructor(dCtx) {
    this.w = dCtx.w;
    this.dCtx = dCtx;
  }
  /**
   * Get Y Axis Dimensions
   * @memberof Dimensions
   * @returns {Array<{width: number, height: number}>}
   **/
  getyAxisLabelsCoords() {
    const w = this.w;
    const width = 0;
    const height = 0;
    const ret = [];
    let labelPad = 10;
    const axesUtils = new AxesUtils(this.w, { theme: this.dCtx.theme, timeScale: this.dCtx.timeScale });
    w.config.yaxis.map((yaxe, index) => {
      const formatterArgs = {
        seriesIndex: index,
        dataPointIndex: -1,
        w
      };
      const yS = w.globals.yAxisScale[index];
      let yAxisMinWidth = 0;
      if (!axesUtils.isYAxisHidden(index) && yaxe.labels.show && yaxe.labels.minWidth !== void 0)
        yAxisMinWidth = yaxe.labels.minWidth;
      if (!axesUtils.isYAxisHidden(index) && yaxe.labels.show && yS.result.length) {
        const lbFormatter = w.formatters.yLabelFormatters[index];
        const minV = yS.niceMin === Number.MIN_VALUE ? 0 : yS.niceMin;
        let val = yS.result.reduce((acc, curr) => {
          var _a, _b;
          return ((_a = String(lbFormatter(acc, formatterArgs))) == null ? void 0 : _a.length) > ((_b = String(lbFormatter(curr, formatterArgs))) == null ? void 0 : _b.length) ? acc : curr;
        }, minV);
        val = lbFormatter(val, formatterArgs);
        let valArr = val;
        if (typeof val === "undefined" || val.length === 0) {
          val = yS.niceMax;
        }
        if (String(val).length === 1) {
          val = val + ".0";
          valArr = val;
        }
        if (w.globals.isBarHorizontal) {
          labelPad = 0;
          const barYaxisLabels = w.labelData.labels.slice();
          val = Utils$1.getLargestStringFromArr(barYaxisLabels);
          val = lbFormatter(val, { seriesIndex: index, dataPointIndex: -1, w });
          valArr = this.dCtx.dimHelpers.getLargestStringFromMultiArr(
            val,
            barYaxisLabels
          );
        }
        const graphics = new Graphics(this.w);
        const rotateStr = "rotate(".concat(yaxe.labels.rotate, " 0 0)");
        const rect = graphics.getTextRects(
          val,
          yaxe.labels.style.fontSize,
          yaxe.labels.style.fontFamily,
          rotateStr,
          false
        );
        let arrLabelrect = rect;
        if (val !== valArr) {
          arrLabelrect = graphics.getTextRects(
            valArr,
            yaxe.labels.style.fontSize,
            yaxe.labels.style.fontFamily,
            rotateStr,
            false
          );
        }
        ret.push({
          width: (yAxisMinWidth > arrLabelrect.width || yAxisMinWidth > rect.width ? yAxisMinWidth : arrLabelrect.width > rect.width ? arrLabelrect.width : rect.width) + labelPad,
          height: arrLabelrect.height > rect.height ? arrLabelrect.height : rect.height
        });
      } else {
        ret.push({
          width,
          height
        });
      }
    });
    return ret;
  }
  /**
   * Get Y Axis Dimensions
   * @memberof Dimensions
   * @returns {Array<{width: number, height: number}>}
   **/
  getyAxisTitleCoords() {
    const w = this.w;
    const ret = [];
    w.config.yaxis.map((yaxe) => {
      if (yaxe.show && yaxe.title.text !== void 0) {
        const graphics = new Graphics(this.w);
        const rotateStr = "rotate(".concat(yaxe.title.rotate, " 0 0)");
        const rect = graphics.getTextRects(
          yaxe.title.text,
          yaxe.title.style.fontSize,
          yaxe.title.style.fontFamily,
          rotateStr,
          false
        );
        ret.push({
          width: rect.width,
          height: rect.height
        });
      } else {
        ret.push({
          width: 0,
          height: 0
        });
      }
    });
    return ret;
  }
  getTotalYAxisWidth() {
    const w = this.w;
    let yAxisWidth = 0;
    let yAxisWidthLeft = 0;
    let yAxisWidthRight = 0;
    const padding = w.globals.yAxisScale.length > 1 ? 10 : 0;
    const axesUtils = new AxesUtils(this.w, { theme: this.dCtx.theme, timeScale: this.dCtx.timeScale });
    const isHiddenYAxis = function(index) {
      return w.globals.ignoreYAxisIndexes.indexOf(index) > -1;
    };
    const padForLabelTitle = (coord, index) => {
      const floating = w.config.yaxis[index].floating;
      let width = 0;
      if (coord.width > 0 && !floating) {
        width = coord.width + padding;
        if (isHiddenYAxis(index)) {
          width = width - coord.width - padding;
        }
      } else {
        width = floating || axesUtils.isYAxisHidden(index) ? 0 : 5;
      }
      w.config.yaxis[index].opposite ? yAxisWidthRight = yAxisWidthRight + width : yAxisWidthLeft = yAxisWidthLeft + width;
      yAxisWidth = yAxisWidth + width;
    };
    w.layout.yLabelsCoords.map((yLabelCoord, index) => {
      padForLabelTitle(yLabelCoord, index);
    });
    w.layout.yTitleCoords.map((yTitleCoord, index) => {
      padForLabelTitle(yTitleCoord, index);
    });
    if (w.globals.isBarHorizontal && !w.config.yaxis[0].floating) {
      yAxisWidth = w.layout.yLabelsCoords[0].width + w.layout.yTitleCoords[0].width + 15;
    }
    this.dCtx.yAxisWidthLeft = yAxisWidthLeft;
    this.dCtx.yAxisWidthRight = yAxisWidthRight;
    return yAxisWidth;
  }
}
class DimGrid {
  /**
   * @param {import('./Dimensions').default} dCtx
   */
  constructor(dCtx) {
    this.w = dCtx.w;
    this.dCtx = dCtx;
  }
  /**
   * @param {number} gridWidth
   */
  gridPadForColumnsInNumericAxis(gridWidth) {
    const { w } = this;
    const { config: cnf, globals: gl } = w;
    if (gl.noData || gl.collapsedSeries.length + gl.ancillaryCollapsedSeries.length === cnf.series.length) {
      return 0;
    }
    const hasBar = (type2) => ["bar", "rangeBar", "candlestick", "boxPlot", "violin"].includes(type2);
    const type = cnf.chart.type;
    let barWidth = 0;
    let seriesLen = hasBar(type) ? cnf.series.length : 1;
    if (gl.comboBarCount > 0) {
      seriesLen = gl.comboBarCount;
    }
    gl.collapsedSeries.forEach((c2) => {
      if (hasBar(c2.type)) {
        seriesLen -= 1;
      }
    });
    if (cnf.chart.stacked) {
      seriesLen = 1;
    }
    const barsPresent = hasBar(type) || gl.comboBarCount > 0;
    let xRange = Math.abs(gl.initialMaxX - gl.initialMinX);
    if (barsPresent && w.axisFlags.isXNumeric && !gl.isBarHorizontal && seriesLen > 0 && xRange !== 0) {
      if (xRange <= 3) {
        xRange = gl.dataPoints;
      }
      const xRatio = xRange / gridWidth;
      let xDivision = gl.minXDiff && gl.minXDiff / xRatio > 0 ? gl.minXDiff / xRatio : 0;
      if (xDivision > gridWidth / 2) {
        xDivision /= 2;
      }
      barWidth = xDivision * parseInt(cnf.plotOptions.bar.columnWidth, 10) / 100;
      if (barWidth < 1) {
        barWidth = 1;
      }
      gl.barPadForNumericAxis = barWidth;
    }
    return barWidth;
  }
  /**
   * Reserve room to the right of the plot for stacked *total* dataLabels on a
   * 100% horizontal bar chart.
   *
   * The total label is placed just past the end of the stack. Under
   * `stackType: '100%'` every stack ends at the axis maximum, i.e. exactly at
   * the right edge of the plot, so the label was drawn outside the grid and
   * clipped by the SVG viewport. See #3579.
   *
   * Scoped to the 100% case on purpose: with ordinary stacking the axis
   * maximum is a rounded "nice" number that normally sits beyond the longest
   * stack, so there is already room and padding every such chart would move
   * layouts that render correctly today.
   *
   * Raises `xPadRight`, which narrows `gridWidth` without translating the plot
   * origin, so the y-axis and its labels stay put and only the bars get
   * shorter.
   */
  gridPadForStackedTotalDataLabels() {
    const { w } = this;
    const totalConfig = w.config.plotOptions.bar.dataLabels.total;
    if (!w.globals.isBarHorizontal || !w.config.chart.stacked || w.config.chart.stackType !== "100%" || !totalConfig.enabled) {
      return;
    }
    const totals = w.seriesData.stackedSeriesTotals || [];
    if (!totals.length) return;
    const formatter = totalConfig.formatter || w.config.dataLabels.formatter;
    const labels = totals.map(
      (val, j) => String(
        formatter ? formatter(val, __spreadProps(__spreadValues({}, w), { seriesIndex: 0, dataPointIndex: j, w })) : val
      )
    );
    const graphics = new Graphics(w);
    const rect = graphics.getTextRects(
      Utils$1.getLargestStringFromArr(labels),
      parseFloat(totalConfig.style.fontSize).toString(),
      totalConfig.style.fontFamily
    );
    const needed = rect.width + Math.abs(totalConfig.offsetX || 0) + 2;
    this.dCtx.xPadRight = Math.max(this.dCtx.xPadRight, needed);
  }
  gridPadFortitleSubtitle() {
    const { w } = this;
    const { globals: gl } = w;
    let gridShrinkOffset = this.dCtx.isSparkline || !gl.axisCharts ? 0 : 10;
    const titleSubtitle = ["title", "subtitle"];
    titleSubtitle.forEach((t2) => {
      if (w.config[t2].text !== void 0) {
        gridShrinkOffset += w.config[t2].margin;
      } else {
        gridShrinkOffset += this.dCtx.isSparkline || !gl.axisCharts ? 0 : 5;
      }
    });
    if (w.config.legend.show && w.config.legend.position === "bottom" && !w.config.legend.floating && !gl.axisCharts) {
      gridShrinkOffset += 10;
    }
    const titleCoords = this.dCtx.dimHelpers.getTitleSubtitleCoords("title");
    const subtitleCoords = this.dCtx.dimHelpers.getTitleSubtitleCoords("subtitle");
    this.dCtx.titleBlockPad = gridShrinkOffset;
    w.layout.gridHeight -= titleCoords.height + subtitleCoords.height + gridShrinkOffset;
    w.layout.translateY += titleCoords.height + subtitleCoords.height + gridShrinkOffset;
  }
  /**
   * @param {{width: number, height: number}[]} yTitleCoords
   * @param {{width: number, height: number}[]} yaxisLabelCoords
   */
  setGridXPosForDualYAxis(yTitleCoords, yaxisLabelCoords) {
    const { w } = this;
    const axesUtils = new AxesUtils(this.w, { theme: this.dCtx.theme, timeScale: this.dCtx.timeScale });
    w.config.yaxis.forEach((yaxe, index) => {
      if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1 && !yaxe.floating && !axesUtils.isYAxisHidden(index)) {
        if (yaxe.opposite) {
          w.layout.translateX -= yaxisLabelCoords[index].width + yTitleCoords[index].width + parseInt(yaxe.labels.style.fontSize, 10) / 1.2 + 12;
        }
        if (w.layout.translateX < 2) {
          w.layout.translateX = 2;
        }
      }
    });
  }
}
const BREADCRUMB_HEIGHT = 18;
const BREADCRUMB_HEIGHT_FULL = 23;
function breadcrumbConfig(w, localCfg) {
  const shared = w.config.drilldown && w.config.drilldown.breadcrumb || {};
  return __spreadValues(__spreadValues({
    show: true,
    position: "top-left",
    separator: " / ",
    rootLabel: "All",
    offsetX: 0,
    offsetY: 0,
    formatter: void 0
  }, shared), localCfg || {});
}
class Dimensions {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.theme = ctx.theme;
    this.timeScale = ctx.timeScale;
    this.lgRect = /** @type {any} */
    {};
    this.yAxisWidth = 0;
    this.yAxisWidthLeft = 0;
    this.yAxisWidthRight = 0;
    this.xAxisHeight = 0;
    this.isSparkline = this.w.config.chart.sparkline.enabled;
    this.dimHelpers = new Helpers(this);
    this.dimYAxis = new DimYAxis(this);
    this.dimXAxis = new DimXAxis(this);
    this.dimGrid = new DimGrid(this);
    this.lgWidthForSideLegends = 0;
    this.gridPad = __spreadValues({}, this.w.config.grid.padding);
    this.xPadRight = 0;
    this.titleBlockPad = 0;
    this.xPadLeft = 0;
    this.datalabelsCoords = { width: 0, height: 0 };
    this.xAxisWidth = 0;
    this.timescaleLabels = [];
  }
  /**
   * @memberof Dimensions
   **/
  plotCoords() {
    const w = this.w;
    const gl = w.globals;
    this.gridPad = __spreadValues({}, w.config.grid.padding);
    this.lgRect = this.dimHelpers.getLegendsRect();
    this.datalabelsCoords = { width: 0, height: 0 };
    if (this.isSparkline) {
      if (this.w.globals.markers.largestSize > 0) {
        Object.entries(this.gridPad).forEach(([k, v]) => {
          this.gridPad[k] = Math.max(
            v,
            this.w.globals.markers.largestSize / 1.5
          );
        });
      }
      const strokeInset = this.dimHelpers.getSparklineStrokeInset();
      this.gridPad.top = Math.max(strokeInset.top, this.gridPad.top);
      this.gridPad.bottom = Math.max(strokeInset.bottom, this.gridPad.bottom);
    }
    if (gl.axisCharts) {
      this.setDimensionsForAxisCharts();
    } else {
      this.setDimensionsForNonAxisCharts();
    }
    this.dimGrid.gridPadFortitleSubtitle();
    this.gridPadForBreadcrumb();
    this.dimGrid.gridPadForStackedTotalDataLabels();
    w.layout.gridHeight = w.layout.gridHeight - this.gridPad.top - this.gridPad.bottom;
    w.layout.gridWidth = w.layout.gridWidth - this.gridPad.left - this.gridPad.right - this.xPadRight - this.xPadLeft;
    const barWidth = this.dimGrid.gridPadForColumnsInNumericAxis(
      w.layout.gridWidth
    );
    w.layout.gridWidth = w.layout.gridWidth - barWidth * 2;
    w.layout.translateX = w.layout.translateX + this.gridPad.left + this.xPadLeft + (barWidth > 0 ? barWidth : 0);
    w.layout.translateY = w.layout.translateY + this.gridPad.top;
    return {
      // w.layout (future slice)
      layout: {
        gridHeight: w.layout.gridHeight,
        gridWidth: w.layout.gridWidth,
        translateX: w.layout.translateX,
        translateY: w.layout.translateY,
        translateXAxisX: w.layout.translateXAxisX,
        translateXAxisY: w.layout.translateXAxisY,
        rotateXLabels: w.layout.rotateXLabels,
        xAxisHeight: w.layout.xAxisHeight,
        xAxisLabelsHeight: w.layout.xAxisLabelsHeight,
        xAxisGroupLabelsHeight: w.layout.xAxisGroupLabelsHeight,
        xAxisLabelsWidth: w.layout.xAxisLabelsWidth,
        yLabelsCoords: w.layout.yLabelsCoords,
        yTitleCoords: w.layout.yTitleCoords,
        gridPad: __spreadValues({}, this.gridPad)
      }
    };
  }
  /**
   * Reserve a strip above the plot for a navigation breadcrumb.
   *
   * A treemap fills its plot edge to edge, so unlike a sunburst - whose rings
   * leave the corners empty - an absolutely-positioned breadcrumb has nowhere
   * to float without covering a tile. Giving it real space is the only way it
   * never overlaps.
   *
   * Reserved whenever click-to-zoom is enabled, not only while zoomed in: the
   * strip appears and disappears as the reader navigates, and sizing the plot
   * around its presence would reflow every tile on each zoom.
   */
  gridPadForBreadcrumb() {
    var _a, _b, _c, _d, _e, _f;
    const w = this.w;
    const isTreemap = w.config.chart.type === "treemap";
    if (isTreemap) {
      const zoom = (_b = (_a = w.config.plotOptions) == null ? void 0 : _a.treemap) == null ? void 0 : _b.zoom;
      if (zoom && zoom.enabled) {
        if (breadcrumbConfig(w, zoom.breadcrumb).show === false) return;
        this.gridPad.top += BREADCRUMB_HEIGHT + 4;
        return;
      }
    }
    if (!w.globals.axisCharts) return;
    if (!this.ctx.drilldown) return;
    if (!w.config.drilldown || !w.config.drilldown.enabled) return;
    if (breadcrumbConfig(w).show === false) return;
    const labelFs = parseFloat(String((_f = (_e = (_d = (_c = w.config.yaxis) == null ? void 0 : _c[0]) == null ? void 0 : _d.labels) == null ? void 0 : _e.style) == null ? void 0 : _f.fontSize)) || 11;
    const yLabelOverhang = isTreemap ? 0 : Math.ceil(labelFs * LINE_HEIGHT_RATIO / 2);
    const needed = BREADCRUMB_HEIGHT_FULL + 1 + yLabelOverhang;
    const alreadyFree = isTreemap ? 0 : this.titleBlockPad || 0;
    this.gridPad.top += Math.max(0, needed - alreadyFree);
  }
  setDimensionsForAxisCharts() {
    const w = this.w;
    const gl = w.globals;
    const yaxisLabelCoords = this.dimYAxis.getyAxisLabelsCoords();
    const yTitleCoords = this.dimYAxis.getyAxisTitleCoords();
    if (gl.isSlopeChart) {
      this.datalabelsCoords = this.dimHelpers.getDatalabelsRect();
    }
    w.layout.yLabelsCoords = [];
    w.layout.yTitleCoords = [];
    w.config.yaxis.map((yaxe, index) => {
      w.layout.yLabelsCoords.push({
        width: yaxisLabelCoords[index].width,
        index
      });
      w.layout.yTitleCoords.push(
        /** @type {any} */
        {
          width: yTitleCoords[index].width,
          index
        }
      );
    });
    this.yAxisWidth = this.dimYAxis.getTotalYAxisWidth();
    const xaxisLabelCoords = this.dimXAxis.getxAxisLabelsCoords();
    const xaxisGroupLabelCoords = this.dimXAxis.getxAxisGroupLabelsCoords();
    const xtitleCoords = this.dimXAxis.getxAxisTitleCoords();
    this.conditionalChecksForAxisCoords(
      xaxisLabelCoords,
      xtitleCoords,
      xaxisGroupLabelCoords
    );
    w.layout.translateXAxisY = w.layout.rotateXLabels ? this.xAxisHeight / 8 : -4;
    w.layout.translateXAxisX = w.layout.rotateXLabels && w.axisFlags.isXNumeric && w.config.xaxis.labels.rotate <= -45 ? -this.xAxisWidth / 4 : 0;
    if (w.globals.isBarHorizontal) {
      w.layout.rotateXLabels = false;
      w.layout.translateXAxisY = -1 * ((parseInt(w.config.xaxis.labels.style.fontSize, 10) || 12) / 1.5);
    }
    w.layout.translateXAxisY = w.layout.translateXAxisY + w.config.xaxis.labels.offsetY;
    w.layout.translateXAxisX = w.layout.translateXAxisX + w.config.xaxis.labels.offsetX;
    let yAxisWidth = this.yAxisWidth;
    let xAxisHeight = this.xAxisHeight;
    w.layout.xAxisLabelsHeight = this.xAxisHeight - xtitleCoords.height;
    w.layout.xAxisGroupLabelsHeight = w.layout.xAxisLabelsHeight - xaxisLabelCoords.height;
    w.layout.xAxisLabelsWidth = this.xAxisWidth;
    w.layout.xAxisHeight = this.xAxisHeight;
    let translateY = 10;
    if (w.config.chart.type === "radar" || this.isSparkline) {
      yAxisWidth = 0;
      xAxisHeight = 0;
    }
    if (this.isSparkline) {
      this.lgRect = {
        height: 0,
        width: 0
      };
    }
    if (this.isSparkline || w.config.chart.type === "treemap") {
      yAxisWidth = 0;
      xAxisHeight = 0;
      translateY = 0;
    }
    if (!this.isSparkline && w.config.chart.type !== "treemap") {
      this.dimXAxis.additionalPaddingXLabels(xaxisLabelCoords);
    }
    const legendTopBottom = () => {
      w.layout.translateX = yAxisWidth + this.datalabelsCoords.width;
      w.layout.gridHeight = gl.svgHeight - this.lgRect.height - xAxisHeight - (!this.isSparkline && w.config.chart.type !== "treemap" ? w.layout.rotateXLabels ? 10 : 15 : 0);
      w.layout.gridWidth = gl.svgWidth - yAxisWidth - this.datalabelsCoords.width * 2;
    };
    if (w.config.xaxis.position === "top")
      translateY = w.layout.xAxisHeight - w.config.xaxis.axisTicks.height - 5;
    switch (w.config.legend.position) {
      case "bottom":
        w.layout.translateY = translateY;
        legendTopBottom();
        break;
      case "top":
        w.layout.translateY = this.lgRect.height + translateY;
        legendTopBottom();
        break;
      case "left":
        w.layout.translateY = translateY;
        w.layout.translateX = this.lgRect.width + yAxisWidth + this.datalabelsCoords.width;
        w.layout.gridHeight = gl.svgHeight - xAxisHeight - 12;
        w.layout.gridWidth = gl.svgWidth - this.lgRect.width - yAxisWidth - this.datalabelsCoords.width * 2;
        break;
      case "right":
        w.layout.translateY = translateY;
        w.layout.translateX = yAxisWidth + this.datalabelsCoords.width;
        w.layout.gridHeight = gl.svgHeight - xAxisHeight - 12;
        w.layout.gridWidth = gl.svgWidth - this.lgRect.width - yAxisWidth - this.datalabelsCoords.width * 2 - 5;
        break;
      default:
        throw new Error("Legend position not supported");
    }
    this.dimGrid.setGridXPosForDualYAxis(yTitleCoords, yaxisLabelCoords);
    const objyAxis = new YAxis(this.w, {
      theme: this.theme,
      timeScale: this.timeScale
    });
    objyAxis.setYAxisXPosition(yaxisLabelCoords, yTitleCoords);
  }
  setDimensionsForNonAxisCharts() {
    const w = this.w;
    const gl = w.globals;
    const cnf = w.config;
    let xPad = 0;
    if (w.config.legend.show && !w.config.legend.floating) {
      xPad = 20;
    }
    if (cnf.chart.type === "unit") {
      const legendVisible = cnf.legend.show && !cnf.legend.floating;
      const pos = cnf.legend.position;
      let top = 0;
      let side = 0;
      if (legendVisible) {
        if (pos === "bottom" || pos === "top") {
          top = this.lgRect.height;
        } else {
          side = this.lgRect.width + xPad;
        }
      }
      w.layout.gridWidth = gl.svgWidth - side;
      w.layout.gridHeight = gl.svgHeight - top;
      w.layout.translateX = pos === "left" ? side : 0;
      w.layout.translateY = pos === "top" ? top : 0;
      return;
    }
    const type = cnf.chart.type === "sunburst" ? "sunburst" : cnf.chart.type === "pie" || cnf.chart.type === "polarArea" || cnf.chart.type === "donut" ? "pie" : "radialBar";
    const offY = cnf.plotOptions[type].offsetY;
    const offX = cnf.plotOptions[type].offsetX;
    if (!cnf.legend.show || cnf.legend.floating) {
      w.layout.gridHeight = gl.svgHeight;
      const maxWidth = w.dom.elWrap.getBoundingClientRect().width;
      w.layout.gridWidth = Math.min(maxWidth, w.layout.gridHeight);
      w.layout.translateY = offY;
      w.layout.translateX = offX + (gl.svgWidth - w.layout.gridWidth) / 2;
      return;
    }
    switch (cnf.legend.position) {
      case "bottom":
        w.layout.gridHeight = gl.svgHeight - this.lgRect.height;
        w.layout.gridWidth = gl.svgWidth;
        w.layout.translateY = offY - 10;
        w.layout.translateX = offX + (gl.svgWidth - w.layout.gridWidth) / 2;
        break;
      case "top":
        w.layout.gridHeight = gl.svgHeight - this.lgRect.height;
        w.layout.gridWidth = gl.svgWidth;
        w.layout.translateY = this.lgRect.height + offY + 10;
        w.layout.translateX = offX + (gl.svgWidth - w.layout.gridWidth) / 2;
        break;
      case "left":
        w.layout.gridWidth = gl.svgWidth - this.lgRect.width - xPad;
        w.layout.gridHeight = cnf.chart.height !== "auto" ? gl.svgHeight : w.layout.gridWidth;
        w.layout.translateY = offY;
        w.layout.translateX = offX + this.lgRect.width + xPad;
        break;
      case "right":
        w.layout.gridWidth = gl.svgWidth - this.lgRect.width - xPad - 5;
        w.layout.gridHeight = cnf.chart.height !== "auto" ? gl.svgHeight : w.layout.gridWidth;
        w.layout.translateY = offY;
        w.layout.translateX = offX + 10;
        break;
      default:
        throw new Error("Legend position not supported");
    }
  }
  /**
   * @param {any} xaxisLabelCoords
   * @param {any} xtitleCoords
   * @param {any} xaxisGroupLabelCoords
   */
  conditionalChecksForAxisCoords(xaxisLabelCoords, xtitleCoords, xaxisGroupLabelCoords) {
    const w = this.w;
    const xAxisNum = w.labelData.hasXaxisGroups ? 2 : 1;
    const baseXAxisHeight = xaxisGroupLabelCoords.height + xaxisLabelCoords.height + xtitleCoords.height;
    const xAxisHeightMultiplicate = w.axisFlags.isMultiLineX ? 1.2 : LINE_HEIGHT_RATIO;
    const rotatedXAxisOffset = w.layout.rotateXLabels ? 22 : 10;
    const rotatedXAxisLegendOffset = w.layout.rotateXLabels && w.config.legend.position === "bottom";
    const additionalOffset = rotatedXAxisLegendOffset ? 10 : 0;
    this.xAxisHeight = baseXAxisHeight * xAxisHeightMultiplicate + xAxisNum * rotatedXAxisOffset + additionalOffset;
    this.xAxisWidth = xaxisLabelCoords.width;
    if (this.xAxisHeight - xtitleCoords.height > w.config.xaxis.labels.maxHeight) {
      this.xAxisHeight = w.config.xaxis.labels.maxHeight;
    }
    if (w.config.xaxis.labels.minHeight && this.xAxisHeight < w.config.xaxis.labels.minHeight) {
      this.xAxisHeight = w.config.xaxis.labels.minHeight;
    }
    if (w.config.xaxis.floating) {
      this.xAxisHeight = 0;
    }
    let minYAxisWidth = 0;
    let maxYAxisWidth = 0;
    w.config.yaxis.forEach((y) => {
      minYAxisWidth += y.labels.minWidth;
      maxYAxisWidth += y.labels.maxWidth;
    });
    if (this.yAxisWidth < minYAxisWidth) {
      this.yAxisWidth = minYAxisWidth;
    }
    if (this.yAxisWidth > maxYAxisWidth) {
      this.yAxisWidth = maxYAxisWidth;
    }
  }
}
const SECOND = 1e3;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
const APPROX_MONTH = 30 * DAY;
const APPROX_YEAR = 365 * DAY;
const MIN_ZOOM_DAYS = 10 / (24 * 60 * 60);
const TICK_LADDER = [
  { unit: "second", step: 1, approxMs: SECOND },
  { unit: "second", step: 5, approxMs: 5 * SECOND },
  { unit: "second", step: 15, approxMs: 15 * SECOND },
  { unit: "second", step: 30, approxMs: 30 * SECOND },
  { unit: "minute", step: 1, approxMs: MINUTE },
  { unit: "minute", step: 5, approxMs: 5 * MINUTE },
  { unit: "minute", step: 15, approxMs: 15 * MINUTE },
  { unit: "minute", step: 30, approxMs: 30 * MINUTE },
  { unit: "hour", step: 1, approxMs: HOUR },
  { unit: "hour", step: 3, approxMs: 3 * HOUR },
  { unit: "hour", step: 6, approxMs: 6 * HOUR },
  { unit: "hour", step: 12, approxMs: 12 * HOUR },
  { unit: "day", step: 1, approxMs: DAY },
  { unit: "day", step: 2, approxMs: 2 * DAY },
  { unit: "week", step: 1, approxMs: WEEK },
  { unit: "week", step: 2, approxMs: 2 * WEEK },
  { unit: "month", step: 1, approxMs: APPROX_MONTH },
  { unit: "month", step: 3, approxMs: 3 * APPROX_MONTH },
  { unit: "month", step: 6, approxMs: 6 * APPROX_MONTH },
  { unit: "year", step: 1, approxMs: APPROX_YEAR },
  { unit: "year", step: 2, approxMs: 2 * APPROX_YEAR },
  { unit: "year", step: 5, approxMs: 5 * APPROX_YEAR },
  { unit: "year", step: 10, approxMs: 10 * APPROX_YEAR },
  { unit: "year", step: 25, approxMs: 25 * APPROX_YEAR },
  { unit: "year", step: 50, approxMs: 50 * APPROX_YEAR },
  { unit: "year", step: 100, approxMs: 100 * APPROX_YEAR }
];
const DEFAULT_TICK_COUNT = 10;
class TimeScale {
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.tickInterval = null;
    this.timeScaleArray = [];
    this.utc = w.config.xaxis.labels.datetimeUTC;
  }
  /**
   * Compute raw ticks for a datetime axis spanning [minX, maxX]. Single
   * uniform stride — one unit, no promotion, no calendar-boundary overlay.
   * Context (year, day) is folded into each label's format string at
   * `formatDates` time, not split across promoted ticks.
   *
   * @param {number} minX
   * @param {number} maxX
   * @returns {Array<any>} raw ticks (pre-formatting). Pass to recalcDimensionsBasedOnFormat for the final timescaleLabels.
   */
  calculateTimeScaleTicks(minX, maxX) {
    const w = this.w;
    if (w.globals.allSeriesCollapsed) {
      w.labelData.labels = [];
      w.labelData.timescaleLabels = [];
      this.timeScaleArray = [];
      return [];
    }
    const span = maxX - minX;
    const daysDiff = span / DAY;
    w.interact.disableZoomIn = false;
    w.interact.disableZoomOut = false;
    if (daysDiff < MIN_ZOOM_DAYS) {
      w.interact.disableZoomIn = true;
    } else if (daysDiff > 5e4) {
      w.interact.disableZoomOut = true;
    }
    const targetCount = Number.isFinite(w.config.xaxis.tickAmount) ? (
      /** @type {number} */
      w.config.xaxis.tickAmount
    ) : DEFAULT_TICK_COUNT;
    this.tickInterval = pickInterval(span, targetCount);
    const ticks = this.generateBaseTicks(minX, maxX, this.tickInterval);
    this.timeScaleArray = ticks;
    return ticks;
  }
  /**
   * Walk the interval stride from `minX` to `maxX`. Every tick carries
   * `unit: interval.unit` — no promotion, no snapping. Uniform spacing is
   * guaranteed.
   *
   * @param {number} minX
   * @param {number} maxX
   * @param {{ unit: string, step: number }} interval
   * @returns {Array<any>}
   */
  generateBaseTicks(minX, maxX, interval) {
    const w = this.w;
    const dt = new DateTime(w);
    const isUTC = this.utc;
    const gridWidth = w.layout.gridWidth;
    const span = maxX - minX;
    const ticks = [];
    let t2 = dt.ceilToBoundary(
      minX,
      /** @type {any} */
      interval.unit,
      interval.step,
      isUTC
    );
    let iter = 0;
    const MAX_ITER = 5e3;
    while (t2 <= maxX && iter < MAX_ITER) {
      const f = dt.getDateFields(t2, isUTC);
      const position = span > 0 ? (t2 - minX) / span * gridWidth : 0;
      ticks.push({
        timestamp: t2,
        position,
        unit: interval.unit,
        year: f.year,
        month: f.month + 1,
        day: f.date,
        hour: f.hour,
        minute: f.minute,
        second: f.second,
        value: t2
      });
      t2 = dt.addInterval(
        t2,
        /** @type {any} */
        interval.unit,
        interval.step,
        isUTC
      );
      iter++;
    }
    return ticks;
  }
  /**
   * Public entry called from Core.js after calculateTimeScaleTicks. Formats
   * the raw ticks into display labels, removes overlapping entries, writes
   * the result to `w.labelData.timescaleLabels`, and re-runs Dimensions to
   * lay out the grid based on the final label widths.
   *
   * @param {Array<any>} rawTicks
   */
  recalcDimensionsBasedOnFormat(rawTicks) {
    const w = this.w;
    const formatted = this.formatDates(rawTicks);
    const filtered = this.removeOverlappingTS(formatted);
    w.labelData.timescaleLabels = filtered.slice();
    const dimensions = new Dimensions(this.w, this.ctx);
    const layoutState = dimensions.plotCoords();
    this.ctx._writeLayoutCoords(layoutState.layout);
  }
  /**
   * Format each raw tick into a display label. All ticks share one
   * effective format computed once from the interval unit and the data
   * range — when the range spans coarser units, the base format from
   * `datetimeFormatter[unit]` is automatically extended with the higher-
   * unit context (e.g. month-scale spanning years → `MMM yyyy`, hour-scale
   * spanning days → `dd MMM HH:mm`). A user-supplied `xaxis.labels.format`
   * overrides everything.
   *
   * @param {Array<any>} rawTicks
   * @returns {Array<any>}
   */
  formatDates(rawTicks) {
    const w = this.w;
    const dt = new DateTime(w);
    const userFormat = w.config.xaxis.labels.format;
    const dtFmt = w.config.xaxis.labels.datetimeFormatter;
    const isUTC = this.utc;
    const pad = (n2, len = 2) => String(n2).padStart(len, "0");
    const effectiveFormat = userFormat ? userFormat : this._effectiveFormat(rawTicks, dtFmt);
    return rawTicks.map((tick) => {
      const date = dt.getDate(tick.timestamp);
      const value = dt.formatDate(date, effectiveFormat);
      const ds = `${tick.year}-${pad(tick.month)}-${pad(tick.day)}T${pad(tick.hour)}:${pad(tick.minute)}:${pad(tick.second)}.000${isUTC ? "Z" : ""}`;
      return {
        dateString: ds,
        position: tick.position,
        value,
        unit: tick.unit,
        year: tick.year,
        month: tick.month
      };
    });
  }
  /**
   * Pick the format string used for every tick this render. Folds coarser
   * context into the base `datetimeFormatter[unit]` when the data range
   * spans it. Skipped when the base format already references the higher
   * unit's tokens (so user customizations aren't doubled).
   *
   * @param {Array<any>} rawTicks
   * @param {Record<string, string>} dtFmt
   * @returns {string}
   */
  _effectiveFormat(rawTicks, dtFmt) {
    if (rawTicks.length === 0) return dtFmt.day || "dd MMM";
    const unit = this.tickInterval && this.tickInterval.unit || rawTicks[0].unit;
    const base = dtFmt[unit === "week" ? "day" : unit] || dtFmt.day || "dd MMM";
    const first = rawTicks[0];
    const last = rawTicks[rawTicks.length - 1];
    const spansYears = first.year !== last.year;
    const spansMonths = spansYears || first.month !== last.month;
    const spansDays = spansMonths || first.day !== last.day;
    const hasYearToken = /y/i.test(base);
    const hasMonthToken = /M/.test(base);
    const hasDayToken = /d/i.test(base);
    if (unit === "month" || unit === "week") {
      if (spansYears && !hasYearToken) return base + " yyyy";
      return base;
    }
    if (unit === "day") {
      if (spansYears && !hasYearToken) return base + " yyyy";
      return base;
    }
    if (unit === "hour" || unit === "minute" || unit === "second") {
      if (spansDays && !hasDayToken && !hasMonthToken) {
        const prefix = spansYears ? "dd MMM yyyy" : "dd MMM";
        return prefix + " " + base;
      }
      return base;
    }
    return base;
  }
  /**
   * Drop labels that would overlap their predecessor (when
   * `xaxis.labels.hideOverlappingLabels` is true). The first label is always
   * kept. Width is measured per-label unless all labels have the same string
   * length, in which case one measurement is reused.
   *
   * @param {Array<any>} arr
   * @returns {Array<any>}
   */
  removeOverlappingTS(arr) {
    if (arr.length === 0) return [];
    const w = this.w;
    const graphics = new Graphics(w);
    let equalLabelLengthFlag = false;
    let constantLabelWidth;
    if (arr[0].value && arr.every((lb) => lb.value.length === arr[0].value.length)) {
      equalLabelLengthFlag = true;
      constantLabelWidth = graphics.getTextRects(
        arr[0].value,
        w.config.xaxis.labels.style.fontSize
      ).width;
    }
    let lastDrawnIndex = 0;
    const filtered = arr.map((item, index) => {
      if (index === 0) return item;
      if (!w.config.xaxis.labels.hideOverlappingLabels) return item;
      const prevLabelWidth = equalLabelLengthFlag ? (
        /** @type {number} */
        constantLabelWidth
      ) : graphics.getTextRects(
        arr[lastDrawnIndex].value,
        w.config.xaxis.labels.style.fontSize
      ).width;
      const prevPos = arr[lastDrawnIndex].position;
      const pos = item.position;
      if (pos > prevPos + prevLabelWidth + 10) {
        lastDrawnIndex = index;
        return item;
      }
      return null;
    }).filter((f) => f !== null);
    return filtered;
  }
}
function pickInterval(span, targetCount) {
  if (!Number.isFinite(targetCount) || targetCount <= 0) {
    targetCount = DEFAULT_TICK_COUNT;
  }
  if (span <= 0) return TICK_LADDER[0];
  const targetMs = span / targetCount;
  let best = TICK_LADDER[0];
  let bestDist = Infinity;
  for (const interval of TICK_LADDER) {
    const dist = Math.abs(Math.log(interval.approxMs / targetMs));
    if (dist < bestDist) {
      bestDist = dist;
      best = interval;
    }
  }
  return best;
}
const REGISTRY_KEY$1 = "__apexcharts_registry__";
const CUSTOM_KEY = "__apexcharts_custom_types__";
if (!/** @type {any} */
globalThis[REGISTRY_KEY$1]) {
  globalThis[REGISTRY_KEY$1] = {};
}
if (!/** @type {any} */
globalThis[CUSTOM_KEY]) {
  globalThis[CUSTOM_KEY] = /* @__PURE__ */ new Set();
}
function getRegistry$1() {
  return (
    /** @type {any} */
    globalThis[REGISTRY_KEY$1]
  );
}
function getCustomTypes() {
  return (
    /** @type {any} */
    globalThis[CUSTOM_KEY]
  );
}
function markCustom(name2) {
  getCustomTypes().add(name2);
}
function isCustom(name2) {
  return getCustomTypes().has(name2);
}
function hasChartClass(type) {
  return !!getRegistry$1()[type];
}
function unregister(name2) {
  delete getRegistry$1()[name2];
  getCustomTypes().delete(name2);
}
function register(typeMap) {
  Object.assign(getRegistry$1(), typeMap);
}
function getChartClass(type) {
  const Cls = getRegistry$1()[type];
  if (!Cls) {
    throw new Error(
      `ApexCharts: chart type "${type}" is not registered. Bundler: import 'apexcharts/${type}'. Script tag: add <script src=".../dist/${type}.js"> after apexcharts.core.js, or load the full apexcharts.js instead.`
    );
  }
  return Cls;
}
class Core {
  /**
   * @param {Element} el
   * @param {import('../types/internal').ChartStateW} w
   * @param {import('../types/internal').ChartContext} ctx
   */
  constructor(el, w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.el = el;
  }
  setupElements() {
    const { globals: gl, config: cnf } = this.w;
    const ct = cnf.chart.type;
    const xyChartsArrTypes = [
      "line",
      "area",
      "bar",
      "rangeBar",
      "rangeArea",
      "candlestick",
      "boxPlot",
      "violin",
      "scatter",
      "bubble"
    ];
    const axisChartsArrTypes = [
      ...xyChartsArrTypes,
      "radar",
      "heatmap",
      "treemap"
    ];
    const isCustomType = !axisChartsArrTypes.includes(ct) && !["pie", "donut", "polarArea", "radialBar"].includes(ct) && isCustom(ct);
    gl.axisCharts = axisChartsArrTypes.includes(ct) || isCustomType;
    gl.xyCharts = xyChartsArrTypes.includes(ct) || isCustomType;
    gl.isBarHorizontal = ["bar", "rangeBar", "boxPlot", "violin"].includes(ct) && cnf.plotOptions.bar.horizontal;
    gl.chartClass = `.apexcharts${gl.chartID}`;
    this.w.dom.baseEl = this.el;
    this.w.dom.elWrap = BrowserAPIs.createElementNS(
      "http://www.w3.org/1999/xhtml",
      "div"
    );
    Graphics.setAttrs(this.w.dom.elWrap, {
      id: gl.chartClass.substring(1),
      class: `apexcharts-canvas ${gl.chartClass.substring(1)}`
    });
    this.el.appendChild(this.w.dom.elWrap);
    const SVG2 = (
      /** @type {any} */
      globalThis.SVG
    );
    this.w.dom.Paper = SVG2().addTo(this.w.dom.elWrap);
    this.w.dom.Paper.attr({
      class: "apexcharts-svg",
      "xmlns:data": "ApexChartsNS",
      transform: `translate(${cnf.chart.offsetX}, ${cnf.chart.offsetY})`
    });
    this.w.dom.Paper.node.style.background = cnf.theme.mode === "dark" && !cnf.chart.background ? "#343A3F" : cnf.theme.mode === "light" && !cnf.chart.background ? "#fff" : cnf.chart.background;
    this.setSVGDimensions();
    this.w.dom.elLegendForeign = BrowserAPIs.createElementNS(
      SVGNS$1,
      "foreignObject"
    );
    Graphics.setAttrs(this.w.dom.elLegendForeign, {
      x: 0,
      y: 0,
      width: gl.svgWidth,
      height: gl.svgHeight
    });
    this.w.dom.elLegendWrap = BrowserAPIs.createElementNS(
      "http://www.w3.org/1999/xhtml",
      "div"
    );
    this.w.dom.elLegendWrap.classList.add("apexcharts-legend");
    this.w.dom.elWrap.appendChild(this.w.dom.elLegendWrap);
    this.w.dom.Paper.node.appendChild(this.w.dom.elLegendForeign);
    if (cnf.chart.accessibility.enabled && cnf.chart.accessibility.announcements.enabled) {
      const srStatus = BrowserAPIs.createElement("div");
      srStatus.className = "apexcharts-sr-status";
      srStatus.setAttribute("role", "status");
      srStatus.setAttribute("aria-live", "polite");
      srStatus.setAttribute("aria-atomic", "true");
      this.w.dom.elWrap.appendChild(srStatus);
    }
    if (cnf.chart.accessibility.enabled) {
      const ariaLabel = this.getAccessibleChartLabel();
      const svgRole = cnf.chart.accessibility.keyboard.enabled && cnf.chart.accessibility.keyboard.navigation.enabled ? "application" : "img";
      this.w.dom.Paper.attr({
        role: svgRole,
        "aria-label": ariaLabel
      });
      if (cnf.chart.accessibility.description) {
        const descEl = BrowserAPIs.createElementNS(SVGNS$1, "desc");
        descEl.textContent = cnf.chart.accessibility.description;
        this.w.dom.Paper.node.insertBefore(
          descEl,
          this.w.dom.elLegendForeign.nextSibling
        );
      }
    }
    this.w.dom.elGraphical = this.w.dom.Paper.group().attr({
      class: "apexcharts-inner apexcharts-graphical"
    });
    this.w.dom.elDefs = this.w.dom.Paper.defs();
    this.w.dom.Paper.add(this.w.dom.elGraphical);
    this.w.dom.elGraphical.add(this.w.dom.elDefs);
  }
  /**
   * Classify each series by its resolved chart type into per-type render
   * buckets (`{ series, i }`, plus `seriesRangeEnd` for rangeArea). Side
   * effects mirror the original inline code: sets `w.globals.columnSeries`,
   * folds `w.globals.comboCharts`, and warns on unsupported combinations (a
   * non-combo type mixed in, or horizontal bars in a combo). Extracted from
   * plotChartType to shrink it (audit C2).
   * @param {any[]} ser
   * @returns {{ seriesTypes: Record<string, any>, customBuckets: Record<string, {series: any[], i: number[]}> }}
   */
  _classifySeriesByType(ser) {
    const { w } = this;
    const { config: cnf, globals: gl } = w;
    const seriesTypes = {
      line: { series: [], i: [] },
      area: { series: [], i: [] },
      scatter: { series: [], i: [] },
      bubble: { series: [], i: [] },
      bar: { series: [], i: [] },
      candlestick: { series: [], i: [] },
      boxPlot: { series: [], i: [] },
      violin: { series: [], i: [] },
      rangeBar: { series: [], i: [] },
      rangeArea: { series: [], seriesRangeEnd: [], i: [] }
    };
    const customBuckets = {};
    const chartType = cnf.chart.type || "line";
    let nonComboType = null;
    let comboCount = 0;
    this.w.seriesData.series.forEach((serie, st) => {
      var _a, _b;
      const seriesType = ((_a = ser[st]) == null ? void 0 : _a.type) === "column" ? "bar" : ((_b = ser[st]) == null ? void 0 : _b.type) || (chartType === "column" ? "bar" : chartType);
      const st_ = (
        /** @type {Record<string,any>} */
        seriesTypes
      );
      if (st_[seriesType]) {
        if (seriesType === "rangeArea") {
          st_[seriesType].series.push(this.w.rangeData.seriesRangeStart[st]);
          st_[seriesType].seriesRangeEnd.push(
            this.w.rangeData.seriesRangeEnd[st]
          );
        } else {
          st_[seriesType].series.push(serie);
        }
        st_[seriesType].i.push(st);
        if (seriesType === "bar") w.globals.columnSeries = seriesTypes.bar;
      } else if ([
        "heatmap",
        "treemap",
        "pie",
        "donut",
        "polarArea",
        "radialBar",
        "radar",
        "unit",
        "sunburst"
      ].includes(seriesType)) {
        nonComboType = seriesType;
      } else if (isCustom(seriesType)) {
        if (!customBuckets[seriesType]) {
          customBuckets[seriesType] = { series: [], i: [] };
        }
        customBuckets[seriesType].series.push(serie);
        customBuckets[seriesType].i.push(st);
      } else {
        console.warn(
          `You have specified an unrecognized series type (${seriesType}).`
        );
      }
      if (chartType !== seriesType && seriesType !== "scatter") comboCount++;
    });
    if (comboCount > 0) {
      if (nonComboType) {
        console.warn(
          `Chart or series type ${nonComboType} cannot appear with other chart or series types.`
        );
      }
      if (seriesTypes.bar.series.length > 0 && cnf.plotOptions.bar.horizontal) {
        comboCount -= seriesTypes.bar.series.length;
        seriesTypes.bar = { series: [], i: [] };
        w.globals.columnSeries = { series: [], i: [] };
        console.warn(
          "Horizontal bars are not supported in a mixed/combo chart. Please turn off `plotOptions.bar.horizontal`"
        );
      }
    }
    gl.comboCharts || (gl.comboCharts = comboCount > 0);
    return { seriesTypes, customBuckets };
  }
  /**
   * @param {any[]} ser
   * @param {import('../types/internal').XYRatios} xyRatios
   */
  plotChartType(ser, xyRatios) {
    const { w, ctx } = this;
    const canvasMode = ctx.renderer && ctx.renderer.kind === "canvas";
    if (canvasMode) ctx.renderer.beginSeries();
    const { seriesTypes, customBuckets } = this._classifySeriesByType(ser);
    const renderers = this._instantiateSeriesRenderers(seriesTypes, xyRatios);
    const elGraph = this._assembleSeriesGraphics(
      seriesTypes,
      customBuckets,
      renderers,
      xyRatios
    );
    if (canvasMode) {
      const rr = (
        /** @type {any} */
        ctx.renderer
      );
      if (rr && rr._repaintHostInPlace) {
        rr._repaintHostInPlace = false;
        const wrapNode = this.w.dom.elGraphical.node.querySelector(
          ".apexcharts-canvas-series-wrap"
        );
        if (wrapNode && rr.canRepaintInPlace && rr.canRepaintInPlace()) {
          rr.repaintInPlace();
          const groups = Array.isArray(elGraph) ? elGraph : [elGraph];
          groups.forEach((g) => {
            if (g && g.node) wrapNode.appendChild(g.node);
          });
          return [];
        }
      }
      const host = ctx.renderer.present();
      if (host) {
        const wrap = new Graphics(w).group({
          class: "apexcharts-canvas-series-wrap"
        });
        wrap.add(host);
        const groups = Array.isArray(elGraph) ? elGraph : [elGraph];
        groups.forEach((g) => {
          if (g) wrap.add(g);
        });
        return wrap;
      }
    }
    return elGraph;
  }
  /**
   * Lazily instantiate the shared series renderers the orchestration below
   * needs. getChartClass() is only called for types actually present, so a page
   * that registers just 'line' never triggers a lookup for 'candlestick' etc.
   * (tree-shaking). Returns the line/candlestick/violin renderers and sets
   * ctx.pie / ctx.rangeBar as a side effect (both may be null). Extracted from
   * plotChartType (audit C2).
   * @param {Record<string, any>} seriesTypes
   * @param {import('../types/internal').XYRatios} xyRatios
   * @returns {{ line: any, boxCandlestick: any, violin: any }}
   */
  _instantiateSeriesRenderers(seriesTypes, xyRatios) {
    const { w, ctx } = this;
    const { config: cnf, globals: gl } = w;
    const needsLine = seriesTypes.line.series.length > 0 || seriesTypes.area.series.length > 0 || seriesTypes.scatter.series.length > 0 || seriesTypes.bubble.series.length > 0 || seriesTypes.rangeArea.series.length > 0 || !gl.comboCharts && ["line", "area", "scatter", "bubble", "rangeArea"].includes(
      cnf.chart.type
    );
    const line = needsLine ? new (getChartClass("line"))(ctx.w, ctx, xyRatios) : null;
    const needsCandlestick = seriesTypes.candlestick.series.length > 0 || seriesTypes.boxPlot.series.length > 0 || !gl.comboCharts && ["candlestick", "boxPlot"].includes(cnf.chart.type);
    const boxCandlestick = needsCandlestick ? new (getChartClass("candlestick"))(ctx.w, ctx, xyRatios) : null;
    const needsViolin = seriesTypes.violin.series.length > 0 || !gl.comboCharts && cnf.chart.type === "violin";
    const violin = needsViolin ? new (getChartClass("violin"))(ctx.w, ctx, xyRatios) : null;
    const needsPie = !gl.comboCharts && ["pie", "donut", "polarArea"].includes(cnf.chart.type);
    ctx.pie = needsPie ? new (getChartClass("pie"))(ctx.w, ctx) : null;
    const needsRangeBar = seriesTypes.rangeBar.series.length > 0 || !gl.comboCharts && cnf.chart.type === "rangeBar";
    ctx.rangeBar = needsRangeBar ? new (getChartClass("rangeBar"))(ctx.w, ctx, xyRatios) : null;
    return { line, boxCandlestick, violin };
  }
  /**
   * Build the ordered list of series graphic groups (elGraph) from the
   * classified buckets. Combo charts layer per-type draws in z-order; a
   * single-type chart dispatches on cnf.chart.type. Sets ctx.bar for the
   * non-stacked bar paths (side effect, preserved). Extracted from
   * plotChartType (audit C2).
   * @param {Record<string, any>} seriesTypes
   * @param {Record<string, {series: any[], i: number[]}>} customBuckets
   * @param {{ line: any, boxCandlestick: any, violin: any }} renderers
   * @param {import('../types/internal').XYRatios} xyRatios
   * @returns {any}
   */
  _assembleSeriesGraphics(seriesTypes, customBuckets, renderers, xyRatios) {
    const { w, ctx } = this;
    const { config: cnf, globals: gl } = w;
    const { line, boxCandlestick, violin } = renderers;
    let elGraph = [];
    if (gl.comboCharts) {
      const coreUtils = new CoreUtils(this.w);
      if (seriesTypes.area.series.length > 0) {
        elGraph.push(
          ...coreUtils.drawSeriesByGroup(
            seriesTypes.area,
            gl.areaGroups,
            "area",
            line
          )
        );
      }
      if (seriesTypes.bar.series.length > 0) {
        if (cnf.chart.stacked) {
          const barStacked = new (getChartClass("barStacked"))(
            ctx.w,
            ctx,
            xyRatios
          );
          elGraph.push(
            barStacked.draw(seriesTypes.bar.series, seriesTypes.bar.i)
          );
        } else {
          ctx.bar = new (getChartClass("bar"))(ctx.w, ctx, xyRatios);
          elGraph.push(ctx.bar.draw(seriesTypes.bar.series, seriesTypes.bar.i));
        }
      }
      if (seriesTypes.rangeArea.series.length > 0) {
        elGraph.push(
          line.draw(
            seriesTypes.rangeArea.series,
            "rangeArea",
            seriesTypes.rangeArea.i,
            seriesTypes.rangeArea.seriesRangeEnd
          )
        );
      }
      if (seriesTypes.line.series.length > 0) {
        elGraph.push(
          ...coreUtils.drawSeriesByGroup(
            seriesTypes.line,
            gl.lineGroups,
            "line",
            line
          )
        );
      }
      if (seriesTypes.candlestick.series.length > 0) {
        elGraph.push(
          boxCandlestick.draw(
            seriesTypes.candlestick.series,
            "candlestick",
            seriesTypes.candlestick.i
          )
        );
      }
      if (seriesTypes.boxPlot.series.length > 0) {
        elGraph.push(
          boxCandlestick.draw(
            seriesTypes.boxPlot.series,
            "boxPlot",
            seriesTypes.boxPlot.i
          )
        );
      }
      if (seriesTypes.violin.series.length > 0) {
        elGraph.push(
          violin.draw(seriesTypes.violin.series, "violin", seriesTypes.violin.i)
        );
      }
      if (seriesTypes.rangeBar.series.length > 0) {
        elGraph.push(
          ctx.rangeBar.draw(
            seriesTypes.rangeBar.series,
            seriesTypes.rangeBar.i
          )
        );
      }
      if (seriesTypes.scatter.series.length > 0) {
        const scatterLine = new (getChartClass("line"))(
          ctx.w,
          ctx,
          xyRatios,
          true
        );
        elGraph.push(
          scatterLine.draw(
            seriesTypes.scatter.series,
            "scatter",
            seriesTypes.scatter.i
          )
        );
      }
      if (seriesTypes.bubble.series.length > 0) {
        const bubbleLine = new (getChartClass("line"))(
          ctx.w,
          ctx,
          xyRatios,
          true
        );
        elGraph.push(
          bubbleLine.draw(
            seriesTypes.bubble.series,
            "bubble",
            seriesTypes.bubble.i
          )
        );
      }
      Object.keys(customBuckets).forEach((cname) => {
        const bucket = customBuckets[cname];
        if (bucket.series.length > 0) {
          const cs = new (getChartClass(cname))(ctx.w, ctx, xyRatios);
          elGraph.push(cs.draw(bucket.series, cname, bucket.i));
        }
      });
    } else {
      const type = cnf.chart.type;
      switch (type) {
        case "line":
          elGraph = line.draw(this.w.seriesData.series, "line");
          break;
        case "area":
          elGraph = line.draw(this.w.seriesData.series, "area");
          break;
        case "bar":
          if (cnf.chart.stacked) {
            const barStacked = new (getChartClass("barStacked"))(
              ctx.w,
              ctx,
              xyRatios
            );
            elGraph = barStacked.draw(this.w.seriesData.series);
          } else {
            ctx.bar = new (getChartClass("bar"))(ctx.w, ctx, xyRatios);
            elGraph = ctx.bar.draw(this.w.seriesData.series);
          }
          break;
        case "candlestick":
          elGraph = boxCandlestick.draw(this.w.seriesData.series, "candlestick");
          break;
        case "boxPlot":
          elGraph = boxCandlestick.draw(this.w.seriesData.series, type);
          break;
        case "violin":
          elGraph = violin.draw(this.w.seriesData.series, "violin");
          break;
        case "rangeBar":
          elGraph = ctx.rangeBar.draw(this.w.seriesData.series);
          break;
        case "rangeArea":
          elGraph = line.draw(
            this.w.rangeData.seriesRangeStart,
            "rangeArea",
            void 0,
            this.w.rangeData.seriesRangeEnd
          );
          break;
        case "heatmap": {
          const heatmap = new (getChartClass("heatmap"))(ctx.w, ctx, xyRatios);
          elGraph = heatmap.draw(this.w.seriesData.series);
          break;
        }
        case "treemap": {
          const treemap = new (getChartClass("treemap"))(ctx.w, ctx);
          elGraph = treemap.draw(this.w.seriesData.series);
          break;
        }
        case "unit": {
          const unit = new (getChartClass("unit"))(ctx.w, ctx);
          elGraph = unit.draw(this.w.seriesData.series);
          break;
        }
        case "sunburst": {
          const sunburst = new (getChartClass("sunburst"))(ctx.w, ctx);
          elGraph = sunburst.draw(this.w.seriesData.series);
          break;
        }
        case "pie":
        case "donut":
        case "polarArea":
          elGraph = ctx.pie.draw(this.w.seriesData.series);
          break;
        case "radialBar": {
          const radialBar = new (getChartClass("radialBar"))(ctx.w, ctx);
          elGraph = radialBar.draw(this.w.seriesData.series);
          break;
        }
        case "radar": {
          const radar = new (getChartClass("radar"))(ctx.w, ctx);
          elGraph = radar.draw(this.w.seriesData.series);
          break;
        }
        default:
          if (isCustom(type)) {
            const cs = new (getChartClass(type))(ctx.w, ctx, xyRatios);
            elGraph = cs.draw(this.w.seriesData.series, type);
          } else {
            elGraph = line.draw(this.w.seriesData.series);
          }
      }
    }
    return elGraph;
  }
  /**
   * Extract the CSS unit suffix from a chart width/height config value
   * (`'100%'` -> `'%'`, `'300px'` -> `'px'`, `300`/`'300'` -> `''`). Kept as the
   * original digit-split idiom so results are identical for every input the
   * call sites already handle ('%', 'px', '', 'auto').
   * @param {string|number} value
   * @returns {string|undefined}
   */
  _extractDimensionUnit(value) {
    return String(value).split(/[0-9]+/g).pop();
  }
  setSVGDimensions() {
    var _a;
    const { globals: gl, config: cnf } = this.w;
    cnf.chart.width = cnf.chart.width || "100%";
    cnf.chart.height = cnf.chart.height || "auto";
    const rawWidth = cnf.chart.width;
    const rawHeight = cnf.chart.height;
    gl.svgWidth = NaN;
    gl.svgHeight = NaN;
    let elDim = Utils$1.getDimensions(this.el);
    const widthUnit = this._extractDimensionUnit(rawWidth);
    if (widthUnit === "%") {
      if (Utils$1.isNumber(elDim[0])) {
        if (elDim[0].width === 0) {
          elDim = Utils$1.getDimensions(this.el.parentNode);
        }
        gl.svgWidth = elDim[0] * parseInt(rawWidth, 10) / 100;
      }
    } else if (widthUnit === "px" || widthUnit === "") {
      gl.svgWidth = parseInt(rawWidth, 10);
    }
    const heightUnit = this._extractDimensionUnit(rawHeight);
    if (rawHeight !== "auto" && rawHeight !== "") {
      if (heightUnit === "%") {
        const elParentDim = Utils$1.getDimensions(this.el.parentNode);
        gl.svgHeight = elParentDim[1] * parseInt(rawHeight, 10) / 100;
      } else {
        gl.svgHeight = parseInt(rawHeight, 10);
      }
    } else {
      gl.svgHeight = gl.axisCharts ? gl.svgWidth / 1.61 : gl.svgWidth / 1.2;
    }
    gl.svgWidth = Math.max(gl.svgWidth, 0);
    gl.svgHeight = Math.max(gl.svgHeight, 0);
    Graphics.setAttrs(this.w.dom.Paper.node, {
      width: gl.svgWidth,
      height: gl.svgHeight
    });
    if (heightUnit !== "%" && Environment.isBrowser()) {
      const needsAxisPadding = gl.axisCharts && (cnf.grid.show || cnf.dataLabels.enabled || cnf.xaxis.labels.show || cnf.xaxis.axisBorder.show || cnf.xaxis.axisTicks.show || cnf.yaxis.some(
        (y) => y.show && (y.labels.show || y.axisBorder.show || y.axisTicks.show)
      ));
      const offsetY = cnf.chart.sparkline.enabled || !needsAxisPadding ? 0 : cnf.chart.parentHeightOffset;
      const paperNode = this.w.dom.Paper.node;
      if ((_a = paperNode.parentNode) == null ? void 0 : _a.parentNode) {
        paperNode.parentNode.parentNode.style.minHeight = `${gl.svgHeight + offsetY}px`;
      }
    }
    this.w.dom.elWrap.style.width = `${gl.svgWidth}px`;
    this.w.dom.elWrap.style.height = `${gl.svgHeight}px`;
    gl.lastResizeSignature = this.getResizeSignature();
  }
  /**
   * A stable fingerprint of the container measurements that actually feed the
   * chart's rendered dimensions, given the width/height config. Only inputs that
   * a resize can change are included: the element width when the width is a
   * percentage, and the parent height when the height is a percentage. A fully
   * pixel-sized chart therefore has a constant signature, so a resize never
   * forces a redraw; a percentage-sized chart's signature tracks the container.
   * The window-resize handler compares this against the last render to skip
   * redraws (and the entrance-animation teardown they cause) that aren't needed.
   * @returns {{ w: number, h: number }}
   */
  getResizeSignature() {
    const { config: cnf } = this.w;
    const rawWidth = (cnf.chart.width || "100%").toString().trim();
    const rawHeight = (cnf.chart.height || "auto").toString().trim();
    let w = 0;
    let h2 = 0;
    if (rawWidth.endsWith("%")) {
      let elDim = Utils$1.getDimensions(this.el);
      if (!elDim[0]) elDim = Utils$1.getDimensions(this.el.parentNode);
      w = elDim[0] || 0;
    }
    if (rawHeight.endsWith("%")) {
      h2 = Utils$1.getDimensions(this.el.parentNode)[1] || 0;
    }
    const sig = { w: Math.round(w), h: Math.round(h2) };
    if (cnf.responsive && cnf.responsive.length && Environment.isBrowser()) {
      sig.iw = window.innerWidth;
    }
    return sig;
  }
  shiftGraphPosition() {
    const { globals: gl } = this.w;
    const { translateY: tY, translateX: tX } = gl;
    Graphics.setAttrs(this.w.dom.elGraphical.node, {
      transform: `translate(${tX}, ${tY})`
    });
  }
  resizeNonAxisCharts() {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i;
    const { w } = this;
    const heightStr = w.config.chart.height ? String(w.config.chart.height) : "";
    const userSetFixedHeight = heightStr !== "" && heightStr !== "auto";
    const isPercentHeight = heightStr.includes("%");
    let legendHeight = 0;
    let offY = w.config.chart.sparkline.enabled ? 1 : 15;
    offY += w.layout.gridPad.bottom;
    if (["top", "bottom"].includes(w.config.legend.position) && w.config.legend.show && !w.config.legend.floating) {
      legendHeight = ((_b = (_a = this.ctx.legend) == null ? void 0 : _a.legendHelpers.getLegendDimensions().clwh) != null ? _b : 0) + 7;
    }
    const el = w.dom.baseEl.querySelector(
      ".apexcharts-radialbar, .apexcharts-pie, .apexcharts-sunburst"
    );
    const externalLabelMarginY = w.globals.pieExternalLabelMarginY || 0;
    let chartInnerDimensions = externalLabelMarginY > 0 ? w.globals.radialSize * 2 + externalLabelMarginY * 2 : w.globals.radialSize * 2.05;
    const angleType = w.config.chart.type === "sunburst" ? "sunburst" : w.config.chart.type === "pie" || w.config.chart.type === "donut" || w.config.chart.type === "polarArea" ? "pie" : "radialBar";
    const radialAngleSpan = Math.abs(
      w.config.plotOptions[angleType].endAngle - w.config.plotOptions[angleType].startAngle
    );
    if (el && !w.config.chart.sparkline.enabled && radialAngleSpan < 360) {
      const svgRect = Utils$1.getBoundingClientRect(this.w.dom.Paper.node);
      let arcTopFromSVGTop = Infinity;
      let arcBottomFromSVGTop = -Infinity;
      const accumulate = (node) => {
        var _a2, _b2, _c2, _d2;
        if ((_a2 = node.classList) == null ? void 0 : _a2.contains("apexcharts-radialbar-hollow")) {
          return;
        }
        const tag = (_c2 = (_b2 = node.tagName) == null ? void 0 : _b2.toLowerCase) == null ? void 0 : _c2.call(_b2);
        if (tag === "text" || tag === "tspan") return;
        const children = Array.from((_d2 = node.children) != null ? _d2 : []);
        if (children.length > 0) {
          children.forEach((c2) => accumulate(
            /** @type {Element} */
            c2
          ));
          return;
        }
        const r2 = Utils$1.getBoundingClientRect(node);
        const height = r2.bottom - r2.top;
        if (height > 0) {
          const top = r2.top - svgRect.top;
          const bottom = r2.bottom - svgRect.top;
          if (top < arcTopFromSVGTop) arcTopFromSVGTop = top;
          if (bottom > arcBottomFromSVGTop) arcBottomFromSVGTop = bottom;
        }
      };
      Array.from((_c = el.children) != null ? _c : []).forEach(
        (c2) => accumulate(
          /** @type {Element} */
          c2
        )
      );
      if (!Number.isFinite(arcTopFromSVGTop)) arcTopFromSVGTop = 0;
      if (!Number.isFinite(arcBottomFromSVGTop)) {
        const elRect = Utils$1.getBoundingClientRect(el);
        arcBottomFromSVGTop = elRect.bottom - svgRect.top;
      }
      const padding = Math.max(offY, w.globals.radialSize * 0.2);
      const verticalShift = Math.max(padding - arcTopFromSVGTop, 0);
      if (verticalShift !== 0) {
        w.layout.translateY = ((_d = w.layout.translateY) != null ? _d : 0) + verticalShift;
        Graphics.setAttrs(this.w.dom.elGraphical.node, {
          transform: `translate(${(_e = w.layout.translateX) != null ? _e : 0}, ${w.layout.translateY})`
        });
        arcBottomFromSVGTop += verticalShift;
      }
      chartInnerDimensions = arcBottomFromSVGTop > 0 ? arcBottomFromSVGTop : w.globals.radialSize * 2.05;
      const bottomPadding = Math.max(padding, arcTopFromSVGTop);
      const svgHeight = Math.ceil(
        chartInnerDimensions + legendHeight + bottomPadding
      );
      const chartOffsetY = (_f = w.config.chart.offsetY) != null ? _f : 0;
      const elWrapHeight = svgHeight + Math.max(chartOffsetY, 0);
      if (!isPercentHeight) {
        if (this.w.dom.elLegendForeign) {
          this.w.dom.elLegendForeign.setAttribute(
            "height",
            String(elWrapHeight)
          );
        }
        this.w.dom.elWrap.style.height = `${elWrapHeight}px`;
        Graphics.setAttrs(this.w.dom.Paper.node, { height: svgHeight });
        if (Environment.isBrowser()) {
          const grandparent = (_g = this.w.dom.Paper.node.parentNode) == null ? void 0 : _g.parentNode;
          if (grandparent) {
            grandparent.style.minHeight = `${elWrapHeight}px`;
          }
        }
        w.globals.svgHeight = svgHeight;
        if (w.config.legend.position === "bottom" && w.config.legend.show && !w.config.legend.floating) {
          (_h = this.ctx.legend) == null ? void 0 : _h.setLegendWrapXY(20, 0);
        }
      }
      return;
    }
    const newHeight = Math.ceil(
      chartInnerDimensions + this.w.layout.translateY + legendHeight + offY
    );
    if (userSetFixedHeight) return;
    if (this.w.dom.elLegendForeign) {
      this.w.dom.elLegendForeign.setAttribute("height", String(newHeight));
    }
    this.w.dom.elWrap.style.height = `${newHeight}px`;
    Graphics.setAttrs(this.w.dom.Paper.node, { height: newHeight });
    if (Environment.isBrowser()) {
      const grandparent = (_i = this.w.dom.Paper.node.parentNode) == null ? void 0 : _i.parentNode;
      if (grandparent) {
        grandparent.style.minHeight = `${newHeight}px`;
      }
    }
  }
  coreCalculations() {
    new Range(this.w).init();
  }
  resetGlobals() {
    const resetxyValues = () => this.w.config.series.map(() => []);
    const globalObj = new Globals();
    const { globals: gl } = this.w;
    const parsingFlags = {
      dataWasParsed: this.w.axisFlags.dataWasParsed,
      originalSeries: gl.originalSeries
    };
    globalObj.initGlobalVars(gl);
    gl.seriesXvalues = resetxyValues();
    gl.seriesYvalues = resetxyValues();
    if (parsingFlags.dataWasParsed) {
      this.w.axisFlags.dataWasParsed = parsingFlags.dataWasParsed;
      gl.originalSeries = parsingFlags.originalSeries;
    }
  }
  isMultipleY() {
    if (Array.isArray(this.w.config.yaxis) && this.w.config.yaxis.length > 1) {
      this.w.globals.isMultipleYAxis = true;
      return true;
    }
    return false;
  }
  xySettings() {
    const { w } = this;
    let xyRatios = null;
    if (w.globals.axisCharts) {
      if (w.config.xaxis.crosshairs.position === "back") {
        new Crosshairs(this.w).drawXCrosshairs();
      }
      if (w.config.yaxis[0].crosshairs.position === "back") {
        new Crosshairs(this.w).drawYCrosshairs();
      }
      if (w.config.xaxis.type === "datetime" && w.config.xaxis.labels.formatter === void 0) {
        this.ctx.timeScale = new TimeScale(this.w, this.ctx);
        let formattedTimeScale = [];
        if (isFinite(w.globals.minX) && isFinite(w.globals.maxX) && !w.globals.isBarHorizontal) {
          formattedTimeScale = this.ctx.timeScale.calculateTimeScaleTicks(
            w.globals.minX,
            w.globals.maxX
          );
        } else if (w.globals.isBarHorizontal) {
          formattedTimeScale = this.ctx.timeScale.calculateTimeScaleTicks(
            w.globals.minY,
            w.globals.maxY
          );
        }
        this.ctx.timeScale.recalcDimensionsBasedOnFormat(formattedTimeScale);
      }
      const coreUtils = new CoreUtils(this.w);
      xyRatios = coreUtils.getCalculatedRatios();
    }
    return xyRatios;
  }
  /**
   * @param {any} targetChart
   */
  updateSourceChart(targetChart) {
    this.ctx.w.interact.selection = void 0;
    this.ctx.updateHelpers._updateOptions(
      {
        chart: {
          selection: {
            xaxis: {
              min: targetChart.w.globals.minX,
              max: targetChart.w.globals.maxX
            }
          }
        }
      },
      false,
      false
    );
  }
  setupBrushHandler() {
    const { ctx, w } = this;
    if (!w.config.chart.brush.enabled) return;
    if (typeof w.config.chart.events.selection !== "function") {
      const targets = Array.isArray(w.config.chart.brush.targets) ? w.config.chart.brush.targets : [w.config.chart.brush.target];
      targets.forEach((target) => {
        const targetChart = (
          /** @type {any} */
          ctx.constructor.getChartByID(
            target
          )
        );
        if (!targetChart) {
          console.warn(
            `ApexCharts: brush target "${target}" was not found. Ensure the target chart is rendered (and its chart.id matches) before the brush chart.`
          );
          return;
        }
        targetChart.w.globals.brushSource = this.ctx;
        if (typeof targetChart.w.config.chart.events.zoomed !== "function") {
          targetChart.w.config.chart.events.zoomed = () => this.updateSourceChart(targetChart);
        }
        if (typeof targetChart.w.config.chart.events.scrolled !== "function") {
          targetChart.w.config.chart.events.scrolled = () => (
            /**
             * @param {any} chart
             * @param {Event} e
             */
            this.updateSourceChart(targetChart)
          );
        }
      });
      w.config.chart.events.selection = (chart, e2) => {
        targets.forEach((target) => {
          const targetChart = (
            /** @type {any} */
            ctx.constructor.getChartByID(
              target
            )
          );
          if (!targetChart) return;
          targetChart.ctx.updateHelpers._updateOptions(
            {
              xaxis: {
                min: e2.xaxis.min,
                max: e2.xaxis.max
              }
            },
            false,
            false,
            false,
            false
          );
        });
      };
    }
  }
  getAccessibleChartLabel() {
    const w = this.w;
    const cnf = w.config;
    if (cnf.chart.accessibility && cnf.chart.accessibility.description) {
      return cnf.chart.accessibility.description;
    }
    const chartType = cnf.chart.type;
    const parts = [];
    if (cnf.title.text) {
      parts.push(`${cnf.title.text}. ${chartType} chart`);
      if (cnf.subtitle.text) parts.push(cnf.subtitle.text);
    } else {
      const namedSeries = (() => {
        if (Array.isArray(w.seriesData.seriesNames) && w.seriesData.seriesNames.length) {
          return w.seriesData.seriesNames.filter(Boolean);
        }
        if (Array.isArray(cnf.series)) {
          return cnf.series.map((s2) => typeof s2 === "object" && s2 !== null ? s2.name : null).filter(Boolean);
        }
        return [];
      })();
      const seriesCount = w.seriesData.series.length || (cnf.series ? cnf.series.length : 0);
      if (namedSeries.length) {
        parts.push(
          `${chartType} chart with ${seriesCount} data series: ${namedSeries.join(", ")}`
        );
      } else {
        parts.push(`${chartType} chart with ${seriesCount} data series`);
      }
    }
    return parts.join(". ");
  }
}
const TRANSFORM_KEY = "__apexcharts_series_transforms__";
if (!/** @type {any} */
globalThis[TRANSFORM_KEY]) {
  globalThis[TRANSFORM_KEY] = {};
}
function getTransforms() {
  return (
    /** @type {any} */
    globalThis[TRANSFORM_KEY]
  );
}
function getSeriesTransform(name2) {
  if (!name2) return null;
  return getTransforms()[name2] || null;
}
function drilldownById(w, id) {
  const dd = w.config.drilldown;
  const list = dd && Array.isArray(dd.series) ? dd.series : [];
  return list.find((s2) => s2 && s2.id === id);
}
function toNode(w, d, i2, paletteFromParent, parentKey, seenIds = null, opts = {}) {
  var _a, _b, _c;
  const isObj = d && typeof d === "object";
  const name2 = isObj ? (_b = (_a = d.x) != null ? _a : d.name) != null ? _b : "" : "";
  const value = isObj ? Number((_c = d.y) != null ? _c : d.value) : Number(d);
  const node = {
    name: String(name2),
    value: isNaN(value) ? null : value,
    color: isObj && d.color ? d.color : void 0,
    // Identity across data updates: the path of names (indexed so same-named
    // siblings stay distinct). Update animations morph matched keys in place.
    _key: `${parentKey}/${i2}:${name2}`
  };
  if (paletteFromParent && !node.color) {
    node.color = paletteFromParent[i2 % paletteFromParent.length];
  }
  if (opts.keepDatum) node._datum = d;
  if (isObj && Array.isArray(d.children) && d.children.length) {
    node.children = d.children.map(
      (c2, j) => toNode(w, c2, j, null, node._key, seenIds, opts)
    );
  } else if (isObj && d.drilldown != null && opts.expandDrilldown !== false) {
    const visited = seenIds || /* @__PURE__ */ new Set();
    if (!visited.has(d.drilldown)) {
      const dd = drilldownById(w, d.drilldown);
      if (dd && Array.isArray(dd.data) && dd.data.length) {
        const nextSeen = new Set(visited);
        nextSeen.add(d.drilldown);
        const palette = Array.isArray(dd.colors) ? dd.colors : null;
        node.children = dd.data.map(
          (c2, j) => toNode(w, c2, j, palette, node._key, nextSeen, opts)
        );
      }
    }
  }
  return node;
}
function buildSeriesRoots(w, series, opts = {}) {
  const cfgSeries = (
    /** @type {any} */
    series || w.config.series
  );
  if (!Array.isArray(cfgSeries)) return [];
  return cfgSeries.map((s2, i2) => {
    var _a, _b;
    const data = s2 && Array.isArray(s2.data) ? s2.data : [];
    const key = `${i2}:${(_a = s2 == null ? void 0 : s2.name) != null ? _a : ""}`;
    const root = {
      name: String((_b = s2 == null ? void 0 : s2.name) != null ? _b : ""),
      value: null,
      color: (s2 == null ? void 0 : s2.color) || void 0,
      _key: key,
      _seriesIndex: i2,
      children: data.map(
        (d, j) => toNode(w, d, j, null, key, null, opts)
      )
    };
    return root;
  });
}
function fillValues(node) {
  if (node.children && node.children.length) {
    node.children.forEach((c2) => fillValues(c2));
    if (node.value == null || isNaN(node.value)) {
      node.value = node.children.reduce(
        (s2, c2) => s2 + Math.max(0, c2.value || 0),
        0
      );
    }
  }
  if (node.value == null || isNaN(node.value)) node.value = 0;
}
function hasNesting(series, opts = {}) {
  if (!Array.isArray(series)) return false;
  const countDrilldown = opts.drilldown !== false;
  for (let i2 = 0; i2 < series.length; i2++) {
    const data = series[i2] && series[i2].data;
    if (!Array.isArray(data)) continue;
    for (let j = 0; j < data.length; j++) {
      const d = data[j];
      if (!d || typeof d !== "object") continue;
      if (Array.isArray(d.children) && d.children.length) return true;
      if (countDrilldown && d.drilldown != null) return true;
    }
  }
  return false;
}
function drilldownAsLevels(w) {
  var _a, _b, _c, _d;
  return !!((_d = (_c = (_b = (_a = w == null ? void 0 : w.config) == null ? void 0 : _a.plotOptions) == null ? void 0 : _b.treemap) == null ? void 0 : _c.nested) == null ? void 0 : _d.drilldownAsLevels);
}
function isNestedTreemap(w, series) {
  var _a, _b, _c;
  const nestedCfg = (_c = (_b = (_a = w == null ? void 0 : w.config) == null ? void 0 : _a.plotOptions) == null ? void 0 : _b.treemap) == null ? void 0 : _c.nested;
  if (nestedCfg && nestedCfg.enabled === false) return false;
  return hasNesting(series, { drilldown: drilldownAsLevels(w) });
}
function annotate(roots) {
  const leaves = [];
  let maxDepth = 0;
  roots.forEach((root, si) => {
    const seriesLeaves = [];
    const walk = (node, depth, parent) => {
      node._parent = parent;
      node._depth = depth;
      node._si = si;
      node._leaf = !(node.children && node.children.length);
      if (depth > maxDepth) maxDepth = depth;
      if (node._leaf) {
        node._di = seriesLeaves.length;
        seriesLeaves.push(node);
      } else {
        node._di = -1;
        node.children.forEach(
          (c2) => walk(c2, depth + 1, node)
        );
      }
    };
    walk(root, 0, null);
    leaves.push(seriesLeaves);
  });
  return { leaves, maxDepth };
}
function leafRow(node) {
  const d = node._datum;
  if (d && typeof d === "object") {
    const row = __spreadProps(__spreadValues({}, d), { x: node.name, y: node.value });
    delete row.children;
    return row;
  }
  return { x: node.name, y: node.value };
}
function resolveTreemapTree(w, series) {
  const roots = buildSeriesRoots(w, series, {
    keepDatum: true,
    expandDrilldown: drilldownAsLevels(w)
  });
  roots.forEach(fillValues);
  const { leaves, maxDepth } = annotate(roots);
  const leafSeries = series.map((s2, i2) => __spreadProps(__spreadValues({}, s2), {
    data: (leaves[i2] || []).map(leafRow)
  }));
  return { roots, leafSeries, maxDepth };
}
const RAW_SAMPLE_TYPES = ["histogram"];
class Data {
  /**
   * @param {import('../types/internal').ChartStateW} w
   */
  constructor(w, { resetGlobals = () => {
  }, isMultipleY = () => {
  } } = {}) {
    this.w = w;
    this.resetGlobals = resetGlobals;
    this.isMultipleY = isMultipleY;
    this.twoDSeries = [];
    this.threeDSeries = [];
    this.twoDSeriesX = [];
    this.seriesGoals = [];
    this._warnedMissingTransform = false;
    this.coreUtils = new CoreUtils(this.w);
    this.activeSeriesIndex = 0;
  }
  // Helper to get the first valid data point from the active series
  getFirstDataPoint() {
    const series = this.w.config.series;
    const sr = new Series(this.w);
    this.activeSeriesIndex = sr.getActiveConfigSeriesIndex();
    const activeItem = (
      /** @type {any} */
      series[this.activeSeriesIndex]
    );
    if (activeItem && activeItem.data && activeItem.data.length > 0 && activeItem.data[0] !== null && typeof activeItem.data[0] !== "undefined") {
      return activeItem.data[0];
    }
    return null;
  }
  isMultiFormat() {
    return this.isFormatXY() || this.isFormat2DArray();
  }
  // given format is [{x, y}, {x, y}]
  isFormatXY() {
    var _a;
    const firstDataPoint = this.getFirstDataPoint();
    if (!firstDataPoint || typeof firstDataPoint.x === "undefined") return false;
    const data = (
      /** @type {any} */
      (_a = this.w.config.series[this.activeSeriesIndex]) == null ? void 0 : _a.data
    );
    if (data) {
      const isXY = (pt) => pt && typeof pt.x !== "undefined";
      for (let k = 1; k < Math.min(3, data.length); k++) {
        if (isXY(data[k]) !== true) {
          console.warn(
            `ApexCharts: series data has mixed formats starting at index ${k}`
          );
          break;
        }
      }
    }
    return true;
  }
  // given format is [[x, y], [x, y]]
  isFormat2DArray() {
    const firstDataPoint = this.getFirstDataPoint();
    return firstDataPoint && Array.isArray(firstDataPoint);
  }
  /**
   * Typed single pass for the dominant [[x, y], ...] shape: scalar numeric or
   * null y, no z, no OHLC tuples. One monomorphic loop fills preallocated
   * x/y arrays and fuses the y-extrema scan that Range.getMinYMaxY would
   * otherwise repeat over every value (the extrema entry is ref+length
   * guarded, so any later reshaping of the series array simply falls back to
   * the scan). Returns false untouched on any non-conforming point so the
   * general loop below handles mixed/exotic data with unchanged output.
   * @param {any[]} data
   * @param {number} i
   * @returns {boolean}
   */
  _fast2DArrayParse(data, i2) {
    var _a, _b;
    const n2 = data.length;
    if (n2 === 0) return false;
    const ys = new Array(n2);
    const xs = new Array(n2);
    let maxY = -Number.MAX_VALUE;
    let lowestY = Number.MAX_VALUE;
    let negMinY = Infinity;
    let hasNulls = false;
    let yDec = 0;
    let xNumeric = true;
    let minX = Infinity;
    let maxX = -Infinity;
    let xSorted = true;
    let minXDiff = Infinity;
    let prevX = NaN;
    for (let j = 0; j < n2; j++) {
      const point = data[j];
      if (!Array.isArray(point) || point.length > 2) return false;
      const x = point[0];
      const y = point[1];
      if (xNumeric) {
        if (typeof x === "number") {
          if (x === x) {
            if (x < minX) minX = x;
            if (x > maxX) maxX = x;
          }
          const d = x - prevX;
          if (d > 0) {
            if (d < minXDiff) minXDiff = d;
          } else if (d < 0) {
            xSorted = false;
          }
          prevX = x;
        } else {
          xNumeric = false;
        }
      }
      if (typeof y === "number") {
        if (y === y && y !== Infinity && y !== -Infinity) {
          if (y > maxY) maxY = y;
          if (y < lowestY) lowestY = y;
          if (y < 0 && y < negMinY) negMinY = y;
          if (!Number.isInteger(y)) {
            const av = y < 0 ? -y : y;
            if (av >= 1e-6 && av < 1e21) {
              const str = "" + y;
              const dot = str.indexOf(".");
              const dec = dot === -1 ? 0 : str.length - dot - 1;
              if (dec > yDec) yDec = dec;
            } else {
              const nv = Utils$1.noExponents(y);
              if (Utils$1.isFloat(nv)) {
                yDec = Math.max(yDec, nv.toString().split(".")[1].length);
              }
            }
          }
        } else {
          hasNulls = true;
        }
      } else if (y === null) {
        hasNulls = true;
      } else {
        return false;
      }
      ys[j] = y;
      xs[j] = x;
    }
    this.twoDSeries = ys;
    this.twoDSeriesX = xs;
    this.w.axisFlags.dataFormatXNumeric = true;
    const extrema = (_b = (_a = this.w.seriesData)._parsedExtrema) != null ? _b : _a._parsedExtrema = [];
    extrema[i2] = {
      ref: ys,
      len: n2,
      maxY,
      lowestY,
      negMinY,
      hasNulls,
      yDec,
      xref: xs,
      xNumeric,
      minX,
      maxX,
      xSorted,
      minXDiff
    };
    return true;
  }
  /**
   * @param {any[]} ser
   * @param {number} i
   */
  handleFormat2DArray(ser, i2) {
    const cnf = this.w.config;
    const data = ser[i2].data;
    const isBoxPlot = cnf.chart.type === "boxPlot" || /** @type {any} */
    cnf.series[i2].type === "boxPlot";
    if (!isBoxPlot && cnf.xaxis.type !== "datetime" && this._fast2DArrayParse(data, i2)) {
      return;
    }
    for (let j = 0; j < data.length; j++) {
      const point = data[j];
      const x = point[0];
      const y = point[1];
      const z = point[2];
      if (typeof y !== "undefined") {
        if (Array.isArray(y) && y.length === 4 && !isBoxPlot) {
          this.twoDSeries.push(Utils$1.parseNumber(y[3]));
        } else if (point.length >= 5) {
          this.twoDSeries.push(Utils$1.parseNumber(point[4]));
        } else {
          this.twoDSeries.push(Utils$1.parseNumber(y));
        }
        this.w.axisFlags.dataFormatXNumeric = true;
      }
      if (cnf.xaxis.type === "datetime") {
        const ts = new Date(x).getTime();
        this.twoDSeriesX.push(ts);
      } else {
        this.twoDSeriesX.push(x);
      }
      if (typeof z !== "undefined") {
        this.threeDSeries.push(z);
        this.w.axisFlags.isDataXYZ = true;
      }
    }
  }
  /**
   * @param {any[]} ser
   * @param {number} i
   */
  handleFormatXY(ser, i2) {
    const cnf = this.w.config;
    const gl = this.w.globals;
    const dt = new DateTime(this.w);
    const data = ser[i2].data;
    let activeI = i2;
    if (gl.collapsedSeriesIndices.indexOf(i2) > -1) {
      activeI = this.activeSeriesIndex;
    }
    const activeData = ser[activeI].data;
    for (let j = 0; j < data.length; j++) {
      const point = data[j];
      if (typeof point.y !== "undefined") {
        const val = Array.isArray(point.y) ? Utils$1.parseNumber(point.y[point.y.length - 1]) : Utils$1.parseNumber(point.y);
        this.twoDSeries.push(val);
      }
      if (typeof this.seriesGoals[i2] === "undefined") {
        this.seriesGoals[i2] = [];
      }
      if (typeof point.goals !== "undefined" && Array.isArray(point.goals)) {
        this.seriesGoals[i2].push(point.goals);
      } else {
        this.seriesGoals[i2].push(null);
      }
      if (typeof point.z !== "undefined") {
        this.threeDSeries.push(point.z);
        this.w.axisFlags.isDataXYZ = true;
      }
    }
    for (let j = 0; j < activeData.length; j++) {
      const point = activeData[j];
      const x = point.x;
      const isXString = typeof x === "string";
      const isXArr = Array.isArray(x);
      const isXDate = !isXArr && !!dt.isValidDate(x);
      if (isXString || isXDate) {
        if (isXString || cnf.xaxis.convertedCatToNumeric) {
          const isRangeColumn = gl.isBarHorizontal && this.w.axisFlags.isRangeData;
          if (cnf.xaxis.type === "datetime" && !isRangeColumn) {
            this.twoDSeriesX.push(dt.parseDate(x));
          } else {
            this.fallbackToCategory = true;
            this.twoDSeriesX.push(x);
            if (!isNaN(x) && this.w.config.xaxis.type !== "category" && typeof x !== "string") {
              this.w.axisFlags.isXNumeric = true;
            }
          }
        } else {
          if (cnf.xaxis.type === "datetime") {
            this.twoDSeriesX.push(
              x instanceof Date ? x.getTime() : dt.parseDate(x.toString())
            );
          } else {
            this.w.axisFlags.dataFormatXNumeric = true;
            this.w.axisFlags.isXNumeric = true;
            this.twoDSeriesX.push(parseFloat(x));
          }
        }
      } else if (isXArr) {
        this.fallbackToCategory = true;
        this.twoDSeriesX.push(x);
      } else {
        this.w.axisFlags.isXNumeric = true;
        this.w.axisFlags.dataFormatXNumeric = true;
        this.twoDSeriesX.push(x);
      }
    }
  }
  /**
   * @param {any[]} ser
   * @param {number} i
   */
  handleRangeData(ser, i2) {
    let range = { start: [], end: [], rangeUniques: [] };
    if (this.isFormat2DArray()) {
      range = this.handleRangeDataFormat("array", ser, i2);
    } else if (this.isFormatXY()) {
      range = this.handleRangeDataFormat("xy", ser, i2);
    }
    this.w.rangeData.seriesRangeStart[i2] = range.start === void 0 ? [] : range.start;
    this.w.rangeData.seriesRangeEnd[i2] = range.end === void 0 ? [] : range.end;
    this.w.rangeData.seriesRange[i2] = range.rangeUniques;
    this.w.rangeData.seriesRange.forEach((sr) => {
      if (!sr) return;
      sr.forEach((sarr) => {
        const yItems = (
          /** @type {any} */
          sarr.y
        );
        const len = (
          /** @type {any[]} */
          yItems.length
        );
        if (len <= 1) return;
        for (let arri = 0; arri < len; arri++) {
          const arr = (
            /** @type {any} */
            yItems[arri]
          );
          const range1y1 = arr.y1;
          const range1y2 = arr.y2;
          for (let sri = arri + 1; sri < len; sri++) {
            const range2 = (
              /** @type {any} */
              yItems[sri]
            );
            const range2y1 = range2.y1;
            const range2y2 = range2.y2;
            if (range1y1 <= range2y2 && range2y1 <= range1y2) {
              const sarrAny = (
                /** @type {any} */
                sarr
              );
              sarrAny.overlaps.add(arr.rangeName);
              sarrAny.overlaps.add(range2.rangeName);
            }
          }
        }
      });
    });
    return range;
  }
  /**
   * Marks (#11) P3: fold a custom series' per-datum y-extent into the
   * range-data slice so both bounds drive the y-axis scale. When `yExtent` is
   * given it supplies the values a datum occupies (scalar or array => min/max
   * across them); otherwise the datum's `y` is used (array => first/last,
   * scalar => itself). The datum still carries a representative scalar `y`
   * (folded by handleFormatXY into seriesData.series) that gates Range.
   * @param {any[]} ser @param {number} i @param {Function|null} yExtent
   */
  handleCustomRangeData(ser, i2, yExtent) {
    const data = ser[i2].data || [];
    const start = [];
    const end = [];
    for (let j = 0; j < data.length; j++) {
      const datum = data[j];
      let lo;
      let hi;
      if (typeof yExtent === "function") {
        let ext = yExtent(datum, j);
        if (!Array.isArray(ext)) ext = [ext];
        const nums = ext.map((v) => Utils$1.parseNumber(v)).filter((v) => v !== null && !isNaN(v));
        lo = nums.length ? Math.min(...nums) : null;
        hi = nums.length ? Math.max(...nums) : null;
      } else {
        const y = datum == null ? null : datum.y;
        if (Array.isArray(y)) {
          lo = Utils$1.parseNumber(y[0]);
          hi = Utils$1.parseNumber(y[y.length - 1]);
        } else {
          lo = hi = Utils$1.parseNumber(y);
        }
      }
      start.push(lo);
      end.push(hi);
    }
    this.w.rangeData.seriesRangeStart[i2] = start;
    this.w.rangeData.seriesRangeEnd[i2] = end;
  }
  /**
   * @param {any[]} ser
   * @param {number} i
   */
  handleCandleStickBoxData(ser, i2) {
    let ohlc = { o: [], h: [], m: [], l: [], c: [] };
    if (this.isFormat2DArray()) {
      ohlc = this.handleCandleStickBoxDataFormat("array", ser, i2);
    } else if (this.isFormatXY()) {
      ohlc = this.handleCandleStickBoxDataFormat("xy", ser, i2);
    }
    this.w.candleData.seriesCandleO[i2] = ohlc.o;
    this.w.candleData.seriesCandleH[i2] = ohlc.h;
    this.w.candleData.seriesCandleM[i2] = ohlc.m;
    this.w.candleData.seriesCandleL[i2] = ohlc.l;
    this.w.candleData.seriesCandleC[i2] = ohlc.c;
    this.w.candleData.seriesBoxPoints[i2] = ohlc.points || [];
    return ohlc;
  }
  /**
   * Parse a violin series. Each data point carries a precomputed density
   * profile (the violin shape) and an array of raw observations (the jitter):
   *
   *   { x, y: { density: [[value, weight], ...], points: [v1, v2, ...] } }
   *
   * Array fallback form: [x, densityPairs, pointsArray].
   *
   * Density `weight` need not be normalized — Violin.js scales each violin by
   * its own maxWeight. The representative scalar pushed into the main series
   * (so generic code paths see a non-null y) is the density mode — the value
   * carrying the greatest weight.
   *
   * @param {any[]} ser
   * @param {number} i
   */
  handleViolinData(ser, i2) {
    var _a, _b, _c, _d, _e, _f;
    const w = this.w;
    const data = ser[i2].data;
    const densityArr = [];
    const pointsArr = [];
    const minArr = [];
    const maxArr = [];
    const placeholders = [];
    for (let j = 0; j < data.length; j++) {
      const d = data[j];
      const dens = (_c = (_b = (_a = d == null ? void 0 : d.y) == null ? void 0 : _a.density) != null ? _b : d == null ? void 0 : d[1]) != null ? _c : [];
      const pts = (_f = (_e = (_d = d == null ? void 0 : d.y) == null ? void 0 : _d.points) != null ? _e : d == null ? void 0 : d[2]) != null ? _f : [];
      const values = [];
      const weights = [];
      let maxWeight = 0;
      let modeValue = null;
      let minVal = Infinity;
      let maxVal = -Infinity;
      for (let k = 0; k < dens.length; k++) {
        const v = Utils$1.parseNumber(dens[k][0]);
        const wt = Utils$1.parseNumber(dens[k][1]);
        if (v === null || wt === null) continue;
        values.push(v);
        weights.push(wt);
        if (wt > maxWeight) {
          maxWeight = wt;
          modeValue = v;
        }
        if (v < minVal) minVal = v;
        if (v > maxVal) maxVal = v;
      }
      const cleanPts = [];
      for (let k = 0; k < pts.length; k++) {
        const p = Utils$1.parseNumber(pts[k]);
        if (p === null) continue;
        cleanPts.push(p);
        if (p < minVal) minVal = p;
        if (p > maxVal) maxVal = p;
      }
      densityArr.push({ values, weights, maxWeight });
      pointsArr.push(cleanPts);
      minArr.push(minVal === Infinity ? 0 : minVal);
      maxArr.push(maxVal === -Infinity ? 0 : maxVal);
      placeholders.push(
        modeValue !== null ? modeValue : cleanPts.length ? cleanPts[Math.floor(cleanPts.length / 2)] : 0
      );
    }
    w.violinData.seriesViolinDensity[i2] = densityArr;
    w.violinData.seriesViolinPoints[i2] = pointsArr;
    w.violinData.seriesViolinMin[i2] = minArr;
    w.violinData.seriesViolinMax[i2] = maxArr;
    this.twoDSeries = placeholders;
  }
  /**
   * @param {string} format
   * @param {any[]} ser
   * @param {number} i
   */
  handleRangeDataFormat(format, ser, i2) {
    const rangeStart = [];
    const rangeEnd = [];
    const uniqueKeysMap = /* @__PURE__ */ new Map();
    const uniqueKeys = [];
    ser[i2].data.forEach((item) => {
      if (!uniqueKeysMap.has(item.x)) {
        const keyObj = {
          x: item.x,
          overlaps: /* @__PURE__ */ new Set(),
          y: []
        };
        uniqueKeysMap.set(item.x, keyObj);
        uniqueKeys.push(keyObj);
      }
    });
    if (format === "array") {
      for (let j = 0; j < ser[i2].data.length; j++) {
        if (Array.isArray(ser[i2].data[j])) {
          rangeStart.push(ser[i2].data[j][1][0]);
          rangeEnd.push(ser[i2].data[j][1][1]);
        } else {
          rangeStart.push(ser[i2].data[j]);
          rangeEnd.push(ser[i2].data[j]);
        }
      }
    } else if (format === "xy") {
      for (let j = 0; j < ser[i2].data.length; j++) {
        const isDataPoint2D = Array.isArray(ser[i2].data[j].y);
        const id = Utils$1.randomId();
        const x = ser[i2].data[j].x;
        const y = {
          y1: isDataPoint2D ? ser[i2].data[j].y[0] : ser[i2].data[j].y,
          y2: isDataPoint2D ? ser[i2].data[j].y[1] : ser[i2].data[j].y,
          rangeName: id
        };
        const gl = this.w.globals;
        if (!gl.seriesRangeName) gl.seriesRangeName = {};
        if (!gl.seriesRangeName[i2]) gl.seriesRangeName[i2] = {};
        gl.seriesRangeName[i2][j] = id;
        const keyObj = uniqueKeysMap.get(x);
        if (keyObj) {
          keyObj.y.push(y);
        }
        rangeStart.push(y.y1);
        rangeEnd.push(y.y2);
      }
    }
    return {
      start: rangeStart,
      end: rangeEnd,
      rangeUniques: uniqueKeys
    };
  }
  /**
   * @param {string} format
   * @param {any[]} ser
   * @param {number} i
   */
  handleCandleStickBoxDataFormat(format, ser, i2) {
    const w = this.w;
    const isBoxPlot = w.config.chart.type === "boxPlot" || /** @type {Record<string,any>} */
    w.config.series[i2].type === "boxPlot";
    const serO = [];
    const serH = [];
    const serM = [];
    const serL = [];
    const serC = [];
    const serPoints = [];
    const data = ser[i2].data;
    let getVals;
    if (format === "array") {
      const first = data[0];
      const isFlat = isBoxPlot && first && first.length === 6 || !isBoxPlot && first && first.length === 5;
      if (isFlat) {
        getVals = (d) => d.slice(1);
      } else {
        getVals = (d) => Array.isArray(d[1]) ? d[1] : [];
      }
    } else {
      getVals = (d) => Array.isArray(d.y) ? d.y : [];
    }
    for (let j = 0; j < data.length; j++) {
      const vals = getVals(data[j]);
      if (vals && vals.length >= 2) {
        serO.push(vals[0]);
        serH.push(vals[1]);
        if (isBoxPlot) {
          serM.push(vals[2]);
          serL.push(vals[3]);
          serC.push(vals[4]);
        } else {
          serL.push(vals[2]);
          serC.push(vals[3]);
        }
      }
      const pts = data[j] && /** @type {any} */
      data[j].points;
      serPoints.push(Array.isArray(pts) ? pts : []);
    }
    return {
      o: serO,
      h: serH,
      m: serM,
      l: serL,
      c: serC,
      points: serPoints
    };
  }
  /**
   * @param {any[]} ser
   */
  parseDataAxisCharts(ser) {
    var _a, _b, _c, _d, _e, _f;
    const cnf = this.w.config;
    const gl = this.w.globals;
    const dt = new DateTime(this.w);
    this.w.seriesData._parsedExtrema = [];
    const xlabels = cnf.labels.length > 0 ? cnf.labels.slice() : cnf.xaxis.categories.slice();
    this.w.axisFlags.isRangeBar = cnf.chart.type === "rangeBar" && gl.isBarHorizontal;
    this.w.labelData.hasXaxisGroups = cnf.xaxis.type === "category" && cnf.xaxis.group.groups.length > 0;
    if (this.w.labelData.hasXaxisGroups) {
      this.w.labelData.groups = cnf.xaxis.group.groups;
    }
    ser.forEach((s2, i2) => {
      if (s2.name !== void 0) {
        this.w.seriesData.seriesNames.push(s2.name);
      } else {
        this.w.seriesData.seriesNames.push(
          "series-" + parseInt(String(i2 + 1), 10)
        );
      }
    });
    this.coreUtils.setSeriesYAxisMappings();
    const buckets = [];
    const groups = [
      ...new Set(cnf.series.map((s2) => s2.group))
    ];
    cnf.series.forEach((s2, i2) => {
      const index = groups.indexOf(s2.group);
      if (!buckets[index]) buckets[index] = [];
      buckets[index].push(this.w.seriesData.seriesNames[i2]);
    });
    this.w.labelData.seriesGroups = buckets;
    const handleDates = () => {
      for (let j = 0; j < xlabels.length; j++) {
        if (typeof xlabels[j] === "string") {
          const isDate = dt.isValidDate(xlabels[j]);
          if (isDate) {
            this.twoDSeriesX.push(dt.parseDate(xlabels[j]));
          } else {
            throw new Error(
              "You have provided invalid Date format. Please provide a valid JavaScript Date"
            );
          }
        } else {
          this.twoDSeriesX.push(xlabels[j]);
        }
      }
    };
    for (let i2 = 0; i2 < ser.length; i2++) {
      this.twoDSeries = [];
      this.twoDSeriesX = [];
      this.threeDSeries = [];
      if (typeof ser[i2].data === "undefined") {
        console.error(
          "It is a possibility that you may have not included 'data' property in series."
        );
        ser[i2] = __spreadProps(__spreadValues({}, ser[i2]), { data: [] });
      }
      const dr = cnf.chart.dataReducer;
      const rawStash = (_b = (_a = gl.dataReducerRawSeries) == null ? void 0 : _a[i2]) == null ? void 0 : _b.data;
      if ((dr == null ? void 0 : dr.enabled) && this.isMultiFormat() && Array.isArray(rawStash) && rawStash.length > ((_c = dr.threshold) != null ? _c : 500)) {
        const targetPoints = (_d = dr.targetPoints) != null ? _d : 250;
        const xmin = cnf.xaxis.min;
        const xmax = cnf.xaxis.max;
        const windowed = xmin == null && xmax == null ? rawStash : Data.sliceByXRange(rawStash, xmin, xmax);
        let reduced = windowed;
        if (windowed.length > targetPoints) {
          const sampleY = !Array.isArray(windowed[0]) ? (_e = windowed[0]) == null ? void 0 : _e.y : (_f = windowed[0]) == null ? void 0 : _f[1];
          if (Array.isArray(sampleY)) {
            if (sampleY.length === 4) {
              reduced = Data.ohlcAggregate(windowed, targetPoints);
            } else if (sampleY.length === 2) {
              reduced = Data.rangeAggregate(windowed, targetPoints);
            }
          } else {
            reduced = Data.lttbDownsample(windowed, targetPoints);
          }
        }
        ser[i2] = __spreadProps(__spreadValues({}, ser[i2]), { data: reduced });
      }
      if (cnf.chart.type === "rangeBar" || cnf.chart.type === "rangeArea" || ser[i2].type === "rangeBar" || ser[i2].type === "rangeArea") {
        this.w.axisFlags.isRangeData = true;
        this.handleRangeData(ser, i2);
      }
      const customType = ser[i2].type || cnf.chart.type;
      if (isCustom(customType)) {
        const cls = (
          /** @type {any} */
          getChartClass(customType)
        );
        const yExtent = cls && cls.yExtent;
        if (cls && cls.dataType === "rangeXY" || typeof yExtent === "function") {
          this.w.axisFlags.isRangeData = true;
          this.handleCustomRangeData(ser, i2, yExtent);
        }
      }
      if (this.isMultiFormat()) {
        if (this.isFormat2DArray()) {
          this.handleFormat2DArray(ser, i2);
        } else if (this.isFormatXY()) {
          this.handleFormatXY(ser, i2);
        }
        if (cnf.chart.type === "candlestick" || ser[i2].type === "candlestick" || cnf.chart.type === "boxPlot" || ser[i2].type === "boxPlot") {
          this.handleCandleStickBoxData(ser, i2);
        }
        if (cnf.chart.type === "violin" || ser[i2].type === "violin") {
          this.handleViolinData(ser, i2);
        }
        this.w.seriesData.series.push(this.twoDSeries);
        this.w.labelData.labels.push(this.twoDSeriesX);
        this.w.seriesData.seriesX.push(this.twoDSeriesX);
        this.w.seriesData.seriesGoals = this.seriesGoals;
        if (i2 === this.activeSeriesIndex && !this.fallbackToCategory) {
          this.w.axisFlags.isXNumeric = true;
        }
      } else {
        if (cnf.xaxis.type === "datetime") {
          this.w.axisFlags.isXNumeric = true;
          handleDates();
          this.w.seriesData.seriesX.push(this.twoDSeriesX);
        } else if (cnf.xaxis.type === "numeric") {
          this.w.axisFlags.isXNumeric = true;
          if (xlabels.length > 0) {
            this.twoDSeriesX = xlabels;
            this.w.seriesData.seriesX.push(this.twoDSeriesX);
          }
        }
        this.w.labelData.labels.push(this.twoDSeriesX);
        const singleArray = ser[i2].data.map(
          (d) => Utils$1.parseNumber(d)
        );
        this.w.seriesData.series.push(singleArray);
      }
      this.w.seriesData.seriesZ.push(this.threeDSeries);
      if (ser[i2].color !== void 0) {
        this.w.seriesData.seriesColors.push(ser[i2].color);
      } else {
        this.w.seriesData.seriesColors.push(
          /** @type {any} */
          void 0
        );
      }
    }
    return this.w;
  }
  /**
   * @param {any[]} ser
   */
  parseDataNonAxisCharts(ser) {
    const cnf = this.w.config;
    this.w.seriesData.unitData = [];
    const hasOldFormat = Array.isArray(ser) && ser.every((s2) => typeof s2 === "number") && cnf.labels.length > 0;
    const hasNewFormat = Array.isArray(ser) && ser.some(
      (s2) => s2 && typeof s2 === "object" && s2.data || s2 && typeof s2 === "object" && s2.parsing
    );
    if (cnf.chart.type === "unit" && hasNewFormat && !hasOldFormat) {
      return this.parseUnitSeries(ser);
    }
    if (hasOldFormat && hasNewFormat) {
      console.warn(
        "ApexCharts: Both old format (numeric series + labels) and new format (series objects with data/parsing) detected. Using old format for backward compatibility."
      );
    }
    if (hasOldFormat) {
      this.w.seriesData.series = /** @type {any} */
      ser.slice();
      this.w.seriesData.seriesNames = cnf.labels.slice();
      for (let i2 = 0; i2 < this.w.seriesData.series.length; i2++) {
        if (this.w.seriesData.seriesNames[i2] === void 0) {
          this.w.seriesData.seriesNames.push("series-" + (i2 + 1));
        }
      }
      return this.w;
    }
    if (Array.isArray(ser) && ser.every((s2) => typeof s2 === "number")) {
      this.w.seriesData.series = /** @type {any} */
      ser.slice();
      this.w.seriesData.seriesNames = [];
      for (let i2 = 0; i2 < this.w.seriesData.series.length; i2++) {
        this.w.seriesData.seriesNames.push(cnf.labels[i2] || `series-${i2 + 1}`);
      }
      return this.w;
    }
    const processedData = this.extractPieDataFromSeries(ser);
    this.w.seriesData.series = processedData.values;
    this.w.seriesData.seriesNames = processedData.labels;
    if (cnf.chart.type === "radialBar") {
      this.w.seriesData.series = this.w.seriesData.series.map((val) => {
        const numVal = Utils$1.parseNumber(val);
        if (numVal > 100) {
          console.warn(
            `ApexCharts: RadialBar value ${numVal} > 100, consider using percentage values (0-100)`
          );
        }
        return numVal;
      });
    }
    for (let i2 = 0; i2 < this.w.seriesData.series.length; i2++) {
      if (this.w.seriesData.seriesNames[i2] === void 0) {
        this.w.seriesData.seriesNames.push("series-" + (i2 + 1));
      }
    }
    return this.w;
  }
  /**
   * Parse the unit chart's per-unit object form:
   *   series: [{ name, data: [datum, datum, ...] }, ...]
   * Each category's dot count is `data.length` (one dot per datum), and the
   * per-unit data is kept on `w.seriesData.unitData` so the renderer can colour
   * dots individually and the tooltip can show each unit's own info.
   * @param {any[]} ser
   * @returns {any} w
   */
  parseUnitSeries(ser) {
    const cnf = this.w.config;
    const series = [];
    const seriesNames = [];
    const unitData = [];
    ser.forEach((s2, i2) => {
      var _a;
      const data = s2 && Array.isArray(s2.data) ? s2.data : [];
      series.push(data.length);
      const name2 = s2 && s2.name !== void 0 && s2.name !== null ? s2.name : void 0;
      seriesNames.push((_a = name2 != null ? name2 : cnf.labels[i2]) != null ? _a : `series-${i2 + 1}`);
      unitData.push(data.slice());
    });
    this.w.seriesData.series = /** @type {any} */
    series;
    this.w.seriesData.seriesNames = seriesNames;
    this.w.seriesData.unitData = unitData;
    return this.w;
  }
  /**
   * Reset parsing flags to allow re-parsing of data during updates
   */
  resetParsingFlags() {
    const w = this.w;
    w.axisFlags.dataWasParsed = false;
    w.globals.originalSeries = null;
    if (w.config.series) {
      w.config.series.forEach((serie) => {
        if (
          /** @type {any} */
          serie.__apexParsed
        ) {
          delete /** @type {any} */
          serie.__apexParsed;
        }
      });
    }
  }
  /**
   * @param {any[]} ser
   */
  extractPieDataFromSeries(ser) {
    const values = [];
    const labels = [];
    if (!Array.isArray(ser)) {
      console.warn("ApexCharts: Expected array for series data");
      return { values: [], labels: [] };
    }
    if (ser.length === 0) {
      console.warn("ApexCharts: Empty series array");
      return { values: [], labels: [] };
    }
    const firstItem = ser[0];
    if (typeof firstItem === "object" && firstItem !== null && firstItem.data) {
      this.extractPieDataFromSeriesObjects(ser, values, labels);
    } else {
      console.warn(
        "ApexCharts: Unsupported series format for pie/donut/radialBar. Expected series objects with data property."
      );
      return { values: [], labels: [] };
    }
    return { values, labels };
  }
  // Extract data from series objects: [{ data: [...], parsing: {...} }]
  /**
   * @param {any[]} seriesArray
   * @param {any[]} values
   * @param {any[]} labels
   */
  extractPieDataFromSeriesObjects(seriesArray, values, labels) {
    seriesArray.forEach((serie, serieIndex) => {
      if (!serie.data || !Array.isArray(serie.data)) {
        console.warn(`ApexCharts: Series ${serieIndex} has no valid data array`);
        return;
      }
      serie.data.forEach((dataPoint) => {
        if (typeof dataPoint === "object" && dataPoint !== null) {
          if (dataPoint.x !== void 0 && dataPoint.y !== void 0) {
            labels.push(String(dataPoint.x));
            values.push(Utils$1.parseNumber(dataPoint.y));
          } else {
            console.warn(
              "ApexCharts: Invalid data point format for pie chart. Expected {x, y} format:",
              dataPoint
            );
          }
        } else {
          console.warn(
            "ApexCharts: Expected object data point, got:",
            typeof dataPoint
          );
        }
      });
    });
  }
  /** User possibly set string categories in xaxis.categories or labels prop
   * Or didn't set xaxis labels at all - in which case we manually do it.
   * If user passed series data as [[3, 2], [4, 5]] or [{ x: 3, y: 55 }],
   * this shouldn't be called
   * @param {any[]} ser - the series which user passed to the config
   */
  handleExternalLabelsData(ser) {
    const cnf = this.w.config;
    if (cnf.xaxis.categories.length > 0) {
      this.w.labelData.labels = cnf.xaxis.categories;
    } else if (cnf.labels.length > 0) {
      this.w.labelData.labels = cnf.labels.slice();
    } else if (this.fallbackToCategory) {
      this.w.labelData.labels = /** @type {string[]} */
      /** @type {unknown} */
      this.w.labelData.labels[0];
      if (this.w.rangeData.seriesRange.length) {
        this.w.rangeData.seriesRange.map((srt) => {
          srt.forEach((sr) => {
            if (this.w.labelData.labels.indexOf(sr.x) < 0 && sr.x) {
              this.w.labelData.labels.push(sr.x);
            }
          });
        });
        const _labels = this.w.labelData.labels;
        if (_labels.length > 0 && (typeof _labels[0] === "number" || typeof _labels[0] === "string")) {
          this.w.labelData.labels = [...new Set(_labels)];
        } else {
          const _seen = /* @__PURE__ */ new Map();
          for (const _label of _labels) {
            const _key = JSON.stringify(_label);
            if (!_seen.has(_key)) _seen.set(_key, _label);
          }
          this.w.labelData.labels = Array.from(_seen.values());
        }
      }
      if (cnf.xaxis.convertedCatToNumeric) {
        const defaults = new Defaults(cnf);
        defaults.convertCatToNumericXaxis(cnf, this.w.seriesData.seriesX[0]);
        this._generateExternalLabels(ser);
      }
    } else {
      this._generateExternalLabels(ser);
    }
  }
  /**
   * @param {any[]} ser
   */
  _generateExternalLabels(ser) {
    const gl = this.w.globals;
    const cnf = this.w.config;
    let labelArr = [];
    if (gl.axisCharts) {
      if (this.w.seriesData.series.length > 0) {
        if (this.isFormatXY()) {
          const seriesDataFiltered = cnf.series.map(
            (serie) => {
              const seen = /* @__PURE__ */ new Map();
              for (const point of serie.data) {
                if (!seen.has(point.x)) seen.set(point.x, point);
              }
              return Array.from(seen.values());
            }
          );
          const len = seriesDataFiltered.reduce(
            (p, c2, i2, a2) => a2[p].length > c2.length ? p : i2,
            0
          );
          for (let i2 = 0; i2 < seriesDataFiltered[len].length; i2++) {
            labelArr.push(i2 + 1);
          }
        } else {
          for (let i2 = 0; i2 < this.w.seriesData.series[gl.maxValsInArrayIndex].length; i2++) {
            labelArr.push(i2 + 1);
          }
        }
      }
      this.w.seriesData.seriesX = [];
      for (let i2 = 0; i2 < ser.length; i2++) {
        this.w.seriesData.seriesX.push(labelArr);
      }
      if (!this.w.globals.isBarHorizontal) {
        this.w.axisFlags.isXNumeric = true;
      }
    }
    if (labelArr.length === 0) {
      labelArr = gl.axisCharts ? [] : (
        /**
         * @param {Record<string, any>} gls
         * @param {number} glsi
         */
        this.w.seriesData.series.map((gls, glsi) => {
          return glsi + 1;
        })
      );
      for (let i2 = 0; i2 < ser.length; i2++) {
        this.w.seriesData.seriesX.push(labelArr);
      }
    }
    this.w.labelData.labels = /** @type {string[]} */
    /** @type {unknown} */
    labelArr;
    if (cnf.xaxis.convertedCatToNumeric) {
      this.w.labelData.categoryLabels = labelArr.map((l2) => {
        return cnf.xaxis.labels.formatter(l2);
      });
    }
    this.w.axisFlags.noLabelsProvided = true;
  }
  /**
   * @param {any[]} series
   */
  parseRawDataIfNeeded(series) {
    const cnf = this.w.config;
    const gl = this.w.globals;
    const globalParsing = cnf.parsing;
    if (this.w.axisFlags.dataWasParsed) {
      return series;
    }
    const hasGlobalParsing = !!(globalParsing && (globalParsing.x || globalParsing.y || globalParsing.z));
    const hasSeriesParsing = series.some(
      (s2) => s2.parsing && (s2.parsing.x || s2.parsing.y || s2.parsing.z)
    );
    if (!hasGlobalParsing && !hasSeriesParsing) {
      return series;
    }
    const processedSeries = series.map((serie, index) => {
      var _a, _b, _c, _d, _e;
      if (!serie.data || !Array.isArray(serie.data) || serie.data.length === 0) {
        return serie;
      }
      const effectiveParsing = {
        x: ((_a = serie.parsing) == null ? void 0 : _a.x) || (globalParsing == null ? void 0 : globalParsing.x),
        y: ((_b = serie.parsing) == null ? void 0 : _b.y) || (globalParsing == null ? void 0 : globalParsing.y),
        z: ((_c = serie.parsing) == null ? void 0 : _c.z) || (globalParsing == null ? void 0 : globalParsing.z)
      };
      if (!effectiveParsing.x && !effectiveParsing.y) {
        return serie;
      }
      const firstDataPoint = serie.data[0];
      if (typeof firstDataPoint === "object" && firstDataPoint !== null && (Object.prototype.hasOwnProperty.call(firstDataPoint, "x") || Object.prototype.hasOwnProperty.call(firstDataPoint, "y")) || Array.isArray(firstDataPoint)) {
        return serie;
      }
      if (!effectiveParsing.x || !effectiveParsing.y || Array.isArray(effectiveParsing.y) && effectiveParsing.y.length === 0) {
        const missing = [];
        if (!effectiveParsing.x) missing.push("x");
        if (!effectiveParsing.y || Array.isArray(effectiveParsing.y) && effectiveParsing.y.length === 0) {
          missing.push("y");
        }
        const seriesName = (_d = serie.name) != null ? _d : `series[${index}]`;
        console.warn(
          `ApexCharts [${this.w.globals.chartID}]: "${seriesName}" has a parseData config but is missing the '${missing.join(
            "', '"
          )}' field specification.`,
          { parsing: (_e = serie.parsing) != null ? _e : globalParsing }
        );
        return serie;
      }
      const transformedData = serie.data.map(
        (item, itemIndex) => {
          if (typeof item !== "object" || item === null) {
            console.warn(
              `ApexCharts: Series ${index}, data point ${itemIndex} is not an object, skipping parsing`
            );
            return item;
          }
          const x = this.getNestedValue(item, effectiveParsing.x);
          let y;
          let z = void 0;
          if (Array.isArray(effectiveParsing.y)) {
            const yValues = effectiveParsing.y.map(
              (fieldName) => this.getNestedValue(item, fieldName)
            );
            if (this.w.config.chart.type === "bubble") {
              if (yValues.length < 2) {
                console.warn(
                  `ApexCharts: series[${index}] bubble chart requires parseData.y to have at least 2 fields (y and z). Got: ${JSON.stringify(effectiveParsing.y)}`
                );
              }
              y = yValues[0];
            } else {
              y = yValues;
            }
          } else {
            y = this.getNestedValue(item, effectiveParsing.y);
          }
          if (effectiveParsing.z) {
            z = this.getNestedValue(item, effectiveParsing.z);
          }
          if (x === void 0) {
            console.warn(
              `ApexCharts: Series ${index}, data point ${itemIndex} missing field '${effectiveParsing.x}'`
            );
          }
          if (y === void 0) {
            console.warn(
              `ApexCharts: Series ${index}, data point ${itemIndex} missing field '${effectiveParsing.y}'`
            );
          }
          const result = { x, y, z: void 0 };
          if (this.w.config.chart.type === "bubble" && Array.isArray(effectiveParsing.y) && effectiveParsing.y.length === 2) {
            const zValue = this.getNestedValue(item, effectiveParsing.y[1]);
            if (zValue !== void 0) {
              result.z = zValue;
            }
          }
          if (z !== void 0) {
            result.z = z;
          }
          return result;
        }
      );
      return __spreadProps(__spreadValues({}, serie), {
        data: transformedData,
        __apexParsed: true
      });
    });
    this.w.axisFlags.dataWasParsed = true;
    if (!gl.originalSeries) {
      gl.originalSeries = Utils$1.clone(series);
    }
    return processedSeries;
  }
  /**
   * Get nested object value using dot notation path
   * @param {Object} obj - The object to search in
   * @param {string} path - Dot notation path (e.g., 'user.profile.name')
   * @returns {*} The value at the path, or undefined if not found
   */
  getNestedValue(obj, path) {
    if (!obj || typeof obj !== "object" || !path) {
      return void 0;
    }
    if (path.indexOf(".") === -1) {
      return (
        /** @type {any} */
        obj[path]
      );
    }
    const keys = path.split(".");
    let current = obj;
    for (let i2 = 0; i2 < keys.length; i2++) {
      if (current === null || current === void 0 || typeof current !== "object") {
        return void 0;
      }
      current = /** @type {any} */
      current[keys[i2]];
    }
    return current;
  }
  /**
   * Optional pre-parse series transform. A chart type whose series carries RAW
   * observations rather than the values it draws (a histogram's sample, and in
   * time a boxPlot's or a violin's) registers a transform through
   * `apexcharts/features/stats`. Core keeps only this lookup, so a bundle that
   * never asks for a raw-sample type never pays for the statistics.
   *
   * @param {any[]} ser
   * @returns {any[]}
   */
  applySeriesTransform(ser) {
    const cnf = this.w.config;
    const name2 = cnf.chart.requestedType || cnf.chart.type;
    const transform = getSeriesTransform(name2);
    if (transform) return transform(ser, this.w);
    if (!Array.isArray(ser) || RAW_SAMPLE_TYPES.indexOf(name2) === -1) return ser;
    if (!this._warnedMissingTransform) {
      this._warnedMissingTransform = true;
      console.warn(
        `ApexCharts: chart.type '${name2}' needs the stats feature. Add \`import 'apexcharts/features/stats'\`, or import from 'apexcharts/${name2}'.`
      );
    }
    return ser.map((s2) => __spreadProps(__spreadValues({}, s2), { data: [] }));
  }
  /**
   * Nested treemap: resolve a `children` hierarchy into the tree the renderer
   * lays out, and return the leaves as a flat series.
   *
   * Everything downstream of here addresses a treemap by `(seriesIndex,
   * dataPointIndex)` into a flat matrix, so the leaves are flattened in
   * depth-first order and `dataPointIndex` keeps meaning "the nth leaf of this
   * series". The tree itself goes on globals for the renderer.
   *
   * `cnf.series` is replaced with the flattened leaves further down parseData,
   * which is the only copy that survives — so the nested input is stashed on
   * the first parse and every later parse resolves from the stash, never from
   * the already-flattened view. That is the same contract the histogram's raw
   * observations and the downsampler's raw series use, and `_updateSeries`
   * clears all three when the user pushes new data.
   *
   * @param {any[]} ser
   * @returns {any[]}
   */
  flattenTreemapHierarchy(ser) {
    const w = this.w;
    const gl = w.globals;
    if (w.config.chart.type !== "treemap" || !Array.isArray(ser)) return ser;
    if (!gl.treemapRawSeries) {
      if (!isNestedTreemap(w, ser)) {
        gl.treemapRoots = null;
        return ser;
      }
      gl.treemapRawSeries = ser.map((s2) => __spreadProps(__spreadValues({}, s2), {
        data: Array.isArray(s2 == null ? void 0 : s2.data) ? s2.data.slice() : s2 == null ? void 0 : s2.data
      }));
    }
    const { roots, leafSeries, maxDepth } = resolveTreemapTree(
      w,
      gl.treemapRawSeries
    );
    gl.treemapRoots = roots;
    gl.treemapMaxDepth = maxDepth;
    return leafSeries;
  }
  /**
   * Scatter strip-plot support. When `plotOptions.scatter.jitter.enabled` and a
   * series carries compact `{ x: 'Category', y: [v1, v2, ...] }` data, expand
   * each observation into its own `{ x: bandIndex, y }` point (so every dot is a
   * first-class, hoverable marker) and frame the x-axis as evenly-spaced,
   * labelled bands. The reference per-point form (numeric x + `xaxis.categories`)
   * is reframed too, without expansion. Returns `ser` unchanged for non-scatter
   * charts and for plain numeric/datetime data (continuous overplotting jitter
   * is offset at render time instead).
   *
   * @param {any[]} ser
   * @returns {any[]}
   */
  expandScatterJitterData(ser) {
    var _a, _b;
    const cnf = this.w.config;
    const isScatter = cnf.chart.type === "scatter" || cnf.chart.type === "bubble";
    const jt = (_b = (_a = cnf.plotOptions) == null ? void 0 : _a.scatter) == null ? void 0 : _b.jitter;
    if (!isScatter || !jt || !jt.enabled || !Array.isArray(ser)) return ser;
    const hasArrayY = ser.some(
      (s2) => Array.isArray(s2 == null ? void 0 : s2.data) && s2.data.some(
        (d) => d && !Array.isArray(d) && Array.isArray(d.y)
      )
    );
    if (!hasArrayY) {
      if (cnf.xaxis.type !== "datetime") {
        if (Array.isArray(cnf.xaxis.categories) && cnf.xaxis.categories.length) {
          this._applyBandAxis(cnf.xaxis.categories.slice());
        } else if (Array.isArray(cnf.xaxis._scatterBandLabels) && cnf.xaxis._scatterBandLabels.length) {
          this._applyBandAxis(cnf.xaxis._scatterBandLabels);
        }
      }
      return ser;
    }
    const bandLabels = [];
    const bandIndex = /* @__PURE__ */ new Map();
    ser.forEach((s2) => {
      if (!Array.isArray(s2 == null ? void 0 : s2.data)) return;
      s2.data.forEach((d) => {
        if (d && Array.isArray(d.y)) {
          const key = String(d.x);
          if (!bandIndex.has(key)) {
            bandIndex.set(key, bandLabels.length);
            bandLabels.push(d.x);
          }
        }
      });
    });
    const maxPoints = jt.maxPoints || 5e3;
    const expanded = ser.map((s2) => {
      if (!Array.isArray(s2 == null ? void 0 : s2.data)) return s2;
      const out = [];
      s2.data.forEach((d) => {
        if (d && Array.isArray(d.y)) {
          const bi = bandIndex.get(String(d.x));
          const ys = d.y;
          const stride = ys.length > maxPoints ? Math.ceil(ys.length / maxPoints) : 1;
          for (let k = 0; k < ys.length; k += stride) {
            const yv = Utils$1.parseNumber(ys[k]);
            if (yv === null) continue;
            out.push({ x: bi, y: yv });
          }
        } else if (d && typeof d === "object" && !Array.isArray(d)) {
          const key = String(d.x);
          out.push({ x: bandIndex.has(key) ? bandIndex.get(key) : d.x, y: d.y });
        } else {
          out.push(d);
        }
      });
      return __spreadProps(__spreadValues({}, s2), { data: out });
    });
    this._applyBandAxis(bandLabels);
    return expanded;
  }
  /**
   * Frame the x-axis as N evenly-spaced bands (one per category) on a numeric
   * scale. Bands sit at integer positions 0..N-1; the range is padded by a full
   * band on each side (min -1, max N) so jittered dots never clip. Crucially the
   * range bounds and tick count are integers, so the ticks land exactly on the
   * band centers regardless of how the numeric scale "nices" the step (e.g. the
   * small-range reduction in Scales._adjustTicksForSmallRange triggered by a
   * y-axis formatter). Only fills in options the user hasn't set, so explicit
   * min/max/tickAmount/formatter still win. The exception is an interactive
   * zoom/pan window (w.interact.zoomed): its fractional bounds are snapped to
   * whole bands so tick labels stay on band centers and edge bands are never
   * half-cropped.
   *
   * @param {any[]} bandLabels
   */
  _applyBandAxis(bandLabels) {
    var _a;
    const xa = this.w.config.xaxis;
    const n2 = bandLabels.length;
    if (!n2) return;
    const owned = (
      /** @type {Record<string, boolean>} */
      xa._scatterBand = xa._scatterBand || {}
    );
    xa._scatterBandLabels = bandLabels.slice();
    xa.type = "numeric";
    if (((_a = this.w.interact) == null ? void 0 : _a.zoomed) && typeof xa.min === "number" && typeof xa.max === "number" && isFinite(xa.min) && isFinite(xa.max)) {
      const clampBand = (b) => Math.max(0, Math.min(n2 - 1, b));
      let first = clampBand(Math.round(xa.min + 0.49));
      let last = clampBand(Math.round(xa.max - 0.49));
      if (last < first) {
        first = last = clampBand(Math.round((xa.min + xa.max) / 2));
      }
      xa.min = first - 1;
      xa.max = last + 1;
      xa.tickAmount = last - first + 2;
      owned.min = true;
      owned.max = true;
      owned.tick = true;
    } else {
      if (xa.min == null || owned.min) {
        xa.min = -1;
        owned.min = true;
      }
      if (xa.max == null || owned.max) {
        xa.max = n2;
        owned.max = true;
      }
      if (xa.tickAmount == null || xa.tickAmount === "dataPoints" || owned.tick) {
        xa.tickAmount = n2 + 1;
        owned.tick = true;
      }
    }
    xa.labels = xa.labels || {};
    const existing = (
      /** @type {any} */
      xa.labels.formatter
    );
    if (typeof existing !== "function" || existing._scatterBand) {
      const fmt = (
        /** @type {any} */
        ((val) => {
          const r2 = Math.round(val);
          return Math.abs(val - r2) < 1e-6 && bandLabels[r2] !== void 0 ? bandLabels[r2] : "";
        })
      );
      fmt._scatterBand = true;
      xa.labels.formatter = fmt;
    }
  }
  // Segregate user provided data into appropriate vars
  /**
   * @param {any[]} ser
   */
  parseData(ser) {
    var _a, _b, _c, _d, _e, _f, _g;
    const w = this.w;
    const cnf = w.config;
    const gl = w.globals;
    ser = this.parseRawDataIfNeeded(ser);
    ser = this.applySeriesTransform(ser);
    ser = this.expandScatterJitterData(ser);
    ser = this.flattenTreemapHierarchy(ser);
    if (((_a = cnf.chart.dataReducer) == null ? void 0 : _a.enabled) && gl.axisCharts && !gl.dataReducerRawSeries) {
      gl.dataReducerRawSeries = ser.map((s2) => ({
        data: Array.isArray(s2 == null ? void 0 : s2.data) ? s2.data.slice() : s2 == null ? void 0 : s2.data
      }));
      let rawMinX = Infinity;
      let rawMaxX = -Infinity;
      for (const s2 of ser) {
        const d = s2 == null ? void 0 : s2.data;
        if (!Array.isArray(d) || d.length === 0) continue;
        const isXY = !Array.isArray(d[0]);
        const firstX = isXY ? (_b = d[0]) == null ? void 0 : _b.x : (_c = d[0]) == null ? void 0 : _c[0];
        const lastX = isXY ? (_d = d[d.length - 1]) == null ? void 0 : _d.x : (_e = d[d.length - 1]) == null ? void 0 : _e[0];
        if (typeof firstX === "number") rawMinX = Math.min(rawMinX, firstX);
        if (typeof lastX === "number") rawMaxX = Math.max(rawMaxX, lastX);
      }
      if (rawMinX !== Infinity) {
        gl.dataReducerRawMinX = rawMinX;
        gl.dataReducerRawMaxX = rawMaxX;
      }
    }
    if (gl.dataReducerRawSeries && ((_f = cnf.chart.dataReducer) == null ? void 0 : _f.enabled)) {
      ser = ser.map((s2) => __spreadValues({}, s2));
    }
    cnf.series = ser;
    if (gl.dataReducerRawSeries && ((_g = cnf.chart.dataReducer) == null ? void 0 : _g.enabled)) {
      const stash = gl.dataReducerRawSeries;
      gl.initialSeries = ser.map((s2, i2) => {
        var _a2, _b2, _c2;
        return __spreadProps(__spreadValues({}, s2), {
          data: (_c2 = (_b2 = (_a2 = stash[i2]) == null ? void 0 : _a2.data) == null ? void 0 : _b2.slice()) != null ? _c2 : s2.data
        });
      });
    } else if (gl.histogramRawSeries) {
      gl.initialSeries = gl.histogramRawSeries;
    } else if (gl.treemapRawSeries) {
      gl.initialSeries = gl.treemapRawSeries;
    } else {
      gl.initialSeries = ser;
    }
    this.excludeCollapsedSeriesInYAxis();
    this.fallbackToCategory = false;
    this.resetGlobals();
    this.isMultipleY();
    if (gl.axisCharts) {
      this.parseDataAxisCharts(ser);
      this.coreUtils.getLargestSeries();
    } else {
      this.parseDataNonAxisCharts(ser);
    }
    if (cnf.chart.stacked) {
      const series = new Series(this.w);
      this.w.seriesData.series = series.setNullSeriesToZeroValues(
        this.w.seriesData.series
      );
    }
    this.coreUtils.getSeriesTotals();
    if (gl.axisCharts) {
      Data._defineLazyResult(
        this.w.seriesData,
        "stackedSeriesTotals",
        () => this.coreUtils.getStackedSeriesTotals()
      );
      Data._defineLazyResult(
        this.w.seriesData,
        "stackedSeriesTotalsByGroups",
        () => this.coreUtils.getStackedSeriesTotalsByGroups()
      );
      Data._defineLazyResult(gl, "seriesPercent", () => {
        this.coreUtils.getPercentSeries();
        return gl.seriesPercent;
      });
    } else {
      this.coreUtils.getPercentSeries();
    }
    if (!this.w.axisFlags.dataFormatXNumeric && (!this.w.axisFlags.isXNumeric || cnf.xaxis.type === "numeric" && cnf.labels.length === 0 && cnf.xaxis.categories.length === 0)) {
      this.handleExternalLabelsData(ser);
    }
    const catLabels = this.coreUtils.getCategoryLabels(this.w.labelData.labels);
    for (let l2 = 0; l2 < catLabels.length; l2++) {
      if (Array.isArray(catLabels[l2])) {
        this.w.axisFlags.isMultiLineX = true;
        break;
      }
    }
    return {
      // w.seriesData (future slice)
      // initialSeries/originalSeries and the stacked totals are deliberately
      // ABSENT: they already live as lazy accessors on gl / w.seriesData, so
      // a snapshot field would either force their materialization (a deep
      // clone plus three O(n) passes per parse that most charts never need)
      // or, as a delegating getter, recurse into itself when a writer copies
      // it back onto the object it delegates to.
      seriesData: {
        series: this.w.seriesData.series,
        seriesNames: this.w.seriesData.seriesNames,
        seriesX: this.w.seriesData.seriesX,
        seriesZ: this.w.seriesData.seriesZ,
        seriesColors: this.w.seriesData.seriesColors,
        seriesGoals: this.w.seriesData.seriesGoals,
        unitData: this.w.seriesData.unitData,
        noLabelsProvided: this.w.axisFlags.noLabelsProvided
      },
      // w.rangeData (future slice)
      rangeData: {
        seriesRangeStart: this.w.rangeData.seriesRangeStart,
        seriesRangeEnd: this.w.rangeData.seriesRangeEnd,
        seriesRange: this.w.rangeData.seriesRange
      },
      // w.candleData (future slice)
      candleData: {
        seriesCandleO: this.w.candleData.seriesCandleO,
        seriesCandleH: this.w.candleData.seriesCandleH,
        seriesCandleM: this.w.candleData.seriesCandleM,
        seriesCandleL: this.w.candleData.seriesCandleL,
        seriesCandleC: this.w.candleData.seriesCandleC,
        seriesBoxPoints: this.w.candleData.seriesBoxPoints
      },
      // w.labelData (future slice)
      labelData: {
        labels: this.w.labelData.labels,
        categoryLabels: this.w.labelData.categoryLabels
      },
      // w.axisFlags (future slice)
      axisFlags: {
        isXNumeric: this.w.axisFlags.isXNumeric,
        dataFormatXNumeric: this.w.axisFlags.dataFormatXNumeric,
        isDataXYZ: this.w.axisFlags.isDataXYZ,
        isRangeData: this.w.axisFlags.isRangeData,
        isRangeBar: this.w.axisFlags.isRangeBar,
        isMultiLineX: this.w.axisFlags.isMultiLineX,
        dataWasParsed: this.w.axisFlags.dataWasParsed,
        hasXaxisGroups: this.w.labelData.hasXaxisGroups,
        groups: this.w.labelData.groups,
        seriesGroups: this.w.labelData.seriesGroups
      }
    };
  }
  /**
   * Slice a sorted-by-x series to a [xmin, xmax] window using binary search.
   *
   * Pads with one extra point on each side so lines extend cleanly to the
   * chart edges. Either bound may be null/undefined to disable that side.
   *
   * @param {any[]} data - Series data in [{x,y}] or [[x,y]] format, sorted by x.
   * @param {number|null|undefined} xmin
   * @param {number|null|undefined} xmax
   * @returns {any[]} Sliced array (new array, never the input reference).
   */
  /**
   * Define `key` on `obj` as a lazily computed property: `compute` runs on
   * first read after this call and its result is cached; assigning to the
   * property stores the assigned value directly (so code that writes the
   * field, like getPercentSeries, keeps working). Re-calling resets the cache
   * (used once per parse).
   * @param {any} obj
   * @param {string} key
   * @param {() => any} compute
   */
  static _defineLazyResult(obj, key, compute) {
    let has = false;
    let value;
    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: true,
      get() {
        if (!has) {
          has = true;
          value = compute();
        }
        return value;
      },
      set(v) {
        has = true;
        value = v;
      }
    });
  }
  /**
   * @param {any[]} data
   * @param {any} xmin
   * @param {any} xmax
   */
  static sliceByXRange(data, xmin, xmax) {
    const len = data.length;
    if (len === 0) return data;
    const isXY = !Array.isArray(data[0]);
    const getX = isXY ? (p) => p.x : (p) => p[0];
    let lo = 0;
    if (xmin != null) {
      let l2 = 0;
      let r2 = len - 1;
      while (l2 <= r2) {
        const m = l2 + r2 >> 1;
        if (getX(data[m]) < xmin) l2 = m + 1;
        else r2 = m - 1;
      }
      lo = Math.max(0, l2 - 1);
    }
    let hi = len;
    if (xmax != null) {
      let l2 = 0;
      let r2 = len - 1;
      while (l2 <= r2) {
        const m = l2 + r2 >> 1;
        if (getX(data[m]) > xmax) r2 = m - 1;
        else l2 = m + 1;
      }
      hi = Math.min(len, l2 + 1);
    }
    return lo === 0 && hi === len ? data.slice() : data.slice(lo, hi);
  }
  /**
   * Largest-Triangle-Three-Bucket (LTTB) downsampling.
   *
   * Reduces `data` to `targetPoints` points while preserving the visual shape
   * of the series as perceived by the human eye.
   *
   * @param {any[]} data   - Raw series data in [{x,y}] or [[x,y]] format.
   * @param {number} targetPoints - Desired output length (>= 3).
   * @returns {any[]} Downsampled array in the same format as the input.
   */
  static lttbDownsample(data, targetPoints) {
    const len = data.length;
    if (targetPoints >= len || targetPoints < 3) return data;
    const isXY = !Array.isArray(data[0]);
    const getX = isXY ? (p) => p.x : (p) => p[0];
    const getY = isXY ? (p) => p.y : (p) => p[1];
    const sampled = [];
    sampled.push(data[0]);
    const bucketSize = (len - 2) / (targetPoints - 2);
    let a2 = 0;
    for (let i2 = 0; i2 < targetPoints - 2; i2++) {
      const avgRangeStart = Math.floor((i2 + 1) * bucketSize) + 1;
      const avgRangeEnd = Math.min(Math.floor((i2 + 2) * bucketSize) + 1, len);
      let avgX = 0;
      let avgY = 0;
      const avgRangeLen = avgRangeEnd - avgRangeStart;
      for (let j = avgRangeStart; j < avgRangeEnd; j++) {
        avgX += getX(data[j]);
        avgY += getY(data[j]);
      }
      avgX /= avgRangeLen;
      avgY /= avgRangeLen;
      const rangeStart = Math.floor(i2 * bucketSize) + 1;
      const rangeEnd = Math.min(Math.floor((i2 + 1) * bucketSize) + 1, len);
      const pointAX = getX(data[a2]);
      const pointAY = getY(data[a2]);
      let maxArea = -1;
      let maxAreaIdx = rangeStart;
      for (let j = rangeStart; j < rangeEnd; j++) {
        const area = Math.abs(
          (pointAX - avgX) * (getY(data[j]) - pointAY) - (pointAX - getX(data[j])) * (avgY - pointAY)
        ) * 0.5;
        if (area > maxArea) {
          maxArea = area;
          maxAreaIdx = j;
        }
      }
      sampled.push(data[maxAreaIdx]);
      a2 = maxAreaIdx;
    }
    sampled.push(data[len - 1]);
    return sampled;
  }
  /**
   * OHLC-aware bucket aggregation for candlestick / OHLC series.
   *
   * Each point's y is a 4-tuple `[open, high, low, close]`. LTTB is unusable
   * here — it treats y as a scalar, so the triangle-area math degenerates and
   * silently discards the high/low extremes that *define* a candle. Instead we
   * split the series into `targetPoints` contiguous buckets and roll each up
   * into a single candle: open = first bucket open, close = last bucket close,
   * high = max of highs, low = min of lows. The x is the first point's x in the
   * bucket. Output keeps the input's format ([{x,y}] or [[x,y]]).
   *
   * @param {any[]} data         - Raw OHLC series in [{x,y:[o,h,l,c]}] or [[x,[o,h,l,c]]] format.
   * @param {number} targetPoints - Desired output length (>= 1).
   * @returns {any[]} Aggregated array in the same format as the input.
   */
  static ohlcAggregate(data, targetPoints) {
    const len = data.length;
    if (targetPoints >= len || targetPoints < 1) return data;
    const isXY = !Array.isArray(data[0]);
    const getX = isXY ? (p) => p.x : (p) => p[0];
    const getY = isXY ? (p) => p.y : (p) => p[1];
    const make = isXY ? (x, y) => ({ x, y }) : (x, y) => [x, y];
    const out = [];
    const bucketSize = len / targetPoints;
    for (let i2 = 0; i2 < targetPoints; i2++) {
      const start = Math.floor(i2 * bucketSize);
      const end = i2 === targetPoints - 1 ? len : Math.floor((i2 + 1) * bucketSize);
      if (end <= start) continue;
      const firstY = getY(data[start]);
      const open = firstY[0];
      let high = firstY[1];
      let low = firstY[2];
      let close = firstY[3];
      for (let j = start + 1; j < end; j++) {
        const y = getY(data[j]);
        if (y[1] > high) high = y[1];
        if (y[2] < low) low = y[2];
        close = y[3];
      }
      out.push(make(getX(data[start]), [open, high, low, close]));
    }
    return out;
  }
  /**
   * Bucket-aggregate 2-tuple range data (`y: [low, high]`, rangeArea/rangeBar)
   * into `targetPoints` points, the range analog of {@link ohlcAggregate}. Each
   * bucket emits `[min low, max high]` so the band's vertical extent is never
   * understated by downsampling (LTTB, built for scalar y, would drop these
   * extremes). Order-agnostic: the min/max scan both tuple slots, so it is
   * correct whether a point is stored `[low, high]` or `[high, low]`.
   *
   * Null bounds (e.g. an indicator's warm-up period) are ignored, not treated
   * as 0 — `Math.min(null, x)` would coerce to 0 and pin the band to the
   * baseline. A bucket with no finite bounds emits `[null, null]` so it renders
   * as a gap, matching the un-downsampled series.
   * @param {any[]} data
   * @param {number} targetPoints
   * @returns {any[]}
   */
  static rangeAggregate(data, targetPoints) {
    const len = data.length;
    if (targetPoints >= len || targetPoints < 1) return data;
    const isXY = !Array.isArray(data[0]);
    const getX = isXY ? (p) => p.x : (p) => p[0];
    const getY = isXY ? (p) => p.y : (p) => p[1];
    const make = isXY ? (x, y) => ({ x, y }) : (x, y) => [x, y];
    const out = [];
    const bucketSize = len / targetPoints;
    for (let i2 = 0; i2 < targetPoints; i2++) {
      const start = Math.floor(i2 * bucketSize);
      const end = i2 === targetPoints - 1 ? len : Math.floor((i2 + 1) * bucketSize);
      if (end <= start) continue;
      let low = Infinity;
      let high = -Infinity;
      for (let j = start; j < end; j++) {
        const y = getY(data[j]);
        if (y == null) continue;
        for (let k = 0; k < 2; k++) {
          const v = y[k];
          if (v == null || !isFinite(v)) continue;
          if (v < low) low = v;
          if (v > high) high = v;
        }
      }
      out.push(
        make(getX(data[start]), low === Infinity ? [null, null] : [low, high])
      );
    }
    return out;
  }
  excludeCollapsedSeriesInYAxis() {
    const w = this.w;
    const yAxisIndexes = [];
    w.globals.seriesYAxisMap.forEach((yAxisArr, yi) => {
      let collapsedCount = 0;
      yAxisArr.forEach((seriesIndex) => {
        if (w.globals.collapsedSeriesIndices.indexOf(seriesIndex) !== -1) {
          collapsedCount++;
        }
      });
      if (collapsedCount > 0 && collapsedCount == yAxisArr.length) {
        yAxisIndexes.push(yi);
      }
    });
    w.globals.ignoreYAxisIndexes = yAxisIndexes.map((x) => x);
  }
}
class UpdateHelpers {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
  }
  /**
   * private method to update Options.
   *
   * @param {Record<string, any>} options - A new config object can be passed which will be merged with the existing config object
   * @param {boolean} redraw - should redraw from beginning or should use existing paths and redraw from there
   * @param {boolean} animate - should animate or not on updating Options
   * @param {boolean} overwriteInitialConfig - should update the initial config or not
   */
  _updateOptions(options2, redraw = false, animate = true, updateSyncedCharts = true, overwriteInitialConfig = false) {
    return new Promise((resolve, reject) => {
      let charts = [this.ctx];
      if (updateSyncedCharts) {
        charts = this.ctx.getSyncedCharts();
      }
      if (this.w.globals.isExecCalled) {
        charts = [this.ctx];
        this.w.globals.isExecCalled = false;
      }
      charts.forEach((ch, chartIndex) => {
        var _a, _b;
        const w = ch.w;
        w.globals.shouldAnimate = animate;
        if (!redraw) {
          w.globals.resized = true;
          w.globals.dataChanged = true;
          if (animate && w.config.chart.animations.enabled) {
            ch.series.getPreviousPaths();
          }
        }
        const fromType = w.config.chart.requestedType || w.config.chart.type;
        if (animate && options2 && typeof options2 === "object") {
          const newType = (_a = options2 == null ? void 0 : options2.chart) == null ? void 0 : _a.type;
          if (newType && newType !== fromType) {
            (_b = ch.morphTypeChange) == null ? void 0 : _b.captureBeforeDestroy({
              fromType,
              toType: newType,
              newSeries: options2.series || w.config.series
            });
          }
        }
        if (options2 && typeof options2 === "object") {
          ch.config = new Config(options2);
          const incomingType = options2.chart && options2.chart.type;
          const isAliasRequest = incomingType === "funnel" || incomingType === "pyramid" || incomingType === "gauge";
          const wasAlias = !!w.config.chart.requestedType;
          if (incomingType && !isAliasRequest && wasAlias) {
            options2.chart = options2.chart || {};
            options2.chart.requestedType = incomingType;
            const prev = w.config.chart.requestedType;
            if (prev === "funnel" || prev === "pyramid") {
              options2.plotOptions = options2.plotOptions || {};
              options2.plotOptions.bar = options2.plotOptions.bar || {};
              if (options2.plotOptions.bar.isFunnel === void 0) {
                options2.plotOptions.bar.isFunnel = false;
              }
              if (options2.plotOptions.bar.isPyramid === void 0) {
                options2.plotOptions.bar.isPyramid = false;
              }
            }
          }
          ch.config.normalizeAliasedChartType(options2);
          options2 = CoreUtils.extendArrayProps(ch.config, options2, w);
          if (ch.w.globals.chartID !== this.w.globals.chartID) {
            delete options2.series;
            delete options2.yaxis;
          }
          w.config = Utils$1.extend(w.config, options2);
          Defaults.handOverTypeDefaults(w.config, fromType, options2);
          if (overwriteInitialConfig) {
            w.globals.lastXAxis = options2.xaxis ? Utils$1.clone(options2.xaxis) : [];
            w.globals.lastYAxis = options2.yaxis ? Utils$1.clone(options2.yaxis) : [];
            w.globals.initialConfig = Utils$1.extend({}, w.config);
            w.globals.initialSeries = w.config.series;
          }
          if (options2.series && (w.globals.collapsedSeriesIndices.length > 0 || w.globals.ancillaryCollapsedSeriesIndices.length > 0)) {
            ch.series.reconcileCollapsedByName();
          }
        }
        return ch.update(options2).then(() => {
          if (chartIndex === charts.length - 1) {
            resolve(ch);
          }
        }).catch(reject);
      });
    });
  }
  /**
   * Private method to update Series.
   *
   * @param {any[]} newSeries - New series which will override the existing
   * @param {boolean} animate
   */
  _updateSeries(newSeries, animate, overwriteInitialSeries = false) {
    return new Promise((resolve, reject) => {
      const w = this.w;
      w.globals.shouldAnimate = animate;
      w.globals.dataChanged = true;
      const prevAxisScaleSig = JSON.stringify({
        y: (w.globals.yAxisScale || []).map((s2) => s2 ? s2.result : null),
        xMin: w.globals.minX,
        xMax: w.globals.maxX
      });
      PerformanceCache.invalidateSelectors(w);
      if (animate && w.config.chart.animations.enabled) {
        this.ctx.series.getPreviousPaths();
      }
      const prevSeriesCount = w.config.series.length;
      const prevDataLengths = w.config.series.map(
        (s2) => {
          var _a, _b;
          return (_b = (_a = s2 == null ? void 0 : s2.data) == null ? void 0 : _a.length) != null ? _b : 0;
        }
      );
      if (overwriteInitialSeries) {
        w.globals.dataReducerRawSeries = null;
        w.globals.histogramRawSeries = null;
        w.globals.treemapRawSeries = null;
      }
      this.ctx.data.resetParsingFlags();
      const parsedState = this.ctx.data.parseData(newSeries);
      this.ctx._writeParsedSeriesData(parsedState.seriesData);
      this.ctx._writeParsedRangeData(parsedState.rangeData);
      this.ctx._writeParsedCandleData(parsedState.candleData);
      this.ctx._writeParsedLabelData(parsedState.labelData);
      this.ctx._writeParsedAxisFlags(parsedState.axisFlags);
      if (overwriteInitialSeries) {
        if (w.globals.initialConfig) {
          w.globals.initialConfig.series = w.config.series;
        }
        w.globals.initialSeries = w.config.series;
      }
      if (this._canUseFastPath(newSeries, prevSeriesCount, prevDataLengths, w)) {
        return this.ctx.fastUpdate(animate, prevAxisScaleSig).then(() => {
          resolve(this.ctx);
        }).catch(reject);
      }
      if (this.ctx._updateStats) this.ctx._updateStats.full++;
      return this.ctx.update().then(() => {
        resolve(this.ctx);
      }).catch(reject);
    });
  }
  /**
   * Returns true if the data-only fast path can be used for this update.
   * Fast path skips rebuilding grid, axes, legend, annotations, and tooltip DOM.
   *
   * Requirements:
   * - Chart has been fully rendered (DOM exists)
   * - Axis chart (non-axis charts like pie always need full rebuild due to radial layout)
   * - Series count unchanged (grid column/row counts depend on it)
   * - Per-series data lengths unchanged (the fast path preserves the axis DOM,
   *   and a changed point count re-slots categories/ticks: with explicit
   *   categories the axis-scale signature can still match, leaving a stale
   *   ruler under the re-slotted marks; length changes also want the full
   *   render so enter/exit and axis transitions run)
   * - No series currently collapsing (collapsed series changes visible data range)
   * - Not a combo chart (combo charts mix types and need coordinated axis recalc)
   * - Not currently zoomed (zoomed charts have altered x-labels that need recalculation)
   * @param {any[]} newSeries
   * @param {number} prevSeriesCount
   * @param {number[]} prevDataLengths
   * @param {import('../../types/internal').ChartStateW} w
   */
  _canUseFastPath(newSeries, prevSeriesCount, prevDataLengths, w) {
    if (!w.dom.elGraphical) return false;
    if (!w.globals.axisCharts) return false;
    if (newSeries.length !== prevSeriesCount) return false;
    if (newSeries.some(
      (s2, i2) => {
        var _a, _b;
        return ((_b = (_a = s2 == null ? void 0 : s2.data) == null ? void 0 : _a.length) != null ? _b : 0) !== prevDataLengths[i2];
      }
    )) {
      return false;
    }
    if (w.globals.collapsedSeries.length > 0) return false;
    if (w.globals.ancillaryCollapsedSeries.length > 0) return false;
    if (w.globals.risingSeries.length > 0) return false;
    if (w.globals.comboCharts) return false;
    if (w.interact.zoomed) return false;
    return true;
  }
  /**
   * @param {any} s
   * @param {number} i
   */
  _extendSeries(s2, i2) {
    const w = this.w;
    const ser = w.config.series[i2];
    return __spreadProps(__spreadValues(
      {},
      /** @type {Record<string,any>} */
      w.config.series[i2]
    ), {
      name: s2.name ? s2.name : (
        /** @type {any} */
        ser == null ? void 0 : ser.name
      ),
      color: s2.color ? s2.color : (
        /** @type {any} */
        ser == null ? void 0 : ser.color
      ),
      type: s2.type ? s2.type : (
        /** @type {any} */
        ser == null ? void 0 : ser.type
      ),
      group: s2.group ? s2.group : (
        /** @type {any} */
        ser == null ? void 0 : ser.group
      ),
      hidden: typeof s2.hidden !== "undefined" ? s2.hidden : (
        /** @type {any} */
        ser == null ? void 0 : ser.hidden
      ),
      data: s2.data ? s2.data : (
        /** @type {any} */
        ser == null ? void 0 : ser.data
      ),
      zIndex: typeof s2.zIndex !== "undefined" ? s2.zIndex : i2
    });
  }
  /**
   * @param {number} seriesIndex
   * @param {number} dataPointIndex
   */
  toggleDataPointSelection(seriesIndex, dataPointIndex) {
    const w = this.w;
    let elPath = null;
    const parent = `.apexcharts-series[data\\:realIndex='${seriesIndex}']`;
    if (w.globals.axisCharts) {
      elPath = w.dom.Paper.findOne(
        `${parent} path[j='${dataPointIndex}'], ${parent} circle[j='${dataPointIndex}'], ${parent} rect[j='${dataPointIndex}']`
      );
    } else {
      if (typeof dataPointIndex === "undefined") {
        elPath = w.dom.Paper.findOne(`${parent} path[j='${seriesIndex}']`);
        if (w.config.chart.type === "pie" || w.config.chart.type === "polarArea" || w.config.chart.type === "donut") {
          this.ctx.pie.pieClicked(seriesIndex);
        }
      }
    }
    if (elPath) {
      const graphics = new Graphics(this.w);
      graphics.pathMouseDown(
        elPath,
        /** @type {any} */
        null
      );
    } else {
      console.warn("toggleDataPointSelection: Element not found");
      return null;
    }
    return elPath.node ? elPath.node : null;
  }
  /**
   * @param {Record<string, any>} options
   */
  forceXAxisUpdate(options2) {
    const w = this.w;
    const minmax = ["min", "max"];
    minmax.forEach((a2) => {
      if (typeof options2.xaxis[a2] !== "undefined") {
        w.config.xaxis[a2] = options2.xaxis[a2];
        w.globals.lastXAxis[a2] = options2.xaxis[a2];
      }
    });
    if (options2.xaxis.categories && options2.xaxis.categories.length) {
      w.config.xaxis.categories = options2.xaxis.categories;
    }
    if (w.config.xaxis.convertedCatToNumeric) {
      const defaults = new Defaults(options2);
      options2 = defaults.convertCatToNumericXaxis(options2, this.ctx);
    }
    return options2;
  }
  /**
   * @param {Record<string, any>} options
   */
  forceYAxisUpdate(options2) {
    if (options2.chart && options2.chart.stacked && options2.chart.stackType === "100%") {
      if (Array.isArray(options2.yaxis)) {
        options2.yaxis.forEach(
          (yaxe, index) => {
            options2.yaxis[index].min = 0;
            options2.yaxis[index].max = 100;
          }
        );
      } else {
        options2.yaxis.min = 0;
        options2.yaxis.max = 100;
      }
    }
    return options2;
  }
  /**
   * This function reverts the yaxis and xaxis min/max values to what it was when the chart was defined.
   * This function fixes an important bug where a user might load a new series after zooming in/out of previous series which resulted in wrong min/max
   * Also, this should never be called internally on zoom/pan - the reset should only happen when user calls the updateSeries() function externally
   * The function also accepts an object {xaxis, yaxis} which when present is set as the new xaxis/yaxis
   * @param {Record<string, any>} opts
   */
  revertDefaultAxisMinMax(opts) {
    const w = this.w;
    let xaxis = w.globals.lastXAxis;
    let yaxis = w.globals.lastYAxis;
    if (opts && opts.xaxis) {
      xaxis = opts.xaxis;
    }
    if (opts && opts.yaxis) {
      yaxis = opts.yaxis;
    }
    const _xaxis = (
      /** @type {any} */
      xaxis
    );
    w.config.xaxis.min = _xaxis.min;
    w.config.xaxis.max = _xaxis.max;
    const getLastYAxis = (index) => {
      if (typeof yaxis[index] !== "undefined") {
        const _y = (
          /** @type {any} */
          yaxis[index]
        );
        w.config.yaxis[index].min = _y.min;
        w.config.yaxis[index].max = _y.max;
      }
    };
    w.config.yaxis.map((yaxe, index) => {
      if (w.interact.zoomed) {
        getLastYAxis(index);
      } else {
        if (typeof yaxis[index] !== "undefined") {
          getLastYAxis(index);
        } else {
          if (typeof this.ctx.opts.yaxis[index] !== "undefined") {
            yaxe.min = this.ctx.opts.yaxis[index].min;
            yaxe.max = this.ctx.opts.yaxis[index].max;
          }
        }
      }
    });
  }
}
class AxisMapping {
  /**
   * Pixels per data-unit on the x-axis. Derived from `minX..maxX` so it is the
   * exact inverse used by both {@link dataXToPx} and {@link pxToDataX}.
   * @param {import('../types/internal').ChartStateW} w
   * @returns {number}
   */
  static xRatio(w) {
    const gw = w.layout.gridWidth || 1;
    return (w.globals.maxX - w.globals.minX) / gw;
  }
  /**
   * Data-x -> pixels from the plot origin (usable as an SVG `x` attribute).
   * @param {import('../types/internal').ChartStateW} w
   * @param {number} dataX
   * @returns {number}
   */
  static dataXToPx(w, dataX) {
    return (dataX - w.globals.minX) / AxisMapping.xRatio(w);
  }
  /**
   * Pixels from the plot origin -> data-x. Feed it `screenX - svgLeft - translateX`.
   * @param {import('../types/internal').ChartStateW} w
   * @param {number} px
   * @returns {number}
   */
  static pxToDataX(w, px) {
    return w.globals.minX + px * AxisMapping.xRatio(w);
  }
  /**
   * Client (screen) x -> pixels from the plot origin. The origin is the svg
   * element's left edge plus `translateX`, never the `.apexcharts-grid` box
   * (fact 2 above), so the result does not depend on what the grid happens to
   * render. `svgWidth` is the unscaled width the svg was drawn at, so the ratio
   * against the measured one is the CSS zoom of any container the chart sits in.
   * @param {import('../types/internal').ChartStateW} w
   * @param {number} screenX
   * @returns {number}
   */
  static screenXToPlotPx(w, screenX) {
    const baseEl = w.dom.baseEl;
    const svg = baseEl && baseEl.querySelector(".apexcharts-svg");
    if (!svg) return screenX - w.layout.translateX;
    const svgRect = svg.getBoundingClientRect();
    const zoom = w.globals.svgWidth ? svgRect.width / w.globals.svgWidth : 1;
    return (screenX - svgRect.left) / (zoom || 1) - w.layout.translateX;
  }
}
class Utils2 {
  /**
   * @param {import('./Tooltip').default} tooltipContext
   */
  constructor(tooltipContext) {
    this.w = tooltipContext.w;
    this.ttCtx = tooltipContext;
  }
  /**
   * The element the pointer was over when a hover event fired, which is not
   * always what `e.target` says later on.
   *
   * Hover events are coalesced through a ~20ms timer (Tooltip.onSeriesHover),
   * so a good half of them are read back after they have finished propagating.
   * At that point a chart living inside a shadow root has had its target
   * retargeted to the host element, every `classList.contains('apexcharts-…')`
   * gate below fails, and the tooltip is left wherever the previous event put
   * it (#3237). `composedPath()` is no help after dispatch either: it returns
   * an empty array.
   *
   * Called while the event is still dispatching (`eventPhase` is then
   * non-zero) this remembers the real target on the event for the deferred
   * readers; called afterwards it hands that back. Outside a shadow root
   * nothing is retargeted and it is `e.target` either way.
   *
   * @param {any} e
   * @returns {any}
   */
  static hoverTarget(e2) {
    if (!e2) return null;
    if (e2.eventPhase && e2.target) {
      e2.apexHoverTarget = e2.target;
    }
    return e2.apexHoverTarget || e2.target;
  }
  /**
   ** When hovering over series, you need to capture which series is being hovered on.
   ** This function will return both capturedseries index as well as inner index of that series
   * @memberof Utils
   * @param {{ hoverArea: any, elGrid: any, clientX: any, clientY: any, context?: any }} opts
   */
  getNearestValues({ hoverArea, elGrid, clientX, clientY }) {
    var _a, _b;
    const w = this.w;
    const seriesBound = elGrid.getBoundingClientRect();
    const hoverWidth = w.layout.gridWidth;
    const hoverHeight = seriesBound.height;
    let xDivisor = hoverWidth / (w.globals.dataPoints - 1);
    const yDivisor = hoverHeight / w.globals.dataPoints;
    const hasBars = this.hasBars();
    if ((w.globals.comboCharts || hasBars) && !w.config.xaxis.convertedCatToNumeric) {
      xDivisor = hoverWidth / w.globals.dataPoints;
    }
    const hoverX = AxisMapping.screenXToPlotPx(w, clientX);
    const hoverY = clientY - seriesBound.top;
    const edgePad = w.globals.barPadForNumericAxis || 0;
    const notInRect = hoverX < -edgePad || hoverY < 0 || hoverX > hoverWidth + edgePad || hoverY > hoverHeight;
    if (notInRect) {
      hoverArea.classList.remove("hovering-zoom");
      hoverArea.classList.remove("hovering-pan");
    } else {
      if (w.interact.zoomEnabled) {
        hoverArea.classList.remove("hovering-pan");
        hoverArea.classList.add("hovering-zoom");
      } else if (w.interact.panEnabled) {
        hoverArea.classList.remove("hovering-zoom");
        hoverArea.classList.add("hovering-pan");
      }
    }
    let j = Math.round(hoverX / xDivisor);
    const jHorz = Math.floor(hoverY / yDivisor);
    if (hasBars && !w.config.xaxis.convertedCatToNumeric) {
      j = Math.ceil(hoverX / xDivisor);
      j = j - 1;
    }
    let capturedSeries = null;
    let closest = null;
    let seriesXValArr = w.globals.seriesXvalues.map(
      (seriesXVal) => {
        return seriesXVal.filter(
          (s2) => Utils$1.isNumber(s2)
        );
      }
    );
    const seriesYValArr = w.globals.seriesYvalues.map(
      (seriesYVal) => {
        return seriesYVal.filter(
          (s2) => Utils$1.isNumber(s2)
        );
      }
    );
    if (w.axisFlags.isXNumeric) {
      closest = this.closestInMultiArray(
        hoverX,
        hoverY,
        seriesXValArr,
        seriesYValArr
      );
      capturedSeries = closest.index;
      j = (_a = closest.j) != null ? _a : 0;
      if (capturedSeries !== null && w.globals.hasNullValues) {
        seriesXValArr = w.globals.seriesXvalues[capturedSeries];
        closest = this.closestInArray(hoverX, seriesXValArr);
        j = (_b = closest.j) != null ? _b : 0;
      }
    }
    w.interact.capturedSeriesIndex = capturedSeries === null ? -1 : capturedSeries;
    if (!j || j < 1) j = 0;
    if (w.globals.isBarHorizontal) {
      w.interact.capturedDataPointIndex = jHorz;
    } else {
      w.interact.capturedDataPointIndex = j;
    }
    return {
      capturedSeries,
      j: w.globals.isBarHorizontal ? jHorz : j,
      hoverX,
      hoverY
    };
  }
  /**
   * @param {any[]} Xarrays
   */
  getFirstActiveXArray(Xarrays) {
    const w = this.w;
    let activeIndex = 0;
    const firstActiveSeriesIndex = Xarrays.map(
      (xarr, index) => {
        return xarr.length > 0 ? index : -1;
      }
    );
    for (let a2 = 0; a2 < firstActiveSeriesIndex.length; a2++) {
      if (firstActiveSeriesIndex[a2] !== -1 && w.globals.collapsedSeriesIndices.indexOf(a2) === -1 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(a2) === -1) {
        activeIndex = firstActiveSeriesIndex[a2];
        break;
      }
    }
    return activeIndex;
  }
  /**
   * @param {number} hoverX
   * @param {number} hoverY
   * @param {any[]} Xarrays
   * @param {any[]} Yarrays
   */
  closestInMultiArray(hoverX, hoverY, Xarrays, Yarrays) {
    const w = this.w;
    const isActiveSeries = (seriesIndex) => {
      return w.globals.collapsedSeriesIndices.indexOf(seriesIndex) === -1 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(seriesIndex) === -1;
    };
    const chartType = w.config.chart.type;
    const isLineArea = !w.globals.comboCharts && (chartType === "line" || chartType === "area");
    let closestDist = Infinity;
    let closestSeriesIndex = null;
    let closestPointIndex = null;
    if (w.globals.allSeriesHasEqualX) {
      let bucketDistX = Infinity;
      for (let i2 = 0; i2 < Xarrays.length; i2++) {
        if (!isActiveSeries(i2)) continue;
        const xArr = Xarrays[i2];
        const yArr = Yarrays[i2];
        const len = Math.min(xArr.length, yArr.length);
        for (let j = 0; j < len; j++) {
          const distX = Math.abs(hoverX - xArr[j]);
          if (distX < bucketDistX) {
            bucketDistX = distX;
            closestPointIndex = j;
          }
        }
      }
      if (closestPointIndex !== null) {
        if (isLineArea) {
          let bestSegDist = Infinity;
          for (let i2 = 0; i2 < Xarrays.length; i2++) {
            if (!isActiveSeries(i2)) continue;
            const xArr = Xarrays[i2];
            const yArr = Yarrays[i2];
            const len = Math.min(xArr.length, yArr.length);
            if (len < 2) {
              const yVal = yArr[closestPointIndex];
              if (typeof yVal !== "number") continue;
              const d = Math.abs(hoverY - yVal);
              if (d < bestSegDist) {
                bestSegDist = d;
                closestSeriesIndex = i2;
              }
              continue;
            }
            for (let j = 0; j < len - 1; j++) {
              const seg = this._distanceToSegment(
                hoverX,
                hoverY,
                xArr[j],
                yArr[j],
                xArr[j + 1],
                yArr[j + 1]
              );
              if (seg.dist < bestSegDist) {
                bestSegDist = seg.dist;
                closestSeriesIndex = i2;
              }
            }
          }
        } else {
          let bestY = Infinity;
          for (let i2 = 0; i2 < Xarrays.length; i2++) {
            if (!isActiveSeries(i2)) continue;
            const yVal = Yarrays[i2][closestPointIndex];
            if (typeof yVal !== "number") continue;
            const distY = Math.abs(hoverY - yVal);
            if (distY < bestY) {
              bestY = distY;
              closestSeriesIndex = i2;
            }
          }
        }
      }
      return {
        index: closestSeriesIndex,
        j: closestPointIndex
      };
    }
    for (let i2 = 0; i2 < Xarrays.length; i2++) {
      if (!isActiveSeries(i2)) {
        continue;
      }
      const xArr = Xarrays[i2];
      const yArr = Yarrays[i2];
      const len = Math.min(xArr.length, yArr.length);
      if (isLineArea && len >= 2) {
        for (let j = 0; j < len - 1; j++) {
          const seg = this._distanceToSegment(
            hoverX,
            hoverY,
            xArr[j],
            yArr[j],
            xArr[j + 1],
            yArr[j + 1]
          );
          if (seg.dist < closestDist) {
            closestDist = seg.dist;
            closestSeriesIndex = i2;
            closestPointIndex = seg.t < 0.5 ? j : j + 1;
          }
        }
        continue;
      }
      for (let j = 0; j < len; j++) {
        const xVal = xArr[j];
        const distX = hoverX - xVal;
        const yVal = yArr[j];
        const distY = hoverY - yVal;
        const dist = Math.sqrt(distX * distX + distY * distY);
        if (dist < closestDist) {
          closestDist = dist;
          closestSeriesIndex = i2;
          closestPointIndex = j;
        }
      }
    }
    return {
      index: closestSeriesIndex,
      j: closestPointIndex
    };
  }
  /**
   * Perpendicular distance from point (px, py) to the line segment
   * (ax, ay) → (bx, by). Returns the distance plus the projection
   * parameter t (0 = at A, 1 = at B, clamped) so callers know which
   * endpoint the projection landed nearest.
   * @param {number} px
   * @param {number} py
   * @param {number} ax
   * @param {number} ay
   * @param {number} bx
   * @param {number} by
   * @returns {{ dist: number, t: number }}
   */
  _distanceToSegment(px, py, ax, ay, bx, by) {
    const dx = bx - ax;
    const dy = by - ay;
    const lenSq = dx * dx + dy * dy;
    let t2 = lenSq === 0 ? 0 : ((px - ax) * dx + (py - ay) * dy) / lenSq;
    if (t2 < 0) t2 = 0;
    else if (t2 > 1) t2 = 1;
    const cx = ax + t2 * dx;
    const cy = ay + t2 * dy;
    const ex = px - cx;
    const ey = py - cy;
    return { dist: Math.sqrt(ex * ex + ey * ey), t: t2 };
  }
  /**
   * @param {number} val
   * @param {any[]} arr
   */
  closestInArray(val, arr) {
    const curr = arr[0];
    let currIndex = null;
    let diff = Math.abs(val - curr);
    for (let i2 = 0; i2 < arr.length; i2++) {
      const newdiff = Math.abs(val - arr[i2]);
      if (newdiff < diff) {
        diff = newdiff;
        currIndex = i2;
      }
    }
    return {
      j: currIndex
    };
  }
  /**
   * When there are multiple series, it is possible to have different x values for each series.
   * But it may be possible in those multiple series, that there is same x value for 2 or more
   * series.
   * @memberof Utils
   * @param {number} j - the inner index of series (series[i][j])
   * @return {boolean}
   */
  isXoverlap(j) {
    const w = this.w;
    const xSameForAllSeriesJArr = [];
    const seriesX = w.seriesData.seriesX.filter(
      (s2) => typeof s2[0] !== "undefined"
    );
    if (seriesX.length > 0) {
      for (let i2 = 0; i2 < seriesX.length - 1; i2++) {
        if (typeof seriesX[i2][j] !== "undefined" && typeof seriesX[i2 + 1][j] !== "undefined") {
          if (seriesX[i2][j] !== seriesX[i2 + 1][j]) {
            xSameForAllSeriesJArr.push("unEqual");
          }
        }
      }
    }
    if (xSameForAllSeriesJArr.length === 0) {
      return true;
    }
    return false;
  }
  isInitialSeriesSameLen() {
    var _a, _b, _c, _d;
    let sameLen = true;
    const initialSeries = (
      /** @type {any[]} */
      ((_b = (_a = this.w.globals._initialSeriesPeek) != null ? _a : this.w.globals.initialSeries) == null ? void 0 : _b.filter(
        /**
         * @param {Record<string, any>} s
         * @param {number} i
         */
        (s2, i2) => {
          var _a2;
          return !((_a2 = this.w.globals.collapsedSeriesIndices) == null ? void 0 : _a2.includes(i2));
        }
      )) || []
    );
    for (let i2 = 0; i2 < initialSeries.length - 1; i2++) {
      if (!((_c = initialSeries[i2]) == null ? void 0 : _c.data) || !((_d = initialSeries[i2 + 1]) == null ? void 0 : _d.data)) return true;
      if (initialSeries[i2].data.length !== initialSeries[i2 + 1].data.length) {
        sameLen = false;
        break;
      }
    }
    return sameLen;
  }
  /**
   * @param {any[]} allbars
   */
  getBarsHeight(allbars) {
    const bars = [...allbars];
    const totalHeight = bars.reduce((acc, bar) => acc + bar.getBBox().height, 0);
    return totalHeight;
  }
  /**
   * @param {number} capturedSeries
   */
  getElMarkers(capturedSeries) {
    if (typeof capturedSeries == "number") {
      return this.w.dom.baseEl.querySelectorAll(
        `.apexcharts-series[data\\:realIndex='${capturedSeries}'] .apexcharts-series-markers-wrap > *`
      );
    }
    return this.w.dom.baseEl.querySelectorAll(
      ".apexcharts-series-markers-wrap > *"
    );
  }
  getAllMarkers(filterCollapsed = false) {
    let markersWraps = (
      /** @type {any[]} */
      [
        ...this.w.dom.baseEl.querySelectorAll(".apexcharts-series-markers-wrap")
      ]
    );
    if (filterCollapsed) {
      markersWraps = markersWraps.filter((m) => {
        const realIndex = Number(m.getAttribute("data:realIndex"));
        return this.w.globals.collapsedSeriesIndices.indexOf(realIndex) === -1;
      });
    }
    markersWraps.sort((a2, b) => {
      var indexA = Number(a2.getAttribute("data:realIndex"));
      var indexB = Number(b.getAttribute("data:realIndex"));
      return indexB < indexA ? 1 : indexB > indexA ? -1 : 0;
    });
    const markers = [];
    markersWraps.forEach((m) => {
      markers.push(m.querySelector(".apexcharts-marker"));
    });
    return markers;
  }
  /**
   * @param {number} capturedSeries
   */
  hasMarkers(capturedSeries) {
    const markers = this.getElMarkers(capturedSeries);
    return markers.length > 0;
  }
  /**
   * @param {any} point
   * @param {number} size
   */
  getPathFromPoint(point, size) {
    const cx = Number(point.getAttribute("cx"));
    const cy = Number(point.getAttribute("cy"));
    const shape = point.getAttribute("shape");
    return new Graphics(this.w).getMarkerPath(cx, cy, shape, size);
  }
  getElBars() {
    return this.w.dom.baseEl.querySelectorAll(
      ".apexcharts-bar-series,  .apexcharts-candlestick-series, .apexcharts-boxPlot-series, .apexcharts-violin-series, .apexcharts-rangebar-series"
    );
  }
  hasBars() {
    const bars = this.getElBars();
    return bars.length > 0;
  }
  /**
   * @param {number} index
   */
  getHoverMarkerSize(index) {
    const w = this.w;
    let hoverSize = w.config.markers.hover.size;
    if (hoverSize === void 0) {
      hoverSize = w.globals.markers.size[index] + w.config.markers.hover.sizeOffset;
    }
    return hoverSize;
  }
  /**
   * @param {string} state
   */
  toggleAllTooltipSeriesGroups(state) {
    const w = this.w;
    const ttCtx = this.ttCtx;
    if (ttCtx.allTooltipSeriesGroups.length === 0) {
      ttCtx.allTooltipSeriesGroups = w.dom.baseEl.querySelectorAll(
        ".apexcharts-tooltip-series-group"
      );
    }
    const allTooltipSeriesGroups = ttCtx.allTooltipSeriesGroups;
    for (let i2 = 0; i2 < allTooltipSeriesGroups.length; i2++) {
      if (state === "enable") {
        allTooltipSeriesGroups[i2].classList.add("apexcharts-active");
        allTooltipSeriesGroups[i2].style.display = w.config.tooltip.items.display;
      } else {
        allTooltipSeriesGroups[i2].classList.remove("apexcharts-active");
        allTooltipSeriesGroups[i2].style.display = "none";
      }
    }
  }
}
class Labels {
  /**
   * @param {import('./Tooltip').default} tooltipContext
   */
  constructor(tooltipContext) {
    this.w = tooltipContext.w;
    this.ttCtx = tooltipContext;
    this.tooltipUtil = new Utils2(tooltipContext);
  }
  /** @param {{ shared?: boolean, ttItems?: any, i?: number, j?: any, y1?: any, y2?: any, e?: any }} opts */
  drawSeriesTexts({ shared = true, ttItems, i: i2 = 0, j = null, y1, y2, e: e2 }) {
    const w = this.w;
    if (w.config.tooltip.custom !== void 0) {
      this.handleCustomTooltip({ i: i2, j, y1, y2, w });
    } else {
      this.toggleActiveInactiveSeries(shared, i2);
    }
    const values = this.getValuesToPrint({
      i: i2,
      j
    });
    this.printLabels({
      i: i2,
      j,
      values,
      ttItems,
      shared,
      e: e2
    });
    const tooltipEl = this.ttCtx.getElTooltip();
    if (tooltipEl) {
      this.ttCtx.tooltipRect.ttWidth = tooltipEl.getBoundingClientRect().width;
      this.ttCtx.tooltipRect.ttHeight = tooltipEl.getBoundingClientRect().height;
    }
  }
  /** @param {{i: any, j: any, values: any, ttItems: any, shared: any, e: any}} opts */
  printLabels({ i: i2, j, values, ttItems, shared, e: e2 }) {
    const w = this.w;
    const { xVal, zVal, xAxisTTVal } = values;
    const seriesLen = w.seriesData.series.length;
    const basePColor = j !== null && w.config.plotOptions.bar.distributed ? w.globals.colors[j] : w.globals.colors[i2];
    for (let t2 = 0; t2 < seriesLen; t2++) {
      const tIndex = w.config.tooltip.inverseOrder ? seriesLen - 1 - t2 : t2;
      const row = this.computeSeriesRow({
        i: i2,
        j,
        t: t2,
        tIndex,
        shared,
        e: e2,
        basePColor
      });
      this.DOMHandling({
        i: i2,
        t: tIndex,
        j,
        ttItems,
        values: {
          val: row.val,
          goalVals: row.goalVals,
          xVal,
          xAxisTTVal,
          zVal
        },
        seriesName: row.seriesName,
        shared,
        pColor: row.pColor
      });
    }
  }
  /**
   * Compute the per-series row values (seriesName, val, goalVals, pColor)
   * for one iteration of the tooltip's series loop. Extracted from
   * printLabels() to keep the outer loop scannable.
   * @param {{i: number, j: any, t: number, tIndex: number, shared: boolean, e: any, basePColor: string}} opts
   */
  computeSeriesRow({ i: i2, j, tIndex, shared, e: e2, basePColor }) {
    const w = this.w;
    let f = this.getFormatters(i2);
    let pColor = basePColor;
    let val;
    let goalVals = (
      /** @type {any[]} */
      []
    );
    let seriesName = w.config.chart.type === "treemap" ? f.yLbTitleFormatter(
      String(
        /** @type {any} */
        w.config.series[i2].data[j].x
      ),
      {
        series: w.seriesData.series,
        seriesIndex: i2,
        dataPointIndex: j,
        w
      }
    ) : this.getSeriesName({
      fn: f.yLbTitleFormatter,
      index: i2,
      seriesIndex: i2,
      j
    });
    if (w.globals.axisCharts) {
      if (shared) {
        f = this.getFormatters(tIndex);
        seriesName = this.getSeriesName({
          fn: f.yLbTitleFormatter,
          index: tIndex,
          seriesIndex: i2,
          j
        });
        pColor = w.globals.colors[tIndex];
        val = this.formatYValue(f, tIndex, j);
        goalVals = this.formatGoalVals(f, tIndex, j);
      } else {
        pColor = this.resolvePatternColor(e2, pColor);
        val = this.formatYValue(f, i2, j);
        goalVals = this.formatGoalVals(f, i2, j);
      }
    }
    if (j === null) {
      val = f.yLbFormatter(w.seriesData.series[i2], __spreadProps(__spreadValues({}, w), {
        seriesIndex: i2,
        dataPointIndex: i2
      }));
    }
    return { seriesName, val, goalVals, pColor };
  }
  /**
   * Run the y-value formatter for a given (seriesIndex, dataPointIndex),
   * handling the range-data case (start - end concatenation).
   * @param {{yLbFormatter: Function}} f
   * @param {number} index
   * @param {any} j
   */
  formatYValue(f, index, j) {
    var _a, _b, _c, _d;
    const w = this.w;
    if (w.axisFlags.isRangeData) {
      return f.yLbFormatter((_b = (_a = w.rangeData.seriesRangeStart) == null ? void 0 : _a[index]) == null ? void 0 : _b[j], {
        series: w.rangeData.seriesRangeStart,
        seriesIndex: index,
        dataPointIndex: j,
        w
      }) + " - " + f.yLbFormatter((_d = (_c = w.rangeData.seriesRangeEnd) == null ? void 0 : _c[index]) == null ? void 0 : _d[j], {
        series: w.rangeData.seriesRangeEnd,
        seriesIndex: index,
        dataPointIndex: j,
        w
      });
    }
    return f.yLbFormatter(w.seriesData.series[index][j], {
      series: w.seriesData.series,
      seriesIndex: index,
      dataPointIndex: j,
      w
    });
  }
  /**
   * Format the goal-line values attached to a given (seriesIndex, dataPointIndex).
   * Returns an empty array when no goals exist.
   * @param {{yLbFormatter: Function}} f
   * @param {number} index
   * @param {any} j
   */
  formatGoalVals(f, index, j) {
    var _a;
    const w = this.w;
    const goals = (_a = w.seriesData.seriesGoals[index]) == null ? void 0 : _a[j];
    if (!Array.isArray(goals)) return [];
    return goals.map((goal) => ({
      attrs: goal,
      val: f.yLbFormatter(goal.value, {
        seriesIndex: index,
        dataPointIndex: j,
        w
      })
    }));
  }
  /**
   * When the hovered element has a pattern fill (url(#…Pattern…)), reach
   * into the pattern's first child to pull a stroke color. Otherwise
   * return the raw fill attribute or the fallback.
   * @param {any} e
   * @param {string} fallback
   */
  resolvePatternColor(e2, fallback) {
    var _a, _b, _c, _d;
    const w = this.w;
    const targetFill = (_b = (_a = Utils2.hoverTarget(e2)) == null ? void 0 : _a.getAttribute) == null ? void 0 : _b.call(_a, "fill");
    if (!targetFill) return fallback;
    if (targetFill.indexOf("url") === -1) return targetFill;
    if (targetFill.indexOf("Pattern") === -1) return fallback;
    const patternEl = w.dom.baseEl.querySelector(
      targetFill.substr(4).slice(0, -1)
    );
    return (_d = (_c = patternEl == null ? void 0 : patternEl.childNodes[0]) == null ? void 0 : _c.getAttribute("stroke")) != null ? _d : fallback;
  }
  /**
   * @param {number} i
   */
  getFormatters(i2) {
    const w = this.w;
    let yLbFormatter = w.formatters.yLabelFormatters[i2];
    let yLbTitleFormatter;
    if (w.formatters.ttVal !== void 0) {
      if (Array.isArray(w.formatters.ttVal)) {
        yLbFormatter = /** @type {any} */
        w.formatters.ttVal[i2] && /** @type {any} */
        w.formatters.ttVal[i2].formatter;
        yLbTitleFormatter = /** @type {any} */
        w.formatters.ttVal[i2] && /** @type {any} */
        w.formatters.ttVal[i2].title && /** @type {any} */
        w.formatters.ttVal[i2].title.formatter;
      } else {
        yLbFormatter = /** @type {any} */
        w.formatters.ttVal.formatter;
        if (typeof /** @type {any} */
        w.formatters.ttVal.title.formatter === "function") {
          yLbTitleFormatter = /** @type {any} */
          w.formatters.ttVal.title.formatter;
        }
      }
    } else {
      yLbTitleFormatter = w.config.tooltip.y.title.formatter;
    }
    if (typeof yLbFormatter !== "function") {
      if (w.formatters.yLabelFormatters[0]) {
        yLbFormatter = w.formatters.yLabelFormatters[0];
      } else {
        yLbFormatter = function(label) {
          return label;
        };
      }
    }
    if (typeof yLbTitleFormatter !== "function") {
      yLbTitleFormatter = function(label) {
        return label ? label + ": " : "";
      };
    }
    return {
      yLbFormatter,
      yLbTitleFormatter
    };
  }
  /** @param {{fn: any, index: any, seriesIndex: any, j: any}} opts */
  getSeriesName({ fn, index, seriesIndex, j }) {
    const w = this.w;
    return fn(String(w.seriesData.seriesNames[index]), {
      series: w.seriesData.series,
      seriesIndex,
      dataPointIndex: j,
      w
    });
  }
  /** @param {{ t?: any, j?: any, i?: any, ttItems?: any, values?: any, seriesName?: any, shared?: any, pColor?: any }} opts */
  DOMHandling({ t: t2, j, ttItems, values, seriesName, shared, pColor }) {
    const w = this.w;
    const ttCtx = this.ttCtx;
    const { val, goalVals, xVal, xAxisTTVal, zVal } = values;
    if (!ttItems || !ttItems[t2]) return;
    let ttItemsChildren = null;
    ttItemsChildren = ttItems[t2].children;
    if (w.config.tooltip.fillSeriesColor) {
      ttItems[t2].style.backgroundColor = pColor;
      ttItemsChildren[0].style.display = "none";
    }
    if (ttCtx.showTooltipTitle) {
      if (ttCtx.tooltipTitle === null) {
        ttCtx.tooltipTitle = w.dom.baseEl.querySelector(
          ".apexcharts-tooltip-title"
        );
      }
      if (ttCtx.tooltipTitle) {
        ttCtx.tooltipTitle.innerHTML = xVal;
      }
    }
    if (ttCtx.isXAxisTooltipEnabled) {
      if (ttCtx.xaxisTooltipText) {
        ttCtx.xaxisTooltipText.innerHTML = xAxisTTVal !== "" ? xAxisTTVal : xVal;
      }
    }
    const ttYLabel = ttItems[t2].querySelector(
      ".apexcharts-tooltip-text-y-label"
    );
    if (ttYLabel) {
      ttYLabel.innerHTML = seriesName ? seriesName : "";
    }
    const ttYVal = ttItems[t2].querySelector(".apexcharts-tooltip-text-y-value");
    if (ttYVal) {
      ttYVal.innerHTML = typeof val !== "undefined" ? val : "";
    }
    if (ttItemsChildren[0] && ttItemsChildren[0].classList.contains("apexcharts-tooltip-marker")) {
      if (w.config.tooltip.marker.fillColors && Array.isArray(w.config.tooltip.marker.fillColors)) {
        pColor = w.config.tooltip.marker.fillColors[t2];
      }
      if (w.config.tooltip.fillSeriesColor) {
        ttItemsChildren[0].style.backgroundColor = pColor;
      } else {
        ttItemsChildren[0].style.color = pColor;
      }
    }
    if (!w.config.tooltip.marker.show) {
      ttItemsChildren[0].style.display = "none";
    }
    const ttGLabel = ttItems[t2].querySelector(
      ".apexcharts-tooltip-text-goals-label"
    );
    const ttGVal = ttItems[t2].querySelector(
      ".apexcharts-tooltip-text-goals-value"
    );
    if (goalVals.length && w.seriesData.seriesGoals[t2]) {
      const createGoalsHtml = () => {
        let gLabels = "<div>";
        let gVals = "<div>";
        goalVals.forEach((goal) => {
          gLabels += ` <div style="display: flex"><span class="apexcharts-tooltip-marker" style="background-color: ${goal.attrs.strokeColor}; height: 3px; border-radius: 0; top: 5px;"></span> ${goal.attrs.name}</div>`;
          gVals += `<div>${goal.val}</div>`;
        });
        ttGLabel.innerHTML = gLabels + `</div>`;
        ttGVal.innerHTML = gVals + `</div>`;
      };
      if (shared) {
        if (w.seriesData.seriesGoals[t2][j] && Array.isArray(w.seriesData.seriesGoals[t2][j])) {
          createGoalsHtml();
        } else {
          ttGLabel.innerHTML = "";
          ttGVal.innerHTML = "";
        }
      } else {
        createGoalsHtml();
      }
    } else {
      ttGLabel.innerHTML = "";
      ttGVal.innerHTML = "";
    }
    if (zVal !== null) {
      const ttZLabel = ttItems[t2].querySelector(
        ".apexcharts-tooltip-text-z-label"
      );
      ttZLabel.innerHTML = w.config.tooltip.z.title;
      const ttZVal = ttItems[t2].querySelector(
        ".apexcharts-tooltip-text-z-value"
      );
      ttZVal.innerHTML = typeof zVal !== "undefined" ? zVal : "";
    }
    if (shared && ttItemsChildren[0]) {
      if (w.config.tooltip.hideEmptySeries) {
        const ttItemMarker = ttItems[t2].querySelector(
          ".apexcharts-tooltip-marker"
        );
        const ttItemText = ttItems[t2].querySelector(".apexcharts-tooltip-text");
        if (parseFloat(val) == 0) {
          ttItemMarker.style.display = "none";
          ttItemText.style.display = "none";
        } else {
          ttItemMarker.style.display = "block";
          ttItemText.style.display = "block";
        }
      }
      if (typeof val === "undefined" || val === null || w.globals.ancillaryCollapsedSeriesIndices.indexOf(t2) > -1 || w.globals.collapsedSeriesIndices.indexOf(t2) > -1 || Array.isArray(ttCtx.tConfig.enabledOnSeries) && ttCtx.tConfig.enabledOnSeries.indexOf(t2) === -1) {
        ttItemsChildren[0].parentNode.style.display = "none";
      } else {
        ttItemsChildren[0].parentNode.style.display = w.config.tooltip.items.display;
      }
    } else {
      if (Array.isArray(ttCtx.tConfig.enabledOnSeries) && ttCtx.tConfig.enabledOnSeries.indexOf(t2) === -1) {
        ttItemsChildren[0].parentNode.style.display = "none";
      }
    }
  }
  /**
   * @param {boolean} shared
   * @param {number} i
   */
  toggleActiveInactiveSeries(shared, i2) {
    const w = this.w;
    if (shared) {
      this.tooltipUtil.toggleAllTooltipSeriesGroups("enable");
    } else {
      this.tooltipUtil.toggleAllTooltipSeriesGroups("disable");
      const firstTooltipSeriesGroup = w.dom.baseEl.querySelector(
        `.apexcharts-tooltip-series-group-${i2}`
      );
      if (firstTooltipSeriesGroup) {
        const ftsGroup = (
          /** @type {HTMLElement} */
          firstTooltipSeriesGroup
        );
        ftsGroup.classList.add("apexcharts-active");
        ftsGroup.style.display = w.config.tooltip.items.display;
      }
    }
  }
  /** @param {{i: any, j: any}} opts */
  getValuesToPrint({ i: i2, j }) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    const w = this.w;
    const filteredSeriesX = w.seriesData.seriesX.map(
      (ser) => ser.length > 0 ? ser : []
    );
    let xVal = "";
    let xAxisTTVal = "";
    let zVal = null;
    let val = null;
    const customFormatterOpts = {
      series: w.seriesData.series,
      seriesIndex: i2,
      dataPointIndex: j,
      w
    };
    const zFormatter = w.formatters.ttZFormatter;
    if (j === null) {
      val = w.seriesData.series[i2];
    } else {
      if (w.axisFlags.isXNumeric && w.config.chart.type !== "treemap") {
        xVal = filteredSeriesX[i2][j];
        if (filteredSeriesX[i2].length === 0) {
          const firstActiveSeriesIndex = this.tooltipUtil.getFirstActiveXArray(filteredSeriesX);
          xVal = filteredSeriesX[firstActiveSeriesIndex][j];
        }
      } else {
        const dataFormat = new Data(this.w);
        if (dataFormat.isFormatXY()) {
          xVal = typeof /** @type {any} */
          w.config.series[i2].data[j] !== "undefined" ? (
            /** @type {any} */
            w.config.series[i2].data[j].x
          ) : "";
        } else {
          xVal = typeof w.labelData.labels[j] !== "undefined" ? w.labelData.labels[j] : "";
        }
      }
    }
    const bufferXVal = xVal;
    if (w.axisFlags.isXNumeric && w.config.xaxis.type === "datetime") {
      const xFormat = new Formatters(this.w);
      xVal = xFormat.xLabelFormat(
        /** @type {Function} */
        w.formatters.ttKeyFormatter,
        bufferXVal,
        bufferXVal,
        {
          i: void 0,
          dateFormatter: new DateTime(this.w).formatDate,
          w: this.w
        }
      );
    } else {
      if (w.globals.isBarHorizontal) {
        xVal = w.formatters.yLabelFormatters[0](bufferXVal, customFormatterOpts);
      } else {
        xVal = (_c = (_b = (_a = w.formatters).xLabelFormatter) == null ? void 0 : _b.call(_a, bufferXVal, customFormatterOpts)) != null ? _c : bufferXVal;
      }
    }
    if (w.config.tooltip.x.formatter !== void 0) {
      xVal = (_f = (_e = (_d = w.formatters).ttKeyFormatter) == null ? void 0 : _e.call(_d, bufferXVal, customFormatterOpts)) != null ? _f : bufferXVal;
    }
    if (w.seriesData.seriesZ.length > 0 && w.seriesData.seriesZ[i2].length > 0) {
      zVal = zFormatter == null ? void 0 : zFormatter(w.seriesData.seriesZ[i2][j], w);
    }
    if (typeof w.config.xaxis.tooltip.formatter === "function") {
      xAxisTTVal = (_h = (_g = w.formatters).xaxisTooltipFormatter) == null ? void 0 : _h.call(
        _g,
        bufferXVal,
        customFormatterOpts
      );
    } else {
      xAxisTTVal = xVal;
    }
    return {
      val: Array.isArray(val) ? val.join(" ") : val,
      xVal: Array.isArray(xVal) ? xVal.join(" ") : xVal,
      xAxisTTVal: Array.isArray(xAxisTTVal) ? xAxisTTVal.join(" ") : xAxisTTVal,
      zVal
    };
  }
  /** @param {{i: any, j: any, y1: any, y2: any, w: any}} opts */
  handleCustomTooltip({ i: i2, j, y1, y2, w }) {
    const tooltipEl = this.ttCtx.getElTooltip();
    let fn = w.config.tooltip.custom;
    if (Array.isArray(fn)) {
      fn = fn[i2];
    }
    if (typeof fn !== "function") return;
    const customTooltip = fn({
      series: w.seriesData.series,
      seriesIndex: i2,
      dataPointIndex: j,
      y1,
      y2,
      w
    });
    if (tooltipEl) {
      const arrowEl = tooltipEl.querySelector(".apexcharts-tooltip-arrow");
      if (typeof customTooltip === "string" || typeof customTooltip === "number") {
        tooltipEl.innerHTML = String(customTooltip);
      } else if (customTooltip != null && (customTooltip instanceof Element || typeof customTooltip.nodeName === "string")) {
        tooltipEl.innerHTML = "";
        tooltipEl.appendChild(customTooltip.cloneNode(true));
      }
      if (arrowEl) tooltipEl.appendChild(arrowEl);
    }
  }
}
const ARROW_TIP_OVERHANG = 7;
const POINT_TIP_GAP = 0;
class Position {
  /**
   * @param {import('./Tooltip').default} tooltipContext
   */
  constructor(tooltipContext) {
    this.ttCtx = tooltipContext;
    this.w = tooltipContext.w;
  }
  /**
   * This will move the crosshair (the vertical/horz line that moves along with mouse)
   * Along with this, this function also calls the xaxisMove function
   * @memberof Position
   * @param {number} cx - point's x position, wherever point's x is, you need to move crosshair
   * @param {number | null} [j]
   */
  moveXCrosshairs(cx, j = null) {
    const ttCtx = this.ttCtx;
    const w = this.w;
    const xcrosshairs = ttCtx.getElXCrosshairs();
    let x = cx - ttCtx.xcrosshairsWidth / 2;
    const tickAmount = w.labelData.labels.slice().length;
    if (j !== null) {
      x = w.layout.gridWidth / tickAmount * j;
    }
    if (xcrosshairs !== null && !w.globals.isBarHorizontal) {
      xcrosshairs.setAttribute("x", String(x));
      xcrosshairs.setAttribute("x1", String(x));
      xcrosshairs.setAttribute("x2", String(x));
      xcrosshairs.setAttribute("y2", String(w.layout.gridHeight));
      xcrosshairs.classList.add("apexcharts-active");
    }
    if (x < 0) {
      x = 0;
    }
    if (x > w.layout.gridWidth) {
      x = w.layout.gridWidth;
    }
    if (ttCtx.isXAxisTooltipEnabled) {
      let tx = x;
      if (w.config.xaxis.crosshairs.width === "tickWidth" || w.config.xaxis.crosshairs.width === "barWidth") {
        tx = x + ttCtx.xcrosshairsWidth / 2;
      }
      this.moveXAxisTooltip(tx);
    }
  }
  /**
   * This will move the crosshair (the vertical/horz line that moves along with mouse)
   * Along with this, this function also calls the xaxisMove function
   * @memberof Position
   * @param {number} cy - point's y position, wherever point's y is, you need to move crosshair
   */
  moveYCrosshairs(cy) {
    const ttCtx = this.ttCtx;
    if (ttCtx.ycrosshairs !== null) {
      Graphics.setAttrs(ttCtx.ycrosshairs, {
        y1: cy,
        y2: cy
      });
    }
    if (ttCtx.ycrosshairsHidden !== null) {
      Graphics.setAttrs(ttCtx.ycrosshairsHidden, {
        y1: cy,
        y2: cy
      });
    }
  }
  /**
   ** AxisTooltip is the small rectangle which appears on x axis with x value, when user moves
   * @memberof Position
   * @param {number} cx - point's x position, wherever point's x is, you need to move
   */
  moveXAxisTooltip(cx) {
    var _a, _b;
    const w = this.w;
    const ttCtx = this.ttCtx;
    if (ttCtx.xaxisTooltip !== null && ttCtx.xcrosshairsWidth !== 0) {
      ttCtx.xaxisTooltip.classList.add("apexcharts-active");
      const cy = ttCtx.xaxisOffY + w.config.xaxis.tooltip.offsetY + w.layout.translateY + 5 + w.config.xaxis.offsetY;
      const xaxisTTText = ttCtx.xaxisTooltip.getBoundingClientRect();
      const xaxisTTTextWidth = xaxisTTText.width;
      cx = cx - xaxisTTTextWidth / 2;
      if (!isNaN(cx)) {
        cx = cx + w.layout.translateX;
        const graphics = new Graphics(this.w);
        const textRect = graphics.getTextRects(
          (_b = (_a = ttCtx.xaxisTooltipText) == null ? void 0 : _a.innerHTML) != null ? _b : "",
          w.config.xaxis.labels.style.fontSize
        );
        if (ttCtx.xaxisTooltipText) {
          ttCtx.xaxisTooltipText.style.minWidth = textRect.width + "px";
        }
        ttCtx.xaxisTooltip.style.left = cx + "px";
        ttCtx.xaxisTooltip.style.top = cy + "px";
      }
    }
  }
  /**
   * @param {number} index
   */
  moveYAxisTooltip(index) {
    var _a, _b;
    const w = this.w;
    const ttCtx = this.ttCtx;
    if (ttCtx.yaxisTTEls === null) {
      ttCtx.yaxisTTEls = /** @type {any[]} */
      [
        ...w.dom.baseEl.querySelectorAll(".apexcharts-yaxistooltip")
      ];
    }
    const ycrosshairsHiddenRectY1 = parseInt(
      (_b = (_a = ttCtx.ycrosshairsHidden) == null ? void 0 : _a.getAttribute("y1")) != null ? _b : "0",
      10
    );
    let cy = w.layout.translateY + ycrosshairsHiddenRectY1;
    if (ttCtx.yaxisTTEls) {
      const yAxisTTRect = ttCtx.yaxisTTEls[index].getBoundingClientRect();
      const yAxisTTHeight = yAxisTTRect.height;
      let cx;
      const labelsGroup = (
        /** @type {SVGGElement | null} */
        w.dom.baseEl.querySelector(
          `.apexcharts-yaxis[rel='${index}'] .apexcharts-yaxis-texts-g`
        )
      );
      const elWrapRect = w.dom.elWrap.getBoundingClientRect();
      if (labelsGroup) {
        const lr = labelsGroup.getBoundingClientRect();
        if (lr.width > 0) {
          const labelsCenterInElWrap = lr.left + lr.width / 2 - elWrapRect.left;
          cx = labelsCenterInElWrap - yAxisTTRect.width / 2;
        }
      }
      if (cx == null) {
        const GAP = 4;
        cx = w.config.yaxis[index].opposite ? w.globals.translateYAxisX[index] + GAP : w.globals.translateYAxisX[index] - yAxisTTRect.width - GAP;
      }
      cy = cy - yAxisTTHeight / 2;
      if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1 && cy > 0 && cy < w.layout.gridHeight) {
        ttCtx.yaxisTTEls[index].classList.add("apexcharts-active");
        ttCtx.yaxisTTEls[index].style.top = cy + "px";
        ttCtx.yaxisTTEls[index].style.left = cx + w.config.yaxis[index].tooltip.offsetX + "px";
      } else {
        ttCtx.yaxisTTEls[index].classList.remove("apexcharts-active");
      }
    }
  }
  /**
   ** moves the whole tooltip by changing x, y attrs
   * @memberof Position
   * @param {number} cx - point's x position, wherever point's x is, you need to move tooltip
   * @param {number} cy - point's y position, wherever point's y is, you need to move tooltip
   * @param {number | null} [markerSize] - point's size
   */
  moveTooltip(cx, cy, markerSize = null) {
    const ttCtx = this.ttCtx;
    const tooltipEl = ttCtx.getElTooltip();
    if (!tooltipEl) return;
    const pos = this.computeTooltipPosition(cx, cy, markerSize);
    if (pos === null) return;
    this.applyTooltipPosition(tooltipEl, pos);
  }
  /**
   * Pure-ish (reads from `this.ttCtx` + `this.w` but performs no DOM writes)
   * computation of the tooltip box position, edge placement (for arrow),
   * and arrow vertical offset. Returns null when inputs are not numeric.
   *
   * @param {number} cx
   * @param {number} cy
   * @param {number | null} [markerSize]
   * @returns {{ x: number, y: number, placement: 'left'|'right', arrowY: number|null } | null}
   */
  computeTooltipPosition(cx, cy, markerSize = null) {
    var _a, _b, _c, _d, _e, _f, _g;
    const w = this.w;
    const ttCtx = this.ttCtx;
    const tooltipRect = ttCtx.tooltipRect;
    const arrowEnabled = !!w.config.tooltip.arrow;
    const pointSize = markerSize !== null ? parseFloat(String(markerSize)) : 1;
    const ttH = tooltipRect.ttHeight || 0;
    const ttW = tooltipRect.ttWidth || 0;
    const cxNum = parseFloat(String(cx));
    const cyNum = parseFloat(String(cy));
    if (isNaN(cxNum) || isNaN(cyNum)) return null;
    const clearance = pointSize + (arrowEnabled ? ARROW_TIP_OVERHANG : 0) + POINT_TIP_GAP;
    let x = cxNum + clearance;
    const pointY = cyNum + w.layout.translateY;
    let y = arrowEnabled ? pointY - ttH / 2 + pointSize / 2 : cyNum + pointSize / 2;
    let placement = "right";
    if (x > w.layout.gridWidth / 2) {
      x = cxNum - ttW - clearance;
      placement = "left";
    }
    if (x > w.layout.gridWidth - ttW - 10) {
      x = placement === "left" ? Math.min(w.layout.gridWidth - ttW, x) : w.layout.gridWidth - ttW;
    }
    if (x < -20) {
      x = -20;
    }
    if (w.config.tooltip.followCursor) {
      const elGrid = ttCtx.getElGrid();
      if (!elGrid) return null;
      const seriesBound = elGrid.getBoundingClientRect();
      x = ttCtx.e.clientX - seriesBound.left;
      if (x > w.layout.gridWidth / 2) {
        x = x - ttW;
        placement = "left";
      } else {
        placement = "right";
      }
      y = ttCtx.e.clientY + w.layout.translateY - seriesBound.top;
      if (y > w.layout.gridHeight / 2) {
        y = y - ttH;
      }
    } else {
      if (!w.globals.isBarHorizontal) {
        if (arrowEnabled) {
          const gridTop = w.layout.translateY;
          const gridBottom = w.layout.translateY + w.layout.gridHeight;
          if (y + ttH > gridBottom) {
            y = gridBottom - ttH;
          }
          if (y < gridTop) {
            y = gridTop;
          }
        } else {
          if (ttH / 2 + y > w.layout.gridHeight) {
            y = w.layout.gridHeight - ttH + w.layout.translateY;
          }
        }
      }
    }
    if (isNaN(x)) return null;
    x = x + w.layout.translateX;
    const a11y = (_b = (_a = w.config) == null ? void 0 : _a.chart) == null ? void 0 : _b.accessibility;
    if ((a11y == null ? void 0 : a11y.enabled) && ((_d = (_c = a11y == null ? void 0 : a11y.keyboard) == null ? void 0 : _c.navigation) == null ? void 0 : _d.enabled) && ((_g = (_f = (_e = w.dom) == null ? void 0 : _e.baseEl) == null ? void 0 : _f.querySelector) == null ? void 0 : _g.call(_f, ".apexcharts-keyboard-focused"))) {
      const refPointY = arrowEnabled ? pointY : cyNum;
      const margin = (pointSize || 1) + 12;
      const tooltipTop = y;
      const tooltipBottom = y + ttH;
      if (!isNaN(refPointY) && ttH > 0 && tooltipTop < refPointY + margin && tooltipBottom > refPointY - margin) {
        y = refPointY - ttH - margin;
        if (y < 0) {
          y = refPointY + margin;
        }
      }
    }
    let arrowY = null;
    if (arrowEnabled && ttH > 0) {
      const localY = pointY - y;
      const minArrowY = 10;
      const maxArrowY = ttH - 10;
      arrowY = Math.max(minArrowY, Math.min(maxArrowY, localY));
    }
    return { x, y, placement, arrowY };
  }
  /**
   * Single DOM-writer used by every positioning path on the main tooltip.
   * Replaces the duplicated `style.left/top` writes that previously lived
   * in Position.moveTooltip, Tooltip.drawFixedTooltipRect, and Intersect.
   *
   * @param {HTMLElement} tooltipEl
   * @param {{
   *   x: number,
   *   y: number,
   *   placement?: 'left'|'right'|'top'|'bottom',
   *   arrowY?: number|null,
   *   arrowX?: number|null,
   * }} pos
   */
  applyTooltipPosition(tooltipEl, pos) {
    if (!tooltipEl) return;
    const firstPaint = tooltipEl.dataset.positioned !== "true";
    if (firstPaint) {
      tooltipEl.style.transitionProperty = "none";
    }
    tooltipEl.style.left = pos.x + "px";
    tooltipEl.style.top = pos.y + "px";
    if (pos.placement) {
      tooltipEl.dataset.placement = pos.placement;
    }
    if (pos.arrowY != null) {
      tooltipEl.style.setProperty("--apx-tt-arrow-y", pos.arrowY + "px");
    }
    if (pos.arrowX != null) {
      tooltipEl.style.setProperty("--apx-tt-arrow-x", pos.arrowX + "px");
    }
    if (firstPaint) {
      void tooltipEl.offsetWidth;
      tooltipEl.dataset.positioned = "true";
      requestAnimationFrame(() => {
        tooltipEl.style.transitionProperty = "";
      });
    }
  }
  /**
   * @param {number} i
   * @param {number} j
   */
  moveMarkers(i2, j) {
    var _a;
    const w = this.w;
    const ttCtx = this.ttCtx;
    if (w.globals.markers.size[i2] > 0 && !w.globals.markers.batched) {
      const allPoints = w.dom.baseEl.querySelectorAll(
        ` .apexcharts-series[data\\:realIndex='${i2}'] .apexcharts-marker`
      );
      for (let p = 0; p < allPoints.length; p++) {
        if (parseInt((_a = allPoints[p].getAttribute("rel")) != null ? _a : "0", 10) === j) {
          ttCtx.marker.resetPointsSize();
          ttCtx.marker.enlargeCurrentPoint(j, allPoints[p]);
        }
      }
    } else {
      ttCtx.marker.resetPointsSize();
      this.moveDynamicPointOnHover(j, i2);
    }
  }
  // This function is used when you need to show markers/points only on hover -
  // DIFFERENT X VALUES in multiple series
  /**
   * @param {number} j
   * @param {number} capturedSeries
   */
  moveDynamicPointOnHover(j, capturedSeries) {
    var _a, _b, _c, _d, _e;
    const w = this.w;
    const ttCtx = this.ttCtx;
    let cx = 0;
    let cy = 0;
    const graphics = new Graphics(this.w);
    const pointsArr = w.globals.pointsArray;
    const hoverSize = ttCtx.tooltipUtil.getHoverMarkerSize(capturedSeries);
    const serType = (
      /** @type {any} */
      w.config.series[capturedSeries].type
    );
    if (serType && (serType === "column" || serType === "candlestick" || serType === "boxPlot" || serType === "violin")) {
      return;
    }
    cx = (_b = (_a = pointsArr[capturedSeries]) == null ? void 0 : _a[j]) == null ? void 0 : _b[0];
    cy = ((_d = (_c = pointsArr[capturedSeries]) == null ? void 0 : _c[j]) == null ? void 0 : _d[1]) || 0;
    const point = w.dom.baseEl.querySelector(
      `.apexcharts-series[data\\:realIndex='${capturedSeries}'] .apexcharts-series-markers path`
    );
    if (point && cy < w.layout.gridHeight && cy > 0) {
      const shape = (_e = point.getAttribute("shape")) != null ? _e : "circle";
      const path = graphics.getMarkerPath(cx, cy, shape, hoverSize * 1.5);
      point.setAttribute("d", path);
    }
    this.moveXCrosshairs(cx);
    if (!ttCtx.fixedTooltip) {
      this.moveTooltip(cx, cy, hoverSize);
    }
  }
  // This function is used when you need to show markers/points only on hover -
  // SAME X VALUES in multiple series
  /**
   * @param {number} j
   */
  moveDynamicPointsOnHover(j) {
    var _a, _b;
    const ttCtx = this.ttCtx;
    const w = ttCtx.w;
    let cx = 0;
    let cy = 0;
    let activeSeries = 0;
    const pointsArr = w.globals.pointsArray;
    const series = new Series(this.w);
    const graphics = new Graphics(this.w);
    activeSeries = series.getActiveConfigSeriesIndex("asc", [
      "line",
      "area",
      "scatter",
      "bubble"
    ]);
    const hoverSize = ttCtx.tooltipUtil.getHoverMarkerSize(activeSeries);
    if ((_a = pointsArr[activeSeries]) == null ? void 0 : _a[j]) {
      cx = pointsArr[activeSeries][j][0];
      cy = pointsArr[activeSeries][j][1];
    }
    if (isNaN(cx)) {
      return;
    }
    const points = ttCtx.tooltipUtil.getAllMarkers();
    if (points.length) {
      for (let p = 0; p < w.seriesData.series.length; p++) {
        const pointArr = pointsArr[p];
        if (w.globals.comboCharts) {
          if (typeof pointArr === "undefined") {
            points.splice(p, 0, null);
          }
        }
        if (points[p] && pointArr && pointArr.length) {
          let pcy = pointsArr[p][j][1];
          let pcy2;
          points[p].setAttribute("cx", cx);
          const shape = (_b = points[p].getAttribute("shape")) != null ? _b : "circle";
          if (w.config.chart.type === "rangeArea" && !w.globals.comboCharts) {
            const rangeStartIndex = j + w.seriesData.series[p].length;
            pcy2 = pointsArr[p][rangeStartIndex][1];
            const pcyDiff = Math.abs(pcy - pcy2) / 2;
            pcy = pcy - pcyDiff;
          }
          if (pcy !== null && !isNaN(pcy) && pcy < w.layout.gridHeight + hoverSize && pcy + hoverSize > 0) {
            const path = graphics.getMarkerPath(cx, pcy, shape, hoverSize);
            points[p].setAttribute("d", path);
          } else {
            points[p].setAttribute("d", "");
          }
        }
      }
    }
    this.moveXCrosshairs(cx);
    if (!ttCtx.fixedTooltip) {
      this.moveTooltip(cx, cy || w.layout.gridHeight, hoverSize);
    }
  }
  /**
   * @param {number} j
   * @param {number} capturedSeries
   */
  moveStickyTooltipOverBars(j, capturedSeries) {
    var _a, _b, _c, _d, _e;
    const w = this.w;
    const ttCtx = this.ttCtx;
    let barLen = w.globals.columnSeries ? (
      /** @type {any} */
      w.globals.columnSeries.length
    ) : w.seriesData.series.length;
    if (w.config.chart.stacked) {
      barLen = w.globals.barGroups.length;
    }
    let i2 = barLen >= 2 && barLen % 2 === 0 ? Math.floor(barLen / 2) : Math.floor(barLen / 2) + 1;
    if (w.globals.isBarHorizontal) {
      const series = new Series(this.w);
      i2 = series.getActiveConfigSeriesIndex("desc") + 1;
    }
    let jBar = w.dom.baseEl.querySelector(
      `.apexcharts-bar-series .apexcharts-series[rel='${i2}'] path[j='${j}'], .apexcharts-candlestick-series .apexcharts-series[rel='${i2}'] path[j='${j}'], .apexcharts-boxPlot-series .apexcharts-series[rel='${i2}'] path[j='${j}'], .apexcharts-violin-series .apexcharts-series[rel='${i2}'] path[j='${j}'], .apexcharts-rangebar-series .apexcharts-series[rel='${i2}'] path[j='${j}']`
    );
    if (!jBar && typeof capturedSeries === "number") {
      jBar = w.dom.baseEl.querySelector(
        `.apexcharts-bar-series .apexcharts-series[data\\:realIndex='${capturedSeries}'] path[j='${j}'],
        .apexcharts-candlestick-series .apexcharts-series[data\\:realIndex='${capturedSeries}'] path[j='${j}'],
        .apexcharts-boxPlot-series .apexcharts-series[data\\:realIndex='${capturedSeries}'] path[j='${j}'],
        .apexcharts-violin-series .apexcharts-series[data\\:realIndex='${capturedSeries}'] path[j='${j}'],
        .apexcharts-rangebar-series .apexcharts-series[data\\:realIndex='${capturedSeries}'] path[j='${j}']`
      );
    }
    let bc = null;
    const bcc = (
      /** @type {any} */
      w.globals.barCanvasCoords
    );
    if (!jBar && bcc) {
      bc = typeof capturedSeries === "number" && ((_a = bcc[capturedSeries]) == null ? void 0 : _a[j]) || null;
      if (!bc) {
        for (const key in bcc) {
          if ((_b = bcc[key]) == null ? void 0 : _b[j]) {
            bc = bcc[key][j];
            break;
          }
        }
      }
    }
    let bcx = jBar ? parseFloat((_c = jBar.getAttribute("cx")) != null ? _c : "0") : bc ? bc.cx : 0;
    let bcy = jBar ? parseFloat((_d = jBar.getAttribute("cy")) != null ? _d : "0") : bc ? bc.cy : 0;
    const bw = jBar ? parseFloat((_e = jBar.getAttribute("barWidth")) != null ? _e : "0") : bc ? bc.barWidth : 0;
    const elGrid = ttCtx.getElGrid();
    if (!elGrid) return;
    const seriesBound = elGrid.getBoundingClientRect();
    const isBoxOrCandle = jBar && (jBar.classList.contains("apexcharts-candlestick-area") || jBar.classList.contains("apexcharts-boxPlot-area"));
    if (w.axisFlags.isXNumeric) {
      if (jBar && !isBoxOrCandle) {
        const center = this._datapointCenterXFromBars(j);
        if (center != null) {
          bcx = center;
        } else {
          bcx = bcx - (barLen % 2 !== 0 ? bw / 2 : 0);
        }
      }
      if (jBar && // fixes apexcharts.js#2354
      isBoxOrCandle) {
        bcx = bcx - bw / 2;
      }
    } else {
      if (!w.globals.isBarHorizontal && !bc) {
        bcx = ttCtx.xAxisTicksPositions[j - 1] + ttCtx.dataPointsDividedWidth / 2;
        if (isNaN(bcx)) {
          bcx = ttCtx.xAxisTicksPositions[j] - ttCtx.dataPointsDividedWidth / 2;
        }
      }
    }
    if (!w.globals.isBarHorizontal) {
      if (w.config.tooltip.followCursor) {
        bcy = ttCtx.e.clientY - seriesBound.top - ttCtx.tooltipRect.ttHeight / 2;
      } else {
        if (bcy + ttCtx.tooltipRect.ttHeight + 15 > w.layout.gridHeight) {
          bcy = w.layout.gridHeight;
        }
      }
    } else {
      bcy = bcy - ttCtx.tooltipRect.ttHeight;
    }
    if (!w.globals.isBarHorizontal) {
      this.moveXCrosshairs(bcx);
    }
    if (!ttCtx.fixedTooltip) {
      if (w.globals.isBarHorizontal && !w.config.tooltip.followCursor) {
        const placed = this.placeHorizontalSharedTooltip(j);
        if (placed) return;
      }
      this.moveTooltip(bcx, bcy || w.layout.gridHeight);
    }
  }
  /**
   * Place tooltip above (or flipped: below) the union rect of all bars at
   * dataPointIndex `j` for horizontal-bar-likes. Returns true when a
   * Compute the true horizontal center of dataPointIndex `j` in grid-local
   * coords from the union of every visible bar's `getBoundingClientRect()`.
   * Used as a replacement for the (buggy on numeric/datetime xaxis) `cx`
   * attribute math in `moveStickyTooltipOverBars`. Returns null when no
   * usable bars are found.
   * @param {number} j
   * @returns {number | null}
   */
  _datapointCenterXFromBars(j) {
    var _a, _b;
    const w = this.w;
    const bars = w.dom.baseEl.querySelectorAll(
      `.apexcharts-bar-series path[j='${j}'],.apexcharts-rangebar-series path[j='${j}']`
    );
    if (!bars.length) return null;
    let unionLeft = Infinity;
    let unionRight = -Infinity;
    for (const bar of bars) {
      const parent = (
        /** @type {Element|null} */
        bar.parentNode
      );
      if ((_b = (_a = parent == null ? void 0 : parent.classList) == null ? void 0 : _a.contains) == null ? void 0 : _b.call(_a, "apexcharts-series-collapsed")) continue;
      const r2 = (
        /** @type {Element} */
        bar.getBoundingClientRect()
      );
      if (r2.width === 0 && r2.height === 0) continue;
      if (r2.left < unionLeft) unionLeft = r2.left;
      if (r2.right > unionRight) unionRight = r2.right;
    }
    if (!isFinite(unionLeft)) return null;
    return AxisMapping.screenXToPlotPx(w, (unionLeft + unionRight) / 2);
  }
  /**
   * Place tooltip above (or flipped: below) the union rect of all bars at
   * dataPointIndex `j` for horizontal-bar-likes. Returns true when a
   * placement was applied; false when no bars found (caller falls back).
   * @param {number} j
   * @returns {boolean}
   */
  placeHorizontalSharedTooltip(j) {
    var _a, _b;
    const w = this.w;
    const ttCtx = this.ttCtx;
    const tooltipEl = ttCtx.getElTooltip();
    if (!tooltipEl) return false;
    const elGrid = ttCtx.getElGrid();
    if (!elGrid) return false;
    const gridRect = elGrid.getBoundingClientRect();
    const bars = w.dom.baseEl.querySelectorAll(
      `.apexcharts-bar-series path[j='${j}'],.apexcharts-rangebar-series path[j='${j}'],.apexcharts-boxPlot-series path[j='${j}']`
    );
    if (!bars.length) return false;
    let unionLeft = Infinity;
    let unionRight = -Infinity;
    let unionTop = Infinity;
    let unionBottom = -Infinity;
    for (const bar of bars) {
      const parent = (
        /** @type {Element|null} */
        bar.parentNode
      );
      if ((_b = (_a = parent == null ? void 0 : parent.classList) == null ? void 0 : _a.contains) == null ? void 0 : _b.call(_a, "apexcharts-series-collapsed")) continue;
      const r2 = (
        /** @type {Element} */
        bar.getBoundingClientRect()
      );
      if (r2.width === 0 && r2.height === 0) continue;
      if (r2.left < unionLeft) unionLeft = r2.left;
      if (r2.right > unionRight) unionRight = r2.right;
      if (r2.top < unionTop) unionTop = r2.top;
      if (r2.bottom > unionBottom) unionBottom = r2.bottom;
    }
    if (!isFinite(unionLeft)) return false;
    const ttW = ttCtx.tooltipRect.ttWidth || 0;
    const ttH = ttCtx.tooltipRect.ttHeight || 0;
    const rowCenterX = (unionLeft + unionRight) / 2 - gridRect.left + w.layout.translateX;
    const rowTopElWrap = unionTop - gridRect.top + w.layout.translateY;
    const rowBottomElWrap = unionBottom - gridRect.top + w.layout.translateY;
    const gridTop = w.layout.translateY;
    const gridBottom = w.layout.translateY + w.layout.gridHeight;
    const gridLeft = w.layout.translateX;
    const gridRight = w.layout.translateX + w.layout.gridWidth;
    let placement = "top";
    let finalY = rowTopElWrap - ttH - ARROW_TIP_OVERHANG;
    if (finalY < gridTop) {
      const belowTop = rowBottomElWrap + ARROW_TIP_OVERHANG;
      if (belowTop + ttH <= gridBottom) {
        placement = "bottom";
        finalY = belowTop;
      }
    }
    let finalX = rowCenterX - ttW / 2;
    if (finalX < gridLeft) finalX = gridLeft;
    if (finalX + ttW > gridRight) finalX = gridRight - ttW;
    const arrowX = Math.max(10, Math.min(ttW - 10, rowCenterX - finalX));
    this.applyTooltipPosition(tooltipEl, {
      x: finalX,
      y: finalY,
      placement,
      arrowY: null,
      arrowX
    });
    return true;
  }
}
function renderMarkerSVG(shape) {
  const svg = (body) => `<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">${body}</svg>`;
  switch (shape) {
    case "square":
    case "rect":
      return svg('<rect x="1" y="1" width="10" height="10" rx="1" fill="currentColor"/>');
    case "line":
      return svg('<rect x="0" y="5" width="12" height="2" rx="1" fill="currentColor"/>');
    case "diamond":
      return svg('<path d="M6 0.5 L11.5 6 L6 11.5 L0.5 6 Z" fill="currentColor"/>');
    case "triangle":
      return svg('<path d="M6 1 L11.2 10.5 L0.8 10.5 Z" fill="currentColor"/>');
    case "cross":
      return svg(
        '<path d="M2 2 L10 10 M10 2 L2 10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>'
      );
    case "plus":
      return svg(
        '<path d="M6 1 L6 11 M1 6 L11 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>'
      );
    case "star":
      return svg(
        '<path d="M6 0.5 L7.5 4.4 L11.5 4.7 L8.4 7.2 L9.5 11.1 L6 8.9 L2.5 11.1 L3.6 7.2 L0.5 4.7 L4.5 4.4 Z" fill="currentColor"/>'
      );
    case "sparkle":
      return svg(
        '<path d="M6 0.5 L7 5 L11.5 6 L7 7 L6 11.5 L5 7 L0.5 6 L5 5 Z" fill="currentColor"/>'
      );
    case "circle":
    default:
      return svg('<circle cx="6" cy="6" r="5" fill="currentColor"/>');
  }
}
class Marker {
  /**
   * @param {import('./Tooltip').default} tooltipContext
   */
  constructor(tooltipContext) {
    this.w = tooltipContext.w;
    this.ttCtx = tooltipContext;
    this.ctx = tooltipContext.ctx;
    this.tooltipPosition = new Position(tooltipContext);
  }
  drawDynamicPoints() {
    const w = this.w;
    const graphics = new Graphics(this.w);
    const marker = new Markers(this.w, this.ctx);
    const elsSeries = (
      /** @type {any[]} */
      [
        ...w.dom.baseEl.querySelectorAll(".apexcharts-series")
      ]
    );
    if (w.config.chart.stacked) {
      elsSeries.sort((a2, b) => {
        return parseFloat(a2.getAttribute("data:realIndex")) - parseFloat(b.getAttribute("data:realIndex"));
      });
    }
    for (let i2 = 0; i2 < elsSeries.length; i2++) {
      const pointsMain = elsSeries[i2].querySelector(
        `.apexcharts-series-markers-wrap`
      );
      if (pointsMain !== null) {
        let PointClasses = `apexcharts-marker w${(Math.random() + 1).toString(36).substring(4)}`;
        if (Markers.markersAreInert(w)) {
          PointClasses += " no-pointer-events";
        }
        const elPointOptions = marker.getMarkerConfig({
          cssClass: PointClasses,
          seriesIndex: Number(pointsMain.getAttribute("data:realIndex"))
          // fixes apexcharts/apexcharts.js #1427
        });
        const point = graphics.drawMarker(0, 0, elPointOptions);
        point.node.setAttribute("default-marker-size", 0);
        const elPointsG = BrowserAPIs.createElementNS(SVGNS$1, "g");
        elPointsG.classList.add("apexcharts-series-markers");
        elPointsG.appendChild(point.node);
        pointsMain.appendChild(elPointsG);
      }
    }
  }
  /**
   * @param {any} rel
   * @param {any} point
   * @param {number | null} [x]
   * @param {number | null} [y]
   */
  enlargeCurrentPoint(rel, point, x = null, y = null) {
    const w = this.w;
    let appliedSize = w.config.markers.hover.size;
    if (w.config.chart.type !== "bubble") {
      appliedSize = this.newPointSize(rel, point);
    }
    let cx = point.getAttribute("cx");
    let cy = point.getAttribute("cy");
    if (x !== null && y !== null) {
      cx = x;
      cy = y;
    }
    this.tooltipPosition.moveXCrosshairs(cx);
    if (!this.fixedTooltip) {
      if (w.config.chart.type === "radar") {
        const elGrid = this.ttCtx.getElGrid();
        if (!elGrid) return;
        const seriesBound = elGrid.getBoundingClientRect();
        cx = this.ttCtx.e.clientX - seriesBound.left;
      }
      this.tooltipPosition.moveTooltip(cx, cy, appliedSize);
    }
  }
  /**
   * @param {number} j
   */
  enlargePoints(j) {
    var _a, _b;
    const w = this.w;
    const me = this;
    const ttCtx = this.ttCtx;
    const col = j;
    const points = w.dom.baseEl.querySelectorAll(
      ".apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker"
    );
    let newSize = w.config.markers.hover.size;
    for (let p = 0; p < points.length; p++) {
      const rel = points[p].getAttribute("rel");
      const index = points[p].getAttribute("index");
      if (newSize === void 0) {
        newSize = w.globals.markers.size[
          /** @type {any} */
          index
        ] + w.config.markers.hover.sizeOffset;
      }
      if (col === parseInt(rel != null ? rel : "0", 10)) {
        me.newPointSize(col, points[p]);
        const cx = (_a = points[p].getAttribute("cx")) != null ? _a : "0";
        const cy = (_b = points[p].getAttribute("cy")) != null ? _b : "0";
        me.tooltipPosition.moveXCrosshairs(parseFloat(cx));
        if (!ttCtx.fixedTooltip) {
          me.tooltipPosition.moveTooltip(
            parseFloat(cx),
            parseFloat(cy),
            newSize
          );
        }
      } else {
        me.oldPointSize(points[p]);
      }
    }
  }
  /**
   * Resizes the hovered marker to its hover size and returns the size applied,
   * so the caller can position the tooltip clear of the enlarged dot. Undefined
   * when nothing was resized (a zero-size marker has nothing to clear).
   * @param {any} rel
   * @param {any} point
   * @returns {number | undefined}
   */
  newPointSize(rel, point) {
    const w = this.w;
    let newSize = w.config.markers.hover.size;
    const elPoint = rel === 0 ? point.parentNode.firstChild : point.parentNode.lastChild;
    if (elPoint.getAttribute("default-marker-size") !== "0") {
      const index = parseInt(elPoint.getAttribute("index"), 10);
      if (newSize === void 0) {
        newSize = w.globals.markers.size[index] + w.config.markers.hover.sizeOffset;
      }
      if (newSize < 0) {
        newSize = 0;
      }
      const path = this.ttCtx.tooltipUtil.getPathFromPoint(point, newSize);
      point.setAttribute("d", path);
      return newSize;
    }
    return void 0;
  }
  /**
   * @param {any} point
   */
  oldPointSize(point) {
    const size = parseFloat(point.getAttribute("default-marker-size"));
    const path = this.ttCtx.tooltipUtil.getPathFromPoint(point, size);
    point.setAttribute("d", path);
  }
  resetPointsSize() {
    var _a;
    const w = this.w;
    const points = w.dom.baseEl.querySelectorAll(
      ".apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker"
    );
    for (let p = 0; p < points.length; p++) {
      const size = parseFloat(
        (_a = points[p].getAttribute("default-marker-size")) != null ? _a : "0"
      );
      if (Utils$1.isNumber(size) && size > 0) {
        const path = this.ttCtx.tooltipUtil.getPathFromPoint(points[p], size);
        points[p].setAttribute("d", path);
      } else {
        points[p].setAttribute("d", "M0,0");
      }
    }
  }
}
class Intersect {
  /**
   * @param {import('./Tooltip').default} tooltipContext
   */
  constructor(tooltipContext) {
    this.w = tooltipContext.w;
    const w = this.w;
    this.ttCtx = tooltipContext;
    this.isVerticalGroupedRangeBar = !w.globals.isBarHorizontal && w.config.chart.type === "rangeBar" && w.config.plotOptions.bar.rangeBarGroupRows;
  }
  // a helper function to get an element's attribute value
  /**
   * @param {Event} e
   * @param {string} attr
   */
  getAttr(e2, attr) {
    var _a;
    return parseFloat(
      /** @type {Element} */
      (_a = Utils2.hoverTarget(e2).getAttribute(attr)) != null ? _a : ""
    );
  }
  // handle tooltip for heatmaps and treemaps
  /** @param {{e: any, opt: any, x: any, y: any, type: any}} opts */
  handleHeatTreeTooltip({ e: e2, opt, x, y, type }) {
    var _a, _b;
    const ttCtx = this.ttCtx;
    const w = this.w;
    const renderer = w.globals.activeRenderer;
    const canvasCells = type === "heatmap" && renderer && renderer.kind === "canvas" && typeof renderer.hitTest === "function";
    const hovered = Utils2.hoverTarget(e2);
    let i2, j, cx, cy, width, height;
    if (canvasCells) {
      const seriesBound = opt.elGrid.getBoundingClientRect();
      const clientX = e2.type === "touchmove" ? e2.touches[0].clientX : e2.clientX;
      const clientY = e2.type === "touchmove" ? e2.touches[0].clientY : e2.clientY;
      const hit = renderer.hitTest(
        clientX - seriesBound.left,
        clientY - seriesBound.top
      );
      if (!hit) {
        return { x, y, noHit: true };
      }
      i2 = hit.seriesIndex;
      j = hit.dataPointIndex;
      cx = hit.x;
      cy = hit.y;
      width = hit.width;
      height = hit.height;
    } else if (hovered.classList.contains(`apexcharts-${type}-rect`)) {
      i2 = this.getAttr(e2, "i");
      j = this.getAttr(e2, "j");
      cx = this.getAttr(e2, "cx");
      cy = this.getAttr(e2, "cy");
      width = this.getAttr(e2, "width");
      height = this.getAttr(e2, "height");
    } else {
      return { x, y };
    }
    ttCtx.tooltipLabels.drawSeriesTexts({
      ttItems: opt.ttItems,
      i: i2,
      j,
      shared: false,
      e: e2
    });
    w.interact.capturedSeriesIndex = i2;
    w.interact.capturedDataPointIndex = j;
    ttCtx.tooltipPosition.moveXCrosshairs(cx + width / 2);
    const tooltipEl = ttCtx.getElTooltip();
    if (type === "heatmap" && w.config.tooltip.arrow && !w.config.tooltip.followCursor && tooltipEl) {
      const elGridRect = opt.elGrid.getBoundingClientRect();
      const elWrapRect = w.dom.elWrap.getBoundingClientRect();
      const gridOffsetXInElWrap = elGridRect.left - elWrapRect.left;
      let clLeft, clTop, clRight, clBottom;
      if (canvasCells) {
        clLeft = cx;
        clTop = cy;
        clRight = cx + width;
        clBottom = cy + height;
      } else {
        const r2 = hovered.getBoundingClientRect();
        clLeft = r2.left - elGridRect.left;
        clTop = r2.top - elGridRect.top;
        clRight = r2.right - elGridRect.left;
        clBottom = r2.bottom - elGridRect.top;
      }
      const ttW = ttCtx.tooltipRect.ttWidth || 0;
      const ttH = ttCtx.tooltipRect.ttHeight || 0;
      const cellCenterXInElWrap = (clLeft + clRight) / 2 + gridOffsetXInElWrap;
      const cellTopInElWrap = clTop + w.layout.translateY;
      const cellBottomInElWrap = clBottom + w.layout.translateY;
      const gridTop = w.layout.translateY;
      const gridBottom = w.layout.translateY + w.layout.gridHeight;
      const gridLeft = gridOffsetXInElWrap;
      const gridRight = gridOffsetXInElWrap + w.layout.gridWidth;
      let placement = "top";
      let finalY = cellTopInElWrap - ttH - ARROW_TIP_OVERHANG;
      if (finalY < gridTop) {
        const belowTop = cellBottomInElWrap + ARROW_TIP_OVERHANG;
        if (belowTop + ttH <= gridBottom) {
          placement = "bottom";
          finalY = belowTop;
        } else {
          finalY = gridTop;
        }
      }
      let finalX = cellCenterXInElWrap - ttW / 2;
      if (finalX < gridLeft) finalX = gridLeft;
      if (finalX + ttW > gridRight) finalX = gridRight - ttW;
      const arrowX = Math.max(10, Math.min(ttW - 10, cellCenterXInElWrap - finalX));
      ttCtx.tooltipPosition.applyTooltipPosition(tooltipEl, {
        x: finalX,
        y: finalY,
        placement,
        arrowY: null,
        arrowX
      });
      return { x: finalX, y: finalY, positioned: true };
    }
    x = cx + ttCtx.tooltipRect.ttWidth / 2 + width;
    y = cy + ttCtx.tooltipRect.ttHeight / 2 - height / 2;
    if (x > w.layout.gridWidth / 2) {
      x = cx - ttCtx.tooltipRect.ttWidth / 2 + width;
    }
    if (ttCtx.w.config.tooltip.followCursor) {
      const seriesBound = w.dom.elWrap.getBoundingClientRect();
      x = ((_a = w.interact.clientX) != null ? _a : 0) - seriesBound.left - (x > w.layout.gridWidth / 2 ? ttCtx.tooltipRect.ttWidth : 0);
      y = ((_b = w.interact.clientY) != null ? _b : 0) - seriesBound.top - (y > w.layout.gridHeight / 2 ? ttCtx.tooltipRect.ttHeight : 0);
    }
    return {
      x,
      y
    };
  }
  /**
   * handle tooltips for line/area/scatter charts where tooltip.intersect is true
   * when user hovers over the marker directly, this function is executed
   */
  /** @param {{e: any, opt: any, x: any, y: any}} opts */
  handleMarkerTooltip({ e: e2, opt, x, y }) {
    const w = this.w;
    const ttCtx = this.ttCtx;
    let i2;
    let j;
    if (Utils2.hoverTarget(e2).classList.contains("apexcharts-marker")) {
      const cx = parseInt(opt.paths.getAttribute("cx"), 10);
      const cy = parseInt(opt.paths.getAttribute("cy"), 10);
      const val = parseFloat(opt.paths.getAttribute("val"));
      j = parseInt(opt.paths.getAttribute("rel"), 10);
      i2 = parseInt(
        opt.paths.parentNode.parentNode.parentNode.getAttribute("rel"),
        10
      ) - 1;
      if (ttCtx.intersect) {
        const el = Utils$1.findAncestor(opt.paths, "apexcharts-series");
        if (el) {
          i2 = parseInt(el.getAttribute("data:realIndex"), 10);
        }
      }
      ttCtx.tooltipLabels.drawSeriesTexts({
        ttItems: opt.ttItems,
        i: i2,
        j,
        shared: ttCtx.showOnIntersect ? false : w.config.tooltip.shared,
        e: e2
      });
      if (e2.type === "mouseup") {
        ttCtx.markerClick(e2, i2, j);
      }
      w.interact.capturedSeriesIndex = i2;
      w.interact.capturedDataPointIndex = j;
      const arrowEnabled = !!w.config.tooltip.arrow;
      x = cx;
      if (arrowEnabled) {
        y = cy;
      } else {
        y = cy + w.layout.translateY - ttCtx.tooltipRect.ttHeight * 1.4;
        if (val < 0) {
          y = cy;
        }
      }
      if (ttCtx.w.config.tooltip.followCursor) {
        const elGrid = ttCtx.getElGrid();
        if (!elGrid) return { x, y };
        const seriesBound = elGrid.getBoundingClientRect();
        y = ttCtx.e.clientY + w.layout.translateY - seriesBound.top;
      }
      ttCtx.marker.enlargeCurrentPoint(j, opt.paths, x, y);
    }
    return {
      x,
      y
    };
  }
  /**
   * handle tooltips for bar/column charts
   */
  /** @param {{e: any, opt: any}} opts */
  handleBarTooltip({ e: e2, opt }) {
    var _a, _b, _c;
    const w = this.w;
    const ttCtx = this.ttCtx;
    const tooltipEl = ttCtx.getElTooltip();
    let bx = 0;
    let x = 0;
    let y = 0;
    let i2 = 0;
    let strokeWidth;
    const barXY = this.getBarTooltipXY({
      e: e2,
      opt
    });
    if (barXY.j === null && barXY.barHeight === 0 && barXY.barWidth === 0) {
      return;
    }
    i2 = barXY.i;
    const j = barXY.j;
    w.interact.capturedSeriesIndex = i2;
    w.interact.capturedDataPointIndex = j !== null ? j : w.interact.capturedDataPointIndex;
    if (w.globals.isBarHorizontal && ttCtx.tooltipUtil.hasBars() || !w.config.tooltip.shared) {
      x = barXY.x;
      y = barXY.y;
      strokeWidth = Array.isArray(w.config.stroke.width) ? w.config.stroke.width[i2] : w.config.stroke.width;
      bx = x;
    } else {
      if (!w.globals.comboCharts && !w.config.tooltip.shared) {
        bx = bx / 2;
      }
    }
    if (isNaN(y)) {
      y = w.globals.svgHeight - ttCtx.tooltipRect.ttHeight;
    }
    if (x + ttCtx.tooltipRect.ttWidth > w.layout.gridWidth) {
      x = x - ttCtx.tooltipRect.ttWidth;
    } else if (x < 0) {
      x = 0;
    }
    if (ttCtx.w.config.tooltip.followCursor) {
      const elGrid = ttCtx.getElGrid();
      if (!elGrid) return;
    }
    if (ttCtx.tooltip === null) {
      ttCtx.tooltip = w.dom.baseEl.querySelector(
        ".apexcharts-tooltip:not(.apexcharts-annotation-tooltip)"
      );
    }
    if (!w.config.tooltip.shared) {
      if (w.globals.comboBarCount > 0) {
        ttCtx.tooltipPosition.moveXCrosshairs(bx + strokeWidth / 2);
      } else {
        ttCtx.tooltipPosition.moveXCrosshairs(bx);
      }
    }
    if (!ttCtx.fixedTooltip && (!w.config.tooltip.shared || w.globals.isBarHorizontal && ttCtx.tooltipUtil.hasBars())) {
      y = y + w.layout.translateY - ttCtx.tooltipRect.ttHeight / 2;
      if (tooltipEl) {
        const ttW = ttCtx.tooltipRect.ttWidth || 0;
        const ttH = ttCtx.tooltipRect.ttHeight || 0;
        const arrowEnabled = !!w.config.tooltip.arrow;
        const { barAnchorXInGrid, barAnchorYInGrid, barRectInGrid } = barXY;
        const elGridRect = (_a = ttCtx.getElGrid()) == null ? void 0 : _a.getBoundingClientRect();
        const elWrapRect = w.dom.elWrap.getBoundingClientRect();
        const gridOffsetXInElWrap = elGridRect ? elGridRect.left - elWrapRect.left : w.layout.translateX;
        let placement;
        let arrowY = null;
        let arrowX = null;
        let finalX = x + gridOffsetXInElWrap;
        let finalY = y;
        if (arrowEnabled && w.globals.isBarHorizontal && barRectInGrid != null) {
          const gridTop = w.layout.translateY;
          const gridBottom = w.layout.translateY + w.layout.gridHeight;
          const gridLeft = gridOffsetXInElWrap;
          const gridRight = gridOffsetXInElWrap + w.layout.gridWidth;
          const barCenterXInElWrap = (barRectInGrid.left + barRectInGrid.right) / 2 + gridOffsetXInElWrap;
          const barTopInElWrap = barRectInGrid.top + w.layout.translateY;
          const barBottomInElWrap = barRectInGrid.bottom + w.layout.translateY;
          let proposedTop = barTopInElWrap - ttH - ARROW_TIP_OVERHANG;
          placement = "top";
          if (proposedTop < gridTop) {
            const belowTop = barBottomInElWrap + ARROW_TIP_OVERHANG;
            if (belowTop + ttH <= gridBottom) {
              placement = "bottom";
              proposedTop = belowTop;
            }
          }
          finalY = proposedTop;
          finalX = barCenterXInElWrap - ttW / 2;
          if (finalX < gridLeft) finalX = gridLeft;
          if (finalX + ttW > gridRight) finalX = gridRight - ttW;
          arrowX = Math.max(
            10,
            Math.min(ttW - 10, barCenterXInElWrap - finalX)
          );
        } else if (arrowEnabled && barAnchorXInGrid != null && barAnchorYInGrid != null) {
          const barCenterXInElWrap = barAnchorXInGrid + gridOffsetXInElWrap;
          const gridCenterXInElWrap = gridOffsetXInElWrap + w.layout.gridWidth / 2;
          const barLeftInElWrap = ((_b = barRectInGrid == null ? void 0 : barRectInGrid.left) != null ? _b : barAnchorXInGrid) + gridOffsetXInElWrap;
          const barRightInElWrap = ((_c = barRectInGrid == null ? void 0 : barRectInGrid.right) != null ? _c : barAnchorXInGrid) + gridOffsetXInElWrap;
          if (barCenterXInElWrap < gridCenterXInElWrap) {
            placement = "right";
            finalX = barRightInElWrap + ARROW_TIP_OVERHANG;
          } else {
            placement = "left";
            finalX = barLeftInElWrap - ttW - ARROW_TIP_OVERHANG;
          }
          if (barRectInGrid) {
            const barCenterYInElWrap = (barRectInGrid.top + barRectInGrid.bottom) / 2 + w.layout.translateY;
            finalY = barCenterYInElWrap - ttH / 2;
            const gridTop = w.layout.translateY;
            const gridBottom = w.layout.translateY + w.layout.gridHeight;
            if (finalY < gridTop) finalY = gridTop;
            if (finalY + ttH > gridBottom) finalY = gridBottom - ttH;
          }
          if (ttH > 0 && barRectInGrid) {
            const barCenterYInElWrap = (barRectInGrid.top + barRectInGrid.bottom) / 2 + w.layout.translateY;
            arrowY = Math.max(
              10,
              Math.min(ttH - 10, barCenterYInElWrap - finalY)
            );
          }
        }
        ttCtx.tooltipPosition.applyTooltipPosition(tooltipEl, {
          x: finalX,
          y: finalY,
          placement,
          arrowY,
          arrowX
        });
      }
    }
  }
  /** @param {{e: any, opt: any}} opts */
  getBarTooltipXY({ e: e2, opt }) {
    const w = this.w;
    let j = null;
    const ttCtx = this.ttCtx;
    let i2 = 0;
    let x = 0;
    let y = 0;
    let barWidth = 0;
    let barHeight = 0;
    let barCx = null;
    let barCy = null;
    let barAnchorXInGrid = null;
    let barAnchorYInGrid = null;
    let barRectInGrid = null;
    const hovered = Utils2.hoverTarget(e2);
    const cl = hovered.classList;
    if (cl.contains("apexcharts-bar-area") || cl.contains("apexcharts-candlestick-area") || cl.contains("apexcharts-boxPlot-area") || cl.contains("apexcharts-rangebar-area")) {
      const bar = hovered;
      const barRect = bar.getBoundingClientRect();
      const seriesBound = opt.elGrid.getBoundingClientRect();
      const bh = barRect.height;
      barHeight = barRect.height;
      const bw = barRect.width;
      const cx = parseInt(bar.getAttribute("cx"), 10);
      const cy = parseInt(bar.getAttribute("cy"), 10);
      barCx = cx;
      barCy = cy;
      barWidth = parseFloat(bar.getAttribute("barWidth"));
      const rectLeftInGrid = barRect.left - seriesBound.left;
      const rectTopInGrid = barRect.top - seriesBound.top;
      const rectCenterXInGrid = rectLeftInGrid + bw / 2;
      const rectCenterYInGrid = rectTopInGrid + bh / 2;
      barAnchorXInGrid = rectCenterXInGrid;
      barAnchorYInGrid = w.globals.isBarHorizontal ? rectCenterYInGrid : rectTopInGrid;
      barRectInGrid = {
        left: rectLeftInGrid,
        top: rectTopInGrid,
        right: rectLeftInGrid + bw,
        bottom: rectTopInGrid + bh
      };
      const clientX = e2.type === "touchmove" ? e2.touches[0].clientX : e2.clientX;
      j = parseInt(bar.getAttribute("j"), 10);
      i2 = parseInt(bar.parentNode.getAttribute("rel"), 10) - 1;
      const y1 = bar.getAttribute("data-range-y1");
      const y2 = bar.getAttribute("data-range-y2");
      if (w.globals.comboCharts) {
        i2 = parseInt(bar.parentNode.getAttribute("data:realIndex"), 10);
      }
      const handleXForColumns = (x2) => {
        if (w.axisFlags.isXNumeric) {
          x2 = cx - bw / 2;
        } else {
          if (this.isVerticalGroupedRangeBar) {
            x2 = cx + bw / 2;
          } else {
            x2 = cx - ttCtx.dataPointsDividedWidth + bw / 2;
          }
        }
        return x2;
      };
      const handleYForBars = () => {
        return cy - ttCtx.dataPointsDividedHeight + bh / 2 - ttCtx.tooltipRect.ttHeight / 2;
      };
      ttCtx.tooltipLabels.drawSeriesTexts({
        ttItems: opt.ttItems,
        i: i2,
        j,
        y1: y1 ? parseInt(y1, 10) : null,
        y2: y2 ? parseInt(y2, 10) : null,
        shared: ttCtx.showOnIntersect ? false : w.config.tooltip.shared,
        e: e2
      });
      if (w.config.tooltip.followCursor) {
        if (w.globals.isBarHorizontal) {
          x = clientX - seriesBound.left + 15;
          y = handleYForBars();
        } else {
          x = handleXForColumns(x);
          y = e2.clientY - seriesBound.top - ttCtx.tooltipRect.ttHeight / 2 - 15;
        }
      } else {
        if (w.globals.isBarHorizontal) {
          x = cx;
          if (ttCtx.xyRatios && x < ttCtx.xyRatios.baseLineInvertedY) {
            x = cx - ttCtx.tooltipRect.ttWidth;
          }
          y = handleYForBars();
        } else {
          x = handleXForColumns(x);
          y = cy;
        }
      }
    }
    return {
      x,
      y,
      barHeight,
      barWidth,
      i: i2,
      j,
      // SVG attribute values — left for any caller that still wants them.
      barCx,
      barCy,
      // Arrow anchor in grid-local coords (rect-derived; column→top,
      // horizontal→center). Used by handleBarTooltip to place the arrow
      // exactly on the bar's data point.
      barAnchorXInGrid,
      barAnchorYInGrid,
      // Full rendered bar rect (grid-local). Used for top/bottom
      // placement and flip-on-overflow detection.
      barRectInGrid
    };
  }
}
class AxesTooltip {
  /**
   * @param {import('./Tooltip').default} tooltipContext
   */
  constructor(tooltipContext) {
    this.w = tooltipContext.w;
    this.ttCtx = tooltipContext;
  }
  /**
   * This method adds the secondary tooltip which appears below x axis
   * @memberof Tooltip
   **/
  drawXaxisTooltip() {
    const w = this.w;
    const ttCtx = this.ttCtx;
    const isBottom = w.config.xaxis.position === "bottom";
    ttCtx.xaxisOffY = isBottom ? w.layout.gridHeight + 1 : -w.layout.xAxisHeight - w.config.xaxis.axisTicks.height + 3;
    const tooltipCssClass = isBottom ? "apexcharts-xaxistooltip apexcharts-xaxistooltip-bottom" : "apexcharts-xaxistooltip apexcharts-xaxistooltip-top";
    const renderTo = w.dom.elWrap;
    if (ttCtx.isXAxisTooltipEnabled) {
      const xaxisTooltip = w.dom.baseEl.querySelector(
        ".apexcharts-xaxistooltip"
      );
      if (xaxisTooltip === null) {
        ttCtx.xaxisTooltip = BrowserAPIs.createElementNS(
          "http://www.w3.org/1999/xhtml",
          "div"
        );
        ttCtx.xaxisTooltip.setAttribute(
          "class",
          tooltipCssClass + " apexcharts-theme-" + w.config.tooltip.theme
        );
        renderTo.appendChild(ttCtx.xaxisTooltip);
        ttCtx.xaxisTooltipText = BrowserAPIs.createElementNS(
          "http://www.w3.org/1999/xhtml",
          "div"
        );
        ttCtx.xaxisTooltipText.classList.add("apexcharts-xaxistooltip-text");
        ttCtx.xaxisTooltipText.style.fontFamily = w.config.xaxis.tooltip.style.fontFamily || w.config.chart.fontFamily;
        ttCtx.xaxisTooltipText.style.fontSize = w.config.xaxis.tooltip.style.fontSize;
        ttCtx.xaxisTooltip.appendChild(ttCtx.xaxisTooltipText);
      }
    }
  }
  /**
   * This method adds the secondary tooltip which appears below x axis
   * @memberof Tooltip
   **/
  drawYaxisTooltip() {
    const w = this.w;
    const ttCtx = this.ttCtx;
    for (let i2 = 0; i2 < w.config.yaxis.length; i2++) {
      const isRight = w.config.yaxis[i2].opposite || w.config.yaxis[i2].crosshairs.opposite;
      ttCtx.yaxisOffX = isRight ? w.layout.gridWidth + 1 : 1;
      const tooltipCssClass = isRight ? `apexcharts-yaxistooltip apexcharts-yaxistooltip-${i2} apexcharts-yaxistooltip-right` : `apexcharts-yaxistooltip apexcharts-yaxistooltip-${i2} apexcharts-yaxistooltip-left`;
      const renderTo = w.dom.elWrap;
      const yaxisTooltip = w.dom.baseEl.querySelector(
        `.apexcharts-yaxistooltip.apexcharts-yaxistooltip-${i2}`
      );
      if (yaxisTooltip === null) {
        ttCtx.yaxisTooltip = BrowserAPIs.createElementNS(
          "http://www.w3.org/1999/xhtml",
          "div"
        );
        ttCtx.yaxisTooltip.setAttribute(
          "class",
          tooltipCssClass + " apexcharts-theme-" + w.config.tooltip.theme
        );
        renderTo.appendChild(ttCtx.yaxisTooltip);
        if (i2 === 0) ttCtx.yaxisTooltipText = [];
        ttCtx.yaxisTooltipText[i2] = BrowserAPIs.createElementNS("http://www.w3.org/1999/xhtml", "div");
        ttCtx.yaxisTooltipText[i2].classList.add(
          "apexcharts-yaxistooltip-text"
        );
        ttCtx.yaxisTooltip.appendChild(
          /** @type {any} */
          ttCtx.yaxisTooltipText[i2]
        );
      }
    }
  }
  /**
   * @memberof Tooltip
   **/
  setXCrosshairWidth() {
    var _a, _b;
    const w = this.w;
    const ttCtx = this.ttCtx;
    const xcrosshairs = ttCtx.getElXCrosshairs();
    ttCtx.xcrosshairsWidth = parseInt(w.config.xaxis.crosshairs.width, 10);
    if (!w.globals.comboCharts) {
      if (w.config.xaxis.crosshairs.width === "tickWidth") {
        const count = w.labelData.labels.length;
        ttCtx.xcrosshairsWidth = w.layout.gridWidth / count;
      } else if (w.config.xaxis.crosshairs.width === "barWidth") {
        const bar = w.dom.baseEl.querySelector(".apexcharts-bar-area");
        if (bar !== null) {
          const barWidth = parseFloat((_a = bar.getAttribute("barWidth")) != null ? _a : "0");
          ttCtx.xcrosshairsWidth = barWidth;
        } else {
          ttCtx.xcrosshairsWidth = 1;
        }
      }
    } else {
      const bar = w.dom.baseEl.querySelector(".apexcharts-bar-area");
      if (bar !== null && w.config.xaxis.crosshairs.width === "barWidth") {
        const barWidth = parseFloat((_b = bar.getAttribute("barWidth")) != null ? _b : "0");
        ttCtx.xcrosshairsWidth = barWidth;
      } else {
        if (w.config.xaxis.crosshairs.width === "tickWidth") {
          const count = w.labelData.labels.length;
          ttCtx.xcrosshairsWidth = w.layout.gridWidth / count;
        }
      }
    }
    if (w.globals.isBarHorizontal) {
      ttCtx.xcrosshairsWidth = 0;
    }
    if (xcrosshairs !== null && ttCtx.xcrosshairsWidth > 0) {
      xcrosshairs.setAttribute("width", String(ttCtx.xcrosshairsWidth));
    }
  }
  handleYCrosshair() {
    const w = this.w;
    const ttCtx = this.ttCtx;
    ttCtx.ycrosshairs = w.dom.baseEl.querySelector(".apexcharts-ycrosshairs");
    ttCtx.ycrosshairsHidden = w.dom.baseEl.querySelector(
      ".apexcharts-ycrosshairs-hidden"
    );
  }
  /**
   * @param {number} index
   * @param {number} clientY
   * @param {import('../../types/internal').XYRatios} xyRatios
   */
  drawYaxisTooltipText(index, clientY, xyRatios) {
    const ttCtx = this.ttCtx;
    const w = this.w;
    const gl = w.globals;
    const yAxisSeriesArr = gl.seriesYAxisMap[index];
    if (ttCtx.yaxisTooltips[index] && yAxisSeriesArr.length > 0) {
      const lbFormatter = w.formatters.yLabelFormatters[index];
      const elGrid = ttCtx.getElGrid();
      if (!elGrid) return;
      const seriesBound = elGrid.getBoundingClientRect();
      const seriesIndex = yAxisSeriesArr[0];
      let translationsIndex = 0;
      if (xyRatios.yRatio.length > 1) {
        translationsIndex = seriesIndex;
      }
      const hoverY = (clientY - seriesBound.top) * xyRatios.yRatio[translationsIndex];
      const height = gl.maxYArr[seriesIndex] - gl.minYArr[seriesIndex];
      let val = gl.minYArr[seriesIndex] + (height - hoverY);
      if (w.config.yaxis[index].reversed) {
        val = gl.maxYArr[seriesIndex] - (height - hoverY);
      }
      ttCtx.tooltipPosition.moveYCrosshairs(clientY - seriesBound.top);
      ttCtx.yaxisTooltipText[index].innerHTML = lbFormatter(val);
      ttCtx.tooltipPosition.moveYAxisTooltip(index);
    }
  }
}
class Tooltip {
  /**
   * @param {import('../../types/internal').ChartStateW} w
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.tConfig = w.config.tooltip;
    this.tooltipUtil = new Utils2(this);
    this.tooltipLabels = new Labels(this);
    this.tooltipPosition = new Position(this);
    this.marker = new Marker(this);
    this.intersect = new Intersect(this);
    this.axesTooltip = new AxesTooltip(this);
    this.showOnIntersect = this.tConfig.intersect;
    this.showTooltipTitle = this.tConfig.x.show;
    this.fixedTooltip = this.tConfig.fixed.enabled;
    this.xaxisTooltip = null;
    this.xaxisTooltipText = null;
    this.yaxisTooltip = null;
    this.yaxisTooltipText = null;
    this.yaxisTTEls = null;
    this.xaxisOffY = 0;
    this.yaxisOffX = 0;
    this.xcrosshairsWidth = 0;
    this.ycrosshairs = null;
    this.ycrosshairsHidden = null;
    this.tooltip = null;
    this.e = null;
    this.isBarShared = !w.globals.isBarHorizontal && this.tConfig.shared;
    this.lastHoverTime = Date.now();
    this.dimensionUpdateScheduled = false;
    this.xyRatios = null;
    this.isXAxisTooltipEnabled = false;
    this.yaxisTooltips = [];
    this.allTooltipSeriesGroups = [];
    this.xAxisTicksPositions = null;
    this.dataPointsDividedHeight = 0;
    this.dataPointsDividedWidth = 0;
    this.tooltipTitle = null;
    this.legendLabels = null;
    this.ttItems = null;
    this.seriesBound = null;
    this.seriesHoverTimeout = void 0;
    this.clientX = 0;
    this.clientY = 0;
    this.barSeriesHeight = 0;
    this.tooltipRect = { x: 0, y: 0, ttWidth: 0, ttHeight: 0 };
  }
  setupDimensionCache() {
    const w = this.w;
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return;
    this.updateDimensionCache();
    if (typeof ResizeObserver !== "undefined" && !w.globals.resizeObserver) {
      w.globals.resizeObserver = new ResizeObserver(() => {
        if (!this.dimensionUpdateScheduled) {
          this.dimensionUpdateScheduled = true;
          requestAnimationFrame(() => {
            this.updateDimensionCache();
            this.dimensionUpdateScheduled = false;
          });
        }
      });
      w.globals.resizeObserver.observe(tooltipEl);
    }
  }
  updateDimensionCache() {
    const w = this.w;
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return;
    const rect = tooltipEl.getBoundingClientRect();
    w.globals.dimensionCache.tooltip = /** @type {any} */
    {
      width: rect.width,
      height: rect.height,
      lastUpdate: Date.now()
    };
  }
  getCachedDimensions() {
    const w = this.w;
    if (w.globals.dimensionCache.tooltip) {
      const cache2 = (
        /** @type {Record<string,any>} */
        w.globals.dimensionCache.tooltip
      );
      const age = Date.now() - cache2.lastUpdate;
      if (age < 1e3) {
        return {
          ttWidth: cache2.width,
          ttHeight: cache2.height
        };
      }
    }
    this.updateDimensionCache();
    const cache = (
      /** @type {Record<string,any>} */
      w.globals.dimensionCache.tooltip
    );
    return cache ? {
      ttWidth: cache.width,
      ttHeight: cache.height
    } : { ttWidth: 0, ttHeight: 0 };
  }
  /**
   * @param {{ w: import('../../types/internal').ChartStateW }} [ctx]
   * @returns {HTMLElement | null}
   */
  getElTooltip(ctx) {
    if (!ctx) ctx = this;
    if (!ctx.w.dom.baseEl) return null;
    return (
      /** @type {HTMLElement | null} */
      ctx.w.dom.baseEl.querySelector(
        ".apexcharts-tooltip:not(.apexcharts-annotation-tooltip)"
      )
    );
  }
  getElXCrosshairs() {
    return this.w.dom.baseEl.querySelector(".apexcharts-xcrosshairs");
  }
  getElGrid() {
    return this.w.dom.baseEl.querySelector(".apexcharts-grid");
  }
  /**
   * @param {import('../../types/internal').XYRatios} xyRatios
   */
  drawTooltip(xyRatios) {
    const w = this.w;
    this.xyRatios = xyRatios;
    this.isXAxisTooltipEnabled = w.config.xaxis.tooltip.enabled && w.globals.axisCharts;
    this.yaxisTooltips = w.config.yaxis.map((y) => {
      return y.show && y.tooltip.enabled && w.globals.axisCharts ? true : false;
    });
    this.allTooltipSeriesGroups = [];
    if (!w.globals.axisCharts) {
      this.showTooltipTitle = false;
    }
    const existingTooltip = this.getElTooltip();
    if (existingTooltip == null ? void 0 : existingTooltip.parentNode) {
      existingTooltip.parentNode.removeChild(existingTooltip);
    }
    this.tooltipTitle = null;
    const tooltipEl = BrowserAPIs.createElementNS(
      "http://www.w3.org/1999/xhtml",
      "div"
    );
    tooltipEl.classList.add("apexcharts-tooltip");
    if (w.config.tooltip.cssClass) {
      tooltipEl.classList.add(w.config.tooltip.cssClass);
    }
    tooltipEl.classList.add(`apexcharts-theme-${this.tConfig.theme || "light"}`);
    if (this.tConfig.fillSeriesColor) {
      tooltipEl.classList.add("apexcharts-tooltip-fill-series");
    }
    if (this.tConfig.compact) {
      tooltipEl.classList.add("apexcharts-tooltip-compact");
      if (w.config.series.length === 1) {
        tooltipEl.classList.add("apexcharts-tooltip-value-only");
      }
    }
    if (this.tConfig.style && this.tConfig.style.background) {
      tooltipEl.style.setProperty(
        "--apx-tt-bg",
        this.tConfig.style.background
      );
    }
    const isSharedMulti = this.tConfig.shared && w.config.series.length > 1 && !w.globals.isBarHorizontal && w.config.chart.type !== "heatmap";
    const shouldDrawArrow = this.tConfig.arrow && !this.tConfig.followCursor && !this.tConfig.fixed.enabled && !isSharedMulti && !this.tConfig.fillSeriesColor && w.globals.axisCharts;
    if (shouldDrawArrow) {
      const arrowEl = BrowserAPIs.createElementNS(
        "http://www.w3.org/1999/xhtml",
        "div"
      );
      arrowEl.classList.add("apexcharts-tooltip-arrow");
      tooltipEl.appendChild(arrowEl);
    }
    if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.announcements.enabled) {
      tooltipEl.setAttribute("role", "tooltip");
      tooltipEl.setAttribute("aria-live", "polite");
      tooltipEl.setAttribute("aria-atomic", "true");
      tooltipEl.setAttribute("aria-hidden", "true");
    }
    w.dom.elWrap.appendChild(tooltipEl);
    if (w.globals.axisCharts) {
      this.axesTooltip.drawXaxisTooltip();
      this.axesTooltip.drawYaxisTooltip();
      this.axesTooltip.setXCrosshairWidth();
      this.axesTooltip.handleYCrosshair();
      const xAxis = new XAxis(this.w, this.ctx, void 0);
      this.xAxisTicksPositions = xAxis.getXAxisTicksPositions();
    }
    if ((w.globals.comboCharts || this.tConfig.intersect || w.config.chart.type === "rangeBar") && !this.tConfig.shared) {
      this.showOnIntersect = true;
    }
    if (w.config.markers.size === 0 || w.globals.markers.largestSize === 0 || // batched markers have no per-point node to enlarge, so the hover dot is
    // served by the same single marker a markers.size: 0 chart uses
    w.globals.markers.batched) {
      this.marker.drawDynamicPoints();
    }
    if (w.globals.collapsedSeries.length === w.seriesData.series.length) return;
    this.dataPointsDividedHeight = w.layout.gridHeight / w.globals.dataPoints;
    this.dataPointsDividedWidth = w.layout.gridWidth / w.globals.dataPoints;
    if (this.showTooltipTitle) {
      this.tooltipTitle = BrowserAPIs.createElementNS(
        "http://www.w3.org/1999/xhtml",
        "div"
      );
      this.tooltipTitle.classList.add("apexcharts-tooltip-title");
      this.tooltipTitle.style.fontFamily = this.tConfig.style.fontFamily || w.config.chart.fontFamily;
      this.tooltipTitle.style.fontSize = this.tConfig.style.fontSize;
      tooltipEl.appendChild(this.tooltipTitle);
    }
    let ttItemsCnt = w.seriesData.series.length;
    if ((w.globals.xyCharts || w.globals.comboCharts) && this.tConfig.shared) {
      if (!this.showOnIntersect) {
        ttItemsCnt = w.seriesData.series.length;
      } else {
        ttItemsCnt = 1;
      }
    }
    this.legendLabels = w.dom.baseEl.querySelectorAll(".apexcharts-legend-text");
    this.ttItems = this.createTTElements(ttItemsCnt);
    this.addSVGEvents();
    this.setupDimensionCache();
  }
  /**
   * @param {number} ttItemsCnt
   */
  createTTElements(ttItemsCnt) {
    const w = this.w;
    const ttItems = [];
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return ttItems;
    for (let i2 = 0; i2 < ttItemsCnt; i2++) {
      const gTxt = BrowserAPIs.createElementNS(
        "http://www.w3.org/1999/xhtml",
        "div"
      );
      gTxt.classList.add(
        "apexcharts-tooltip-series-group",
        `apexcharts-tooltip-series-group-${i2}`
      );
      gTxt.style.order = String(
        w.config.tooltip.inverseOrder ? ttItemsCnt - i2 : i2 + 1
      );
      const point = BrowserAPIs.createElementNS(
        "http://www.w3.org/1999/xhtml",
        "span"
      );
      point.classList.add("apexcharts-tooltip-marker");
      if (w.config.tooltip.fillSeriesColor) {
        point.style.backgroundColor = w.globals.colors[i2];
      } else {
        point.style.color = w.globals.colors[i2];
      }
      const mShape = w.config.markers.shape;
      let shape = mShape;
      if (Array.isArray(mShape)) {
        shape = mShape[i2];
      }
      point.setAttribute("shape", shape);
      point.innerHTML = renderMarkerSVG(shape);
      gTxt.appendChild(point);
      const gYZ = BrowserAPIs.createElementNS(
        "http://www.w3.org/1999/xhtml",
        "div"
      );
      gYZ.classList.add("apexcharts-tooltip-text");
      gYZ.style.fontFamily = this.tConfig.style.fontFamily || w.config.chart.fontFamily;
      gYZ.style.fontSize = this.tConfig.style.fontSize;
      ["y", "goals", "z"].forEach((g) => {
        const gValText = BrowserAPIs.createElementNS(
          "http://www.w3.org/1999/xhtml",
          "div"
        );
        gValText.classList.add(`apexcharts-tooltip-${g}-group`);
        const txtLabel = BrowserAPIs.createElementNS(
          "http://www.w3.org/1999/xhtml",
          "span"
        );
        txtLabel.classList.add(`apexcharts-tooltip-text-${g}-label`);
        gValText.appendChild(txtLabel);
        const txtValue = BrowserAPIs.createElementNS(
          "http://www.w3.org/1999/xhtml",
          "span"
        );
        txtValue.classList.add(`apexcharts-tooltip-text-${g}-value`);
        gValText.appendChild(txtValue);
        gYZ.appendChild(gValText);
      });
      gTxt.appendChild(gYZ);
      tooltipEl.appendChild(gTxt);
      ttItems.push(gTxt);
    }
    return ttItems;
  }
  addSVGEvents() {
    const w = this.w;
    const type = w.config.chart.type;
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return;
    const commonBar = !!(type === "bar" || type === "candlestick" || type === "boxPlot" || type === "violin" || type === "rangeBar");
    const chartWithmarkers = type === "area" || type === "line" || type === "scatter" || type === "bubble" || type === "radar";
    const isPolarMarkerChart = chartWithmarkers && !w.globals.xyCharts;
    const hoverArea = w.dom.Paper.node;
    const elGrid = this.getElGrid();
    if (elGrid) {
      this.seriesBound = elGrid.getBoundingClientRect();
    }
    const tooltipY = [];
    const tooltipX = [];
    const seriesHoverParams = {
      hoverArea,
      elGrid,
      tooltipEl,
      tooltipY,
      tooltipX,
      ttItems: this.ttItems
    };
    let points;
    if (w.globals.axisCharts) {
      if (chartWithmarkers) {
        points = w.dom.baseEl.querySelectorAll(
          ".apexcharts-series[data\\:longestSeries='true'] .apexcharts-marker"
        );
      } else if (commonBar) {
        points = w.dom.baseEl.querySelectorAll(
          ".apexcharts-series .apexcharts-bar-area, .apexcharts-series .apexcharts-candlestick-area, .apexcharts-series .apexcharts-boxPlot-area, .apexcharts-series .apexcharts-violin-area, .apexcharts-series .apexcharts-rangebar-area"
        );
      } else if (type === "heatmap" || type === "treemap") {
        points = w.dom.baseEl.querySelectorAll(
          ".apexcharts-series .apexcharts-heatmap, .apexcharts-series .apexcharts-treemap"
        );
      }
      if (points && points.length) {
        for (let p = 0; p < points.length; p++) {
          tooltipY.push(points[p].getAttribute("cy"));
          tooltipX.push(points[p].getAttribute("cx"));
        }
      }
    }
    const validSharedChartTypes = w.globals.xyCharts && !this.showOnIntersect || w.globals.comboCharts && !this.showOnIntersect || commonBar && this.tooltipUtil.hasBars() && this.tConfig.shared;
    if (validSharedChartTypes) {
      this.addPathsEventListeners([hoverArea], seriesHoverParams);
    } else if (commonBar && !w.globals.comboCharts || chartWithmarkers && this.showOnIntersect || isPolarMarkerChart) {
      this.addDatapointEventsListeners(seriesHoverParams);
    } else if (type === "heatmap" && w.globals.activeRenderer && w.globals.activeRenderer.kind === "canvas") {
      this.addPathsEventListeners([hoverArea], seriesHoverParams);
    } else if (!w.globals.axisCharts || type === "heatmap" || type === "treemap") {
      const seriesAll = w.dom.baseEl.querySelectorAll(".apexcharts-series");
      this.addPathsEventListeners(seriesAll, seriesHoverParams);
    }
    if (this.showOnIntersect) {
      const lineAreaPoints = w.dom.baseEl.querySelectorAll(
        ".apexcharts-line-series .apexcharts-marker, .apexcharts-area-series .apexcharts-marker"
      );
      if (lineAreaPoints.length > 0) {
        this.addPathsEventListeners(lineAreaPoints, seriesHoverParams);
      }
      if (this.tooltipUtil.hasBars() && !this.tConfig.shared) {
        this.addDatapointEventsListeners(seriesHoverParams);
      }
    }
  }
  drawFixedTooltipRect() {
    const w = this.w;
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return { x: 0, y: 0, ttWidth: 0, ttHeight: 0 };
    const tooltipRect = tooltipEl.getBoundingClientRect();
    const ttWidth = tooltipRect.width + 10;
    const ttHeight = tooltipRect.height + 10;
    let x = this.tConfig.fixed.offsetX;
    let y = this.tConfig.fixed.offsetY;
    const fixed = this.tConfig.fixed.position.toLowerCase();
    if (fixed.indexOf("right") > -1) {
      x = x + w.globals.svgWidth - ttWidth + 10;
    }
    if (fixed.indexOf("bottom") > -1) {
      y = y + w.globals.svgHeight - ttHeight - 10;
    }
    this.tooltipPosition.applyTooltipPosition(tooltipEl, { x, y });
    return {
      x,
      y,
      ttWidth,
      ttHeight
    };
  }
  /**
   * @param {Record<string, any>} seriesHoverParams
   */
  addDatapointEventsListeners(seriesHoverParams) {
    const w = this.w;
    const points = w.dom.baseEl.querySelectorAll(
      ".apexcharts-series-markers .apexcharts-marker, .apexcharts-bar-area, .apexcharts-candlestick-area, .apexcharts-boxPlot-area, .apexcharts-rangebar-area"
    );
    this.addPathsEventListeners(points, seriesHoverParams);
  }
  /**
   * @param {any} paths
   * @param {Record<string, any>} opts
   */
  addPathsEventListeners(paths, opts) {
    const self = this;
    for (let p = 0; p < paths.length; p++) {
      const extendedOpts = {
        paths: paths[p],
        tooltipEl: opts.tooltipEl,
        tooltipY: opts.tooltipY,
        tooltipX: opts.tooltipX,
        elGrid: opts.elGrid,
        hoverArea: opts.hoverArea,
        ttItems: opts.ttItems
      };
      const events = [
        "mousemove",
        "mouseup",
        "touchmove",
        "mouseout",
        "touchend"
      ];
      events.map((ev) => {
        return paths[p].addEventListener(
          ev,
          self.onSeriesHover.bind(self, extendedOpts),
          { capture: false, passive: true }
        );
      });
    }
  }
  /*
   ** Check to see if the tooltips should be updated based on a mouse / touch event
   * @param {Record<string, any>} opt
   * @param {Event} e
   */
  /** @param {Record<string, any>} opt @param {any} e */
  onSeriesHover(opt, e2) {
    Utils2.hoverTarget(e2);
    const targetDelay = 20;
    const timeSinceLastUpdate = Date.now() - this.lastHoverTime;
    if (timeSinceLastUpdate >= targetDelay) {
      this.seriesHover(opt, e2);
    } else {
      clearTimeout(this.seriesHoverTimeout);
      this.seriesHoverTimeout = setTimeout(() => {
        this.seriesHover(opt, e2);
      }, targetDelay - timeSinceLastUpdate);
    }
  }
  /*
   ** The actual series hover function
   * @param {Record<string, any>} opt
   * @param {Event} e
   */
  /** @param {Record<string, any>} opt @param {any} e */
  seriesHover(opt, e2) {
    if (this.w.globals.isDestroyed) return;
    this.lastHoverTime = Date.now();
    let chartGroups = [];
    const w = this.w;
    const isCfMember = (chart) => {
      var _a, _b, _c;
      const link = (_c = (_b = (_a = chart == null ? void 0 : chart.w) == null ? void 0 : _a.config) == null ? void 0 : _b.chart) == null ? void 0 : _c.link;
      return !!(link && typeof link.dimension === "function");
    };
    if (w.config.chart.group && !isCfMember(this.ctx)) {
      chartGroups = this.ctx.getSyncedCharts().filter((ch) => !isCfMember(ch));
    }
    if (w.globals.axisCharts && (w.globals.minX === -Infinity && w.globals.maxX === Infinity || w.globals.dataPoints === 0)) {
      return;
    }
    if (chartGroups.length) {
      chartGroups.forEach((ch) => {
        const tooltipEl = this.getElTooltip(ch);
        const newOpts = {
          paths: opt.paths,
          tooltipEl,
          tooltipY: opt.tooltipY,
          tooltipX: opt.tooltipX,
          elGrid: opt.elGrid,
          hoverArea: opt.hoverArea,
          ttItems: ch.w.globals.tooltip.ttItems
        };
        if (ch.w.globals.minX === this.w.globals.minX && ch.w.globals.maxX === this.w.globals.maxX) {
          ch.w.globals.tooltip.seriesHoverByContext({
            chartCtx: ch,
            ttCtx: ch.w.globals.tooltip,
            opt: newOpts,
            e: e2
          });
        }
      });
    } else {
      this.seriesHoverByContext({
        chartCtx: this.ctx,
        ttCtx: this.w.globals.tooltip,
        opt,
        e: e2
      });
    }
  }
  /** @param {{chartCtx: any, ttCtx: any, opt: any, e: any}} opts */
  seriesHoverByContext({ chartCtx, ttCtx, opt, e: e2 }) {
    var _a;
    const w = chartCtx.w;
    const tooltipEl = this.getElTooltip(chartCtx);
    if (!tooltipEl) return;
    const cachedDims = ttCtx.getCachedDimensions();
    ttCtx.tooltipRect = {
      x: 0,
      y: 0,
      ttWidth: cachedDims.ttWidth,
      ttHeight: cachedDims.ttHeight
    };
    ttCtx.e = e2;
    if (ttCtx.tooltipUtil.hasBars() && !w.globals.comboCharts && !ttCtx.isBarShared) {
      if (this.tConfig.onDatasetHover.highlightDataSeries) {
        const series = new Series(chartCtx.w);
        series.toggleSeriesOnHover(e2, (_a = Utils2.hoverTarget(e2)) == null ? void 0 : _a.parentNode);
      }
    }
    if (w.globals.axisCharts) {
      ttCtx.axisChartsTooltips({
        e: e2,
        opt,
        tooltipRect: ttCtx.tooltipRect
      });
    } else {
      ttCtx.nonAxisChartsTooltips({
        e: e2,
        opt,
        tooltipRect: ttCtx.tooltipRect
      });
    }
    if (ttCtx.fixedTooltip) {
      ttCtx.drawFixedTooltipRect();
    }
  }
  // tooltip handling for line/area/bar/columns/scatter
  /** @param {{e: any, opt: any}} opts */
  axisChartsTooltips({ e: e2, opt }) {
    var _a;
    const w = this.w;
    let x, y;
    if (!opt.elGrid) return;
    const seriesBound = opt.elGrid.getBoundingClientRect();
    const clientX = e2.type === "touchmove" ? e2.touches[0].clientX : e2.clientX;
    const clientY = e2.type === "touchmove" ? e2.touches[0].clientY : e2.clientY;
    this.clientY = clientY;
    this.clientX = clientX;
    w.interact.capturedSeriesIndex = -1;
    w.interact.capturedDataPointIndex = -1;
    if (clientY < seriesBound.top || clientY > seriesBound.top + seriesBound.height) {
      this.handleMouseOut(opt);
      return;
    }
    if (w.dom.elWrap.querySelector(
      ".apexcharts-annotation-tooltip.apexcharts-active"
    )) {
      this.handleMouseOut(opt);
      return;
    }
    if (Array.isArray(this.tConfig.enabledOnSeries) && !w.config.tooltip.shared) {
      const index = parseInt(opt.paths.getAttribute("index"), 10);
      if (this.tConfig.enabledOnSeries.indexOf(index) < 0) {
        this.handleMouseOut(opt);
        return;
      }
    }
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return;
    const xcrosshairs = this.getElXCrosshairs();
    const isCellChart = ["heatmap", "treemap"].includes(w.config.chart.type);
    let syncedCharts = [];
    if (w.config.chart.group && !isCellChart) {
      syncedCharts = this.ctx.getSyncedCharts();
    }
    const isStickyTooltip = w.globals.xyCharts || w.config.chart.type === "bar" && !w.globals.isBarHorizontal && this.tooltipUtil.hasBars() && this.tConfig.shared || w.globals.comboCharts && this.tooltipUtil.hasBars();
    if (e2.type === "mousemove" || e2.type === "touchmove" || e2.type === "mouseup") {
      if (w.globals.collapsedSeries.length + w.globals.ancillaryCollapsedSeries.length === w.seriesData.series.length) {
        return;
      }
      if (xcrosshairs !== null) {
        xcrosshairs.classList.add("apexcharts-active");
      }
      const hasYAxisTooltip = (_a = this.yaxisTooltips) == null ? void 0 : _a.filter(
        (b) => {
          return b === true;
        }
      );
      const _yc = (
        /** @type {any} */
        this.ycrosshairs
      );
      if (_yc !== null && (hasYAxisTooltip == null ? void 0 : hasYAxisTooltip.length)) {
        _yc.classList.add("apexcharts-active");
      }
      if (!isCellChart && (isStickyTooltip && !this.showOnIntersect || syncedCharts.length > 1)) {
        this.handleStickyTooltip(e2, clientX, clientY, opt);
      } else {
        if (w.config.chart.type === "heatmap" || w.config.chart.type === "treemap") {
          const markerXY = this.intersect.handleHeatTreeTooltip({
            e: e2,
            opt,
            x,
            y,
            type: w.config.chart.type
          });
          if (markerXY.noHit) {
            this.handleMouseOut(opt);
            return;
          }
          x = markerXY.x;
          y = markerXY.y;
          if (!markerXY.positioned) {
            tooltipEl.style.left = x + "px";
            tooltipEl.style.top = y + "px";
          }
        } else {
          if (this.tooltipUtil.hasBars()) {
            this.intersect.handleBarTooltip({
              e: e2,
              opt
            });
          }
          if (this.tooltipUtil.hasMarkers(0)) {
            this.intersect.handleMarkerTooltip({
              e: e2,
              opt,
              x,
              y
            });
          }
        }
      }
      if (this.yaxisTooltips && this.yaxisTooltips.length) {
        for (let yt = 0; yt < w.config.yaxis.length; yt++) {
          this.axesTooltip.drawYaxisTooltipText(
            yt,
            clientY,
            /** @type {import('../../types/internal').XYRatios} */
            this.xyRatios
          );
        }
      }
      w.dom.baseEl.classList.add("apexcharts-tooltip-active");
      opt.tooltipEl.classList.add("apexcharts-active");
      if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.announcements.enabled) {
        opt.tooltipEl.removeAttribute("aria-hidden");
      }
    } else if (e2.type === "mouseout" || e2.type === "touchend") {
      this.handleMouseOut(opt);
    }
  }
  /**
   * Where a pie / donut / polarArea slice wants its tooltip anchored, in
   * elWrap-relative pixels.
   *
   * Pie.js stamps the arc centroid on the path as `data:cx` / `data:cy`, in
   * the slice's OWN user space: below the inner group's translate, and below
   * the pie group's customScale. Reading those as if they were SVG-root
   * coordinates silently drops both, and the inner translate is exactly the
   * offset that centres a pie in a chart wider than it is tall, so on such a
   * chart the tooltip landed a couple of hundred pixels to the left of the
   * slice it described. The element's screen matrix accounts for every
   * ancestor transform at once, including the translate a slice picks up while
   * it is slid out on click.
   *
   * @param {any} el a slice path carrying data:cx / data:cy
   * @returns {{x: number, y: number} | null} null when it carries neither
   */
  getSliceAnchor(el) {
    var _a, _b;
    const w = this.w;
    const cx = parseFloat((_a = el == null ? void 0 : el.getAttribute("data:cx")) != null ? _a : "");
    const cy = parseFloat((_b = el == null ? void 0 : el.getAttribute("data:cy")) != null ? _b : "");
    if (isNaN(cx) || isNaN(cy)) return null;
    const wrapBound = w.dom.elWrap.getBoundingClientRect();
    const ctm = typeof el.getScreenCTM === "function" ? el.getScreenCTM() : null;
    if (!ctm) {
      const svgBound = w.dom.Paper.node.getBoundingClientRect();
      return {
        x: svgBound.left - wrapBound.left + cx,
        y: svgBound.top - wrapBound.top + cy
      };
    }
    return {
      x: ctm.a * cx + ctm.c * cy + ctm.e - wrapBound.left,
      y: ctm.b * cx + ctm.d * cy + ctm.f - wrapBound.top
    };
  }
  // tooltip handling for pie/donuts
  /** @param {{e: any, opt: any, tooltipRect: any}} opts */
  nonAxisChartsTooltips({ e: e2, opt, tooltipRect }) {
    var _a, _b, _c, _d;
    const w = this.w;
    const rel = opt.paths.getAttribute("rel");
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return;
    const seriesBound = w.dom.elWrap.getBoundingClientRect();
    if (e2.type === "mousemove" || e2.type === "touchmove") {
      w.dom.baseEl.classList.add("apexcharts-tooltip-active");
      tooltipEl.classList.add("apexcharts-active");
      if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.announcements.enabled) {
        tooltipEl.removeAttribute("aria-hidden");
      }
      if (w.config.chart.type === "unit") {
        const hovered = Utils2.hoverTarget(e2);
        const unitDot = hovered && typeof hovered.closest === "function" ? hovered.closest(".apexcharts-unit-area") : null;
        if (!unitDot) return;
        this.renderUnitTooltip(unitDot);
      } else {
        this.tooltipLabels.drawSeriesTexts({
          ttItems: opt.ttItems,
          i: parseInt(rel, 10) - 1,
          shared: false
        });
      }
      let x, y;
      const arcPath = opt.paths.querySelector("path[data\\:cx]") || opt.paths;
      const anchor = w.config.tooltip.intersect ? this.getSliceAnchor(arcPath) : null;
      if (anchor) {
        x = anchor.x - tooltipRect.ttWidth / 2;
        y = anchor.y - tooltipRect.ttHeight - 10;
      } else {
        x = ((_a = w.interact.clientX) != null ? _a : 0) - seriesBound.left - tooltipRect.ttWidth / 2;
        y = ((_b = w.interact.clientY) != null ? _b : 0) - seriesBound.top - tooltipRect.ttHeight - 10;
      }
      tooltipEl.style.left = x + "px";
      tooltipEl.style.top = y + "px";
      if (w.config.legend.tooltipHoverFormatter) {
        const legendFormatter = w.config.legend.tooltipHoverFormatter;
        const i2 = rel - 1;
        const legendEl = (
          /** @type {HTMLElement | undefined} */
          (_c = this.legendLabels) == null ? void 0 : _c[i2]
        );
        if (!legendEl) return;
        const legendName = legendEl.getAttribute("data:default-text");
        const text = legendFormatter(legendName, {
          seriesIndex: i2,
          dataPointIndex: i2,
          w
        });
        legendEl.innerHTML = text;
      }
    } else if (e2.type === "mouseout" || e2.type === "touchend") {
      tooltipEl.classList.remove("apexcharts-active");
      w.dom.baseEl.classList.remove("apexcharts-tooltip-active");
      if (w.config.legend.tooltipHoverFormatter) {
        (_d = this.legendLabels) == null ? void 0 : _d.forEach((l2) => {
          const defaultText = l2.getAttribute("data:default-text");
          l2.innerHTML = decodeURIComponent(
            defaultText != null ? defaultText : ""
          );
        });
      }
    }
  }
  /**
   * Fill the tooltip for one hovered unit-chart dot. Each dot carries `i` (its
   * category / series index) and `j` (its index within that category). The
   * default body reads "#<j+1> of <count>"; `plotOptions.unit.tooltip.formatter`
   * overrides just the body text (it is handed i/j so it can look up per-unit
   * data), and the global `tooltip.custom` still overrides the whole markup.
   * @param {Element} dotEl the hovered `.apexcharts-unit-area` node
   */
  renderUnitTooltip(dotEl) {
    var _a, _b, _c, _d, _e;
    const w = this.w;
    const tooltipEl = this.getElTooltip();
    if (!tooltipEl) return;
    const i2 = parseInt(dotEl.getAttribute("i") || "0", 10);
    const j = parseInt(dotEl.getAttribute("j") || "0", 10);
    if (typeof w.config.tooltip.custom === "function") {
      this.tooltipLabels.handleCustomTooltip({ i: i2, j, y1: null, y2: null, w });
      return;
    }
    const seriesName = w.seriesData.seriesNames[i2] || `series-${i2 + 1}`;
    const value = Math.round(Number(w.seriesData.series[i2]) || 0);
    const group = dotEl.parentNode;
    const count = group && group.querySelectorAll ? group.querySelectorAll(".apexcharts-unit-area").length : value;
    const unitOpts = w.config.plotOptions.unit || {};
    const unitValue = unitOpts.unitValue > 0 ? unitOpts.unitValue : 1;
    const catData = w.seriesData.unitData && w.seriesData.unitData[i2];
    const datum = catData ? catData[j] : void 0;
    const datumObj = datum && typeof datum === "object" ? datum : null;
    const color = datumObj && datumObj.fillColor || w.globals.colors && w.globals.colors[i2] || "#008FFB";
    let body;
    const fmt = unitOpts.tooltip && unitOpts.tooltip.formatter;
    if (typeof fmt === "function") {
      body = fmt({
        seriesName,
        seriesIndex: i2,
        dataPointIndex: j,
        count,
        value,
        unitValue,
        datum,
        color,
        w
      });
    } else if (datum !== void 0 && datum !== null) {
      const label = datumObj ? (_c = (_b = (_a = datumObj.name) != null ? _a : datumObj.label) != null ? _b : datumObj.x) != null ? _c : null : null;
      const dVal = datumObj ? (_e = (_d = datumObj.value) != null ? _d : datumObj.y) != null ? _e : null : datum;
      body = label != null && dVal != null ? `${label}: ${dVal}` : label != null ? String(label) : dVal != null ? String(dVal) : `#${(j + 1).toLocaleString()} of ${count.toLocaleString()}`;
    } else {
      body = `#${(j + 1).toLocaleString()} of ${count.toLocaleString()}`;
      if (unitValue !== 1) {
        body += ` &middot; ${unitValue.toLocaleString()} per dot`;
      }
    }
    const fontFamily = w.config.chart.fontFamily || "inherit";
    const fontSize = w.config.tooltip.style && w.config.tooltip.style.fontSize || "12px";
    const arrowEl = tooltipEl.querySelector(".apexcharts-tooltip-arrow");
    tooltipEl.innerHTML = `<div class="apexcharts-tooltip-title" style="font-family: ${fontFamily}; font-size: ${fontSize};">${seriesName}</div><div class="apexcharts-tooltip-series-group apexcharts-active" style="display: flex;"><span class="apexcharts-tooltip-marker" style="background-color: ${color};"></span><div class="apexcharts-tooltip-text" style="font-family: ${fontFamily}; font-size: ${fontSize};"><div class="apexcharts-tooltip-y-group"><span class="apexcharts-tooltip-text-y-value">${body}</span></div></div></div>`;
    if (arrowEl) tooltipEl.appendChild(arrowEl);
    const rect = tooltipEl.getBoundingClientRect();
    this.tooltipRect.ttWidth = rect.width;
    this.tooltipRect.ttHeight = rect.height;
  }
  /**
   * @param {Event} e
   * @param {number} clientX
   * @param {number} clientY
   * @param {Record<string, any>} opt
   */
  handleStickyTooltip(e2, clientX, clientY, opt) {
    const w = this.w;
    const capj = this.tooltipUtil.getNearestValues({
      context: this,
      hoverArea: opt.hoverArea,
      elGrid: opt.elGrid,
      clientX,
      clientY
    });
    const j = capj.j;
    let capturedSeries = capj.capturedSeries;
    if (capturedSeries !== null && w.globals.collapsedSeriesIndices.includes(capturedSeries != null ? capturedSeries : -1))
      capturedSeries = null;
    const edgePad = w.globals.barPadForNumericAxis || 0;
    if (capj.hoverX < -edgePad || capj.hoverX > w.layout.gridWidth + edgePad) {
      this.handleMouseOut(opt);
      return;
    }
    if (capturedSeries !== null) {
      this.handleStickyCapturedSeries(e2, capturedSeries != null ? capturedSeries : -1, opt, j != null ? j : 0);
    } else {
      if (this.tooltipUtil.isXoverlap(j != null ? j : 0) || w.globals.isBarHorizontal) {
        const firstVisibleSeries = w.seriesData.series.findIndex(
          /**
           * @param {any} s
           * @param {number} i
           */
          (s2, i2) => !w.globals.collapsedSeriesIndices.includes(i2)
        );
        this.create(e2, this, firstVisibleSeries, j != null ? j : 0, opt.ttItems);
      }
    }
  }
  /**
   * @param {Event} e
   * @param {number} capturedSeries
   * @param {Record<string, any>} opt
   * @param {number} j
   */
  handleStickyCapturedSeries(e2, capturedSeries, opt, j) {
    const w = this.w;
    if (!this.tConfig.shared) {
      const ignoreNull = w.seriesData.series[capturedSeries][j] === null;
      if (ignoreNull) {
        this.handleMouseOut(opt);
        return;
      }
    }
    if (typeof w.seriesData.series[capturedSeries][j] !== "undefined") {
      if (this.tConfig.shared && this.tooltipUtil.isXoverlap(j) && this.tooltipUtil.isInitialSeriesSameLen()) {
        this.create(e2, this, capturedSeries, j, opt.ttItems);
      } else {
        this.create(e2, this, capturedSeries, j, opt.ttItems, false);
      }
    } else {
      if (this.tooltipUtil.isXoverlap(j)) {
        const firstVisibleSeries = w.seriesData.series.findIndex(
          /**
           * @param {any} s
           * @param {number} i
           */
          (s2, i2) => !w.globals.collapsedSeriesIndices.includes(i2)
        );
        this.create(e2, this, firstVisibleSeries, j, opt.ttItems);
      }
    }
  }
  deactivateHoverFilter() {
    const w = this.w;
    const graphics = new Graphics(this.w, this.ctx);
    const allPaths = w.dom.Paper.find(`.apexcharts-bar-area`);
    for (let b = 0; b < allPaths.length; b++) {
      graphics.pathMouseLeave(
        /** @type {any} */
        allPaths[b],
        /** @type {any} */
        void 0
      );
    }
  }
  /**
   * @param {Record<string, any>} opt
   */
  handleMouseOut(opt) {
    var _a, _b;
    const w = this.w;
    const xcrosshairs = this.getElXCrosshairs();
    w.dom.baseEl.classList.remove("apexcharts-tooltip-active");
    opt.tooltipEl.classList.remove("apexcharts-active");
    delete opt.tooltipEl.dataset.positioned;
    if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.announcements.enabled) {
      opt.tooltipEl.setAttribute("aria-hidden", "true");
    }
    this.deactivateHoverFilter();
    if (w.config.chart.type !== "bubble") {
      this.marker.resetPointsSize();
    }
    if (xcrosshairs !== null) {
      xcrosshairs.classList.remove("apexcharts-active");
    }
    const _yc2 = (
      /** @type {any} */
      this.ycrosshairs
    );
    if (_yc2 !== null) {
      _yc2.classList.remove("apexcharts-active");
    }
    if (this.isXAxisTooltipEnabled) {
      (_a = this.xaxisTooltip) == null ? void 0 : _a.classList.remove("apexcharts-active");
    }
    if (this.yaxisTooltips && this.yaxisTooltips.length) {
      if (this.yaxisTTEls === null) {
        this.yaxisTTEls = /** @type {HTMLElement[]} */
        [
          ...w.dom.baseEl.querySelectorAll(".apexcharts-yaxistooltip")
        ];
      }
      for (let i2 = 0; i2 < this.yaxisTTEls.length; i2++) {
        this.yaxisTTEls[i2].classList.remove("apexcharts-active");
      }
    }
    if (w.config.legend.tooltipHoverFormatter) {
      (_b = this.legendLabels) == null ? void 0 : _b.forEach((l2) => {
        const defaultText = l2.getAttribute("data:default-text");
        l2.innerHTML = decodeURIComponent(
          defaultText != null ? defaultText : ""
        );
      });
    }
  }
  /**
   * @param {Event} e
   * @param {number} seriesIndex
   * @param {number} dataPointIndex
   */
  markerClick(e2, seriesIndex, dataPointIndex) {
    const w = this.w;
    if (typeof w.config.chart.events.markerClick === "function") {
      w.config.chart.events.markerClick(e2, this.ctx, {
        seriesIndex,
        dataPointIndex,
        w
      });
    }
    this.ctx.events.fireEvent("markerClick", [
      e2,
      this.ctx,
      { seriesIndex, dataPointIndex, w }
    ]);
  }
  /**
   * Marks (#11): whether the chart's type (or any series' type) is a registered
   * custom series, whose marks live outside the built-in marker DOM.
   * @returns {boolean}
   */
  _hasCustomSeries() {
    const w = this.w;
    if (isCustom(w.config.chart.type)) return true;
    const series = w.config.series || [];
    return series.some(
      (s2) => s2 && s2.type && isCustom(s2.type)
    );
  }
  /**
   * @param {Event} e
   * @param {any} context
   * @param {number} capturedSeries
   * @param {number} j
   * @param {any} ttItems
   * @param {boolean | null} shared
   */
  create(e2, context, capturedSeries, j, ttItems, shared = null) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
    const w = this.w;
    const ttCtx = context;
    if (e2.type === "mouseup") {
      this.markerClick(e2, capturedSeries, j);
    }
    if (shared === null) shared = this.tConfig.shared;
    const hasMarkers = this.tooltipUtil.hasMarkers(capturedSeries);
    const canvasMode = ((_b = (_a = this.ctx) == null ? void 0 : _a.renderer) == null ? void 0 : _b.kind) === "canvas";
    const canvasNonBar = canvasMode && !this.tooltipUtil.hasBars();
    const marksMode = !canvasMode && !hasMarkers && !this.tooltipUtil.hasBars() && this._hasCustomSeries();
    const dynamicPoints = canvasNonBar || marksMode;
    const bars = this.tooltipUtil.getElBars();
    const handlePoints = () => {
      if (w.globals.markers.largestSize > 0 && !canvasMode && !w.globals.markers.batched) {
        ttCtx.marker.enlargePoints(j);
      } else {
        ttCtx.tooltipPosition.moveDynamicPointsOnHover(j);
      }
    };
    if (w.config.legend.tooltipHoverFormatter) {
      const legendFormatter = w.config.legend.tooltipHoverFormatter;
      const els = (
        /** @type {HTMLElement[]} */
        Array.from((_c = this.legendLabels) != null ? _c : [])
      );
      els.forEach((l2) => {
        const legendName = l2.getAttribute("data:default-text");
        l2.innerHTML = decodeURIComponent(legendName != null ? legendName : "");
      });
      for (let i2 = 0; i2 < els.length; i2++) {
        const l2 = els[i2];
        const lsIndex = parseInt((_d = l2.getAttribute("i")) != null ? _d : "", 10);
        const legendName = decodeURIComponent(
          (_e = l2.getAttribute("data:default-text")) != null ? _e : ""
        );
        const text = legendFormatter(legendName, {
          seriesIndex: shared ? lsIndex : capturedSeries,
          dataPointIndex: j,
          w
        });
        if (!shared) {
          l2.innerHTML = lsIndex === capturedSeries ? text : legendName;
          if (capturedSeries === lsIndex) {
            break;
          }
        } else {
          l2.innerHTML = w.globals.collapsedSeriesIndices.indexOf(lsIndex) < 0 ? text : legendName;
        }
      }
    }
    const _rangeData = (
      /** @type {any} */
      w.rangeData
    );
    const commonSeriesTextsParams = __spreadValues(__spreadValues({
      ttItems,
      i: capturedSeries,
      j
    }, ((_i = (_h = (_g = (_f = _rangeData.seriesRange) == null ? void 0 : _f[capturedSeries]) == null ? void 0 : _g[j]) == null ? void 0 : _h.y[0]) == null ? void 0 : _i.y1) !== void 0 && {
      y1: (_m = (_l = (_k = (_j = _rangeData.seriesRange) == null ? void 0 : _j[capturedSeries]) == null ? void 0 : _k[j]) == null ? void 0 : _l.y[0]) == null ? void 0 : _m.y1
    }), ((_q = (_p = (_o = (_n = _rangeData.seriesRange) == null ? void 0 : _n[capturedSeries]) == null ? void 0 : _o[j]) == null ? void 0 : _p.y[0]) == null ? void 0 : _q.y2) !== void 0 && {
      y2: (_u = (_t = (_s = (_r = _rangeData.seriesRange) == null ? void 0 : _r[capturedSeries]) == null ? void 0 : _s[j]) == null ? void 0 : _t.y[0]) == null ? void 0 : _u.y2
    });
    if (shared) {
      ttCtx.tooltipLabels.drawSeriesTexts(__spreadProps(__spreadValues({}, commonSeriesTextsParams), {
        shared: this.showOnIntersect ? false : this.tConfig.shared
      }));
      if (hasMarkers || dynamicPoints) {
        handlePoints();
      } else if (this.tooltipUtil.hasBars()) {
        if (canvasMode) {
          ttCtx.tooltipPosition.moveStickyTooltipOverBars(j, capturedSeries);
        }
        this.barSeriesHeight = this.tooltipUtil.getBarsHeight(
          /** @type {any[]} */
          [...bars]
        );
        if (this.barSeriesHeight > 0) {
          const graphics = new Graphics(this.w, this.ctx);
          const paths = w.dom.Paper.find(`.apexcharts-bar-area[j='${j}']`);
          this.deactivateHoverFilter();
          const points = ttCtx.tooltipUtil.getAllMarkers(true);
          if (points.length && !this.barSeriesHeight) {
            handlePoints();
          }
          ttCtx.tooltipPosition.moveStickyTooltipOverBars(j, capturedSeries);
          for (let b = 0; b < paths.length; b++) {
            graphics.pathMouseEnter(
              /** @type {any} */
              paths[b],
              /** @type {any} */
              void 0
            );
          }
        }
      }
    } else {
      ttCtx.tooltipLabels.drawSeriesTexts(__spreadValues({
        shared: false
      }, commonSeriesTextsParams));
      if (this.tooltipUtil.hasBars()) {
        ttCtx.tooltipPosition.moveStickyTooltipOverBars(j, capturedSeries);
      }
      if (hasMarkers) {
        ttCtx.tooltipPosition.moveMarkers(capturedSeries, j);
      } else if (dynamicPoints) {
        ttCtx.tooltipPosition.moveDynamicPointOnHover(j, capturedSeries);
      }
    }
  }
}
class SvgRenderer {
  /**
   * @param {any} w
   * @param {any} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.kind = "svg";
  }
  // ── lifecycle (SVG builds its layer via the existing plotChartType flow) ──
  beginSeries() {
  }
  present() {
    return null;
  }
  clear() {
  }
  // ── emit primitives (delegate to Graphics: the canvas renderer mirrors
  //    this exact surface) ──
  /** @param {any} attrs */
  group(attrs) {
    return this.ctx.graphics.group(attrs);
  }
  /** @param {any} opts */
  drawPath(opts) {
    return this.ctx.graphics.drawPath(opts);
  }
  /** @param {any[]} args */
  drawLine(...args) {
    return this.ctx.graphics.drawLine(...args);
  }
  /** @param {any[]} args */
  drawRect(...args) {
    return this.ctx.graphics.drawRect(...args);
  }
  /**
   * @param {number} r
   * @param {any} attrs
   */
  drawCircle(r2, attrs) {
    return this.ctx.graphics.drawCircle(r2, attrs);
  }
  /** @param {any} opts */
  drawText(opts) {
    return this.ctx.graphics.drawText(opts);
  }
  /**
   * A series mark path (animation-aware). Faithful passthrough to Graphics.
   * Note: the SVG emit path in the per-type draw() methods routes through
   * `seriesEmitter`, which returns the caller's own `Graphics` in SVG mode: so
   * this method is the interface contract surface (mirrored by the canvas
   * renderer), not the hot path.
   * @param {any} opts
   */
  renderPaths(opts) {
    return this.ctx.graphics.renderPaths(opts);
  }
  /**
   * @param {number} x
   * @param {number} y
   * @param {any} opts
   */
  drawMarker(x, y, opts = {}) {
    return this.ctx.graphics.drawMarker(x, y, opts);
  }
  // ── capabilities: SVG supports everything the interface enumerates ──
  /** @param {string} _feature */
  supports(_feature) {
    return true;
  }
  // ── interaction: the DOM does this natively in SVG mode ──
  hitTest() {
    return null;
  }
  restyle() {
  }
  // ── export: SVG serializes directly; no bitmap to composite ──
  toBitmap() {
    return null;
  }
  destroy() {
  }
}
const RENDERER_REGISTRY_KEY = "__apexcharts_renderers__";
function getRendererRegistry() {
  const g = (
    /** @type {any} */
    globalThis
  );
  if (!g[RENDERER_REGISTRY_KEY]) g[RENDERER_REGISTRY_KEY] = /* @__PURE__ */ new Map();
  return g[RENDERER_REGISTRY_KEY];
}
class RendererController {
  /** Same Map as getRendererRegistry(); exposed for tests/tooling. */
  static get _rendererRegistry() {
    return getRendererRegistry();
  }
  /**
   * @param {string} kind
   * @param {(w: any, ctx: any) => any} factory
   */
  static registerRenderer(kind, factory) {
    getRendererRegistry().set(kind, factory);
  }
  /**
   * Remove a registered renderer backend (tests / hot-reload). Charts fall
   * back to SVG on their next resolve().
   * @param {string} kind
   */
  static unregisterRenderer(kind) {
    getRendererRegistry().delete(kind);
  }
  /**
   * @param {any} w
   * @param {any} ctx
   */
  constructor(w, ctx) {
    this.w = w;
    this.ctx = ctx;
    this.svg = new SvgRenderer(w, ctx);
    this.active = this.svg;
    this._activeKind = "svg";
    this._instances = {};
  }
  /**
   * The kind selection WANTS (before availability/fallback). Pure.
   * @returns {import('../renderers/Renderer').RendererKind}
   */
  _desiredKind() {
    const cfg = this.w.config.chart;
    const mode = cfg.renderer || "svg";
    if (!Environment.isBrowser()) return "svg";
    if (mode === "svg") return "svg";
    if (hasCanvasUnsupportedFeature(this.w)) return "svg";
    if (mode === "canvas") return "canvas";
    const marks = computeMarkCount(this.w);
    const threshold = cfg.rendererThreshold || 8e3;
    return marks >= threshold ? "canvas" : "svg";
  }
  /**
   * Resolve + instantiate the active renderer and set `ctx.renderer`. Falls
   * back to SVG (with a warning only when canvas was explicitly requested) if
   * the desired backend is not registered.
   * @returns {import('../renderers/Renderer').RendererKind}
   */
  resolve() {
    const mode = this.w.config.chart.renderer || "svg";
    const desired = this._desiredKind();
    if (desired !== "svg") {
      const factory = getRendererRegistry().get(desired);
      if (factory) {
        if (!this._instances[desired]) {
          this._instances[desired] = factory(this.w, this.ctx);
        }
        this.active = this._instances[desired];
        this._activeKind = desired;
        this.ctx.renderer = this.active;
        this.w.globals.activeRenderer = this.active;
        return this._activeKind;
      }
      if (mode === desired) {
        console.warn(
          `[apexcharts] renderer:"${desired}" requested but that renderer is not in the default bundle. Bundler: import 'apexcharts/features/renderer-${desired}'. Script tag: add <script src=".../dist/features/renderer-${desired}.js"> after apexcharts.js. Falling back to SVG.`
        );
      }
    } else if (mode === "canvas" && hasCanvasUnsupportedFeature(this.w)) {
      console.warn(
        `[apexcharts] renderer:"canvas" requested but this chart uses a feature the canvas renderer does not render yet (gradient/pattern/image fill or a state color-matrix filter); falling back to SVG.`
      );
    }
    this.active = this.svg;
    this._activeKind = "svg";
    this.ctx.renderer = this.active;
    this.w.globals.activeRenderer = this.active;
    return this._activeKind;
  }
  /** @returns {import('../renderers/Renderer').RendererKind} */
  getActiveKind() {
    return this._activeKind;
  }
  /** Destroy the owned non-SVG renderer instances (full chart destroy). */
  teardown() {
    for (const kind in this._instances) {
      const r2 = this._instances[kind];
      if (r2 && typeof r2.destroy === "function") r2.destroy();
    }
    this._instances = {};
    this.active = this.svg;
    this._activeKind = "svg";
  }
}
class SVGElement {
  /**
   * @param {any} node
   */
  constructor(node) {
    this.node = node;
    if (node) {
      node.instance = this;
    }
    this._listeners = [];
    this._filter = null;
  }
  // ---- Attribute methods ----
  /**
   * @param {any} a
   * @param {any} [v]
   */
  attr(a2, v) {
    if (typeof a2 === "string" && v === void 0) {
      return this.node.getAttribute(a2);
    }
    const attrs = typeof a2 === "string" ? { [a2]: v } : a2;
    for (const key in attrs) {
      let val = attrs[key];
      if (val === null) {
        this.node.removeAttribute(key);
      } else if (val !== void 0) {
        if (typeof val === "number" && isNaN(val)) val = 0;
        this.node.setAttribute(key, val);
      }
    }
    if (this.node.nodeName === "text" && attrs.x != null) {
      const tspans = this.node.querySelectorAll("tspan[data-newline]");
      for (let i2 = 0; i2 < tspans.length; i2++) {
        tspans[i2].setAttribute("x", attrs.x);
      }
    }
    return this;
  }
  /**
   * @param {Record<string, string>} styles
   */
  css(styles) {
    for (const k in styles) {
      this.node.style[k] = styles[k];
    }
    return this;
  }
  /**
   * @param {any} v
   */
  fill(v) {
    if (typeof v === "object") {
      return this.attr(v);
    }
    return this.attr("fill", v);
  }
  /**
   * @param {any} v
   */
  stroke(v) {
    if (typeof v === "object") {
      if (v.color !== void 0) this.attr("stroke", v.color);
      if (v.width !== void 0) this.attr("stroke-width", v.width);
      if (v.dasharray !== void 0) this.attr("stroke-dasharray", v.dasharray);
      if (v.linecap !== void 0) this.attr("stroke-linecap", v.linecap);
      if (v.opacity !== void 0) this.attr("stroke-opacity", v.opacity);
      return this;
    }
    return this.attr("stroke", v);
  }
  /**
   * @param {number} w
   * @param {number} h
   */
  size(w, h2) {
    return this.attr({ width: w, height: h2 });
  }
  /**
   * @param {number} x
   * @param {number} y
   */
  move(x, y) {
    return this.attr({ x, y });
  }
  /**
   * @param {number} cx
   * @param {number} cy
   */
  center(cx, cy) {
    if (this.node.nodeName === "g") {
      const box = this.bbox();
      const dx = cx - (box.x + box.width / 2);
      const dy = cy - (box.y + box.height / 2);
      return this.attr("transform", `translate(${dx}, ${dy})`);
    }
    return this.attr({ cx, cy });
  }
  // ---- Tree operations ----
  /**
   * @param {any} child
   */
  add(child) {
    if (child && child.__isCanvasMark) return this;
    this.node.appendChild(child.node || child);
    return this;
  }
  /**
   * @param {any} parent
   */
  addTo(parent) {
    const p = parent.node || parent;
    p.appendChild(this.node);
    return this;
  }
  remove() {
    if (this.node.parentNode) {
      this.node.parentNode.removeChild(this.node);
    }
    return this;
  }
  clear() {
    while (this.node.firstChild) {
      this.node.removeChild(this.node.firstChild);
    }
    return this;
  }
  // ---- Query ----
  /**
   * @param {string} selector
   */
  find(selector) {
    return Array.from(this.node.querySelectorAll(selector)).map(
      (n2) => n2.instance || new SVGElement(n2)
    );
  }
  /**
   * @param {string} selector
   */
  findOne(selector) {
    const n2 = this.node.querySelector(selector);
    return n2 ? n2.instance || new SVGElement(n2) : null;
  }
  // ---- Events ----
  /**
   * @param {Event} event
   * @param {Function} handler
   */
  on(event, handler) {
    const eventType = (
      /** @type {string} */
      /** @type {any} */
      event.split(
        "."
      )[0]
    );
    this._listeners.push({ event, eventType, handler });
    this.node.addEventListener(eventType, handler);
    return this;
  }
  /**
   * @param {Event} event
   * @param {Function} handler
   */
  off(event, handler) {
    if (!event && !handler) {
      this._listeners.forEach((l2) => {
        this.node.removeEventListener(l2.eventType, l2.handler);
      });
      this._listeners = [];
    } else if (event && !handler) {
      const eventType = (
        /** @type {string} */
        /** @type {any} */
        event.split(".")[0]
      );
      this._listeners = this._listeners.filter((l2) => {
        if (l2.eventType === eventType) {
          this.node.removeEventListener(l2.eventType, l2.handler);
          return false;
        }
        return true;
      });
    } else {
      const eventType = (
        /** @type {string} */
        /** @type {any} */
        event.split(".")[0]
      );
      this._listeners = this._listeners.filter((l2) => {
        if (l2.eventType === eventType && l2.handler === handler) {
          this.node.removeEventListener(l2.eventType, l2.handler);
          return false;
        }
        return true;
      });
    }
    return this;
  }
  // ---- Iteration ----
  /**
   * @param {Function} fn
   * @param {boolean} deep
   */
  each(fn, deep) {
    const children = Array.from(this.node.children);
    children.forEach((child) => {
      const inst = child.instance || new SVGElement(child);
      fn.call(inst);
      if (deep) inst.each(fn, deep);
    });
    return this;
  }
  // ---- CSS classes ----
  /**
   * @param {string} cls
   */
  removeClass(cls) {
    if (cls === "*") {
      this.node.removeAttribute("class");
    } else {
      this.node.classList.remove(cls);
    }
    return this;
  }
  // ---- Children ----
  children() {
    return Array.from(this.node.childNodes).filter((n2) => n2.nodeType === 1).map((n2) => n2.instance || new SVGElement(n2));
  }
  // ---- Visibility ----
  hide() {
    this.node.style.display = "none";
    return this;
  }
  show() {
    this.node.style.display = "";
    return this;
  }
  // ---- Measurement ----
  bbox() {
    if (typeof this.node.getBBox === "function") {
      try {
        return this.node.getBBox();
      } catch (e2) {
      }
    }
    return { x: 0, y: 0, width: 0, height: 0 };
  }
  // ---- Text-specific ----
  /**
   * @param {string} text
   */
  tspan(text) {
    const tspan = BrowserAPIs.createElementNS(
      "http://www.w3.org/2000/svg",
      "tspan"
    );
    tspan.textContent = text;
    this.node.appendChild(tspan);
    return new SVGElement(tspan);
  }
  // ---- Path-specific ----
  /**
   * @param {string} d
   */
  plot(d) {
    if (typeof d === "string") {
      this.attr("d", d);
    }
    return this;
  }
  // ---- Animation (overridden by SVGAnimation mixin) ----
  animate() {
    throw new Error("Animation module not loaded");
  }
  // ---- Filter methods (set up by SVGFilter module) ----
  // `filterWith`, `unfilter` and `filterer` are installed on the prototype by
  // installFilterMethods() (svg/index.js). This stub only exists so a call
  // before the filter module is installed fails with a clear message.
  filterWith() {
    throw new Error("Filter module not loaded");
  }
}
let gradientCounter = 0;
class SVGGradient extends SVGElement {
  /**
   * @param {any} container
   * @param {string} type
   * @param {object} builder
   */
  constructor(container, type, builder) {
    const tag = type === "radial" ? "radialGradient" : "linearGradient";
    const node = BrowserAPIs.createElementNS(SVGNS$1, tag);
    super(node);
    this._id = "SvgjsGradient" + ++gradientCounter;
    this.attr("id", this._id);
    if (typeof builder === "function") {
      builder(new StopBuilder(this));
    }
    let defs = container.node.querySelector("defs");
    if (!defs) {
      defs = BrowserAPIs.createElementNS(SVGNS$1, "defs");
      container.node.appendChild(defs);
    }
    defs.appendChild(this.node);
  }
  /**
   * @param {any} offset
   * @param {string} color
   * @param {number} opacity
   */
  stop(offset, color, opacity) {
    const s2 = BrowserAPIs.createElementNS(SVGNS$1, "stop");
    s2.setAttribute("offset", offset);
    s2.setAttribute("stop-color", color);
    if (opacity !== void 0) s2.setAttribute("stop-opacity", String(opacity));
    this.node.appendChild(s2);
    return this;
  }
  /**
   * @param {number} x
   * @param {number} y
   */
  from(x, y) {
    return this.attr({ x1: x, y1: y });
  }
  /**
   * @param {number} x
   * @param {number} y
   */
  to(x, y) {
    return this.attr({ x2: x, y2: y });
  }
  url() {
    return "url(#" + this._id + ")";
  }
  toString() {
    return this.url();
  }
  valueOf() {
    return this.url();
  }
  fill() {
    return this.url();
  }
}
class StopBuilder {
  /**
   * @param {any} gradient
   */
  constructor(gradient) {
    this.gradient = gradient;
  }
  /**
   * @param {any} offset
   * @param {string} color
   * @param {number} opacity
   */
  stop(offset, color, opacity) {
    this.gradient.stop(offset, color, opacity);
    return this;
  }
}
let patternCounter = 0;
class SVGPattern extends SVGElement {
  /**
   * @param {any} container
   * @param {number} w
   * @param {number} h
   * @param {Function} builder
   */
  constructor(container, w, h2, builder) {
    const node = BrowserAPIs.createElementNS(SVGNS$1, "pattern");
    super(node);
    this._id = "SvgjsPattern" + ++patternCounter;
    this.attr({
      id: this._id,
      width: w,
      height: h2,
      patternUnits: "userSpaceOnUse"
    });
    if (typeof builder === "function") {
      const patternContainer = new SVGContainer(this.node);
      builder(patternContainer);
    }
    let defs = container.node.querySelector("defs");
    if (!defs) {
      defs = BrowserAPIs.createElementNS(SVGNS$1, "defs");
      container.node.appendChild(defs);
    }
    defs.appendChild(this.node);
  }
  url() {
    return "url(#" + this._id + ")";
  }
  toString() {
    return this.url();
  }
  valueOf() {
    return this.url();
  }
  fill() {
    return this.url();
  }
}
class SVGContainer extends SVGElement {
  /**
   * @param {number} x1
   * @param {number} y1
   * @param {number} x2
   * @param {number} y2
   */
  line(x1, y1, x2, y2) {
    const el = this._make("line");
    if (x1 !== void 0) {
      el.attr({ x1, y1, x2, y2 });
    }
    return el;
  }
  /**
   * @param {import('../types/internal').ChartStateW} w
   * @param {number} h
   */
  rect(w, h2) {
    const el = this._make("rect");
    if (w !== void 0) {
      el.attr({ width: w, height: h2 });
    }
    return el;
  }
  /**
   * @param {number} d
   */
  circle(d) {
    const el = this._make("circle");
    if (d !== void 0) {
      el.attr({ r: d / 2, cx: d / 2, cy: d / 2 });
    }
    return el;
  }
  /**
   * @param {string} d
   */
  path(d) {
    const el = this._make("path");
    if (d) el.attr("d", d);
    return el;
  }
  /**
   * @param {string} pts
   */
  polygon(pts) {
    const el = this._make("polygon");
    if (pts) el.attr("points", pts);
    return el;
  }
  group() {
    return this._makeContainer("g");
  }
  defs() {
    return this._makeContainer("defs");
  }
  /**
   * @param {string} textContent
   */
  plain(textContent) {
    const node = BrowserAPIs.createElementNS(SVGNS$1, "text");
    node.textContent = textContent;
    const el = new SVGElement(node);
    this.node.appendChild(node);
    return el;
  }
  /**
   * @param {object} builder
   */
  text(builder) {
    const node = BrowserAPIs.createElementNS(SVGNS$1, "text");
    const el = new SVGElement(node);
    this.node.appendChild(node);
    if (typeof builder === "function") {
      builder(new TspanBuilder(node));
    }
    return el;
  }
  /**
   * @param {string} url
   * @param {Function} callback
   */
  image(url, callback) {
    const node = BrowserAPIs.createElementNS(SVGNS$1, "image");
    node.setAttributeNS("http://www.w3.org/1999/xlink", "href", url);
    const el = new SVGElement(node);
    this.node.appendChild(node);
    if (typeof callback === "function" && Environment.isBrowser()) {
      const img = new Image();
      img.onload = function() {
        el.size(img.width, img.height);
        callback.call(el, { width: img.width, height: img.height });
      };
      img.src = url;
    }
    return el;
  }
  /**
   * @param {string} type
   * @param {object} builder
   */
  gradient(type, builder) {
    return new SVGGradient(this, type, builder);
  }
  /**
   * @param {number} w
   * @param {number} h
   * @param {Function} builder
   */
  pattern(w, h2, builder) {
    return new SVGPattern(this, w, h2, builder);
  }
  /**
   * @param {string} tag
   */
  _make(tag) {
    const node = BrowserAPIs.createElementNS(SVGNS$1, tag);
    this.node.appendChild(node);
    return new SVGElement(node);
  }
  /**
   * @param {string} tag
   */
  _makeContainer(tag) {
    const node = BrowserAPIs.createElementNS(SVGNS$1, tag);
    this.node.appendChild(node);
    return new SVGContainer(node);
  }
}
class TspanBuilder {
  /**
   * @param {any} textNode
   */
  constructor(textNode) {
    this.textNode = textNode;
  }
  /**
   * @param {string} text
   */
  tspan(text) {
    const tspan = BrowserAPIs.createElementNS(SVGNS$1, "tspan");
    tspan.textContent = text;
    this.textNode.appendChild(tspan);
    return new TspanWrapper(tspan, this.textNode);
  }
}
class TspanWrapper {
  /**
   * @param {any} node
   * @param {any} textNode
   */
  constructor(node, textNode) {
    this.node = node;
    this.textNode = textNode;
  }
  newLine() {
    this.node.setAttribute("dy", "1.1em");
    this.node.dataset.newline = "1";
    return this;
  }
}
let filterCounter = 0;
class SVGFilter extends SVGElement {
  constructor() {
    const node = BrowserAPIs.createElementNS(SVGNS$1, "filter");
    super(node);
    this._id = "SvgjsFilter" + ++filterCounter;
    this.attr("id", this._id);
  }
}
class FilterBuilder {
  /**
   * @param {any} filter
   */
  constructor(filter) {
    this.filter = filter;
  }
  /**
   * @param {object} attrs
   */
  colorMatrix(attrs) {
    return this._primitive("feColorMatrix", attrs);
  }
  /**
   * @param {object} attrs
   */
  offset(attrs) {
    return this._primitive("feOffset", attrs);
  }
  /**
   * @param {object} attrs
   */
  gaussianBlur(attrs) {
    return this._primitive("feGaussianBlur", attrs);
  }
  /**
   * @param {object} attrs
   */
  flood(attrs) {
    return this._primitive("feFlood", attrs);
  }
  /**
   * @param {object} attrs
   */
  composite(attrs) {
    return this._primitive("feComposite", attrs);
  }
  /**
   * @param {string[]} sources
   */
  merge(sources) {
    const m = BrowserAPIs.createElementNS(SVGNS$1, "feMerge");
    sources.forEach((src) => {
      const mn = BrowserAPIs.createElementNS(SVGNS$1, "feMergeNode");
      mn.setAttribute("in", src);
      m.appendChild(mn);
    });
    this.filter.node.appendChild(m);
    return new SVGElement(m);
  }
  /**
   * @param {string} tag
   * @param {Record<string, any>} attrs
   */
  _primitive(tag, attrs) {
    const el = BrowserAPIs.createElementNS(SVGNS$1, tag);
    for (const key in attrs) {
      el.setAttribute(key, attrs[key]);
    }
    this.filter.node.appendChild(el);
    return new SVGElement(el);
  }
}
function installFilterMethods(ElementClass) {
  ElementClass.prototype.filterWith = function(fn) {
    const filter = new SVGFilter();
    this._filter = filter;
    let svgRoot = this.node;
    while (svgRoot && svgRoot.nodeName !== "svg") {
      svgRoot = svgRoot.parentNode;
    }
    if (svgRoot) {
      let defs = svgRoot.querySelector("defs");
      if (!defs) {
        defs = BrowserAPIs.createElementNS(SVGNS$1, "defs");
        svgRoot.insertBefore(defs, svgRoot.firstChild);
      }
      defs.appendChild(filter.node);
    }
    fn(new FilterBuilder(filter));
    this.attr("filter", "url(#" + filter._id + ")");
    return this;
  };
  ElementClass.prototype.unfilter = function(all) {
    if (this._filter) {
      this.node.removeAttribute("filter");
      if (all && this._filter.node && this._filter.node.parentNode) {
        this._filter.node.parentNode.removeChild(this._filter.node);
      }
      this._filter = null;
    }
    return this;
  };
  ElementClass.prototype.filterer = function() {
    return this._filter;
  };
}
function installDraggable(ElementClass) {
  ElementClass.prototype.draggable = function(opts) {
    if (opts === false) {
      if (this._dragCleanup) {
        this._dragCleanup();
        this._dragCleanup = null;
      }
      return this;
    }
    const el = this;
    const constraints = opts || {};
    const onPointerDown = (e2) => {
      if (e2.button && e2.button !== 0) return;
      e2.stopPropagation();
      const isTouch = e2.type === "touchstart";
      const ev = isTouch ? e2.touches[0] : e2;
      const svgEl = el.node;
      const startAttrX = parseFloat(svgEl.getAttribute("x")) || 0;
      const startAttrY = parseFloat(svgEl.getAttribute("y")) || 0;
      const startClientX = ev.clientX;
      const startClientY = ev.clientY;
      const svgRoot = svgEl.ownerSVGElement;
      let ctm = null;
      if (svgRoot) {
        ctm = svgRoot.getScreenCTM();
      }
      const onMove = (me) => {
        const mev = me.type === "touchmove" ? me.touches[0] : me;
        let dx = mev.clientX - startClientX;
        let dy = mev.clientY - startClientY;
        if (ctm) {
          dx = dx / ctm.a;
          dy = dy / ctm.d;
        }
        let newX = startAttrX + dx;
        let newY = startAttrY + dy;
        const w = parseFloat(svgEl.getAttribute("width")) || 0;
        const h2 = parseFloat(svgEl.getAttribute("height")) || 0;
        if (constraints.minX !== void 0 && newX < constraints.minX)
          newX = constraints.minX;
        if (constraints.minY !== void 0 && newY < constraints.minY)
          newY = constraints.minY;
        if (constraints.maxX !== void 0 && newX + w > constraints.maxX)
          newX = constraints.maxX - w;
        if (constraints.maxY !== void 0 && newY + h2 > constraints.maxY)
          newY = constraints.maxY - h2;
        const box = {
          x: newX,
          y: newY,
          w,
          h: h2,
          x2: newX + w,
          y2: newY + h2
        };
        const event = new CustomEvent("dragmove", {
          detail: {
            handler: {
              /**
               * @param {number} x
               * @param {number} y
               */
              move: function(x, y) {
                svgEl.setAttribute("x", x);
                svgEl.setAttribute("y", y);
              }
            },
            box
          }
        });
        svgEl.dispatchEvent(event);
      };
      const onUp = () => {
        if (Environment.isBrowser()) {
          document.removeEventListener("mousemove", onMove);
          document.removeEventListener("touchmove", onMove);
          document.removeEventListener("mouseup", onUp);
          document.removeEventListener("touchend", onUp);
        }
        el._activeDrag = null;
      };
      if (Environment.isBrowser()) {
        document.addEventListener("mousemove", onMove);
        document.addEventListener("touchmove", onMove);
        document.addEventListener("mouseup", onUp);
        document.addEventListener("touchend", onUp);
        el._activeDrag = { onMove, onUp };
      }
    };
    el.node.addEventListener("mousedown", onPointerDown);
    el.node.addEventListener("touchstart", onPointerDown);
    el._dragCleanup = () => {
      el.node.removeEventListener("mousedown", onPointerDown);
      el.node.removeEventListener("touchstart", onPointerDown);
      if (el._activeDrag && Environment.isBrowser()) {
        document.removeEventListener("mousemove", el._activeDrag.onMove);
        document.removeEventListener("touchmove", el._activeDrag.onMove);
        document.removeEventListener("mouseup", el._activeDrag.onUp);
        document.removeEventListener("touchend", el._activeDrag.onUp);
        el._activeDrag = null;
      }
    };
    return el;
  };
}
function installSelectable(ElementClass) {
  ElementClass.prototype.select = function(opts) {
    if (opts === false) {
      if (this._selectCleanup) {
        this._selectCleanup();
        this._selectCleanup = null;
      }
      return this;
    }
    const el = this;
    const { createHandle, updateHandle } = opts;
    const handleGroup = document.createElementNS(SVGNS$1, "g");
    handleGroup.setAttribute("class", "svg_select_points");
    const parent = el.node.parentNode;
    if (parent) {
      parent.appendChild(handleGroup);
    }
    const handles = {};
    const handleNames = ["t", "b", "l", "r", "lt", "rt", "lb", "rb"];
    handleNames.forEach((name2, index) => {
      const subGroup = new SVGContainer(document.createElementNS(SVGNS$1, "g"));
      handleGroup.appendChild(subGroup.node);
      const handle = createHandle(subGroup, [0, 0], index, [], name2);
      handles[name2] = { group: subGroup, handle };
    });
    const updatePositions = () => {
      const x = parseFloat(el.attr("x")) || 0;
      const y = parseFloat(el.attr("y")) || 0;
      const w = parseFloat(el.attr("width")) || 0;
      const h2 = parseFloat(el.attr("height")) || 0;
      const elTransform = el.node.getAttribute("transform");
      if (elTransform) {
        handleGroup.setAttribute("transform", elTransform);
      } else {
        handleGroup.removeAttribute("transform");
      }
      const positions = {
        t: [x + w / 2, y],
        b: [x + w / 2, y + h2],
        l: [x, y + h2 / 2],
        r: [x + w, y + h2 / 2],
        lt: [x, y],
        rt: [x + w, y],
        lb: [x, y + h2],
        rb: [x + w, y + h2]
      };
      handleNames.forEach((name2) => {
        if (handles[name2] && positions[name2]) {
          updateHandle(handles[name2].group, positions[name2]);
        }
      });
    };
    updatePositions();
    el._selectHandles = handleGroup;
    el._selectHandlesMap = handles;
    el._updateSelectPositions = updatePositions;
    el._selectCleanup = () => {
      if (handleGroup.parentNode) {
        handleGroup.parentNode.removeChild(handleGroup);
      }
      el._selectHandles = null;
      el._selectHandlesMap = null;
      el._updateSelectPositions = null;
    };
    return el;
  };
  ElementClass.prototype.resize = function(enable) {
    if (enable === false) {
      if (this._resizeCleanup) {
        this._resizeCleanup();
        this._resizeCleanup = null;
      }
      return this;
    }
    const el = this;
    const handles = el._selectHandlesMap;
    if (!handles) return el;
    const cleanupFns = [];
    const makeHandleDraggable = (name2) => {
      const handleInfo = handles[name2];
      if (!handleInfo || !handleInfo.group || !handleInfo.group.node) return;
      const handleNode = handleInfo.group.node;
      const onPointerDown = (e2) => {
        if (e2.button && e2.button !== 0) return;
        e2.stopPropagation();
        const isTouch = e2.type === "touchstart";
        const ev = isTouch ? e2.touches[0] : e2;
        const startClientX = ev.clientX;
        const svgRoot = el.node.ownerSVGElement;
        let ctm = null;
        if (svgRoot) {
          ctm = svgRoot.getScreenCTM();
        }
        const startX = parseFloat(el.attr("x")) || 0;
        const startW = parseFloat(el.attr("width")) || 0;
        const onMove = (me) => {
          const mev = me.type === "touchmove" ? me.touches[0] : me;
          let dx = mev.clientX - startClientX;
          if (ctm) dx = dx / /** @type {any} */
          ctm.a;
          let newX = startX;
          let newW = startW;
          if (name2 === "l") {
            newX = startX + dx;
            newW = startW - dx;
          } else if (name2 === "r") {
            newW = startW + dx;
          }
          if (newW < 0) {
            newW = 0;
          }
          el.attr({ x: newX, width: newW });
          if (el._updateSelectPositions) {
            el._updateSelectPositions();
          }
          const event = new CustomEvent("resize", {
            detail: { el }
          });
          el.node.dispatchEvent(event);
        };
        const onUp = () => {
          if (Environment.isBrowser()) {
            document.removeEventListener("mousemove", onMove);
            document.removeEventListener("touchmove", onMove);
            document.removeEventListener("mouseup", onUp);
            document.removeEventListener("touchend", onUp);
          }
          const event = new CustomEvent("resize", {
            detail: { el }
          });
          el.node.dispatchEvent(event);
        };
        if (Environment.isBrowser()) {
          document.addEventListener("mousemove", onMove);
          document.addEventListener("touchmove", onMove);
          document.addEventListener("mouseup", onUp);
          document.addEventListener("touchend", onUp);
        }
      };
      handleNode.addEventListener("mousedown", onPointerDown);
      handleNode.addEventListener("touchstart", onPointerDown);
      cleanupFns.push(() => {
        handleNode.removeEventListener("mousedown", onPointerDown);
        handleNode.removeEventListener("touchstart", onPointerDown);
      });
    };
    makeHandleDraggable("l");
    makeHandleDraggable("r");
    el._resizeCleanup = () => {
      cleanupFns.forEach((fn) => fn());
    };
    return el;
  };
}
installFilterMethods(SVGElement);
installAnimationMethods(SVGElement);
installDraggable(SVGElement);
installSelectable(SVGElement);
function SVG() {
  const svgEl = BrowserAPIs.createElementNS(SVGNS$1, "svg");
  const svg = new SVGContainer(svgEl);
  svg.attr({ xmlns: SVGNS$1 });
  return svg;
}
SVG.xlink = "http://www.w3.org/1999/xlink";
if (Environment.isBrowser() && typeof window.SVG === "undefined") {
  window.SVG = SVG;
}
if (Environment.isBrowser()) {
  if (typeof window.SVG === "undefined") {
    window.SVG = SVG;
  }
  if (typeof window.Apex === "undefined") {
    window.Apex = {};
  }
} else {
  if (typeof global !== "undefined") {
    if (typeof /** @type {any} */
    global.Apex === "undefined") {
      global.Apex = {};
    }
    if (typeof /** @type {any} */
    global.SVG === "undefined") {
      global.SVG = SVG;
    }
  }
}
const FEATURE_REGISTRY_KEY = "__apexcharts_features_v1__";
if (!/** @type {any} */
globalThis[FEATURE_REGISTRY_KEY]) {
  globalThis[FEATURE_REGISTRY_KEY] = /* @__PURE__ */ new Map();
}
function getFeatureRegistry() {
  return (
    /** @type {any} */
    globalThis[FEATURE_REGISTRY_KEY]
  );
}
class InitCtxVariables {
  /**
   * Registry of optional feature modules.
   *
   * Populated by ApexCharts.registerFeatures() (called from feature entry
   * files such as src/features/legend.js). Keys match the ctx property name
   * the module is stored under (e.g. 'legend', 'exports').
   *
   * Core modules that every chart needs are NOT in this registry — they are
   * always instantiated unconditionally in initModules().
   */
  static get _featureRegistry() {
    return getFeatureRegistry();
  }
  /**
   * Register one or more optional feature modules.
   *
   * @param {Record<string, new (w: object, ctx: object) => unknown>} featureMap
   *   Plain object mapping ctx property name → constructor.
   *
   * Example (called from src/features/legend.js):
   *   InitCtxVariables.registerFeatures({ legend: Legend })
   */
  static registerFeatures(featureMap) {
    for (const [key, Ctor] of Object.entries(featureMap)) {
      InitCtxVariables._featureRegistry.set(key, Ctor);
    }
  }
  /**
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(ctx) {
    this.ctx = ctx;
    this.w = ctx.w;
  }
  initModules() {
    this.ctx.publicMethods = [
      "updateOptions",
      "updateSeries",
      "appendData",
      "appendSeries",
      "isSeriesHidden",
      "highlightSeries",
      "toggleSeries",
      "showSeries",
      "hideSeries",
      "setLocale",
      "resetSeries",
      "zoomX",
      "toggleDataPointSelection",
      "dataURI",
      "exportToCSV",
      "addXaxisAnnotation",
      "addYaxisAnnotation",
      "addPointAnnotation",
      "clearAnnotations",
      "removeAnnotation",
      "drillDown",
      "drillUp",
      "drillToRoot",
      "clearDrilldownCache",
      "paper",
      "getActiveRenderer",
      "destroy"
    ];
    this.ctx.eventList = [
      "click",
      "mousedown",
      "mousemove",
      "mouseleave",
      "touchstart",
      "touchmove",
      "touchleave",
      "mouseup",
      "touchend",
      "keydown",
      "keyup"
    ];
    this.ctx.animations = new Animations(this.w, this.ctx);
    this.ctx.axes = new Axes(this.w, this.ctx);
    this.ctx.core = new Core(this.ctx.el, this.w, this.ctx);
    this.ctx.config = new Config({});
    this.ctx.data = new Data(this.w, {
      resetGlobals: () => this.ctx.core.resetGlobals(),
      isMultipleY: () => this.ctx.core.isMultipleY()
    });
    this.ctx.grid = new Grid(this.w, this.ctx);
    this.ctx.graphics = new Graphics(this.w, this.ctx);
    this.ctx.coreUtils = new CoreUtils(this.w);
    this.ctx.crosshairs = new Crosshairs(this.w);
    this.ctx.events = new Events(this.w, this.ctx);
    this.ctx.fill = new Fill(this.w);
    this.ctx.localization = new Localization(this.w);
    this.ctx.options = new Options();
    this.ctx.responsive = new Responsive(this.w);
    this.ctx.series = new Series(this.w, {
      // legend may not be registered — guard with ?.
      toggleDataSeries: (...a2) => {
        var _a;
        return (_a = this.ctx.legend) == null ? void 0 : _a.legendHelpers.toggleDataSeries(...a2);
      },
      revertDefaultAxisMinMax: () => this.ctx.updateHelpers.revertDefaultAxisMinMax(),
      updateSeries: (...a2) => this.ctx.updateHelpers._updateSeries(...a2)
    });
    this.ctx.theme = new Theme(this.w);
    this.ctx.formatters = new Formatters(this.w);
    this.ctx.titleSubtitle = new TitleSubtitle(this.w);
    this.ctx.dimensions = new Dimensions(this.w, this.ctx);
    this.ctx.updateHelpers = new UpdateHelpers(this.w, this.ctx);
    this.ctx.rendererController = new RendererController(this.w, this.ctx);
    this.ctx.renderer = this.ctx.rendererController.active;
    const tooltipInstance = new Tooltip(this.w, this.ctx);
    this.w.globals.tooltip = tooltipInstance;
    Object.defineProperty(this.ctx, "tooltip", {
      get() {
        return this.w.globals.tooltip;
      },
      configurable: true
    });
    this._initOptionalModules();
  }
  /**
   * Instantiate optional feature modules from the registry.
   *
   * Modules that are not registered are set to null on ctx so that call sites
   * can safely use optional-chaining (ctx.tooltip?.drawTooltip(...)).
   *
   * Lazy-getter features (toolbar, zoomPanSelection, keyboardNavigation) are
   * installed as on-demand getters so they are only constructed if accessed,
   * and only if their constructor was registered.
   */
  _initOptionalModules() {
    const reg = InitCtxVariables._featureRegistry;
    const w = this.w;
    const ctx = this.ctx;
    const ExportsCtor = reg.get("exports");
    ctx.exports = ExportsCtor ? new ExportsCtor(w, ctx) : null;
    const LegendCtor = reg.get("legend");
    ctx.legend = LegendCtor ? new LegendCtor(w, ctx) : null;
    const MorphCtor = reg.get("morphTypeChange");
    ctx.morphTypeChange = MorphCtor ? new MorphCtor(w, ctx) : null;
    const DrilldownCtor = reg.get("drilldown");
    ctx.drilldown = DrilldownCtor ? new DrilldownCtor(w, ctx) : null;
    const PerspectivesCtor = reg.get("perspectives");
    ctx.perspectives = PerspectivesCtor ? new PerspectivesCtor(w, ctx) : null;
    const StoryboardCtor = reg.get("storyboard");
    ctx.storyboard = StoryboardCtor ? new StoryboardCtor(w, ctx) : null;
    const HistoryCtor = reg.get("history");
    ctx.history = HistoryCtor ? new HistoryCtor(w, ctx) : null;
    const LinkedViewsCtor = reg.get("linkedViews");
    ctx.linkedViews = LinkedViewsCtor ? new LinkedViewsCtor(w, ctx) : null;
    const InkCtor = reg.get("ink");
    ctx.ink = InkCtor ? new InkCtor(w, ctx) : null;
    const MeasureCtor = reg.get("measure");
    ctx.measure = MeasureCtor ? new MeasureCtor(w, ctx) : null;
    const ContextMenuCtor = reg.get("contextMenu");
    ctx.contextMenu = ContextMenuCtor ? new ContextMenuCtor(w, ctx) : null;
    const WeaveCtor = reg.get("weave");
    ctx.weave = WeaveCtor ? new WeaveCtor(w, ctx) : null;
    const TrellisCtor = reg.get("trellis");
    ctx.trellis = TrellisCtor ? new TrellisCtor(w, ctx) : null;
    const OSThemeCtor = reg.get("osThemeWatcher");
    ctx.osThemeWatcher = OSThemeCtor ? new OSThemeCtor(w, ctx) : null;
    const ToolbarCtor = reg.get("toolbar");
    Object.defineProperty(ctx, "toolbar", {
      get() {
        var _a;
        if (!this._toolbar && ToolbarCtor)
          this._toolbar = new ToolbarCtor(w, this);
        return (_a = this._toolbar) != null ? _a : null;
      },
      configurable: true
    });
    const ZoomPanCtor = reg.get("zoomPanSelection");
    Object.defineProperty(ctx, "zoomPanSelection", {
      get() {
        var _a;
        if (!this._zoomPanSelection && ZoomPanCtor)
          this._zoomPanSelection = new ZoomPanCtor(w, this);
        return (_a = this._zoomPanSelection) != null ? _a : null;
      },
      configurable: true
    });
    const KeyboardCtor = reg.get("keyboardNavigation");
    Object.defineProperty(ctx, "keyboardNavigation", {
      get() {
        var _a;
        if (!this._keyboardNavigation && KeyboardCtor)
          this._keyboardNavigation = new KeyboardCtor(w, this);
        return (_a = this._keyboardNavigation) != null ? _a : null;
      },
      configurable: true
    });
  }
}
class Destroy {
  /**
   * @param {import('../../types/internal').ChartContext} ctx
   */
  constructor(ctx) {
    this.ctx = ctx;
    this.w = ctx.w;
  }
  /**
   * @param {{ isUpdating: boolean }} opts
   */
  clear({ isUpdating }) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
    (_a = this.ctx.weave) == null ? void 0 : _a.teardown(isUpdating);
    if (!isUpdating) {
      this.w.globals.isDestroyed = true;
    }
    if (this.ctx._zoomPanSelection) {
      this.ctx._zoomPanSelection.destroy();
    }
    if (this.ctx._toolbar) {
      this.ctx._toolbar.destroy();
    }
    if (this.w.globals.resizeObserver && typeof this.w.globals.resizeObserver.disconnect === "function") {
      this.w.globals.resizeObserver.disconnect();
      this.w.globals.resizeObserver = null;
    }
    PerformanceCache.invalidateAll(this.w);
    if (isUpdating) {
      this.ctx._zoomPanSelection = null;
      this.ctx._toolbar = null;
      (_b = this.ctx._keyboardNavigation) == null ? void 0 : _b.destroy();
      this.ctx._keyboardNavigation = null;
    } else {
      (_c = this.ctx.perspectives) == null ? void 0 : _c.teardown();
      this.ctx.perspectives = null;
      (_d = this.ctx.storyboard) == null ? void 0 : _d.teardown();
      this.ctx.storyboard = null;
      (_e = this.ctx.history) == null ? void 0 : _e.teardown();
      this.ctx.history = null;
      (_f = this.ctx.linkedViews) == null ? void 0 : _f.teardown();
      this.ctx.linkedViews = null;
      (_g = this.ctx.trellis) == null ? void 0 : _g.teardown();
      this.ctx.trellis = null;
      (_h = this.ctx.ink) == null ? void 0 : _h.teardown();
      this.ctx.ink = null;
      (_i = this.ctx.measure) == null ? void 0 : _i.teardown();
      this.ctx.measure = null;
      (_j = this.ctx.contextMenu) == null ? void 0 : _j.teardown();
      this.ctx.contextMenu = null;
      (_k = this.ctx.osThemeWatcher) == null ? void 0 : _k.teardown();
      this.ctx.osThemeWatcher = null;
      this.ctx.weave = null;
      (_m = (_l = this.ctx.rendererController) == null ? void 0 : _l.teardown) == null ? void 0 : _m.call(_l);
      this.ctx.rendererController = null;
      this.ctx.renderer = null;
      this.ctx.drilldown = null;
      this.ctx.morphTypeChange = null;
      this.ctx.exports = null;
      this.ctx.animations = null;
      this.ctx.axes = null;
      this.ctx.annotations = null;
      this.ctx.core = null;
      this.ctx.data = null;
      this.ctx.grid = null;
      this.ctx.series = null;
      this.ctx.responsive = null;
      this.ctx.theme = null;
      this.ctx.formatters = null;
      this.ctx.titleSubtitle = null;
      this.ctx.legend = null;
      this.ctx.dimensions = null;
      this.ctx.options = null;
      this.ctx.crosshairs = null;
      this.ctx._zoomPanSelection = null;
      this.ctx.updateHelpers = null;
      this.ctx._toolbar = null;
      this.ctx.localization = null;
      this.ctx._keyboardNavigation = null;
      this.ctx.w.globals.tooltip = null;
    }
    this.clearDomElements({ isUpdating });
  }
  /**
   * @param {any} draw
   */
  killSVG(draw) {
    draw.each(
      /** @this {any} */
      function() {
        this.removeClass("*");
        this.off();
      },
      true
    );
    draw.clear();
  }
  /**
   * @param {{ isUpdating: boolean }} opts
   */
  clearDomElements({ isUpdating }) {
    const domEls = (
      /** @type {any} */
      this.w.dom
    );
    if (Environment.isBrowser() && domEls.Paper) {
      const elSVG = domEls.Paper.node;
      if (elSVG.parentNode && elSVG.parentNode.parentNode && !isUpdating) {
        elSVG.parentNode.parentNode.style.minHeight = "unset";
      }
      const baseEl = domEls.baseEl;
      if (baseEl) {
        this.ctx.eventList.forEach((event) => {
          baseEl.removeEventListener(event, this.ctx.events.documentEvent);
        });
      }
      if (this.ctx.el !== null) {
        while (this.ctx.el.firstChild) {
          this.ctx.el.removeChild(this.ctx.el.firstChild);
        }
      }
      this.killSVG(domEls.Paper);
      domEls.Paper.remove();
    }
    domEls.Paper = null;
    domEls.elWrap = null;
    domEls.elGraphical = null;
    domEls.elLegendWrap = null;
    domEls.elLegendForeign = null;
    domEls.baseEl = null;
    domEls.elGridRect = null;
    domEls.elGridRectMask = null;
    domEls.elGridRectBarMask = null;
    domEls.elGridRectMarkerMask = null;
    domEls.elForecastMask = null;
    domEls.elNonForecastMask = null;
    domEls.elDefs = null;
  }
}
const LAYOUT_KEY = "__apexcharts_unit_layouts__";
if (!/** @type {any} */
globalThis[LAYOUT_KEY]) {
  globalThis[LAYOUT_KEY] = {};
}
function getLayouts() {
  return (
    /** @type {any} */
    globalThis[LAYOUT_KEY]
  );
}
function registerUnitLayout(name2, fn) {
  if (!name2 || typeof name2 !== "string") {
    console.warn("ApexCharts: registerUnitLayout requires a non-empty name.");
    return;
  }
  if (typeof fn !== "function") {
    console.warn(
      `ApexCharts: registerUnitLayout("${name2}") expects a function (objects, rect) => [{id, x, y}].`
    );
    return;
  }
  getLayouts()[name2] = fn;
}
function unregisterUnitLayout(name2) {
  delete getLayouts()[name2];
}
const MARK_KEY = "__apexcharts_unit_marks__";
if (!/** @type {any} */
globalThis[MARK_KEY]) {
  globalThis[MARK_KEY] = {};
}
function getMarks() {
  return (
    /** @type {any} */
    globalThis[MARK_KEY]
  );
}
function normalizeUnitMark(def, name2) {
  if (typeof def === "string") {
    const d = def.trim();
    if (!d) return null;
    return Object.freeze({
      name: name2 || "anonymous",
      path: d,
      viewBox: (
        /** @type {[number,number,number,number]} */
        [0, 0, 100, 100]
      )
    });
  }
  if (!def || typeof def !== "object") return null;
  if (typeof def.path !== "string" || !def.path.trim()) return null;
  const vb = Array.isArray(def.viewBox) && def.viewBox.length === 4 ? def.viewBox.map(Number) : [0, 0, 100, 100];
  if (!vb.every((n2) => isFinite(n2)) || vb[2] <= 0 || vb[3] <= 0) {
    return null;
  }
  return Object.freeze(__spreadProps(__spreadValues({}, def), {
    name: name2 || def.name || "anonymous",
    path: def.path.trim(),
    viewBox: (
      /** @type {[number,number,number,number]} */
      /** @type {any} */
      vb
    ),
    fillRule: def.fillRule === "evenodd" ? "evenodd" : void 0
  }));
}
function registerUnitMark(name2, def) {
  if (!name2 || typeof name2 !== "string") {
    console.warn("ApexCharts: registerUnitMark requires a non-empty name.");
    return;
  }
  const mark = normalizeUnitMark(def, name2);
  if (!mark) {
    console.warn(
      `ApexCharts: registerUnitMark("${name2}") expects path data, or {path, viewBox?, fillRule?}.`
    );
    return;
  }
  getMarks()[name2] = mark;
}
function unregisterUnitMark(name2) {
  delete getMarks()[name2];
}
const ROW_SOURCE_KEY = "__apexcharts_row_sources__";
if (!/** @type {any} */
globalThis[ROW_SOURCE_KEY]) {
  globalThis[ROW_SOURCE_KEY] = {};
}
function getSources() {
  return (
    /** @type {any} */
    globalThis[ROW_SOURCE_KEY]
  );
}
function registerRowSource(name2, fn) {
  if (!name2 || typeof name2 !== "string") {
    console.warn("ApexCharts: registerRowSource requires a non-empty name.");
    return;
  }
  if (typeof fn !== "function") {
    console.warn(
      `ApexCharts: registerRowSource("${name2}") expects a function (w, opts) => series.`
    );
    return;
  }
  getSources()[name2] = fn;
}
function getRowSource(name2) {
  if (!name2) return null;
  return getSources()[name2] || null;
}
function unregisterRowSource(name2) {
  delete getSources()[name2];
}
function rowSourceFor(w) {
  const cnf = w && w.config && w.config.chart;
  if (!cnf) return null;
  return getRowSource(cnf.requestedType) || getRowSource(cnf.type);
}
const REGISTRY_KEY = "__apexcharts_plugins__";
function getRegistry() {
  const g = (
    /** @type {any} */
    globalThis
  );
  if (!g[REGISTRY_KEY]) g[REGISTRY_KEY] = {};
  return g[REGISTRY_KEY];
}
function registerPlugin(def) {
  if (!def || typeof def.name !== "string" || typeof def.setup !== "function") {
    console.error(
      "[apexcharts] registerPlugin: a plugin needs a { name, setup } shape."
    );
    return;
  }
  getRegistry()[def.name] = def;
}
function unregisterPlugin(name2) {
  delete getRegistry()[name2];
}
const ros = /* @__PURE__ */ new WeakMap();
function addResizeListener(el, fn) {
  if (Environment.isSSR()) return;
  let called = false;
  if (el.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
    const elRect = el.getBoundingClientRect();
    if (el.style.display === "none" || elRect.width === 0) {
      called = true;
    }
  }
  const ro = new ResizeObserver((r2) => {
    if (called) {
      fn.call(el, r2);
    }
    called = true;
  });
  if (el.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
    Array.from(el.children).forEach((c2) => ro.observe(c2));
  } else {
    ro.observe(el);
  }
  ros.set(fn, ro);
}
function removeResizeListener(el, fn) {
  if (Environment.isSSR()) return;
  const ro = ros.get(fn);
  if (ro) {
    ro.disconnect();
    ros.delete(fn);
  }
}
const apexCSS = "@keyframes opaque {\n  0% {\n    opacity: 0\n  }\n\n  to {\n    opacity: 1\n  }\n}\n\n@keyframes resizeanim {\n\n  0%,\n  to {\n    opacity: 0\n  }\n}\n\n.apexcharts-canvas {\n  position: relative;\n  direction: ltr !important;\n  user-select: none;\n  /* Focus indicator colour. Themes override below. */\n  --apexcharts-focus-color: #008FFB;\n}\n\n/* Dark theme & high-contrast: brighter focus colour for sufficient contrast. */\n.apexcharts-canvas .apexcharts-theme-dark,\n.apexcharts-theme-dark.apexcharts-canvas {\n  --apexcharts-focus-color: #FFD500;\n}\n.apexcharts-canvas.apexcharts-high-contrast,\n.apexcharts-high-contrast.apexcharts-canvas {\n  --apexcharts-focus-color: #FFFF00;\n}\n\n/* Visually-hidden aria-live status region (WCAG 4.1.3 Status Messages). */\n.apexcharts-sr-status {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n\n/* Respect OS-level reduced-motion preference (WCAG 2.3.3). */\n@media (prefers-reduced-motion: reduce) {\n  .apexcharts-canvas *,\n  .apexcharts-canvas *::before,\n  .apexcharts-canvas *::after {\n    animation-duration: 0.01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: 0.01ms !important;\n  }\n}\n\n.apexcharts-canvas ::-webkit-scrollbar {\n  -webkit-appearance: none;\n  width: 6px\n}\n\n.apexcharts-canvas ::-webkit-scrollbar-thumb {\n  border-radius: 4px;\n  background-color: rgba(0, 0, 0, .5);\n  box-shadow: 0 0 1px rgba(255, 255, 255, .5);\n  -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, .5)\n}\n\n.apexcharts-inner {\n  position: relative\n}\n\n.apexcharts-text tspan {\n  font-family: inherit\n}\n\nrect.legend-mouseover-inactive,\n.legend-mouseover-inactive rect,\n.legend-mouseover-inactive path,\n.legend-mouseover-inactive circle,\n.legend-mouseover-inactive line,\n.legend-mouseover-inactive text.apexcharts-yaxis-title-text,\n.legend-mouseover-inactive text.apexcharts-yaxis-label {\n  transition: .15s ease all;\n  opacity: .2\n}\n\n/* Linked Views (#4): per-mark crossfilter dim. Applied to individual data\n   marks (not whole series) whose x is outside the brushed range. Opacity is\n   overridable per chart via the --apx-cf-dim custom property. */\n.apexcharts-crossfilter-dimmed {\n  transition: opacity .25s ease;\n  opacity: var(--apx-cf-dim, .2)\n}\n\n/* Linked Views (#4): default styling for the built-in crossfilter data table\n   (cf.dataTable). Deliberately light so host styles can override. */\n.apexcharts-cf-table {\n  border-collapse: collapse;\n  width: 100%;\n  font-size: 13px;\n}\n.apexcharts-cf-table caption {\n  caption-side: bottom;\n  text-align: right;\n  padding: 6px 2px;\n  font-size: 12px;\n  opacity: .7\n}\n.apexcharts-cf-table th,\n.apexcharts-cf-table td {\n  padding: 6px 10px;\n  text-align: left;\n  border-bottom: 1px solid rgba(0, 0, 0, .08)\n}\n.apexcharts-cf-table th {\n  font-weight: 600;\n  border-bottom-width: 2px\n}\n.apexcharts-cf-table tbody tr:hover {\n  background: rgba(99, 102, 241, .06)\n}\n\n/* Measure ruler (#18): measure / delta ruler.\n   Theme via these classes or the --apx-measure-* custom properties below\n   (config `chart.measure.colors` overrides both). The ruler group also carries\n   a direction class: apexcharts-measure-up | -down | -flat.\n   Element classes:\n     .apexcharts-measure-band     shaded span band\n     .apexcharts-measure-vline    vertical guide lines\n     .apexcharts-measure-line     free-mode diagonal line\n     .apexcharts-measure-label-bg readout box     .apexcharts-measure-label text\n   Colors are applied as SVG presentation attributes, so any rule you write on\n   these classes overrides them. */\n.apexcharts-canvas {\n  --apx-measure-up: #16a34a;\n  --apx-measure-down: #dc2626;\n  --apx-measure-neutral: #64748b;\n  --apx-measure-guide: #94a3b8;\n}\n.apexcharts-measure-capture {\n  cursor: crosshair;\n}\n\n/* Radial Actions (#chrome): right-click context menu. Theme via these classes\n   or the --apx-menu-* custom properties. */\n.apexcharts-canvas {\n  --apx-menu-bg: #ffffff;\n  --apx-menu-fg: #1e293b;\n  --apx-menu-border: #e2e8f0;\n  --apx-menu-hover: #f1f5f9;\n  --apx-menu-shadow: rgba(15, 23, 42, 0.18);\n}\n.apexcharts-context-menu {\n  min-width: 168px;\n  padding: 4px;\n  border-radius: 8px;\n  background: var(--apx-menu-bg);\n  border: 1px solid var(--apx-menu-border);\n  box-shadow: 0 6px 22px var(--apx-menu-shadow);\n  font-family: Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  z-index: 20;\n  user-select: none;\n}\n.apexcharts-context-menu-item {\n  display: block;\n  width: 100%;\n  box-sizing: border-box;\n  text-align: left;\n  padding: 7px 12px;\n  border: 0;\n  border-radius: 5px;\n  background: transparent;\n  color: var(--apx-menu-fg);\n  font: inherit;\n  cursor: pointer;\n}\n.apexcharts-context-menu-item:hover,\n.apexcharts-context-menu-item--active {\n  background: var(--apx-menu-hover);\n}\n.apexcharts-context-menu-item:focus {\n  outline: none;\n}\n\n/* Ink Layer (#7): the floating note editor card, opened by clicking an\n   ink-managed annotation. Theme via these classes or the --apx-ink-* vars. */\n.apexcharts-canvas {\n  --apx-ink-card-bg: #ffffff;\n  --apx-ink-card-fg: #1e293b;\n  --apx-ink-card-border: #e2e8f0;\n  --apx-ink-card-hover: #f1f5f9;\n  --apx-ink-card-accent: #6366f1;\n  --apx-ink-card-shadow: rgba(15, 23, 42, 0.18);\n}\n.apexcharts-ink-card {\n  position: absolute;\n  z-index: 25;\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n  padding: 8px;\n  border-radius: 8px;\n  background: var(--apx-ink-card-bg);\n  border: 1px solid var(--apx-ink-card-border);\n  box-shadow: 0 6px 22px var(--apx-ink-card-shadow);\n  font-family: Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  color: var(--apx-ink-card-fg);\n  user-select: none;\n}\n.apexcharts-ink-card-row {\n  display: flex;\n  align-items: center;\n  gap: 4px;\n}\n.apexcharts-ink-card input.apexcharts-ink-editor {\n  flex: 1 1 auto;\n  width: 150px;\n  min-width: 0;\n  box-sizing: border-box;\n  padding: 4px 6px;\n  font: inherit;\n  color: inherit;\n  background: transparent;\n  border: 1px solid var(--apx-ink-card-border);\n  border-radius: 5px;\n}\n.apexcharts-ink-card input.apexcharts-ink-editor:focus {\n  outline: none;\n  border-color: var(--apx-ink-card-accent);\n}\n.apexcharts-ink-btn {\n  flex: 0 0 auto;\n  width: 24px;\n  height: 24px;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  padding: 0;\n  border: 0;\n  border-radius: 5px;\n  background: transparent;\n  color: inherit;\n  font: inherit;\n  font-size: 12px;\n  line-height: 1;\n  cursor: pointer;\n}\n.apexcharts-ink-btn:hover,\n.apexcharts-ink-btn--active {\n  background: var(--apx-ink-card-hover);\n}\n.apexcharts-ink-btn:focus-visible,\n.apexcharts-ink-swatch:focus-visible {\n  outline: 2px solid var(--apx-ink-card-accent);\n  outline-offset: 1px;\n}\n.apexcharts-ink-btn--bold {\n  font-weight: 700;\n}\n.apexcharts-ink-btn--delete:hover {\n  color: #dc2626;\n}\n.apexcharts-ink-swatch {\n  flex: 0 0 auto;\n  width: 16px;\n  height: 16px;\n  padding: 0;\n  border: 1px solid rgba(100, 116, 139, 0.45);\n  border-radius: 50%;\n  cursor: pointer;\n}\n.apexcharts-ink-swatch--active {\n  box-shadow:\n    0 0 0 2px var(--apx-ink-card-bg),\n    0 0 0 4px var(--apx-ink-card-accent);\n}\n.apexcharts-ink-sep {\n  flex: 0 0 auto;\n  width: 1px;\n  height: 16px;\n  margin: 0 2px;\n  background: var(--apx-ink-card-border);\n}\n.apexcharts-ink-cardlabel {\n  flex: 0 0 auto;\n  font-size: 10px;\n  letter-spacing: 0.4px;\n  text-transform: uppercase;\n  opacity: 0.65;\n  margin-right: 2px;\n}\n.apexcharts-ink-marker-size {\n  flex: 0 0 auto;\n  min-width: 16px;\n  text-align: center;\n  font-variant-numeric: tabular-nums;\n}\n\n.apexcharts-legend-text {\n  padding-left: 15px;\n  margin-left: -15px;\n}\n\n.apexcharts-legend-series[role=\"button\"]:focus {\n  outline: 2px solid var(--apexcharts-focus-color, #008FFB);\n  outline-offset: 2px;\n}\n\n.apexcharts-legend-series[role=\"button\"]:focus:not(:focus-visible) {\n  outline: none;\n}\n\n.apexcharts-legend-series[role=\"button\"]:focus-visible {\n  outline: 2px solid var(--apexcharts-focus-color, #008FFB);\n  outline-offset: 2px;\n}\n\n.apexcharts-series-collapsed {\n  opacity: 0\n}\n\n/* A series still playing its exit tween stays painted so it can visibly shrink\n   away, hiding it on the first frame leaves a hole in a stacked chart for the\n   length of the animation. Dropped once the tween lands. */\n.apexcharts-series-collapsed.apexcharts-series-collapsing {\n  opacity: 1\n}\n\n/* Its labels ride the shrinking marks, but a mark runs out of room for its text\n   well before it reaches zero, so fade them across the exit instead of holding\n   them crisp over a sliver. Duration is set inline from dynamicAnimation.speed. */\n.apexcharts-datalabels.apexcharts-series-collapsing {\n  animation: apexcharts-datalabels-exit var(--apexcharts-dl-exit, 400ms) ease-in\n    forwards;\n}\n\n@keyframes apexcharts-datalabels-exit {\n  from {\n    opacity: 1\n  }\n  to {\n    opacity: 0\n  }\n}\n\n.apexcharts-canvas svg:focus:not(:focus-visible) {\n  outline: none;\n}\n\n/* Keyboard navigation focus indicator on SVG data elements.\n   SVG elements don't support CSS outline, so we use stroke. */\n.apexcharts-bar-area.apexcharts-keyboard-focused,\n.apexcharts-candlestick-area.apexcharts-keyboard-focused,\n.apexcharts-boxPlot-area.apexcharts-keyboard-focused,\n.apexcharts-rangebar-area.apexcharts-keyboard-focused,\n.apexcharts-pie-area.apexcharts-keyboard-focused,\n.apexcharts-heatmap-rect.apexcharts-keyboard-focused,\n.apexcharts-treemap-rect.apexcharts-keyboard-focused {\n  stroke: var(--apexcharts-focus-color, #008FFB);\n  stroke-width: 2;\n  stroke-opacity: 1;\n}\n\n.apexcharts-tooltip {\n  --apx-tt-bg: #ffffff;\n  /* Shared by the body and the arrow's two outward facets, so the\n   * hairline reads as one continuous outline around the whole shape.\n   * Keep it strong enough to survive on its own: the shadow below is\n   * elevation, not edge definition. */\n  --apx-tt-border: rgba(15, 23, 42, 0.12);\n  /* Elevation, in three layers: a tight contact shadow that anchors the\n   * bottom edge, a directional key shadow for the lift, and a wide\n   * ambient one that grounds the whole box. Each is weaker and more\n   * diffuse than the last.\n   *\n   * A tooltip is unusual in that it floats over *data*, so reach costs\n   * more than it does on a page: every pixel the shadow travels tints a\n   * bar or a line the reader is trying to compare. These numbers are\n   * tuned to keep the near-edge contrast that reads as elevation while\n   * dropping the long low haze that only muddies the plot.\n   *\n   * Note there is deliberately no `0 0 0 1px` ring layer. That used to\n   * stand in for edge definition back when --apx-tt-border was barely\n   * visible; now that the border is a real hairline (and the arrow\n   * shares it) a ring only double-draws the outline, and being spread\n   * rather than offset it leaked ink upward too, flattening the lift.\n   *\n   * `--apx-tt-shadow-dir` flips the whole stack's Y in one place — see\n   * the `[data-placement=\"bottom\"]` rule further down. */\n  --apx-tt-shadow-dir: 1;\n  --apx-tt-shadow: 0 calc(var(--apx-tt-shadow-dir) * 1px) 2px rgba(15, 23, 42, 0.06), 0 calc(var(--apx-tt-shadow-dir) * 4px) 8px -2px rgba(15, 23, 42, 0.10), 0 calc(var(--apx-tt-shadow-dir) * 12px) 20px -8px rgba(15, 23, 42, 0.14);\n  --apx-tt-arrow-bg: var(--apx-tt-bg);\n  --apx-tt-color: #0f172a;\n  --apx-tt-color-muted: rgba(15, 23, 42, 0.55);\n  border-radius: 8px;\n  background: var(--apx-tt-bg);\n  border: 1px solid var(--apx-tt-border);\n  box-shadow: var(--apx-tt-shadow);\n  color: var(--apx-tt-color);\n  cursor: default;\n  font-size: 13px;\n  left: 0;\n  top: 0;\n  opacity: 0;\n  pointer-events: none;\n  position: absolute;\n  display: flex;\n  flex-direction: column;\n  padding: 2px 0;\n  white-space: nowrap;\n  z-index: 12;\n  transition: opacity .12s ease\n}\n\n/* While the tooltip is visible, smoothly animate position changes\n * between data points. Kept short (160 ms) and ease-out so it stays\n * responsive — too long would feel laggy when sweeping across many\n * points fast. The position transition is only attached after the\n * first paint (Position.applyTooltipPosition flips `data-positioned`\n * once the tooltip has been placed) so the *first* show doesn't slide\n * the tooltip in from the previously-stale (0,0) coordinates. */\n.apexcharts-tooltip.apexcharts-active {\n  opacity: 1;\n  transition: opacity .12s ease\n}\n.apexcharts-tooltip.apexcharts-active[data-positioned=\"true\"] {\n  transition: opacity .12s ease, left .16s ease-out, top .16s ease-out\n}\n\n.apexcharts-tooltip.apexcharts-theme-light {\n  /* defaults already set above; class kept for backward-compat selectors */\n}\n\n.apexcharts-tooltip.apexcharts-theme-dark {\n  --apx-tt-bg: #1c1c1f;\n  --apx-tt-border: rgba(255, 255, 255, 0.16);\n  /* Dark needs more alpha than light to register at all, but not as much\n   * as it used to: the light rim above now carries the edge, so the\n   * shadow is free to be pure elevation instead of doubling as an\n   * outline. Same geometry as light, heavier ink. */\n  --apx-tt-shadow: 0 calc(var(--apx-tt-shadow-dir) * 1px) 2px rgba(0, 0, 0, 0.24), 0 calc(var(--apx-tt-shadow-dir) * 4px) 8px -2px rgba(0, 0, 0, 0.30), 0 calc(var(--apx-tt-shadow-dir) * 12px) 20px -8px rgba(0, 0, 0, 0.38);\n  --apx-tt-color: #f3f4f6;\n  --apx-tt-color-muted: rgba(243, 244, 246, 0.55);\n}\n\n.apexcharts-tooltip * {\n  font-family: inherit\n}\n\n/* Point-annotation hover tooltip (apexcharts/apexcharts.js#2424). Reuses the\n * glass body/border/shadow from `.apexcharts-tooltip` but holds free-form\n * content, so it needs its own padding, wrapping and a sane max width. */\n.apexcharts-tooltip.apexcharts-annotation-tooltip {\n  padding: 6px 10px;\n  max-width: 240px;\n  white-space: normal;\n  line-height: 1.4;\n  pointer-events: none;\n  z-index: 13\n}\n\n.apexcharts-tooltip-title {\n  padding: 8px 12px 4px;\n  font-size: 12px;\n  font-weight: 600;\n  letter-spacing: 0.01em;\n  color: var(--apx-tt-color-muted);\n  background: transparent;\n  border-bottom: none;\n  margin-bottom: 0\n}\n\n.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title,\n.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {\n  background: transparent;\n  border-bottom: none\n}\n\n/* `fillSeriesColor`: each series-group already paints itself with the\n * series colour. Drop the glass body entirely (transparent bg, no\n * border, no backdrop-filter, no padding) and clip the coloured\n * series-group(s) to the tooltip's rounded corners so they fill the\n * shell edge-to-edge. Text inside the coloured group is forced to\n * white for contrast. */\n.apexcharts-tooltip.apexcharts-tooltip-fill-series {\n  background: transparent;\n  -webkit-backdrop-filter: none;\n  backdrop-filter: none;\n  border: none;\n  padding: 0;\n  overflow: hidden;\n  color: #fff\n}\n\n.apexcharts-tooltip.apexcharts-tooltip-fill-series .apexcharts-tooltip-title {\n  background: rgba(0, 0, 0, 0.22);\n  color: #fff;\n  opacity: 1;\n  padding: 6px 12px\n}\n\n.apexcharts-tooltip.apexcharts-tooltip-fill-series .apexcharts-tooltip-series-group {\n  color: #fff\n}\n\n/* Arrow connector — a 45°-rotated square straddling the body's edge, so\n * the body's 1px border runs continuously out across the arrow and back.\n * The two facets that face away from the tooltip carry the border; the\n * two that face into it carry none, and the square's opaque fill covers\n * the segment of the body's own border it sits on, hiding the seam.\n *\n * This is why it's a rotated square and not a triangle: `clip-path`\n * erases `border` and `box-shadow` along with everything outside the\n * polygon, which left `filter: drop-shadow` as the only way to suggest\n * an edge — and a drop-shadow can only ever blur one, never draw a\n * hairline. Nothing here needs a filter.\n *\n * Geometry: a square of side S rotated 45° reaches S/√2 from its centre\n * to each corner, so S = 10px gives the ~7px tip overhang that\n * ARROW_TIP_OVERHANG assumes (tooltip/constants.js) over a ~14px base.\n * The offsets park the square's *centre* 1px outside the padding box\n * (-6px = -1px border - 10px/2), i.e. exactly on the body's border line,\n * so the two borders meet end to end instead of overlapping or gapping.\n * `box-sizing` must be border-box or the bordered sides would grow the\n * square asymmetrically and knock its centre off that line. */\n.apexcharts-tooltip-arrow {\n  position: absolute;\n  box-sizing: border-box;\n  width: 10px;\n  height: 10px;\n  background: var(--apx-tt-arrow-bg);\n  transform: rotate(45deg);\n  pointer-events: none;\n  top: calc(var(--apx-tt-arrow-y, 50%) - 5px)\n}\n\n/* Which two sides face outward depends on the placement. Under\n * `rotate(45deg)` the square's bottom-left corner swings to the left,\n * top-right to the right, top-left to the top and bottom-right to the\n * bottom — so the pair of borders below is always the two sharing the\n * corner that ends up as the tip. */\n.apexcharts-tooltip[data-placement=\"right\"] .apexcharts-tooltip-arrow {\n  left: -6px;\n  border-left: 1px solid var(--apx-tt-border);\n  border-bottom: 1px solid var(--apx-tt-border)\n}\n\n.apexcharts-tooltip[data-placement=\"left\"] .apexcharts-tooltip-arrow {\n  right: -6px;\n  border-top: 1px solid var(--apx-tt-border);\n  border-right: 1px solid var(--apx-tt-border)\n}\n\n/* Vertical arrow variants: tooltip is above/below the data point and the\n * arrow points down/up. The base rule above uses `--apx-tt-arrow-y` for\n * left/right placement; for top/bottom we centre on `--apx-tt-arrow-x`\n * instead (set by applyTooltipPosition). */\n.apexcharts-tooltip[data-placement=\"top\"] .apexcharts-tooltip-arrow,\n.apexcharts-tooltip[data-placement=\"bottom\"] .apexcharts-tooltip-arrow {\n  top: auto;\n  left: calc(var(--apx-tt-arrow-x, 50%) - 5px)\n}\n\n.apexcharts-tooltip[data-placement=\"top\"] .apexcharts-tooltip-arrow {\n  bottom: -6px;\n  border-right: 1px solid var(--apx-tt-border);\n  border-bottom: 1px solid var(--apx-tt-border)\n}\n\n.apexcharts-tooltip[data-placement=\"bottom\"] .apexcharts-tooltip-arrow {\n  top: -6px;\n  border-top: 1px solid var(--apx-tt-border);\n  border-left: 1px solid var(--apx-tt-border)\n}\n\n/* When the tooltip is flipped below the data point, the default\n * downward-biased shadow leaves its top edge undefined. Negating the\n * direction casts the whole elevation upward instead, so the shadow\n * falls between the tooltip and the mark above it. One multiplier flips\n * all three layers together; the arrow needs no counterpart, since its\n * border doesn't depend on light direction. */\n.apexcharts-tooltip[data-placement=\"bottom\"] {\n  --apx-tt-shadow-dir: -1\n}\n\n.apexcharts-tooltip-text-goals-value,\n.apexcharts-tooltip-text-y-value,\n.apexcharts-tooltip-text-z-value {\n  display: inline-block;\n  margin-left: 5px;\n  font-weight: 600\n}\n\n.apexcharts-tooltip-text-goals-label:empty,\n.apexcharts-tooltip-text-goals-value:empty,\n.apexcharts-tooltip-text-y-label:empty,\n.apexcharts-tooltip-text-y-value:empty,\n.apexcharts-tooltip-text-z-value:empty,\n.apexcharts-tooltip-title:empty {\n  display: none\n}\n\n.apexcharts-tooltip-text-goals-label,\n.apexcharts-tooltip-text-goals-value {\n  padding: 6px 0 5px\n}\n\n.apexcharts-tooltip-goals-group,\n.apexcharts-tooltip-text-goals-label,\n.apexcharts-tooltip-text-goals-value {\n  display: flex\n}\n\n.apexcharts-tooltip-text-goals-label:not(:empty),\n.apexcharts-tooltip-text-goals-value:not(:empty) {\n  margin-top: -6px\n}\n\n.apexcharts-tooltip-marker {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  position: relative;\n  width: 12px;\n  height: 12px;\n  margin-right: 6px;\n  vertical-align: middle;\n  color: inherit;\n}\n\n.apexcharts-tooltip-marker svg {\n  width: 100%;\n  height: 100%;\n  display: block;\n}\n\n.apexcharts-tooltip-series-group {\n  padding: 4px 12px;\n  display: none;\n  gap: 8px;\n  text-align: left;\n  justify-content: left;\n  align-items: center\n}\n\n.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {\n  opacity: 1\n}\n\n.apexcharts-tooltip-series-group.apexcharts-active:last-child,\n.apexcharts-tooltip-series-group:last-child {\n  padding-bottom: 8px\n}\n\n.apexcharts-tooltip-y-group {\n  padding: 6px 0 5px\n}\n\n/* `tooltip.compact`: a tight box instead of a card, for panels a normal card\n   would cover (small multiples, sparklines, tiles). Only the box shrinks, so\n   the arrow and every anchor rule still apply. Rows stay stacked when there\n   are several series (the names are what tells them apart); a one-series\n   chart collapses to a single line, see `-value-only` below. */\n.apexcharts-tooltip.apexcharts-tooltip-compact {\n  padding: 3px 8px;\n  font-size: 11px;\n  line-height: 1.35\n}\n\n.apexcharts-tooltip-compact .apexcharts-tooltip-title {\n  padding: 0;\n  font-size: 11px;\n  white-space: nowrap\n}\n\n.apexcharts-tooltip-compact .apexcharts-tooltip-series-group,\n.apexcharts-tooltip-compact .apexcharts-tooltip-series-group.apexcharts-active:last-child,\n.apexcharts-tooltip-compact .apexcharts-tooltip-series-group:last-child {\n  padding: 0;\n  gap: 5px\n}\n\n.apexcharts-tooltip-compact .apexcharts-tooltip-y-group {\n  padding: 0\n}\n\n.apexcharts-tooltip-compact .apexcharts-tooltip-marker {\n  width: 8px;\n  height: 8px\n}\n\n/* A one-series panel: the series name repeats what the panel header already\n   says, so the value stands alone and the x label becomes its prefix on one\n   line (\"Aug 2024  6.59\"). */\n.apexcharts-tooltip.apexcharts-tooltip-compact.apexcharts-tooltip-value-only {\n  /* The tooltip body is a flex COLUMN by default (title row, then series\n     rows); one series needs no column, so the same box turns into one line. */\n  flex-direction: row;\n  align-items: baseline;\n  gap: 6px\n}\n\n.apexcharts-tooltip-value-only .apexcharts-tooltip-marker {\n  display: none\n}\n\n.apexcharts-tooltip-value-only .apexcharts-tooltip-text-y-label {\n  display: none\n}\n\n.apexcharts-custom-tooltip,\n.apexcharts-tooltip-box {\n  padding: 4px 8px\n}\n\n.apexcharts-tooltip-boxPlot {\n  display: flex;\n  flex-direction: column-reverse\n}\n\n.apexcharts-tooltip-box>div {\n  margin: 4px 0\n}\n\n.apexcharts-tooltip-box span.value {\n  font-weight: 700\n}\n\n.apexcharts-tooltip-rangebar {\n  padding: 5px 8px\n}\n\n.apexcharts-tooltip-rangebar .category {\n  font-weight: 600;\n  color: #777\n}\n\n.apexcharts-tooltip-rangebar .series-name {\n  font-weight: 700;\n  display: block;\n  margin-bottom: 5px\n}\n\n/* X/Y axis tooltips — small popovers that label the crosshair on the\n * axes. Restyled to match the modern data-tooltip palette: solid white\n * body with a subtle border + soft drop-shadow, smaller font, rounded\n * corners. The arrows still use the CSS border-triangle technique\n * (cheap, crisp at small sizes); their colours flow from CSS variables\n * so light/dark themes only need one override per axis. */\n.apexcharts-xaxistooltip,\n.apexcharts-yaxistooltip {\n  --apx-axt-bg: #ffffff;\n  --apx-axt-border: rgba(15, 23, 42, 0.08);\n  --apx-axt-color: #0f172a;\n  --apx-axt-shadow: 0 4px 12px -4px rgba(15, 23, 42, 0.18), 0 1px 3px -1px rgba(15, 23, 42, 0.12);\n  opacity: 0;\n  pointer-events: none;\n  color: var(--apx-axt-color);\n  font-size: 12px;\n  font-weight: 500;\n  text-align: center;\n  border-radius: 6px;\n  position: absolute;\n  z-index: 10;\n  background: var(--apx-axt-bg);\n  border: 1px solid var(--apx-axt-border);\n  box-shadow: var(--apx-axt-shadow)\n}\n\n.apexcharts-xaxistooltip.apexcharts-theme-dark,\n.apexcharts-yaxistooltip.apexcharts-theme-dark {\n  --apx-axt-bg: #1c1c1f;\n  --apx-axt-border: rgba(255, 255, 255, 0.1);\n  --apx-axt-color: #f3f4f6;\n  --apx-axt-shadow: 0 4px 12px -4px rgba(0, 0, 0, 0.55), 0 1px 3px -1px rgba(0, 0, 0, 0.45)\n}\n\n.apexcharts-xaxistooltip {\n  padding: 4px 8px;\n  transition: .15s ease all\n}\n\n.apexcharts-xaxistooltip:after,\n.apexcharts-xaxistooltip:before {\n  left: 50%;\n  border: solid transparent;\n  content: \" \";\n  height: 0;\n  width: 0;\n  position: absolute;\n  pointer-events: none\n}\n\n/* :before paints the 1px border outline of the triangle (slightly larger\n * than :after); :after sits inside and paints the fill — leaves a 1px\n * ring of :before visible at the edges. */\n.apexcharts-xaxistooltip:after {\n  border-color: transparent;\n  border-width: 5px;\n  margin-left: -5px\n}\n\n.apexcharts-xaxistooltip:before {\n  border-color: transparent;\n  border-width: 6px;\n  margin-left: -6px\n}\n\n.apexcharts-xaxistooltip-bottom:after,\n.apexcharts-xaxistooltip-bottom:before {\n  bottom: 100%\n}\n\n.apexcharts-xaxistooltip-top:after,\n.apexcharts-xaxistooltip-top:before {\n  top: 100%\n}\n\n.apexcharts-xaxistooltip-bottom:after {\n  border-bottom-color: var(--apx-axt-bg)\n}\n\n.apexcharts-xaxistooltip-bottom:before {\n  border-bottom-color: var(--apx-axt-border)\n}\n\n.apexcharts-xaxistooltip-top:after {\n  border-top-color: var(--apx-axt-bg)\n}\n\n.apexcharts-xaxistooltip-top:before {\n  border-top-color: var(--apx-axt-border)\n}\n\n.apexcharts-xaxistooltip.apexcharts-active {\n  opacity: 1;\n  transition: .15s ease all\n}\n\n.apexcharts-yaxistooltip {\n  padding: 3px 8px\n}\n\n.apexcharts-yaxistooltip:after,\n.apexcharts-yaxistooltip:before {\n  top: 50%;\n  border: solid transparent;\n  content: \" \";\n  height: 0;\n  width: 0;\n  position: absolute;\n  pointer-events: none\n}\n\n.apexcharts-yaxistooltip:after {\n  border-color: transparent;\n  border-width: 5px;\n  margin-top: -5px\n}\n\n.apexcharts-yaxistooltip:before {\n  border-color: transparent;\n  border-width: 6px;\n  margin-top: -6px\n}\n\n.apexcharts-yaxistooltip-left:after,\n.apexcharts-yaxistooltip-left:before {\n  left: 100%\n}\n\n.apexcharts-yaxistooltip-right:after,\n.apexcharts-yaxistooltip-right:before {\n  right: 100%\n}\n\n.apexcharts-yaxistooltip-left:after {\n  border-left-color: var(--apx-axt-bg)\n}\n\n.apexcharts-yaxistooltip-left:before {\n  border-left-color: var(--apx-axt-border)\n}\n\n.apexcharts-yaxistooltip-right:after {\n  border-right-color: var(--apx-axt-bg)\n}\n\n.apexcharts-yaxistooltip-right:before {\n  border-right-color: var(--apx-axt-border)\n}\n\n.apexcharts-yaxistooltip.apexcharts-active {\n  opacity: 1\n}\n\n.apexcharts-yaxistooltip-hidden {\n  display: none\n}\n\n.apexcharts-xcrosshairs,\n.apexcharts-ycrosshairs {\n  pointer-events: none;\n  opacity: 0;\n  transition: .15s ease all\n}\n\n.apexcharts-xcrosshairs.apexcharts-active,\n.apexcharts-ycrosshairs.apexcharts-active {\n  opacity: 1;\n  transition: .15s ease all\n}\n\n.apexcharts-ycrosshairs-hidden {\n  opacity: 0\n}\n\n.apexcharts-selection-rect {\n  cursor: move\n}\n\n.svg_select_shape {\n  stroke-width: 1;\n  stroke-dasharray: 10 10;\n  stroke: black;\n  stroke-opacity: 0.1;\n  pointer-events: none;\n  fill: none;\n}\n\n.svg_select_handle {\n  stroke-width: 3;\n  stroke: black;\n  fill: none;\n}\n\n.svg_select_handle_r {\n  cursor: e-resize;\n}\n\n.svg_select_handle_l {\n  cursor: w-resize;\n}\n\n.apexcharts-svg.apexcharts-zoomable.hovering-zoom {\n  cursor: crosshair\n}\n\n.apexcharts-svg.apexcharts-zoomable.hovering-pan {\n  cursor: move\n}\n\n.apexcharts-menu-icon,\n.apexcharts-measure-icon,\n.apexcharts-pan-icon,\n.apexcharts-reset-icon,\n.apexcharts-selection-icon,\n.apexcharts-toolbar-custom-icon,\n.apexcharts-zoom-icon,\n.apexcharts-zoomin-icon,\n.apexcharts-zoomout-icon {\n  cursor: pointer;\n  /* WCAG 2.5.8 Target Size (Minimum): 24×24 CSS px hit target. */\n  width: 26px;\n  height: 24px;\n  line-height: 24px;\n  color: #6e8192;\n  text-align: center;\n  /* Reset native <button> chrome — these are styled via SVG icons. */\n  padding: 0;\n  margin: 0;\n  background: transparent;\n  border: 0;\n  border-radius: 5px;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  transition: background-color .12s ease, color .12s ease;\n}\n\n.apexcharts-menu-icon svg,\n.apexcharts-measure-icon svg,\n.apexcharts-pan-icon svg,\n.apexcharts-reset-icon svg,\n.apexcharts-selection-icon svg,\n.apexcharts-zoom-icon svg,\n.apexcharts-zoomin-icon svg,\n.apexcharts-zoomout-icon svg {\n  width: 18px;\n  height: 18px;\n  fill: none;\n  stroke: currentColor;\n  stroke-width: 2;\n  stroke-linecap: round;\n  stroke-linejoin: round\n}\n\n.apexcharts-theme-dark .apexcharts-menu-icon,\n.apexcharts-theme-dark .apexcharts-measure-icon,\n.apexcharts-theme-dark .apexcharts-pan-icon,\n.apexcharts-theme-dark .apexcharts-reset-icon,\n.apexcharts-theme-dark .apexcharts-selection-icon,\n.apexcharts-theme-dark .apexcharts-toolbar-custom-icon,\n.apexcharts-theme-dark .apexcharts-zoom-icon,\n.apexcharts-theme-dark .apexcharts-zoomin-icon,\n.apexcharts-theme-dark .apexcharts-zoomout-icon {\n  color: #d4d6dc\n}\n\n.apexcharts-canvas .apexcharts-measure-icon.apexcharts-selected,\n.apexcharts-canvas .apexcharts-pan-icon.apexcharts-selected,\n.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected,\n.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected,\n.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected {\n  background: rgba(0, 143, 251, 0.12);\n  color: #008ffb\n}\n\n.apexcharts-theme-light .apexcharts-menu-icon:hover,\n.apexcharts-theme-light .apexcharts-measure-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-light .apexcharts-pan-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-light .apexcharts-reset-icon:hover,\n.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-light .apexcharts-zoomin-icon:hover,\n.apexcharts-theme-light .apexcharts-zoomout-icon:hover {\n  background: rgba(15, 23, 42, 0.06);\n  color: #1f2937\n}\n\n.apexcharts-theme-dark .apexcharts-menu-icon:hover,\n.apexcharts-theme-dark .apexcharts-measure-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-dark .apexcharts-pan-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-dark .apexcharts-reset-icon:hover,\n.apexcharts-theme-dark .apexcharts-selection-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-dark .apexcharts-zoom-icon:not(.apexcharts-selected):hover,\n.apexcharts-theme-dark .apexcharts-zoomin-icon:hover,\n.apexcharts-theme-dark .apexcharts-zoomout-icon:hover {\n  background: rgba(255, 255, 255, 0.08);\n  color: #fff\n}\n\n.apexcharts-menu-icon,\n.apexcharts-selection-icon {\n  position: relative\n}\n\n.apexcharts-toolbar {\n  position: absolute;\n  z-index: 11;\n  display: inline-flex;\n  align-items: center;\n  gap: 1px;\n  padding: 3px;\n  border-radius: 8px;\n  background: rgba(255, 255, 255, 0.85);\n  backdrop-filter: blur(8px);\n  -webkit-backdrop-filter: blur(8px);\n}\n\n.apexcharts-theme-dark .apexcharts-toolbar {\n  background: rgba(28, 28, 31, 0.82);\n}\n\n.apexcharts-menu {\n  background: rgba(255, 255, 255, 0.95);\n  backdrop-filter: blur(8px);\n  -webkit-backdrop-filter: blur(8px);\n  position: absolute;\n  top: calc(100% + 4px);\n  border: 1px solid rgba(15, 23, 42, 0.08);\n  border-radius: 8px;\n  padding: 4px;\n  right: 0;\n  opacity: 0;\n  min-width: 120px;\n  transition: opacity .15s ease, transform .15s ease;\n  transform: translateY(-2px);\n  pointer-events: none;\n  box-shadow: 0 4px 16px -4px rgba(15, 23, 42, 0.12), 0 2px 4px -1px rgba(15, 23, 42, 0.06)\n}\n\n.apexcharts-menu.apexcharts-menu-open {\n  opacity: 1;\n  transform: translateY(0);\n  pointer-events: all\n}\n\n.apexcharts-menu-item {\n  padding: 6px 9px;\n  font-size: 12px;\n  border-radius: 5px;\n  cursor: pointer\n}\n\n.apexcharts-theme-light .apexcharts-menu-item:hover {\n  background: rgba(15, 23, 42, 0.06)\n}\n\n.apexcharts-theme-dark .apexcharts-menu {\n  background: rgba(28, 28, 31, 0.92);\n  border-color: rgba(255, 255, 255, 0.08);\n  color: #f3f4f6;\n  box-shadow: 0 4px 16px -4px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.4)\n}\n\n.apexcharts-theme-dark .apexcharts-menu-item:hover {\n  background: rgba(255, 255, 255, 0.08)\n}\n\n@media screen and (min-width:768px) {\n  .apexcharts-canvas:hover .apexcharts-toolbar {\n    opacity: 1\n  }\n}\n\n/* Toolbar keyboard accessibility: show toolbar when any button inside it is focused */\n.apexcharts-toolbar:focus-within {\n  opacity: 1\n}\n\n/* Focus indicator for toolbar icon buttons */\n.apexcharts-menu-icon:focus-visible,\n.apexcharts-measure-icon:focus-visible,\n.apexcharts-pan-icon:focus-visible,\n.apexcharts-reset-icon:focus-visible,\n.apexcharts-selection-icon:focus-visible,\n.apexcharts-toolbar-custom-icon:focus-visible,\n.apexcharts-zoom-icon:focus-visible,\n.apexcharts-zoomin-icon:focus-visible,\n.apexcharts-zoomout-icon:focus-visible {\n  outline: 2px solid var(--apexcharts-focus-color, #008FFB);\n  outline-offset: 1px;\n  border-radius: 5px\n}\n\n/* Focus indicator for hamburger menu items */\n.apexcharts-menu-item:focus-visible {\n  outline: 2px solid var(--apexcharts-focus-color, #008FFB);\n  outline-offset: -2px;\n  background: #eee\n}\n\n.apexcharts-canvas .apexcharts-element-hidden,\n.apexcharts-datalabel.apexcharts-element-hidden,\n.apexcharts-hide .apexcharts-series-points {\n  opacity: 0;\n}\n\n.apexcharts-hidden-element-shown {\n  opacity: 1;\n  transition: 0.25s ease all;\n}\n\n.apexcharts-datalabel,\n.apexcharts-datalabel-label,\n.apexcharts-datalabel-value,\n.apexcharts-datalabels,\n.apexcharts-pie-label,\n.apexcharts-pie-name-label,\n.apexcharts-pie-name-label-group,\n.apexcharts-pie-label-connector,\n.apexcharts-unit-outer-label,\n.apexcharts-unit-outer-label-group,\n.apexcharts-unit-label-connector {\n  cursor: default;\n  pointer-events: none\n}\n\n.apexcharts-pie-label-connector,\n.apexcharts-unit-label-connector {\n  fill: none\n}\n\n.apexcharts-pie-label-delay,\n.apexcharts-unit-label-delay {\n  opacity: 0;\n  animation-name: opaque;\n  animation-duration: .3s;\n  animation-fill-mode: forwards;\n  animation-timing-function: ease\n}\n\n/* Slower than the pie's, on purpose: these come in while the dots are still\n   easing into place, so a longer fade reads as arriving WITH the crowd. */\n.apexcharts-unit-label-delay {\n  animation-duration: .5s\n}\n\n.apexcharts-radialbar-label {\n  cursor: pointer;\n}\n\n.apexcharts-annotation-rect,\n.apexcharts-area-series .apexcharts-area,\n.apexcharts-gridline,\n.apexcharts-line,\n.apexcharts-point-annotation-label,\n.apexcharts-radar-series path:not(.apexcharts-marker),\n.apexcharts-radar-series polygon,\n.apexcharts-toolbar svg,\n.apexcharts-tooltip .apexcharts-marker,\n.apexcharts-xaxis-annotation-label,\n.apexcharts-yaxis-annotation-label,\n.apexcharts-zoom-rect,\n.no-pointer-events {\n  pointer-events: none\n}\n\n.apexcharts-tooltip-active .apexcharts-marker {\n  transition: .15s ease all\n}\n\n.apexcharts-radar-series .apexcharts-yaxis {\n  pointer-events: none;\n}\n\n.resize-triggers {\n  animation: 1ms resizeanim;\n  visibility: hidden;\n  opacity: 0;\n  height: 100%;\n  width: 100%;\n  overflow: hidden\n}\n\n.contract-trigger:before,\n.resize-triggers,\n.resize-triggers>div {\n  content: \" \";\n  display: block;\n  position: absolute;\n  top: 0;\n  left: 0\n}\n\n.resize-triggers>div {\n  height: 100%;\n  width: 100%;\n  background: #eee;\n  overflow: auto\n}\n\n.contract-trigger:before {\n  overflow: hidden;\n  width: 200%;\n  height: 200%\n}\n\n.apexcharts-bar-goals-markers {\n  pointer-events: none\n}\n\n.apexcharts-bar-shadows {\n  pointer-events: none\n}\n\n.apexcharts-rangebar-goals-markers {\n  pointer-events: none\n}\n\n.apexcharts-drilldown-target {\n  cursor: pointer\n}\n\n.apexcharts-breadcrumb {\n  position: absolute;\n  z-index: 11;\n  display: inline-flex;\n  align-items: center;\n  gap: 2px;\n  font-size: 12px;\n  font-family: inherit;\n  padding: 2px 4px\n}\n\n.apexcharts-breadcrumb-item {\n  background: transparent;\n  border: none;\n  padding: 2px 6px;\n  border-radius: 3px;\n  font: inherit;\n  color: inherit;\n  cursor: pointer;\n  line-height: 1.2\n}\n\n.apexcharts-breadcrumb-item:hover:not(.apexcharts-breadcrumb-current) {\n  background: rgba(0, 0, 0, 0.08)\n}\n\n.apexcharts-breadcrumb-arrow {\n  margin-right: 4px;\n  font-weight: 600;\n  user-select: none\n}\n\n.apexcharts-breadcrumb-current {\n  cursor: default;\n  font-weight: 600;\n  opacity: 0.85\n}\n\n.apexcharts-breadcrumb-separator {\n  opacity: 0.5;\n  user-select: none\n}\n\n.apexcharts-theme-dark .apexcharts-breadcrumb-item:hover:not(.apexcharts-breadcrumb-current) {\n  background: rgba(255, 255, 255, 0.12)\n}\n\n.apexcharts-drilldown-loading {\n  position: absolute;\n  inset: 0;\n  z-index: 12;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 10px;\n  font-size: 13px;\n  font-family: inherit;\n  color: inherit;\n  background: rgba(255, 255, 255, 0.62);\n  /* The chart underneath stays interactive-looking but must not take clicks\n     while a level is resolving, or a second drill can start mid-fetch. */\n  cursor: progress\n}\n\n.apexcharts-drilldown-loading-spinner {\n  width: 26px;\n  height: 26px;\n  border-radius: 50%;\n  border: 2.5px solid rgba(0, 0, 0, 0.16);\n  border-top-color: rgba(0, 0, 0, 0.55);\n  animation: apexcharts-drilldown-spin 0.7s linear infinite\n}\n\n.apexcharts-drilldown-loading-text {\n  opacity: 0.8\n}\n\n.apexcharts-theme-dark .apexcharts-drilldown-loading {\n  background: rgba(30, 30, 30, 0.62)\n}\n\n.apexcharts-theme-dark .apexcharts-drilldown-loading-spinner {\n  border-color: rgba(255, 255, 255, 0.22);\n  border-top-color: rgba(255, 255, 255, 0.7)\n}\n\n@keyframes apexcharts-drilldown-spin {\n  to {\n    transform: rotate(360deg)\n  }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .apexcharts-drilldown-loading-spinner {\n    animation: apexcharts-drilldown-pulse 1.4s ease-in-out infinite\n  }\n\n  @keyframes apexcharts-drilldown-pulse {\n    0%, 100% {\n      opacity: 0.35\n    }\n\n    50% {\n      opacity: 1\n    }\n  }\n}\n\n.apexcharts-disable-transitions * {\n  transition: none !important;\n}\n/* ── Trellis (#22): small multiples ─────────────────────────────────────── */\n.apexcharts-trellis {\n  position: relative;\n}\n.apexcharts-trellis-grid {\n  display: grid;\n}\n.apexcharts-trellis-cell {\n  min-width: 0;\n  position: relative;\n}\n.apexcharts-trellis-header {\n  font-size: 12px;\n  font-weight: 600;\n  line-height: 22px;\n  height: 22px;\n  text-align: center;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  color: var(--apx-fore, #373d3f);\n}\n.apexcharts-trellis-title {\n  font-size: 14px;\n  font-weight: 700;\n  padding: 2px 0 6px;\n  color: var(--apx-fore, #373d3f);\n}\n/* Edge-label policy: a muted cell hides its axis-label INK, never the label\n   SPACE — every panel keeps the identical plot rectangle, and flipping the\n   policy on a resize is a class toggle, not a re-render. */\n.apexcharts-trellis-mute-y .apexcharts-yaxis {\n  opacity: 0;\n}\n.apexcharts-trellis-mute-x .apexcharts-xaxis {\n  opacity: 0;\n}\n/* The shared toolbar floats at the top-right, so a grid that has one starts\n   below it: from four columns on, the last cell's header (or a 2-D column\n   strip label) would otherwise run under the buttons. One band for the whole\n   grid, not per panel. */\n.apexcharts-trellis-has-toolbar {\n  padding-top: 24px;\n}\n/* 2-D faceting (P4): column labels once across the top, row labels once\n   down the left. The row strip column is auto-sized; panel columns stay\n   equal fractions, so panel alignment is independent of the strip width. */\n.apexcharts-trellis-strip {\n  font-size: 12px;\n  font-weight: 600;\n  color: var(--apx-fore, #373d3f);\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.apexcharts-trellis-strip-column {\n  text-align: center;\n  line-height: 22px;\n  height: 22px;\n  align-self: end;\n}\n.apexcharts-trellis-strip-row {\n  align-self: center;\n  max-width: 140px;\n  padding-right: 6px;\n}\n/* Empty (row, column) combinations. 'placeholder' keeps a REAL panel with a\n   quiet label; 'skip' shows the tinted skeleton; 'hide' shows nothing while\n   keeping the grid slot. */\n.apexcharts-trellis-cell-empty {\n  position: relative;\n}\n.apexcharts-trellis-empty-label {\n  position: absolute;\n  inset: 0;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 12px;\n  color: var(--apx-fore, #373d3f);\n  opacity: 0.45;\n  pointer-events: none;\n}\n.apexcharts-trellis-cell-hidden > * {\n  visibility: hidden;\n}\n/* P5: one shared gradient strip is a heatmap grid's legend. The slot is\n   content-sized inline (the strip svg's own box); centering is its own. */\n.apexcharts-trellis-gradient-legend {\n  margin: 10px auto 0;\n}\n/* Virtualization (P2): an unmounted panel's mount div reserves the exact\n   panel height (inline min-height) so page height and scroll position never\n   shift; the skeleton itself is a quiet tinted block. Deliberately not\n   animated: a shimmering grid of 200 placeholders is noise. */\n.apexcharts-trellis-panel.apexcharts-trellis-skeleton {\n  background: var(--apx-fore, #373d3f);\n  opacity: 0.05;\n  border-radius: 4px;\n}\n/* tooltip: 'panel' — the group still syncs every panel's crosshair, but only\n   the hovered cell shows its tooltip cards. */\n.apexcharts-trellis[data-tooltip-mode='panel'] .apexcharts-trellis-cell:not(:hover) .apexcharts-tooltip,\n.apexcharts-trellis[data-tooltip-mode='panel'] .apexcharts-trellis-cell:not(:hover) .apexcharts-xaxistooltip,\n.apexcharts-trellis[data-tooltip-mode='panel'] .apexcharts-trellis-cell:not(:hover) .apexcharts-yaxistooltip {\n  opacity: 0 !important;\n}\n/* tooltip: 'grid' (P3) — ALL per-panel tooltip ink is hidden (the group\n   still computes it; the trellis card reads it) and one trellis-owned card\n   follows the cursor with one row per panel. */\n.apexcharts-trellis[data-tooltip-mode='grid'] .apexcharts-trellis-cell .apexcharts-tooltip,\n.apexcharts-trellis[data-tooltip-mode='grid'] .apexcharts-trellis-cell .apexcharts-xaxistooltip,\n.apexcharts-trellis[data-tooltip-mode='grid'] .apexcharts-trellis-cell .apexcharts-yaxistooltip {\n  opacity: 0 !important;\n}\n.apexcharts-trellis-tooltip {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 14;\n  pointer-events: none;\n  opacity: 0;\n  transition: opacity 0.1s ease;\n  background: var(--apx-bg, #fff);\n  color: var(--apx-fore, #373d3f);\n  border: 1px solid rgba(120, 120, 120, 0.25);\n  border-radius: 5px;\n  box-shadow: 2px 2px 6px -4px rgba(0, 0, 0, 0.4);\n  font-size: 12px;\n  min-width: 140px;\n  max-width: 320px;\n}\n.apexcharts-trellis-tooltip-active {\n  opacity: 1;\n}\n.apexcharts-trellis-tooltip .apexcharts-tooltip-title {\n  padding: 5px 10px;\n  font-weight: 600;\n  background: rgba(120, 120, 120, 0.08);\n  border-bottom: 1px solid rgba(120, 120, 120, 0.18);\n  margin-bottom: 2px;\n}\n.apexcharts-trellis-tooltip-row {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 14px;\n  padding: 2px 10px;\n  line-height: 1.6;\n}\n.apexcharts-trellis-tooltip-row-active {\n  background: rgba(120, 120, 120, 0.1);\n  font-weight: 600;\n}\n.apexcharts-trellis-tooltip-key {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.apexcharts-trellis-tooltip-vals {\n  display: flex;\n  gap: 10px;\n  white-space: nowrap;\n}\n.apexcharts-trellis-tooltip-val {\n  display: inline-flex;\n  align-items: center;\n  gap: 5px;\n}\n.apexcharts-trellis-tooltip-marker {\n  width: 8px;\n  height: 8px;\n  border-radius: 50%;\n  display: inline-block;\n  flex: none;\n}\n/* Panel promotion (P3): the promoted cell spans the grid; the rest park.\n   The promoted panel is the only visible one, so both its axes unmute. */\n.apexcharts-trellis-cell-promoted {\n  grid-column: 1 / -1;\n}\n.apexcharts-trellis-cell-parked {\n  display: none;\n}\n.apexcharts-trellis-cell-promoted.apexcharts-trellis-mute-y .apexcharts-yaxis,\n.apexcharts-trellis-cell-promoted.apexcharts-trellis-mute-x .apexcharts-xaxis {\n  opacity: 1;\n}\n.apexcharts-trellis-header-clickable {\n  cursor: pointer;\n}\n.apexcharts-trellis-header-clickable:hover {\n  text-decoration: underline;\n  text-underline-offset: 3px;\n}\n.apexcharts-trellis-breadcrumb {\n  display: flex;\n  align-items: center;\n  gap: 6px;\n  font-size: 12px;\n  padding: 2px 0 6px;\n  color: var(--apx-fore, #373d3f);\n}\n.apexcharts-trellis-breadcrumb-back {\n  border: none;\n  background: none;\n  padding: 0;\n  font-size: 12px;\n  cursor: pointer;\n  color: var(--apx-accent, #008ffb);\n}\n.apexcharts-trellis-breadcrumb-back:hover {\n  text-decoration: underline;\n}\n.apexcharts-trellis-breadcrumb-sep {\n  opacity: 0.5;\n}\n.apexcharts-trellis-breadcrumb-current {\n  font-weight: 600;\n}\n/* The toolbar download menu (P3). */\n.apexcharts-trellis-menu {\n  position: absolute;\n  top: 26px;\n  right: 0;\n  display: none;\n  flex-direction: column;\n  min-width: 132px;\n  background: var(--apx-bg, #fff);\n  border: 1px solid rgba(120, 120, 120, 0.25);\n  border-radius: 5px;\n  box-shadow: 2px 2px 6px -4px rgba(0, 0, 0, 0.4);\n  padding: 4px;\n  z-index: 15;\n}\n.apexcharts-trellis-menu-open {\n  display: flex;\n}\n.apexcharts-trellis-menu-item {\n  border: none;\n  background: none;\n  text-align: left;\n  font-size: 12px;\n  padding: 5px 8px;\n  border-radius: 3px;\n  cursor: pointer;\n  color: var(--apx-fore, #373d3f);\n}\n.apexcharts-trellis-menu-item:hover {\n  background: rgba(120, 120, 120, 0.12);\n}\n.apexcharts-trellis-toolbar {\n  position: absolute;\n  top: 0;\n  right: 0;\n  display: flex;\n  gap: 2px;\n  z-index: 12;\n}\n.apexcharts-trellis-tool {\n  border: 0;\n  background: transparent;\n  padding: 2px;\n  cursor: pointer;\n  border-radius: 3px;\n  color: #6e8192;\n  line-height: 0;\n}\n.apexcharts-trellis-tool:hover {\n  color: var(--apx-fore, #373d3f);\n}\n.apexcharts-trellis-tool.apexcharts-selected {\n  color: var(--apx-accent, #008ffb);\n}\n.apexcharts-trellis-legend {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  gap: 4px 14px;\n  padding: 8px 10px 2px;\n}\n.apexcharts-trellis-legend-item {\n  display: flex;\n  align-items: center;\n  gap: 6px;\n  cursor: pointer;\n  line-height: 1;\n}\n.apexcharts-trellis-legend-item .apexcharts-legend-marker {\n  width: 12px;\n  height: 12px;\n  border-radius: 50%;\n  display: inline-block;\n}\n.apexcharts-trellis-legend-item .apexcharts-legend-text {\n  font-size: 12px;\n  color: var(--apx-fore, #373d3f);\n}\n.apexcharts-trellis-legend-item.apexcharts-inactive-legend {\n  opacity: 0.45;\n}\n";
const e = globalThis.console;
function t(t2) {
  e.error(t2);
}
function s(t2) {
  e.warn(t2);
}
const i = "APEX-", n = /* @__PURE__ */ new Date("2027-07-31T00:00:00Z"), r = "__apex_license_v1__";
function a() {
  const e2 = globalThis;
  let t2 = e2[r];
  return t2 || (t2 = { key: null, listeners: /* @__PURE__ */ new Set(), result: null }, e2[r] = t2), t2;
}
const l = class {
  static get licenseKey() {
    return a().key;
  }
  static set licenseKey(e2) {
    a().key = e2;
  }
  static get listeners() {
    return a().listeners;
  }
  static get validationResult() {
    return a().result;
  }
  static set validationResult(e2) {
    a().result = e2;
  }
  static getKey() {
    return this.licenseKey;
  }
  static getLicenseStatus() {
    return this.licenseKey ? (this.validationResult = this.validateKey(this.licenseKey), this.validationResult) : { expired: false, signatureVerified: false, valid: false };
  }
  static isKeyValid(e2) {
    return !!e2 && this.validateKey(e2).valid;
  }
  static isLicenseValid() {
    return this.getLicenseStatus().valid;
  }
  static onChange(e2) {
    return this.listeners.add(e2), () => {
      this.listeners.delete(e2);
    };
  }
  static setLicense(e2) {
    var _a;
    var i2;
    if (!e2) return this.licenseKey = null, void this.publish({ expired: false, signatureVerified: false, valid: false });
    const n2 = this.validateKey(e2);
    n2.valid || e2 === this.licenseKey || !(null == (i2 = this.validationResult) ? void 0 : i2.valid) ? (this.licenseKey = e2, this.publish(n2), n2.valid || t(`[Apex] ${n2.message}`)) : s(`[Apex] Ignoring license key: ${(_a = n2.message) != null ? _a : "it is not valid"} A valid license is already active on this page.`);
  }
  static validateKey(e2) {
    const t2 = this.parseKey(e2), s2 = this.validateStructure(e2, t2);
    if (!s2.valid || !(null == t2 ? void 0 : t2.signature)) return s2;
    const i2 = this.verdicts.get(e2);
    return false === i2 ? { data: t2.data, expired: false, message: "Invalid license key. The license signature does not verify.", signatureVerified: true, valid: false } : (void 0 === i2 && this.verifySignature(e2, t2, s2), __spreadProps(__spreadValues({}, s2), { signatureVerified: true === i2 }));
  }
  static _resetSignatureState() {
    this.verdicts.clear(), this.verifying.clear(), this.warnedUnverifiable = false, this.epoch++;
  }
  static base64ToBytes(e2) {
    const t2 = e2.replace(/-/g, "+").replace(/_/g, "/"), s2 = t2.padEnd(4 * Math.ceil(t2.length / 4), "="), i2 = globalThis.atob;
    if ("function" != typeof i2) throw new Error("no base64 decoder available");
    const n2 = i2(s2), r2 = new Uint8Array(n2.length);
    for (let e3 = 0; e3 < n2.length; e3++) r2[e3] = n2.charCodeAt(e3);
    return r2;
  }
  static canonicalPayload(e2) {
    const t2 = e2.domains && e2.domains.length > 0 ? e2.domains.join(",") : "";
    return `v1|${e2.issueDate}|${e2.expiryDate}|${e2.plan}|${t2}`;
  }
  static notify(e2) {
    for (const t2 of this.listeners) try {
      t2(e2);
    } catch (e3) {
    }
  }
  static parseKey(e2) {
    if ("string" != typeof e2 || !e2.startsWith(i)) return null;
    const t2 = e2.slice(5);
    if (!t2) return null;
    try {
      const e3 = new TextDecoder().decode(this.base64ToBytes(t2)), s2 = JSON.parse(e3);
      return s2.issueDate && s2.expiryDate && s2.plan ? { data: { domains: Array.isArray(s2.domains) ? s2.domains : void 0, expiryDate: s2.expiryDate, issueDate: s2.issueDate, plan: s2.plan, valid: true }, signature: "string" == typeof s2.sig && s2.sig ? s2.sig : null } : null;
    } catch (e3) {
      return null;
    }
  }
  static publish(e2) {
    this.validationResult = e2, this.notify(e2);
  }
  static validateStructure(e2, t2) {
    const s2 = (e3) => ({ expired: false, message: e3, signatureVerified: false, valid: false });
    if ("string" != typeof e2 || !e2.startsWith(i)) return s2('Invalid license key format. License key must start with "APEX-".');
    if (!t2) return s2("Invalid license key. Unable to decode license data.");
    const { data: r2, signature: a2 } = t2;
    if (!a2 && /* @__PURE__ */ new Date() >= n) return s2("This license key is in the old unsigned format, which is no longer accepted. Please request a replacement key.");
    if (new Date(r2.expiryDate) < /* @__PURE__ */ new Date()) return { data: r2, expired: true, message: `License expired on ${r2.expiryDate}. Please renew your license.`, signatureVerified: false, valid: false };
    if (r2.domains && r2.domains.length > 0) {
      const e3 = "undefined" == typeof location ? "" : location.hostname;
      if (!r2.domains.some(((t3) => e3 === t3 || e3.endsWith(`.${t3}`)))) return { data: r2, expired: false, message: `License is not valid for this domain (${e3}). Allowed domains: ${r2.domains.join(", ")}.`, signatureVerified: false, valid: false };
    }
    return { data: r2, expired: false, signatureVerified: false, valid: true };
  }
  static verifySignature(e2, i2, n2) {
    return __async(this, null, function* () {
      var r2;
      if (this.verifying.has(e2) || this.verdicts.has(e2)) return;
      this.verifying.add(e2);
      const a2 = this.epoch, l2 = null == (r2 = globalThis.crypto) ? void 0 : r2.subtle;
      if (!l2 || 0 === this.publicKeysSpki.length) return this.verifying.delete(e2), void (this.warnedUnverifiable || (this.warnedUnverifiable = true, s(l2 ? "[Apex] No license signing key is configured in this build, so license signatures cannot be verified." : "[Apex] Web Crypto is unavailable (a secure context is required), so the license signature cannot be verified.")));
      const o2 = new TextEncoder().encode(this.canonicalPayload(i2.data));
      let c2 = false;
      for (const e3 of this.publicKeysSpki) {
        try {
          const t2 = yield l2.importKey("spki", this.base64ToBytes(e3), { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
          c2 = yield l2.verify({ hash: "SHA-256", name: "ECDSA" }, t2, this.base64ToBytes(i2.signature), o2);
        } catch (e4) {
          c2 = false;
        }
        if (c2) break;
      }
      if (this.verifying.delete(e2), this.epoch !== a2) return;
      if (this.verdicts.set(e2, c2), c2) {
        const t2 = __spreadProps(__spreadValues({}, n2), { signatureVerified: true });
        return void (this.licenseKey === e2 ? this.publish(t2) : this.notify(t2));
      }
      const h2 = "Invalid license key. The license signature does not verify.", d = { data: i2.data, expired: false, message: h2, signatureVerified: true, valid: false };
      this.licenseKey === e2 ? this.publish(d) : this.notify(d), t(`[Apex] ${h2}`);
    });
  }
};
l.publicKeysSpki = ["MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQIaK9UMD6n0oR/FIy8QdL0uSzKMQlf1BB+tOrji4/WuHsyRNxeDhVykoSsNURozMi1xhmqWvBH1L//xIfugTPA=="], l.verdicts = /* @__PURE__ */ new Map(), l.verifying = /* @__PURE__ */ new Set(), l.warnedUnverifiable = false, l.epoch = 0;
let o = l;
const c = class {
  static applyStyles(e2) {
    Object.assign(e2.style, this.CRITICAL_STYLES, { backgroundImage: this.createWatermarkPattern(), backgroundRepeat: "repeat" });
  }
  static node(e2) {
    return e2 ? e2.querySelector(`[${this.WATERMARK_ATTR}]`) : null;
  }
  static add(e2, t2) {
    return e2 && "undefined" != typeof document ? (this.setManaged(e2, t2), this.paint(e2)) : null;
  }
  static exists(e2) {
    return !!this.node(e2);
  }
  static remove(e2, t2) {
    e2 && (this.setManaged(e2, t2), this.erase(e2));
  }
  static untrack(e2) {
    this.managed.delete(e2);
  }
  static createWatermarkPattern() {
    const e2 = this.WATERMARK_TEXT;
    return `url("data:image/svg+xml,${encodeURIComponent(`
      <svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
        <text
          x="50%"
          y="50%"
          dominant-baseline="middle"
          text-anchor="middle"
          font-family="-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Arial, sans-serif"
          font-size="18"
          font-weight="600"
          fill="rgba(134, 134, 134, 0.1)"
          transform="rotate(-35, 100, 60)"
        >${e2}</text>
      </svg>
    `.trim())}")`;
  }
  static erase(e2) {
    var t2;
    null == (t2 = this.node(e2)) || t2.remove();
  }
  static paint(e2) {
    let t2 = this.node(e2);
    return t2 || (t2 = document.createElement("div"), t2.setAttribute(this.WATERMARK_ATTR, ""), e2.appendChild(t2)), this.applyStyles(t2), "function" == typeof getComputedStyle && "static" === getComputedStyle(e2).position && (e2.style.position = "relative"), t2;
  }
  static reconcile() {
    const e2 = o.isLicenseValid();
    for (const t2 of this.managed) t2.isConnected ? e2 ? this.erase(t2) : this.paint(t2) : this.managed.delete(t2);
  }
  static setManaged(e2, t2) {
    false !== (null == t2 ? void 0 : t2.manage) ? this.track(e2) : this.managed.delete(e2);
  }
  static track(e2) {
    this.managed.add(e2), this.subscribed || (this.subscribed = true, o.onChange((() => {
      this.reconcile();
    })));
  }
};
c.WATERMARK_ATTR = "data-apexcharts-watermark", c.WATERMARK_TEXT = "APEXCHARTS", c.ATTR = "data-apexcharts-watermark", c.CRITICAL_STYLES = { bottom: "0", display: "block", left: "0", msUserSelect: "none", opacity: "1", pointerEvents: "none", position: "absolute", right: "0", top: "0", userSelect: "none", visibility: "visible", webkitUserSelect: "none", zIndex: "10000" }, c.managed = /* @__PURE__ */ new Set(), c.subscribed = false;
let h = c;
const PRICING_URL = "https://apexcharts.com/pricing";
let _perspectivesTokenDecoded = false;
const enforced = /* @__PURE__ */ new Set();
function untrackChart(ctx) {
  enforced.delete(ctx);
}
function premiumFeaturesInUse(w, ctx) {
  const chart = w && w.config && w.config.chart || {};
  const used = [];
  if (chart.type === "unit") used.push("unit");
  if (ctx.trellis && typeof ctx.trellis.isActive === "function" && ctx.trellis.isActive()) {
    used.push("trellis");
  }
  if (ctx.storyboard && ctx.storyboard._used) used.push("storyboard");
  const link = chart.link;
  if (ctx.linkedViews && link && (link.enabled === true || typeof link.dimension === "function")) {
    used.push("link");
  }
  if (ctx.ink && chart.ink && chart.ink.enabled === true) used.push("ink");
  if (ctx.measure && chart.measure && chart.measure.enabled === true) {
    used.push("measure");
  }
  if (ctx.contextMenu && chart.contextMenu && chart.contextMenu.enabled === true) {
    used.push("context-menu");
  }
  if (ctx.perspectives && (ctx.perspectives._used || _perspectivesTokenDecoded)) {
    used.push("perspectives");
  }
  if (ctx.history && chart.history && chart.history.enabled === true) {
    used.push("history");
  }
  return used;
}
function resolveKey(w) {
  const perChart = w && w.config && w.config.chart && w.config.chart.license;
  if (perChart) return perChart;
  const singleton = o.getKey();
  if (singleton) return singleton;
  const apex = Environment.getApex();
  if (apex && apex.license) return apex.license;
  return null;
}
const PREMIUM_PLANS = /* @__PURE__ */ new Set(["premium", "enterprise"]);
function licensedForPremium(key) {
  if (!key) return false;
  const result = o.validateKey(key);
  if (!result.valid) return false;
  const plan = result.data && result.data.plan;
  return typeof plan === "string" && PREMIUM_PLANS.has(plan.toLowerCase());
}
function reinstateWatermark(ctx, elWrap) {
  const node = h.add(elWrap, { manage: false });
  if (!node || typeof MutationObserver === "undefined") return;
  if (ctx._wmNodeObserver && ctx._wmObservedNode === node) return;
  if (ctx._wmNodeObserver) ctx._wmNodeObserver.disconnect();
  const nodeObs = new MutationObserver(() => {
    const n2 = h.node(elWrap);
    if (!n2) return;
    nodeObs.disconnect();
    h.applyStyles(n2);
    nodeObs.takeRecords();
    nodeObs.observe(n2, { attributes: true, attributeFilter: ["style"] });
  });
  nodeObs.observe(node, { attributes: true, attributeFilter: ["style"] });
  ctx._wmNodeObserver = nodeObs;
  ctx._wmObservedNode = node;
}
function addWatermark(ctx, elWrap) {
  reinstateWatermark(ctx, elWrap);
  if (typeof MutationObserver === "undefined" || ctx._wmWrapObserver) return;
  const wrapObs = new MutationObserver(() => {
    if (!h.node(elWrap)) reinstateWatermark(ctx, elWrap);
  });
  wrapObs.observe(elWrap, { childList: true });
  ctx._wmWrapObserver = wrapObs;
}
function teardownWatermark(ctx, elWrap) {
  if (ctx._wmWrapObserver) {
    ctx._wmWrapObserver.disconnect();
    ctx._wmWrapObserver = null;
  }
  if (ctx._wmNodeObserver) {
    ctx._wmNodeObserver.disconnect();
    ctx._wmNodeObserver = null;
  }
  ctx._wmObservedNode = null;
  const wrap = elWrap || ctx.w && ctx.w.dom && ctx.w.dom.elWrap;
  if (wrap) h.remove(wrap, { manage: false });
}
function notifyTrial(ctx, key, features) {
  if (ctx._premiumLicenseNotified) return;
  ctx._premiumLicenseNotified = true;
  const many = features.length > 1;
  if (!key) {
    console.warn(
      `[ApexCharts] Premium feature${many ? "s" : ""} in use (${features.join(", ")}) without a license. Running in trial mode with a watermark. Get a license: ${PRICING_URL}`
    );
    return;
  }
  const result = o.validateKey(key);
  if (result.valid) {
    const plan = result.data && result.data.plan || "current";
    console.warn(
      `[ApexCharts] Premium feature${many ? "s" : ""} in use (${features.join(", ")}) require a Premium or Enterprise license; the ${plan} plan does not include ${many ? "them" : "it"}. Running in trial mode with a watermark. Upgrade: ${PRICING_URL}`
    );
    return;
  }
  if (key !== o.getKey()) {
    console.error(`[Apex] ${result.message}`);
  }
}
function enforceLicense(w, ctx) {
  try {
    if (!Environment.isBrowser()) return;
    if (w && w.globals && w.globals.isDestroyed) {
      enforced.delete(ctx);
      return;
    }
    const elWrap = w && w.dom && w.dom.elWrap;
    if (!elWrap) return;
    const features = premiumFeaturesInUse(w, ctx);
    if (features.length === 0) {
      enforced.delete(ctx);
      teardownWatermark(ctx, elWrap);
      return;
    }
    enforced.add(ctx);
    const key = resolveKey(w);
    if (licensedForPremium(key)) {
      teardownWatermark(ctx, elWrap);
      return;
    }
    addWatermark(ctx, elWrap);
    notifyTrial(ctx, key, features);
  } catch (e2) {
  }
}
function reevaluateLicenseAcrossCharts() {
  if (!Environment.isBrowser()) return;
  const visited = /* @__PURE__ */ new Set();
  const apex = Environment.getApex();
  const instances = apex && apex._chartInstances;
  if (Array.isArray(instances)) {
    instances.forEach((entry) => {
      const chart = entry && entry.chart;
      if (chart && chart.w && !chart.w.globals.isDestroyed) {
        visited.add(chart);
        enforceLicense(chart.w, chart);
      }
    });
  }
  Array.from(enforced).forEach((ctx) => {
    const w = ctx && ctx.w;
    const elWrap = w && w.dom && w.dom.elWrap;
    if (!w || w.globals.isDestroyed || !elWrap || elWrap.isConnected === false) {
      enforced.delete(ctx);
      return;
    }
    if (visited.has(ctx)) return;
    enforceLicense(w, ctx);
  });
}
o.onChange(reevaluateLicenseAcrossCharts);
const _ApexCharts = class _ApexCharts {
  /**
   * Creates a new ApexCharts instance.
   *
   * @param {HTMLElement} el - The DOM element to render the chart into.
   * @param {ApexOptions} opts - Chart configuration options.
   */
  constructor(el, opts) {
    // Module properties set dynamically by InitCtxVariables.initModules().
    // Declared as typed class fields so @ts-check resolves them throughout the
    // class body without errors. Each field typed as `any` since the modules are
    // plain objects whose specific shapes are not yet typed.
    /** @type {any} */
    __publicField(this, "core");
    /** @type {any} */
    __publicField(this, "responsive");
    /** @type {any} */
    __publicField(this, "axes");
    /** @type {any} */
    __publicField(this, "grid");
    /** @type {any} */
    __publicField(this, "graphics");
    /** @type {any} */
    __publicField(this, "coreUtils");
    /** @type {any} */
    __publicField(this, "crosshairs");
    /** @type {any} */
    __publicField(this, "events");
    /** @type {any} */
    __publicField(this, "fill");
    /** @type {any} */
    __publicField(this, "localization");
    /** @type {any} */
    __publicField(this, "options");
    /** @type {any} */
    __publicField(this, "series");
    /** @type {any} */
    __publicField(this, "theme");
    /** @type {any} */
    __publicField(this, "formatters");
    /** @type {any} */
    __publicField(this, "titleSubtitle");
    /** @type {any} */
    __publicField(this, "dimensions");
    /** @type {any} */
    __publicField(this, "updateHelpers");
    /** @type {any} */
    __publicField(this, "tooltip");
    /** @type {any} */
    __publicField(this, "data");
    /** @type {any} */
    __publicField(this, "animations");
    /** @type {any} */
    __publicField(this, "exports");
    /** @type {any} */
    __publicField(this, "legend");
    /** @type {any} */
    __publicField(this, "toolbar");
    /** @type {any} */
    __publicField(this, "zoomPanSelection");
    /** @type {any} */
    __publicField(this, "keyboardNavigation");
    /** @type {any} */
    __publicField(this, "annotations");
    /** @type {any} */
    __publicField(this, "morphTypeChange");
    /** @type {any} */
    __publicField(this, "timeScale");
    /** @type {any} */
    __publicField(this, "_keyboardNavigation");
    /** @type {any} */
    __publicField(this, "_zoomPanSelection");
    /** @type {any} */
    __publicField(this, "windowResizeHandler");
    /** @type {any} */
    __publicField(this, "parentResizeHandler");
    /** @type {string[]} */
    __publicField(this, "publicMethods", []);
    /** @type {string[]} */
    __publicField(this, "eventList", []);
    /** @type {Promise<any> | null} */
    __publicField(this, "_renderPromise", null);
    /** @type {any} */
    __publicField(this, "config");
    /** @type {any} */
    __publicField(this, "perspectives");
    /** @type {any} */
    __publicField(this, "storyboard");
    /** @type {any} */
    __publicField(this, "history");
    /** @type {any} */
    __publicField(this, "linkedViews");
    /** @type {any} */
    __publicField(this, "trellis");
    /** @type {any} */
    __publicField(this, "ink");
    /** @type {any} */
    __publicField(this, "measure");
    /** @type {any} */
    __publicField(this, "contextMenu");
    /** @type {any} */
    __publicField(this, "weave");
    /** @type {any} */
    __publicField(this, "renderer");
    /** @type {any} */
    __publicField(this, "rendererController");
    this.opts = opts;
    this.ctx = this;
    this.w = new Base(opts).init();
    this.el = el;
    this.w.globals.cuid = Utils$1.randomId();
    this.w.globals.chartID = this.w.config.chart.id ? Utils$1.escapeString(this.w.config.chart.id) : this.w.globals.cuid;
    applyAnimationPolicy(this.w);
    const initCtx = new InitCtxVariables(this);
    initCtx.initModules();
    this.lastUpdateOptions = null;
    this._updateStats = { fast: 0, fastWithAxes: 0, full: 0 };
    this.create = this.create.bind(this);
    if (Environment.isBrowser()) {
      this.windowResizeHandler = this._windowResizeHandler.bind(this);
      this.parentResizeHandler = this._parentResizeCallback.bind(this);
    }
  }
  /**
   * Renders the chart. Must be called once after construction.
   *
   * @returns {Promise<ApexCharts>} Resolves with the chart instance after mount.
   */
  render() {
    var _a, _b;
    if (!((_b = (_a = this.w) == null ? void 0 : _a.config) == null ? void 0 : _b.chart)) {
      return Promise.reject(
        new Error(
          "ApexCharts: chart configuration is missing or invalid. Ensure the options object includes a `chart` property."
        )
      );
    }
    if (this._renderPromise) return this._renderPromise;
    const renderPromise = new Promise((resolve, reject) => {
      var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
      if (Utils$1.elementExists(this.el)) {
        if (typeof Apex._chartInstances === "undefined") {
          Apex._chartInstances = [];
        }
        if (this.w.config.chart.id) {
          Apex._chartInstances.push({
            id: this.w.globals.chartID,
            group: this.w.config.chart.group,
            chart: this
          });
        }
        this.setLocale(this.w.config.chart.defaultLocale);
        const beforeMount = this.w.config.chart.events.beforeMount;
        if (typeof beforeMount === "function") {
          beforeMount(this, this.w);
        }
        this.events.fireEvent("beforeMount", [this, this.w]);
        const trellisCfg = this.w.config.trellis;
        const wantsTrellis = !!(trellisCfg && (trellisCfg.by || trellisCfg.row || trellisCfg.column));
        const isTrellisHost = !!(wantsTrellis && this.trellis && this.trellis.isActive());
        if (wantsTrellis && !this.trellis) {
          console.warn(
            "ApexCharts: `trellis` requires the trellis feature, which is not in the default bundle. Bundler: import 'apexcharts/features/trellis'. Script tag: add <script src='.../dist/features/trellis.js'> after apexcharts.js. Rendering as a single chart."
          );
        }
        if (((_b2 = (_a2 = this.w.config.chart) == null ? void 0 : _a2.measure) == null ? void 0 : _b2.enabled) && !this.measure) {
          console.warn(
            "ApexCharts: `chart.measure` requires the measure feature, which is not in the default bundle. Bundler: import 'apexcharts/features/measure'. Script tag: add <script src='.../dist/features/measure.js'> after apexcharts.js."
          );
        }
        if (((_d = (_c = this.w.config.chart) == null ? void 0 : _c.link) == null ? void 0 : _d.enabled) && !this.linkedViews) {
          console.warn(
            "ApexCharts: `chart.link` requires the link feature, which is not in the default bundle. Bundler: import 'apexcharts/features/link'. Script tag: add <script src='.../dist/features/link.js'> after apexcharts.js."
          );
        }
        if (!this.ink) {
          const inkOn = (_f = (_e = this.w.config.chart) == null ? void 0 : _e.ink) == null ? void 0 : _f.enabled;
          const anyDraggable = ((_h = (_g = this.w.config.annotations) == null ? void 0 : _g.points) != null ? _h : []).some((p) => p && p.draggable);
          if (inkOn || anyDraggable) {
            console.warn(
              "ApexCharts: `chart.ink` / `annotations.points[].draggable` requires the ink feature, which is not in the default bundle. Bundler: import 'apexcharts/features/ink'. Script tag: add <script src='.../dist/features/ink.js'> after apexcharts.js."
            );
          }
        }
        if (((_j = (_i = this.w.config.chart) == null ? void 0 : _i.contextMenu) == null ? void 0 : _j.enabled) && !this.contextMenu) {
          console.warn(
            "ApexCharts: `chart.contextMenu` requires the context-menu feature, which is not in the default bundle. Bundler: import 'apexcharts/features/context-menu'. Script tag: add <script src='.../dist/features/context-menu.js'> after apexcharts.js."
          );
        }
        if (((_l = (_k = this.w.config.chart) == null ? void 0 : _k.history) == null ? void 0 : _l.enabled) && !this.history) {
          console.warn(
            "ApexCharts: `chart.history` requires the history feature, which is not in the default bundle. Bundler: import 'apexcharts/features/history'. Script tag: add <script src='.../dist/features/history.js'> after apexcharts.js."
          );
        }
        if (Environment.isBrowser()) {
          if (!isTrellisHost) {
            window.addEventListener("resize", this.windowResizeHandler);
            addResizeListener(
              /** @type {HTMLElement} */
              this.el.parentNode,
              this.parentResizeHandler
            );
          }
          const rootNode = (
            /** @type {any} */
            this.el.getRootNode && this.el.getRootNode()
          );
          const inShadowRoot = Utils$1.is("ShadowRoot", rootNode);
          const doc = this.el.ownerDocument;
          let css = inShadowRoot ? rootNode.getElementById("apexcharts-css") : doc.getElementById("apexcharts-css");
          if (!css) {
            css = BrowserAPIs.createElementNS(
              "http://www.w3.org/1999/xhtml",
              "style"
            );
            css.id = "apexcharts-css";
            css.textContent = apexCSS;
            const nonce = ((_m = this.opts.chart) == null ? void 0 : _m.nonce) || this.w.config.chart.nonce;
            if (nonce) {
              css.setAttribute("nonce", nonce);
            }
            if (inShadowRoot) {
              rootNode.prepend(css);
            } else if (this.w.config.chart.injectStyleSheet !== false) {
              doc.head.appendChild(css);
            }
          }
        }
        if (isTrellisHost) {
          this.trellis.render().then(() => {
            enforceLicense(this.w, this);
            if (typeof this.w.config.chart.events.mounted === "function") {
              this.w.config.chart.events.mounted(this, this.w);
            }
            this.events.fireEvent("mounted", [this, this.w]);
            resolve(this);
          }).catch((e2) => {
            var _a3, _b3;
            const enriched = e2 instanceof Error ? e2 : new Error(String(e2));
            const err = (
              /** @type {any} */
              enriched
            );
            err.chartId = (_b3 = (_a3 = this.w) == null ? void 0 : _a3.globals) == null ? void 0 : _b3.chartID;
            err.el = this.el;
            reject(enriched);
          });
          return;
        }
        const graphData = this.create(this.w.config.series, {});
        if (!graphData) return resolve(this);
        this.mount(graphData).then(() => {
          if (typeof this.w.config.chart.events.mounted === "function") {
            this.w.config.chart.events.mounted(this, this.w);
          }
          this.events.fireEvent("mounted", [this, this.w]);
          resolve(graphData);
        }).catch((e2) => {
          var _a3, _b3;
          const enriched = e2 instanceof Error ? e2 : new Error(String(e2));
          const err = (
            /** @type {any} */
            enriched
          );
          err.chartId = (_b3 = (_a3 = this.w) == null ? void 0 : _a3.globals) == null ? void 0 : _b3.chartID;
          err.el = this.el;
          reject(enriched);
        });
      } else {
        reject(new Error("Element not found"));
      }
    });
    this._renderPromise = renderPromise;
    renderPromise.catch(() => {
      if (this._renderPromise === renderPromise) this._renderPromise = null;
    });
    return renderPromise;
  }
  /**
   * @param {any[]} ser
   * @param {object} opts
   */
  create(ser, opts) {
    var _a, _b, _c, _d, _e, _f;
    const w = this.w;
    if (!this.core) {
      const initCtx = new InitCtxVariables(this);
      initCtx.initModules();
    }
    const gl = this.w.globals;
    gl.noData = false;
    gl.animationEnded = false;
    if (!Utils$1.elementExists(this.el)) {
      gl.animationEnded = true;
      return null;
    }
    this.responsive.checkResponsiveConfig(opts);
    applyAnimationPolicy(w);
    if (w.config.xaxis.convertedCatToNumeric) {
      const defaults = new Defaults(w.config);
      defaults.convertCatToNumericXaxis(w.config, this.ctx);
    }
    this.core.setupElements();
    if (w.config.chart.type === "treemap") {
      w.config.grid.show = false;
      w.config.yaxis[0].show = false;
    }
    if (gl.svgWidth === 0) {
      gl.animationEnded = true;
      return null;
    }
    let series = ser;
    ser.forEach((s2, realIndex) => {
      if (s2.hidden) {
        series = this.legend.legendHelpers.getSeriesAfterCollapsing({
          realIndex
        });
      }
    });
    const combo = CoreUtils.checkComboSeries(series, w.config.chart.type);
    gl.comboCharts = combo.comboCharts;
    gl.comboBarCount = combo.comboBarCount;
    const allSeriesAreEmpty = series.every((s2) => s2.data && s2.data.length === 0);
    if (series.length === 0 || allSeriesAreEmpty && gl.collapsedSeries.length < 1) {
      this.series.handleNoData();
    }
    if (Environment.isBrowser()) {
      this.events.setupEventHandlers();
    }
    const parsedState = this.data.parseData(series);
    this._writeParsedSeriesData(parsedState.seriesData);
    this._writeParsedRangeData(parsedState.rangeData);
    this._writeParsedCandleData(parsedState.candleData);
    this._writeParsedLabelData(parsedState.labelData);
    this._writeParsedAxisFlags(parsedState.axisFlags);
    (_a = this.rendererController) == null ? void 0 : _a.resolve();
    (_b = this.weave) == null ? void 0 : _b.dispatch("afterParse");
    this.theme.init();
    const markers = new Markers(this.w, this);
    markers.setGlobalMarkerSize();
    this.formatters.setLabelFormatters();
    this.titleSubtitle.draw();
    if (!gl.noData || gl.collapsedSeries.length === w.seriesData.series.length || w.config.legend.showForSingleSeries) {
      (_c = this.legend) == null ? void 0 : _c.init();
    }
    this.series.hasAllSeriesEqualX();
    if (gl.axisCharts) {
      this.core.coreCalculations();
      if (w.config.xaxis.type !== "category") {
        this.formatters.setLabelFormatters();
      }
      if (this.ctx.toolbar) {
        this.ctx.toolbar.minX = w.globals.minX;
        this.ctx.toolbar.maxX = w.globals.maxX;
      }
    }
    this.formatters.heatmapLabelFormatters();
    const coreUtils = new CoreUtils(this.w);
    coreUtils.getLargestMarkerSize();
    const layoutState = this.dimensions.plotCoords();
    this._writeLayoutCoords(layoutState.layout);
    const xyRatios = this.core.xySettings();
    (_d = this.weave) == null ? void 0 : _d.dispatch("afterScales", { xyRatios });
    this.grid.createGridMask();
    const elGraph = this.core.plotChartType(series, xyRatios);
    const dataLabels = new DataLabels(this.w, this);
    dataLabels.bringForward();
    if (w.config.dataLabels.background.enabled) {
      dataLabels.dataLabelsBackground();
    }
    this.core.shiftGraphPosition();
    (_f = (_e = this.legend) == null ? void 0 : _e.heatmapGradientLegend) == null ? void 0 : _f.repositionToPlot();
    if (w.globals.dataPoints > 50) {
      w.dom.elWrap.classList.add("apexcharts-disable-transitions");
    }
    const dim = {
      plot: {
        left: w.layout.translateX,
        top: w.layout.translateY,
        width: w.layout.gridWidth,
        height: w.layout.gridHeight
      }
    };
    return {
      elGraph,
      xyRatios,
      dimensions: dim
    };
  }
  /**
   * @param {any} graphData
   */
  mount(graphData = null) {
    const me = this;
    const w = me.w;
    return new Promise((resolve, reject) => {
      var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
      if (me.el === null) {
        return reject(
          new Error("Not enough data to display or target element not found")
        );
      } else if (w.globals.allSeriesCollapsed) {
        me.series.handleNoData();
      }
      me.grid = new Grid(me.w, me);
      const elgrid = me.grid.drawGrid();
      const AnnotationsCtor = InitCtxVariables._featureRegistry.get("annotations");
      me.annotations = AnnotationsCtor ? new AnnotationsCtor(me.w, {
        theme: me.theme,
        timeScale: me.timeScale
      }) : null;
      (_a = me.annotations) == null ? void 0 : _a.drawImageAnnos();
      (_b = me.annotations) == null ? void 0 : _b.drawTextAnnos();
      if (w.config.grid.position === "back") {
        if (elgrid) {
          w.dom.elGraphical.add(elgrid.el);
        }
        if ((_c = elgrid == null ? void 0 : elgrid.elGridBorders) == null ? void 0 : _c.node) {
          w.dom.elGraphical.add(elgrid.elGridBorders);
        }
      }
      if (Array.isArray(graphData.elGraph)) {
        for (let g = 0; g < graphData.elGraph.length; g++) {
          w.dom.elGraphical.add(graphData.elGraph[g]);
        }
      } else {
        w.dom.elGraphical.add(graphData.elGraph);
      }
      if (w.config.grid.position === "front") {
        if (elgrid) {
          w.dom.elGraphical.add(elgrid.el);
        }
        if ((_d = elgrid == null ? void 0 : elgrid.elGridBorders) == null ? void 0 : _d.node) {
          w.dom.elGraphical.add(elgrid.elGridBorders);
        }
      }
      if (w.config.xaxis.crosshairs.position === "front") {
        me.crosshairs.drawXCrosshairs();
      }
      if (w.config.yaxis[0].crosshairs.position === "front") {
        me.crosshairs.drawYCrosshairs();
      }
      if (w.config.chart.type !== "treemap") {
        me.axes.drawAxis(w.config.chart.type, elgrid);
      }
      const xAxis = new XAxis(this.w, this.ctx, elgrid);
      const yaxis = new YAxis(
        this.w,
        { theme: this.theme, timeScale: this.timeScale },
        elgrid
      );
      if (elgrid !== null) {
        xAxis.xAxisLabelCorrections();
        yaxis.setYAxisTextAlignments();
        w.config.yaxis.map((yaxe, index) => {
          if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1) {
            yaxis.yAxisTitleRotate(index, yaxe.opposite);
          }
        });
      }
      (_e = me.annotations) == null ? void 0 : _e.drawAxesAnnotations();
      if (!w.globals.noData) {
        if (Environment.isBrowser() && w.config.tooltip.enabled && !w.globals.noData) {
          (_f = me.w.globals.tooltip) == null ? void 0 : _f.drawTooltip(graphData.xyRatios);
        }
        if (w.config.chart.accessibility.enabled && w.config.chart.accessibility.keyboard.enabled && w.config.chart.accessibility.keyboard.navigation.enabled) {
          (_g = me.keyboardNavigation) == null ? void 0 : _g.init();
        }
        if (Environment.isBrowser() && w.globals.axisCharts && (w.axisFlags.isXNumeric || /** @type {Record<string,any>} */
        w.config.xaxis.convertedCatToNumeric || w.axisFlags.isRangeBar)) {
          if (w.config.chart.zoom.enabled || w.config.chart.selection && w.config.chart.selection.enabled || // @ts-ignore — chart.pan is an internal toolbar config property
          w.config.chart.pan && w.config.chart.pan.enabled) {
            (_h = me.zoomPanSelection) == null ? void 0 : _h.init({
              xyRatios: graphData.xyRatios
            });
          }
        } else {
          const tools = w.config.chart.toolbar.tools;
          const toolsArr = [
            "zoom",
            "zoomin",
            "zoomout",
            "selection",
            "pan",
            "reset"
          ];
          toolsArr.forEach((t2) => {
            tools[t2] = false;
          });
        }
        if (w.config.chart.toolbar.show && !w.globals.allSeriesCollapsed) {
          (_i = me.toolbar) == null ? void 0 : _i.createToolbar();
        }
      }
      (_j = me.weave) == null ? void 0 : _j.dispatch("draw", {
        pass: "full",
        xyRatios: graphData == null ? void 0 : graphData.xyRatios
      });
      if (w.globals.memory.methodsToExec.length > 0) {
        w.globals.memory.methodsToExec.forEach((fn) => {
          fn.method(fn.params, false, fn.context);
        });
      }
      if (!w.globals.axisCharts && !w.globals.noData) {
        me.core.resizeNonAxisCharts();
      }
      enforceLicense(w, me);
      resolve(me);
    });
  }
  /**
   * Destroys the chart instance, removes all DOM elements and event listeners.
   * After calling this, the instance should not be used again.
   */
  destroy() {
    var _a;
    if (this.trellis) {
      this.trellis.teardown();
    }
    this._renderPromise = null;
    if (Environment.isBrowser()) {
      window.removeEventListener("resize", this.windowResizeHandler);
      removeResizeListener(
        /** @type {Element} */
        this.el.parentNode,
        this.parentResizeHandler
      );
      clearTimeout((_a = this.w.globals.resizeTimer) != null ? _a : void 0);
    }
    const chartID = this.w.config.chart.id;
    if (chartID && Array.isArray(Apex._chartInstances)) {
      Apex._chartInstances.forEach(
        (c2, i2) => {
          if (c2.id === Utils$1.escapeString(chartID)) {
            Apex._chartInstances.splice(i2, 1);
          }
        }
      );
    }
    if (this._keyboardNavigation) {
      this._keyboardNavigation.destroy();
    }
    teardownWatermark(this);
    untrackChart(this);
    new Destroy(this.ctx).clear({ isUpdating: false });
  }
  /**
   * Merges new options into the existing config and re-renders the chart.
   *
   * @param {ApexOptions} options - Partial config object merged with the existing config.
   * @param {boolean} [redraw=false] - When true, redraws the chart from scratch instead of animating from previous paths.
   * @param {boolean} [animate=true] - Whether to animate the update.
   * @param {boolean} [updateSyncedCharts=true] - Whether to propagate the update to charts in the same group.
   * @param {boolean} [overwriteInitialConfig=true] - When true, replaces the stored initial config used by resetSeries().
   * @returns {Promise<ApexCharts>} Resolves with the chart instance after re-render.
   */
  updateOptions(options2, redraw = false, animate = true, updateSyncedCharts = true, overwriteInitialConfig = true) {
    const w = this.w;
    if (options2 && "series" in options2 && !Array.isArray(options2.series)) {
      console.warn(
        "ApexCharts: updateOptions() ignored `series` because it is not an array."
      );
      options2 = __spreadValues({}, options2);
      delete options2.series;
    }
    if (this.trellis && this.trellis._mounted) {
      this.opts = Utils$1.extend(this.opts || {}, options2 || {});
      this.w.config = Utils$1.extend(w.config, options2 || {});
      this.trellis.teardown();
      return this.render();
    }
    w.interact.selection = void 0;
    if (this.lastUpdateOptions) {
      if (Utils$1.shallowEqual(this.lastUpdateOptions, options2)) {
        return Promise.resolve(this);
      }
      if (options2.series && this.lastUpdateOptions.series && !_ApexCharts._optionsTooBigToCompare(options2)) {
        if (Utils$1.stringifyForCompare(this.lastUpdateOptions.series) === Utils$1.stringifyForCompare(options2.series)) {
          const optionsWithoutSeries = __spreadValues({}, options2);
          const lastWithoutSeries = __spreadValues({}, this.lastUpdateOptions);
          delete optionsWithoutSeries.series;
          delete lastWithoutSeries.series;
          if (Utils$1.shallowEqual(optionsWithoutSeries, lastWithoutSeries)) {
            return Promise.resolve(this);
          }
        }
      }
    }
    if (options2.series) {
      this.data.resetParsingFlags();
      this.series.resetSeries(false, true, false);
      if (options2.series.length && options2.series[0].data) {
        options2.series = options2.series.map(
          (s2, i2) => {
            return this.updateHelpers._extendSeries(s2, i2);
          }
        );
      }
      this.updateHelpers.revertDefaultAxisMinMax();
    }
    if (options2.xaxis) {
      options2 = this.updateHelpers.forceXAxisUpdate(options2);
    }
    if (options2.yaxis) {
      options2 = this.updateHelpers.forceYAxisUpdate(options2);
    }
    if (w.globals.collapsedSeriesIndices.length > 0) {
      this.series.clearPreviousPaths();
    }
    if (options2.theme) {
      options2 = this.theme.updateThemeOptions(options2);
    }
    return this.updateHelpers._updateOptions(
      options2,
      redraw,
      animate,
      updateSyncedCharts,
      overwriteInitialConfig
    );
  }
  /**
   * Replaces the chart's series data and re-renders.
   *
   * @param {ApexAxisChartSeries | ApexNonAxisChartSeries} [newSeries=[]] - The replacement series array.
   * @param {boolean} [animate=true] - Whether to animate the update.
   * @param {boolean} [overwriteInitialSeries=true] - When true, replaces the stored initial series used by resetSeries().
   * @returns {Promise<ApexCharts>} Resolves with the chart instance after re-render.
   */
  updateSeries(newSeries = [], animate = true, overwriteInitialSeries = true) {
    if (!Array.isArray(newSeries)) {
      console.warn(
        "ApexCharts: updateSeries() ignored the call because the series is not an array."
      );
      return Promise.resolve(this);
    }
    if (this.trellis && this.trellis._mounted) {
      return this.trellis.updateSeries(newSeries, animate);
    }
    this.data.resetParsingFlags();
    this.series.prepareDataUpdate();
    this.updateHelpers.revertDefaultAxisMinMax();
    return this.updateHelpers._updateSeries(
      newSeries,
      animate,
      overwriteInitialSeries
    );
  }
  /**
   * Appends a new series to the existing series array and re-renders.
   *
   * @param {ApexAxisChartSeries[0] | ApexNonAxisChartSeries} newSerie - The series object to append.
   * @param {boolean} [animate=true] - Whether to animate the update.
   * @param {boolean} [overwriteInitialSeries=true] - When true, replaces the stored initial series used by resetSeries().
   * @returns {Promise<ApexCharts>} Resolves with the chart instance after re-render.
   */
  appendSeries(newSerie, animate = true, overwriteInitialSeries = true) {
    this.data.resetParsingFlags();
    const newSeries = this.w.config.series.slice();
    newSeries.push(
      /** @type {any} */
      newSerie
    );
    this.series.prepareDataUpdate();
    this.updateHelpers.revertDefaultAxisMinMax();
    return this.updateHelpers._updateSeries(
      newSeries,
      animate,
      overwriteInitialSeries
    );
  }
  /**
   * Appends data points to existing series without replacing them.
   * Each element of `newData` corresponds to the series at the same index.
   *
   * @param {Array<{ data: any[] }>} newData - Data to append, in the same shape as series[].data.
   * @param {boolean} [overwriteInitialSeries=true] - When true, updates the stored initial series used by resetSeries().
   * @returns {Promise<ApexCharts>} Resolves with the chart instance after re-render.
   */
  appendData(newData, overwriteInitialSeries = true) {
    const me = this;
    me.data.resetParsingFlags();
    me.w.globals.dataChanged = true;
    if (me.w.config.chart.animations.enabled) {
      me.series.getPreviousPaths();
    }
    const histRaw = me.w.globals.histogramRawSeries;
    if (histRaw) {
      for (let i2 = 0; i2 < histRaw.length; i2++) {
        const src = (
          /** @type {any} */
          newData[i2]
        );
        if (src && Array.isArray(src.data) && Array.isArray(histRaw[i2].data)) {
          for (let j = 0; j < src.data.length; j++) {
            histRaw[i2].data.push(src.data[j]);
          }
        }
      }
      return this.update();
    }
    const newSeries = me.w.config.series.slice();
    for (let i2 = 0; i2 < newSeries.length; i2++) {
      if (newData[i2] !== null && typeof newData[i2] !== "undefined") {
        const srcSerie = (
          /** @type {any} */
          newData[i2]
        );
        const dstSerie = (
          /** @type {any} */
          newSeries[i2]
        );
        for (let j = 0; j < srcSerie.data.length; j++) {
          dstSerie.data.push(srcSerie.data[j]);
        }
      }
    }
    trimStreamingSeries(newSeries, me.w);
    me.w.config.series = newSeries;
    if (overwriteInitialSeries) {
      me.w.globals.initialSeries = me.w.config.series;
    }
    return this.update();
  }
  /**
   * True when an options object carries enough series data that a
   * JSON.stringify equality check (and the Utils.clone needed to store it for
   * later comparison) would cost more than the re-render it tries to avoid.
   * @param {any} options
   * @returns {boolean}
   */
  static _optionsTooBigToCompare(options2) {
    const series = options2 && options2.series;
    if (!Array.isArray(series)) return false;
    let points = 0;
    for (let i2 = 0; i2 < series.length; i2++) {
      const d = series[i2] && series[i2].data;
      points += Array.isArray(d) ? d.length : 1;
      if (points > 1e3) return true;
    }
    return false;
  }
  /**
   * @param {object} [options]
   */
  update(options2) {
    return new Promise((resolve, reject) => {
      if (options2 && this.lastUpdateOptions && !_ApexCharts._optionsTooBigToCompare(options2) && Utils$1.stringifyForCompare(this.lastUpdateOptions) === Utils$1.stringifyForCompare(options2)) {
        return resolve(this);
      }
      this.lastUpdateOptions = options2 && !_ApexCharts._optionsTooBigToCompare(options2) ? Utils$1.clone(options2) : null;
      new Destroy(this.ctx).clear({ isUpdating: true });
      const graphData = this.create(this.w.config.series, options2 != null ? options2 : {});
      if (!graphData) return resolve(this);
      this.mount(graphData).then(() => {
        var _a;
        (_a = this.morphTypeChange) == null ? void 0 : _a.applyChromeFade();
        applyAxisTransition(this.w);
        applyDataLabelTransition(this.w);
        if (typeof this.w.config.chart.events.updated === "function") {
          this.w.config.chart.events.updated(this, this.w);
        }
        this.events.fireEvent("updated", [this, this.w]);
        this.w.globals.isDirty = true;
        resolve(this);
      }).catch((e2) => {
        reject(e2);
      });
    });
  }
  /**
   * Redraws the scale-dependent chrome (grid lines, x-axis, y-axes) IN PLACE
   * within the frozen layout after a data-only update changed the axis
   * domain. The rebuilt groups replace the old nodes positionally, so z-order
   * (grid back/front) is preserved without re-running mount. Legend,
   * annotations containers, toolbar, defs/masks, and the plot geometry are
   * untouched.
   *
   * Returns false when the refresh cannot faithfully reproduce the chart and
   * the caller must fall back to a full render:
   * - horizontal bar charts (inversed axes draw through a different path)
   * - charts with annotations or ink notes (their positions are scale-bound
   *   and are laid out by the full render)
   * - the new y labels no longer fit the width reserved at layout time
   *
   * @param {any} _xyRatios
   * @returns {boolean} true when the chrome was refreshed in place
   */
  _fastAxisChromeRefresh(_xyRatios) {
    const w = this.w;
    const gl = w.globals;
    this._fastAxisBailReason = "";
    try {
      if (gl.isBarHorizontal) {
        this._fastAxisBailReason = "barHorizontal";
        return false;
      }
      if (w.config.chart.sparkline.enabled) return true;
      const a2 = w.config.annotations;
      if (a2 && (a2.yaxis && a2.yaxis.length || a2.xaxis && a2.xaxis.length || a2.points && a2.points.length || a2.texts && a2.texts.length || a2.images && a2.images.length)) {
        this._fastAxisBailReason = "annotations";
        return false;
      }
      if (w.config.chart.ink && w.config.chart.ink.enabled) {
        this._fastAxisBailReason = "ink";
        return false;
      }
      const dim = this.dimensions;
      if (!dim || !dim.dimYAxis) {
        this._fastAxisBailReason = "noDimensions";
        return false;
      }
      const prevYLabelsCoords = w.layout.yLabelsCoords;
      const prevYTitleCoords = w.layout.yTitleCoords;
      const yaxisLabelCoords = dim.dimYAxis.getyAxisLabelsCoords();
      const yTitleCoords = dim.dimYAxis.getyAxisTitleCoords();
      w.layout.yLabelsCoords = [];
      w.layout.yTitleCoords = [];
      w.config.yaxis.map((_yaxe, index) => {
        w.layout.yLabelsCoords.push({
          width: yaxisLabelCoords[index].width,
          index
        });
        w.layout.yTitleCoords.push(
          /** @type {any} */
          { width: yTitleCoords[index].width, index }
        );
      });
      const newYAxisWidth = dim.dimYAxis.getTotalYAxisWidth();
      if (newYAxisWidth > dim.yAxisWidth + 2) {
        w.layout.yLabelsCoords = prevYLabelsCoords;
        w.layout.yTitleCoords = prevYTitleCoords;
        this._fastAxisBailReason = `labelWidth ${newYAxisWidth} > ${dim.yAxisWidth}`;
        return false;
      }
      const innerEl = w.dom.elGraphical.node;
      const oldGrid = innerEl.querySelector(".apexcharts-grid");
      const oldGridBorders = innerEl.querySelector(".apexcharts-grid-borders");
      if (!oldGrid) {
        this._fastAxisBailReason = "missingGridNode";
        return false;
      }
      const gridParent = oldGrid.parentNode;
      const gridNext = oldGridBorders ? oldGridBorders.nextSibling : oldGrid.nextSibling;
      oldGrid.remove();
      if (oldGridBorders) oldGridBorders.remove();
      innerEl.querySelectorAll(".apexcharts-xaxis-tick").forEach((t2) => t2.remove());
      this.grid = new Grid(w, this);
      const elgrid = this.grid.drawGrid();
      if (elgrid && elgrid.el) {
        gridParent.insertBefore(elgrid.el.node, gridNext);
        if (elgrid.elGridBorders && elgrid.elGridBorders.node) {
          gridParent.insertBefore(elgrid.elGridBorders.node, gridNext);
        }
      }
      const xAxis = new XAxis(this.w, this.ctx, elgrid);
      const oldXaxis = innerEl.querySelector(".apexcharts-xaxis");
      if (oldXaxis) {
        const xParent = oldXaxis.parentNode;
        const xNext = oldXaxis.nextSibling;
        oldXaxis.remove();
        const elXaxis = xAxis.drawXaxis();
        xParent.insertBefore(elXaxis.node, xNext);
      }
      const yAxis = new YAxis(
        this.w,
        { theme: this.theme, timeScale: this.timeScale },
        elgrid
      );
      for (let index = 0; index < w.config.yaxis.length; index++) {
        if (gl.ignoreYAxisIndexes.indexOf(index) !== -1) continue;
        const oldY = w.dom.baseEl.querySelector(
          `.apexcharts-yaxis[rel='${index}']`
        );
        if (!oldY) {
          this._fastAxisBailReason = "missingYAxisNode";
          return false;
        }
        const yParent = oldY.parentNode;
        if (!yParent) {
          this._fastAxisBailReason = "missingYAxisParent";
          return false;
        }
        const yNext = oldY.nextSibling;
        oldY.remove();
        const elYaxis = yAxis.drawYaxis(index);
        yParent.insertBefore(elYaxis.node, yNext);
      }
      if (elgrid !== null) {
        xAxis.xAxisLabelCorrections();
        yAxis.setYAxisTextAlignments();
        w.config.yaxis.map((yaxe, index) => {
          if (gl.ignoreYAxisIndexes.indexOf(index) === -1) {
            yAxis.yAxisTitleRotate(index, yaxe.opposite);
          }
        });
      }
      return true;
    } catch (e2) {
      this._fastAxisBailReason = "error: " + (e2 && /** @type {any} */
      e2.message);
      return false;
    }
  }
  /**
   * Fast update path for data-only series changes.
   *
   * Skips rebuilding grid, axes, dimensions, legend, annotations, tooltip DOM,
   * and toolbar. Only recalculates scales and replots the series paths.
   * Called automatically by _updateSeries() when the fast path is eligible.
   *
   * @param {boolean} animate - Whether to animate the update.
   * @param {string} [prevAxisScaleSig] - Signature of the on-screen axis scale
   *   captured by _updateSeries() before parseData recomputed bounds. When the
   *   recomputed scale differs, the fast path can't repaint the ruler in place,
   *   so it delegates to a full render. Omitted -> the check is skipped.
   * @returns {Promise<ApexCharts>} Resolves with the chart instance.
   */
  fastUpdate(animate, prevAxisScaleSig) {
    return new Promise((resolve, reject) => {
      var _a, _b, _c;
      try {
        const w = this.w;
        const gl = w.globals;
        gl.shouldAnimate = animate;
        gl.dataChanged = true;
        gl.animationEnded = false;
        PerformanceCache.invalidateSelectors(w);
        const gl2 = w.globals;
        gl2.maxY = -Number.MAX_VALUE;
        gl2.minY = Number.MIN_VALUE;
        gl2.minYArr = [];
        gl2.maxYArr = [];
        gl2.maxX = -Number.MAX_VALUE;
        gl2.minX = Number.MAX_VALUE;
        gl2.initialMaxX = -Number.MAX_VALUE;
        gl2.initialMinX = Number.MAX_VALUE;
        gl2.yAxisScale = [];
        gl2.xAxisScale = null;
        gl2.xAxisTicksPositions = [];
        gl2.xRange = 0;
        gl2.yRange = [];
        gl2.zRange = 0;
        gl2.xTickAmount = 0;
        gl2.multiAxisTickAmount = 0;
        gl2.pointsArray = [];
        gl2.barCanvasCoords = null;
        gl2.dataLabelsRects = [];
        gl2.lastDrawnDataLabelsIndexes = [];
        gl2.textRectsCache = /* @__PURE__ */ new Map();
        gl2.domCache = /* @__PURE__ */ new Map();
        gl2.cachedSelectors = {};
        gl2.disableZoomIn = false;
        gl2.disableZoomOut = false;
        if (gl.axisCharts) {
          this.core.coreCalculations();
          if (w.config.xaxis.type !== "category") {
            this.formatters.setLabelFormatters();
          }
        }
        this.formatters.heatmapLabelFormatters();
        const xyRatios = this.core.xySettings();
        if (this._zoomPanSelection) this._zoomPanSelection.xyRatios = xyRatios;
        const newAxisScaleSig = JSON.stringify({
          y: (gl.yAxisScale || []).map((s2) => s2 ? s2.result : null),
          xMin: gl.minX,
          xMax: gl.maxX
        });
        const scaleChanged = gl.axisCharts && prevAxisScaleSig != null && newAxisScaleSig !== prevAxisScaleSig;
        if (scaleChanged && !this._fastAxisChromeRefresh(xyRatios)) {
          this._updateStats.full++;
          return this.update().then(() => resolve(this)).catch(reject);
        }
        if (scaleChanged) {
          this._updateStats.fastWithAxes++;
        } else {
          this._updateStats.fast++;
        }
        (_a = this.weave) == null ? void 0 : _a.dispatch("afterScales", { pass: "fast", xyRatios });
        const rr = (
          /** @type {any} */
          this.ctx.renderer
        );
        const reuseCanvasHost = !!(rr && rr.kind === "canvas" && rr.canRepaintInPlace && rr.canRepaintInPlace());
        if (reuseCanvasHost) rr._repaintHostInPlace = true;
        const innerEl = w.dom.elGraphical.node;
        const toRemove = innerEl.querySelectorAll(
          (reuseCanvasHost ? "" : ".apexcharts-canvas-series-wrap, ") + ".apexcharts-plot-series, .apexcharts-series, .apexcharts-datalabels, .apexcharts-datalabels-background"
        );
        toRemove.forEach(
          (el) => {
            var _a2;
            return (_a2 = el.parentNode) == null ? void 0 : _a2.removeChild(el);
          }
        );
        const elGraph = this.core.plotChartType(w.config.series, xyRatios);
        const gridEl = innerEl.querySelector(".apexcharts-grid");
        const xaxisEl = innerEl.querySelector(".apexcharts-xaxis");
        const graphs = Array.isArray(elGraph) ? elGraph : [elGraph];
        const anchor = gridEl && w.config.grid.position === "front" ? gridEl : xaxisEl;
        if (anchor) {
          graphs.forEach((g) => {
            const node = g && g.node ? g.node : g;
            if (node) innerEl.insertBefore(node, anchor);
          });
        } else {
          graphs.forEach((g) => {
            w.dom.elGraphical.add(g);
          });
        }
        const dataLabels = new DataLabels(w, this);
        dataLabels.bringForward();
        if (w.config.dataLabels.background.enabled) {
          dataLabels.dataLabelsBackground();
        }
        if (!gl.streamScrolled) applyAxisTransition(w);
        applyDataLabelTransition(w);
        if (Environment.isBrowser() && w.config.tooltip.enabled && !gl.noData) {
          (_b = w.globals.tooltip) == null ? void 0 : _b.drawTooltip(xyRatios);
        }
        (_c = this.weave) == null ? void 0 : _c.dispatch("draw", { pass: "fast", xyRatios });
        if (typeof w.config.chart.events.updated === "function") {
          w.config.chart.events.updated(this, w);
        }
        this.events.fireEvent("updated", [this, w]);
        enforceLicense(w, this);
        gl.isDirty = true;
        resolve(this);
      } catch (e2) {
        reject(e2);
      }
    });
  }
  /**
   * Returns all charts in the same `chart.group` (including this instance),
   * used to synchronise zoom/pan across grouped charts.
   *
   * @returns {ApexCharts[]}
   */
  getSyncedCharts() {
    const group = (
      /** @type {ApexCharts[]} */
      this.getGroupedCharts()
    );
    group.splice(0, 0, this);
    return group;
  }
  /**
   * Trellis (#22): the panels of a trellis host, in grid order. Empty for a
   * chart that is not a trellis.
   *
   * @returns {Array<{ key: string, index: number, chart: ApexCharts|null, el: HTMLElement|null }>}
   */
  getPanels() {
    return this.trellis ? this.trellis.getPanels() : [];
  }
  /**
   * Trellis (#22): one panel's own ApexCharts instance by facet key — the
   * escape hatch to every per-chart API the trellis does not re-expose.
   *
   * @param {string} key
   * @returns {ApexCharts|null}
   */
  getPanel(key) {
    return this.trellis ? this.trellis.getPanel(key) : null;
  }
  /**
   * Returns all charts in the same `chart.group`, excluding this instance.
   * Used internally to apply hover/zoom effects to sibling charts.
   *
   * @returns {ApexCharts[]}
   */
  getGroupedCharts() {
    return Apex._chartInstances.filter(
      (ch) => this !== ch.chart && !!this.w.config.chart.group && this.w.config.chart.group === ch.group
    ).map((ch) => ch.chart);
  }
  /**
   * Retrieves a rendered chart instance by its `chart.id` config value.
   *
   * @param {string} id - The chart ID set via `chart.id` in options.
   * @returns {ApexCharts | undefined}
   */
  static getChartByID(id) {
    const chartId = Utils$1.escapeString(id);
    if (!Apex._chartInstances) return void 0;
    const c2 = Apex._chartInstances.filter(
      (ch) => ch.id === chartId
    )[0];
    return c2 && c2.chart;
  }
  /**
   * Trellis (#22): imperative entry point. Creates a trellis host and starts
   * rendering it; `render()` is idempotent, so `await chart.render()` on the
   * returned instance settles with the same in-flight mount.
   *
   * Requires the trellis feature, which is NOT in the default bundle
   * (`import 'apexcharts/features/trellis'`, or add `dist/features/trellis.js`
   * after apexcharts.js on a script-tag page); warns and returns null otherwise.
   *
   * @param {HTMLElement} el
   * @param {ApexOptions} options must carry `trellis.by` (or `trellis.row`
   *   / `trellis.column` for a 2-D grid)
   * @returns {ApexCharts|null}
   */
  static trellis(el, options2) {
    if (!InitCtxVariables._featureRegistry.get("trellis")) {
      console.warn(
        "ApexCharts.trellis requires the trellis feature, which is not in the default bundle. Bundler: import 'apexcharts/features/trellis'. Script tag: add <script src='.../dist/features/trellis.js'> after apexcharts.js."
      );
      return null;
    }
    const chart = new _ApexCharts(el, options2);
    chart.render();
    return chart;
  }
  /**
   * Scans the document for elements with a `data-apexcharts` attribute and
   * `data-options` JSON, then renders a chart in each one automatically.
   * Useful for non-framework HTML pages.
   */
  static initOnLoad() {
    var _a;
    const els = document.querySelectorAll("[data-apexcharts]");
    for (let i2 = 0; i2 < els.length; i2++) {
      const el = (
        /** @type {HTMLElement} */
        els[i2]
      );
      const options2 = JSON.parse((_a = els[i2].getAttribute("data-options")) != null ? _a : "");
      const apexChart = new _ApexCharts(el, options2);
      apexChart.render();
    }
  }
  /**
   * This static method allows users to call chart methods without necessarily from the
   * instance of the chart in case user has assigned chartID to the targeted chart.
   * The chartID is used for mapping the instance stored in Apex._chartInstances global variable
   *
   * This is helpful in cases when you don't have reference of the chart instance
   * easily and need to call the method from anywhere.
   * For eg, in React/Vue applications when you have many parent/child components,
   * and need easy reference to other charts for performing dynamic operations
   *
   * @param {string} chartID - The unique identifier which will be used to call methods
   * on that chart instance
   * @param {string} fn - The method name to call
   * @param {...any} opts - The parameters which are accepted in the original method will be passed here in the same order.
   */
  static exec(chartID, fn, ...opts) {
    const chart = this.getChartByID(chartID);
    if (!chart) return;
    chart.w.globals.isExecCalled = true;
    let ret = null;
    if (chart.publicMethods.indexOf(fn) !== -1) {
      ret = /** @type {any} */
      chart[fn](...opts);
    }
    return ret;
  }
  /**
   * Deep-merges `source` into `target` and returns the result.
   * Thin wrapper around the internal `Utils.extend` utility.
   *
   * @param {object} target
   * @param {object} source
   * @returns {object}
   */
  static merge(target, source) {
    return Utils$1.extend(target, source);
  }
  static getThemePalettes() {
    return getThemePalettes();
  }
  /**
   * Register additional chart types. Used by sub-entry points so that only
   * the types they include are bundled.
   *
   * @param {Record<string, new (...args: any[]) => any>} typeMap  e.g. { line: Line, area: Line }
   */
  static use(typeMap) {
    register(typeMap);
  }
  /**
   * Register optional feature modules (Exports, Legend, Toolbar,
   * ZoomPanSelection, KeyboardNavigation, Annotations).
   *
   * Call this before rendering any chart. Feature entry files (e.g.
   * `apexcharts/features/legend`) call this automatically when imported.
   * Note: Tooltip is part of core and does not need to be registered.
   *
   * @param {Record<string, new (...args: any[]) => any>} featureMap  e.g. { legend: Legend, exports: Exports }
   */
  static registerFeatures(featureMap) {
    InitCtxVariables.registerFeatures(featureMap);
  }
  /**
   * Set the license key that unlocks the premium features (storyboard, link /
   * crossfilter, ink, measure, contextMenu, perspectives, history). Without a
   * valid key those features still work but the chart shows an "APEXCHARTS"
   * trial watermark; a valid key removes it. Keys are shared across the whole
   * ApexCharts family (apexgantt, apextree, apexsankey, apex-grid-enterprise,
   * apexstock), so one customer key works everywhere.
   *
   * Call before render(). The watermark is re-evaluated on every render/update,
   * so a late setLicense(validKey) followed by chart.update() clears it.
   *
   * Precedence per chart: `chart.license` (most specific) -> this key ->
   * `window.Apex.license` -> unlicensed (trial).
   *
   * @param {string} key  the `APEX-<base64(JSON)>` license key
   * @returns {typeof ApexCharts}
   */
  static setLicense(key) {
    o.setLicense(key);
    reevaluateLicenseAcrossCharts();
    return _ApexCharts;
  }
  /**
   * Register a Weave plugin definition (a plain { name, setup } object).
   * Lives in core so plugins can always be registered; they only activate when
   * the Weave host is bundled (`import 'apexcharts/features/weave'`, included in
   * the full bundle) and listed in a chart's `plugins` config.
   *
   * @param {{ name: string, apiVersion?: number, setup: Function, destroy?: Function }} def
   * @returns {typeof ApexCharts}
   */
  static registerPlugin(def) {
    registerPlugin(def);
    return _ApexCharts;
  }
  /**
   * Remove a registered Weave plugin definition. Charts already holding an
   * active instance keep it until their plugins config changes or they are
   * destroyed; the name simply stops resolving for new activations. Intended
   * for tests and hot-reload flows.
   * @param {string} name
   * @returns {typeof ApexCharts}
   */
  static unregisterPlugin(name2) {
    unregisterPlugin(name2);
    return _ApexCharts;
  }
  /**
   * Register a non-SVG series renderer (Strata #2). SVG is built in; the canvas
   * backend registers itself via `import 'apexcharts/features/renderer-canvas'`.
   * When a `kind` is not registered, selection falls back to SVG.
   *
   * @param {string} kind  e.g. 'canvas'
   * @param {(w: any, ctx: any) => any} factory  returns a Renderer instance
   */
  static registerRenderer(kind, factory) {
    RendererController.registerRenderer(kind, factory);
  }
  /**
   * Register a custom series type (Marks #11): a `{ renderItem }` definition
   * that draws primitives (path/line/rect/circle/text) per datum. Requires the
   * Marks feature to be bundled (`import 'apexcharts/features/marks'`, included
   * in the full bundle); without it this warns and no-ops. Once registered, use
   * it via `series[].type` or `chart.type`.
   *
   * @param {string} name  the type name, e.g. 'dumbbell'
   * @param {{ renderItem: Function, dataType?: string, yExtent?: Function, tooltip?: Function }} def
   * @returns {typeof ApexCharts}
   */
  static registerSeriesType(name2, def) {
    const factory = (
      /** @type {any} */
      _ApexCharts._customSeriesFactory
    );
    if (!factory) {
      console.warn(
        `[apexcharts] registerSeriesType("${name2}") requires the Marks feature: import 'apexcharts/features/marks'.`
      );
      return _ApexCharts;
    }
    if (!def || typeof def.renderItem !== "function") {
      console.warn(
        `[apexcharts] registerSeriesType("${name2}") needs a def with a renderItem() function.`
      );
      return _ApexCharts;
    }
    if (hasChartClass(name2) && !isCustom(name2)) {
      console.warn(
        `[apexcharts] registerSeriesType("${name2}") would override the built-in "${name2}" chart type; pick another name.`
      );
      return _ApexCharts;
    }
    register({ [name2]: factory(name2, def) });
    markCustom(name2);
    return _ApexCharts;
  }
  /**
   * Remove a custom series type registered via registerSeriesType. Built-in
   * chart types cannot be unregistered. Intended for tests and hot-reload.
   * @param {string} name
   * @returns {typeof ApexCharts}
   */
  static unregisterSeriesType(name2) {
    if (isCustom(name2)) unregister(name2);
    return _ApexCharts;
  }
  /**
   * Facet (#13): register a named theme (palette + design tokens + mode)
   * referenceable via `theme: { name }`. The theme sits below explicit config
   * and CSS `--apx-*` tokens, above the built-in palette/mode defaults.
   *
   * @param {string} name  the theme name, e.g. 'brand'
   * @param {any} def  { mode?, palette?, tokens?, monochrome?, accessibility? }
   * @returns {typeof ApexCharts}
   */
  static registerTheme(name2, def) {
    registerTheme(name2, def);
    return _ApexCharts;
  }
  /**
   * Remove a theme registered via registerTheme. Charts referencing it by
   * `theme.name` fall back to the built-in defaults on their next render.
   * Intended for tests and hot-reload flows.
   * @param {string} name
   * @returns {typeof ApexCharts}
   */
  static unregisterTheme(name2) {
    unregisterTheme(name2);
    return _ApexCharts;
  }
  /**
   * Cadence (#6): register a named easing function referenceable via
   * `chart.animations.easing: '<name>'`. `fn` maps linear progress t in [0,1]
   * to eased progress (back/elastic curves may overshoot 1).
   *
   * @param {string} name  the easing name, e.g. 'bounce'
   * @param {(t:number)=>number} fn
   * @returns {typeof ApexCharts}
   */
  static registerEasing(name2, fn) {
    registerEasing(name2, fn);
    return _ApexCharts;
  }
  /**
   * Register a named unit-chart layout, referenceable via
   * `plotOptions.unit.positions: '<name>'` with `plotOptions.unit.layout:
   * 'custom'`.
   *
   * A layout is objects in, positions out: `(objects, rect) => [{id, x, y,
   * r?}]`, in plot pixels. It knows nothing about animation, because the engine
   * already tweens position, radius and colour and already keeps each mark's
   * identity across a relayout. That is what lets an arrangement the engine
   * cannot know about - a country silhouette, a hex grid, a timeline, a
   * projection supplied by ApexMaps - be a plugin rather than a core change.
   *
   * Marks whose id the layout omits animate out; ids matching no mark are
   * ignored.
   *
   * @param {string} name  the layout name, e.g. 'silhouette'
   * @param {(objects: any[], rect: {x:number,y:number,width:number,height:number}) => any[]} fn
   * @returns {typeof ApexCharts}
   */
  static registerUnitLayout(name2, fn) {
    registerUnitLayout(name2, fn);
    return _ApexCharts;
  }
  /**
   * Remove a layout registered via registerUnitLayout. Charts referencing it by
   * name fall back to the grouped layout on their next render.
   * @param {string} name
   * @returns {typeof ApexCharts}
   */
  static unregisterUnitLayout(name2) {
    unregisterUnitLayout(name2);
    return _ApexCharts;
  }
  /**
   * Register a named unit-chart MARK (pictogram), referenceable via
   * `plotOptions.unit.pictogram.mark: '<name>'` with
   * `plotOptions.unit.shape: 'pictogram'`.
   *
   * This is the twin of registerUnitLayout, and the split between them is the
   * one the unit chart is built on: a LAYOUT is where the marks go, a MARK is
   * what one of them looks like. They compose freely - a person glyph arranged
   * into a heart, a house glyph on a waffle grid - so neither has to know about
   * the other.
   *
   * A mark is fill-only path data. The chart positions it with a uniform
   * `scale()` fitted to the radius the layout chose, so the glyph occupies the
   * box the dot would have and any stroke width would scale with it.
   *
   * @param {string} name  the mark name, e.g. 'person'
   * @param {string|any} def path data in a 0..100 box, or
   *   `{path, viewBox?, fillRule?}`
   * @returns {typeof ApexCharts}
   */
  static registerUnitMark(name2, def) {
    registerUnitMark(name2, def);
    return _ApexCharts;
  }
  /**
   * Remove a mark registered via registerUnitMark. Charts referencing it by
   * name fall back to `plotOptions.unit.pictogram.fallback` on their next
   * render.
   * @param {string} name
   * @returns {typeof ApexCharts}
   */
  static unregisterUnitMark(name2) {
    unregisterUnitMark(name2);
    return _ApexCharts;
  }
  /**
   * Register a row source: given a chart's state, what rows is each of its
   * marks standing for?
   *
   * Most marks cannot answer. An ordinary bar aggregates rows the library never
   * saw. The types that can are the ones whose series carries raw observations
   * (histogram, boxPlot, violin), and their sources ship with the statistics in
   * `apexcharts/features/stats`; core keeps only the lookup.
   *
   * The function returns a unit-chart series (one cluster per mark, one datum
   * per row) in the marks' own draw order, or null. See RowSourceRegistry for
   * why that order is a contract rather than a convention.
   *
   * @param {string} name  chart type name, matched against `chart.requestedType` then `chart.type`
   * @param {(w: any, opts?: any) => any[] | null} fn
   * @returns {typeof ApexCharts}
   */
  static registerRowSource(name2, fn) {
    registerRowSource(name2, fn);
    return _ApexCharts;
  }
  /**
   * Remove a row source registered via registerRowSource.
   * @param {string} name
   * @returns {typeof ApexCharts}
   */
  static unregisterRowSource(name2) {
    unregisterRowSource(name2);
    return _ApexCharts;
  }
  /**
   * The rows behind this chart's marks, as a unit-chart series.
   *
   * A histogram bar stands for the observations it counted, a box for the
   * sample it summarises. This hands them back as one cluster per mark, so a
   * mark can come apart into its own rows:
   *
   *     chart.updateOptions({ chart: { type: 'unit' }, series: chart.rowSeries() })
   *
   * With the morph feature loaded, each dot then leaves from the part of the
   * mark that was standing for it, and collapsing back is the inverse.
   *
   * Returns null when the chart's type cannot name its rows, or when
   * `apexcharts/features/stats` (which carries the sources for the types that
   * can) is not loaded.
   *
   * @param {{ maxRows?: number }} [opts] `maxRows` caps the dots produced
   *   (default 3000, matching the jitter overlay); past it every cluster is
   *   thinned by one shared stride so their relative sizes survive.
   * @returns {any[]|null}
   */
  rowSeries(opts) {
    const source = rowSourceFor(this.w);
    if (!source) return null;
    return source(this.w, opts) || null;
  }
  /**
   * Linked Views (#4) Phase 2: get-or-create a crossfilter coordinator by id.
   * Register one shared record set, then let each chart declare a dimension +
   * reduction under `chart.link`. Selecting in one chart re-aggregates the
   * others over the filtered subset.
   *
   * Lives in core (always callable) but the engine ships in the `link` feature,
   * which is NOT in the default bundle (`import 'apexcharts/features/link'`, or
   * add `dist/features/link.js` after apexcharts.js on a script-tag page);
   * without it this warns and returns null so the engine shakes out when
   * unused.
   *
   * @param {{ id: string, records?: any[] }} opts
   * @returns {any} the coordinator handle, or null if the feature is absent
   */
  static crossfilter(opts) {
    if (!opts || typeof opts.id !== "string") {
      throw new Error("ApexCharts.crossfilter requires an { id } string.");
    }
    const factory = (
      /** @type {any} */
      _ApexCharts._crossfilterFactory
    );
    if (!factory) {
      console.warn(
        `[apexcharts] ApexCharts.crossfilter(...) requires the link feature, which is not in the default bundle. Bundler: import 'apexcharts/features/link'. Script tag: add <script src='.../dist/features/link.js'> after apexcharts.js.`
      );
      return null;
    }
    const coordinator = factory(opts);
    reevaluateLicenseAcrossCharts();
    return coordinator;
  }
  /**
   * Look up an existing crossfilter coordinator by id (null if none / feature
   * absent).
   * @param {string} id
   * @returns {any}
   */
  static getCrossfilter(id) {
    const get = (
      /** @type {any} */
      _ApexCharts._crossfilterGet
    );
    return get ? get(id) : null;
  }
  /**
   * Linked Views (#4): clear crossfilter dimming across this chart and every
   * chart in its `chart.group`. No-op unless the `link` feature is bundled.
   */
  clearCrossfilter() {
    var _a;
    (_a = this.linkedViews) == null ? void 0 : _a.clearGroup();
  }
  /**
   * Measure ruler (#18): arm a sticky measure-ruler mode (drag A->B on the
   * plot to read dx/dy/%change/slope). Alternatively hold the measure key
   * (chart.measure.key, default 'm') and drag. No-op unless the `measure`
   * feature is bundled and chart.measure.enabled.
   */
  startMeasure() {
    var _a;
    (_a = this.measure) == null ? void 0 : _a.startMeasure();
  }
  /** Measure ruler (#18): leave measure mode. */
  stopMeasure() {
    var _a;
    (_a = this.measure) == null ? void 0 : _a.stopMeasure();
  }
  /** Measure ruler (#18): remove all pinned measure rulers. */
  clearMeasures() {
    var _a;
    (_a = this.measure) == null ? void 0 : _a.clearMeasures();
  }
  /**
   * Toggles (show/hide) the series identified by name.
   * Mirrors a click on the corresponding legend item.
   *
   * @param {string} seriesName
   * @returns {object | undefined} The collapsed series object, if now hidden.
   */
  toggleSeries(seriesName) {
    return this.series.toggleSeries(seriesName);
  }
  /**
   * Highlights or un-highlights a series when the user hovers a legend item.
   * Called internally by the legend; not typically called by consumers.
   *
   * @param {MouseEvent} e
   * @param {HTMLElement} targetElement - The legend marker element being hovered.
   */
  highlightSeriesOnLegendHover(e2, targetElement) {
    return this.series.toggleSeriesOnHover(e2, targetElement);
  }
  /**
   * Makes a previously hidden series visible and re-renders.
   *
   * @param {string} seriesName
   */
  showSeries(seriesName) {
    this.series.showSeries(seriesName);
  }
  /**
   * Hides a visible series and re-renders.
   *
   * @param {string} seriesName
   */
  hideSeries(seriesName) {
    this.series.hideSeries(seriesName);
  }
  /**
   * Highlights (dims all other series) the series identified by name.
   *
   * @param {string} seriesName
   */
  highlightSeries(seriesName) {
    this.series.highlightSeries(seriesName);
  }
  /**
   * Returns whether the series identified by name is currently hidden.
   *
   * @param {string} seriesName
   * @returns {boolean}
   */
  isSeriesHidden(seriesName) {
    return this.series.isSeriesHidden(seriesName);
  }
  /**
   * Resets the chart to the initial series and optionally the initial zoom level.
   *
   * @param {boolean} [shouldUpdateChart=true] - When true, triggers a re-render.
   * @param {boolean} [shouldResetZoom=true] - When true, restores the initial zoom level.
   */
  resetSeries(shouldUpdateChart = true, shouldResetZoom = true) {
    this.series.resetSeries(shouldUpdateChart, shouldResetZoom);
  }
  /**
   * Subscribes to a chart event by name.
   * Supported event names mirror the `chart.events` option keys
   * (e.g. `'mounted'`, `'updated'`, `'dataPointMouseEnter'`).
   *
   * @param {string} name - Event name.
   * @param {Function} handler - Callback invoked when the event fires.
   */
  addEventListener(name2, handler) {
    this.events.addEventListener(name2, handler);
  }
  /**
   * Removes a previously registered event listener.
   *
   * @param {string} name - Event name.
   * @param {Function} handler - The exact function reference passed to addEventListener.
   */
  removeEventListener(name2, handler) {
    this.events.removeEventListener(name2, handler);
  }
  /**
   * Adds an x-axis annotation dynamically after render.
   *
   * @param {XAxisAnnotations} opts - Annotation configuration.
   * @param {boolean} [pushToMemory=true] - When true, the annotation persists across re-renders.
   * @param {ApexCharts} [context] - Override the target chart instance (used by exec()).
   */
  addXaxisAnnotation(opts, pushToMemory = true, context = void 0) {
    var _a;
    let me = (
      /** @type {ApexCharts} */
      /** @type {unknown} */
      this
    );
    if (context) {
      me = context;
    }
    (_a = me.annotations) == null ? void 0 : _a.addXaxisAnnotationExternal(opts, pushToMemory, me);
  }
  /**
   * Adds a y-axis annotation dynamically after render.
   *
   * @param {YAxisAnnotations} opts - Annotation configuration.
   * @param {boolean} [pushToMemory=true] - When true, the annotation persists across re-renders.
   * @param {ApexCharts} [context] - Override the target chart instance (used by exec()).
   */
  addYaxisAnnotation(opts, pushToMemory = true, context = void 0) {
    var _a;
    let me = (
      /** @type {ApexCharts} */
      /** @type {unknown} */
      this
    );
    if (context) {
      me = context;
    }
    (_a = me.annotations) == null ? void 0 : _a.addYaxisAnnotationExternal(opts, pushToMemory, me);
  }
  /**
   * Adds a point annotation dynamically after render.
   *
   * @param {PointAnnotations} opts - Annotation configuration.
   * @param {boolean} [pushToMemory=true] - When true, the annotation persists across re-renders.
   * @param {ApexCharts} [context] - Override the target chart instance (used by exec()).
   */
  addPointAnnotation(opts, pushToMemory = true, context = void 0) {
    var _a;
    let me = (
      /** @type {ApexCharts} */
      /** @type {unknown} */
      this
    );
    if (context) {
      me = context;
    }
    (_a = me.annotations) == null ? void 0 : _a.addPointAnnotationExternal(opts, pushToMemory, me);
  }
  /**
   * Removes all annotations from the chart.
   *
   * @param {ApexCharts} [context] - Override the target chart instance (used by exec()).
   */
  clearAnnotations(context = void 0) {
    var _a;
    let me = (
      /** @type {ApexCharts} */
      /** @type {unknown} */
      this
    );
    if (context) {
      me = context;
    }
    me.lastUpdateOptions = null;
    (_a = me.annotations) == null ? void 0 : _a.clearAnnotations(me);
  }
  /**
   * Removes a specific annotation by its `id`.
   *
   * @param {string} id - The annotation id as set in the annotation config.
   * @param {ApexCharts} [context] - Override the target chart instance (used by exec()).
   */
  removeAnnotation(id, context = void 0) {
    var _a;
    let me = (
      /** @type {ApexCharts} */
      /** @type {unknown} */
      this
    );
    if (context) {
      me = context;
    }
    me.lastUpdateOptions = null;
    (_a = me.annotations) == null ? void 0 : _a.removeAnnotation(me, id);
  }
  /**
   * Returns the inner SVG group element that contains all chart graphics.
   *
   * @returns {Element | null}
   */
  getChartArea() {
    const el = this.w.dom.baseEl.querySelector(".apexcharts-inner");
    return el;
  }
  /**
   * Returns the sum of all data points whose x value falls within [minX, maxX].
   *
   * @param {number} minX
   * @param {number} maxX
   * @returns {number[]} One total per series.
   */
  getSeriesTotalXRange(minX, maxX) {
    return this.coreUtils.getSeriesTotalsXRange(minX, maxX);
  }
  /**
   * Returns the highest y value in the specified series.
   *
   * @param {number} [seriesIndex=0]
   * @returns {number}
   */
  getHighestValueInSeries(seriesIndex = 0) {
    const range = new Range(this.w);
    return range.getMinYMaxY(seriesIndex).highestY;
  }
  /**
   * Returns the lowest y value in the specified series.
   *
   * @param {number} [seriesIndex=0]
   * @returns {number}
   */
  getLowestValueInSeries(seriesIndex = 0) {
    const range = new Range(this.w);
    return range.getMinYMaxY(seriesIndex).lowestY;
  }
  /**
   * Returns the sum of each series (the totals used for percentage calculations).
   *
   * @returns {number[]}
   */
  getSeriesTotal() {
    return this.w.globals.seriesTotals;
  }
  /**
   * Returns a curated snapshot of chart state for use in formatters, events,
   * and external integrations. Prefer this over accessing `chart.w` directly.
   *
   * The shape of this object is stable and versioned. `chart.w` is internal
   * and will be restricted in a future major version.
   */
  getState() {
    const w = this.w;
    const gl = w.globals;
    return {
      // Series data — computed/parsed form used for rendering
      series: w.seriesData.series,
      seriesNames: w.seriesData.seriesNames,
      colors: gl.colors,
      labels: w.labelData.labels,
      seriesTotals: gl.seriesTotals,
      seriesPercent: gl.seriesPercent,
      seriesXvalues: gl.seriesXvalues,
      seriesYvalues: gl.seriesYvalues,
      // Axis bounds — updated after each render
      minX: gl.minX,
      maxX: gl.maxX,
      minY: gl.minY,
      maxY: gl.maxY,
      minYArr: gl.minYArr,
      maxYArr: gl.maxYArr,
      minXDiff: gl.minXDiff,
      dataPoints: gl.dataPoints,
      // Axis scale objects — computed tick/scale results
      xAxisScale: gl.xAxisScale,
      yAxisScale: gl.yAxisScale,
      xTickAmount: gl.xTickAmount,
      // Axis type flags
      isXNumeric: w.axisFlags.isXNumeric,
      // Multi-axis series mapping
      seriesYAxisMap: gl.seriesYAxisMap,
      seriesYAxisReverseMap: gl.seriesYAxisReverseMap,
      // Chart dimensions — updated after each render/resize
      svgWidth: gl.svgWidth,
      svgHeight: gl.svgHeight,
      gridWidth: w.layout.gridWidth,
      gridHeight: w.layout.gridHeight,
      // Interactive state
      selectedDataPoints: w.interact.selectedDataPoints,
      collapsedSeriesIndices: gl.collapsedSeriesIndices,
      zoomed: w.interact.zoomed,
      // Chart-type-specific series data (null when not applicable)
      seriesX: w.seriesData.seriesX,
      seriesZ: w.seriesData.seriesZ,
      seriesCandleO: w.candleData.seriesCandleO,
      seriesCandleH: w.candleData.seriesCandleH,
      seriesCandleM: w.candleData.seriesCandleM,
      seriesCandleL: w.candleData.seriesCandleL,
      seriesCandleC: w.candleData.seriesCandleC,
      seriesRangeStart: w.rangeData.seriesRangeStart,
      seriesRangeEnd: w.rangeData.seriesRangeEnd,
      seriesGoals: w.seriesData.seriesGoals
    };
  }
  /**
   * Programmatically selects or deselects a data point.
   * Equivalent to a user click on the data point.
   *
   * @param {number} seriesIndex - Zero-based series index.
   * @param {number} [dataPointIndex] - Zero-based data point index within the series.
   * @returns {number[][] | null} Updated selectedDataPoints array, or null.
   */
  toggleDataPointSelection(seriesIndex, dataPointIndex) {
    return this.updateHelpers.toggleDataPointSelection(
      seriesIndex,
      dataPointIndex
    );
  }
  /**
   * Programmatically zooms the x-axis to the given range.
   * Requires zoom to be enabled (`chart.zoom.enabled: true`).
   *
   * @param {number} min - The minimum x value (timestamp or numeric).
   * @param {number} max - The maximum x value (timestamp or numeric).
   */
  zoomX(min, max) {
    var _a;
    (_a = this.ctx.toolbar) == null ? void 0 : _a.zoomUpdateOptions(min, max);
  }
  /**
   * Switches the active locale, updating all locale-dependent labels (toolbar tooltips, month names, etc.).
   *
   * @param {string} localeName - Must match a locale name defined in `chart.locales`.
   */
  setLocale(localeName) {
    this.localization.setCurrentLocaleValues(localeName);
  }
  /**
   * Exports the chart to a PNG or SVG data URI.
   * Requires the Exports feature: `import 'apexcharts/features/exports'`.
   *
   * @param {{ scale?: number, width?: number }} [options]
   * @returns {Promise<{ imgURI: string } | { blob: Blob }>}
   */
  dataURI(options2) {
    if (!this.ctx.exports)
      throw new Error(
        "apexcharts: Exports feature is not registered. Import apexcharts/features/exports."
      );
    if (this.trellis && this.trellis._mounted) {
      return this.trellis.exports.dataURI(options2);
    }
    return this.ctx.exports.dataURI(options2);
  }
  /**
   * Returns the chart's SVG markup as a string, optionally scaled.
   * Requires the Exports feature: `import 'apexcharts/features/exports'`.
   *
   * @param {number} [scale=1]
   * @returns {Promise<string>}
   */
  getSvgString(scale) {
    if (!this.ctx.exports)
      throw new Error(
        "apexcharts: Exports feature is not registered. Import apexcharts/features/exports."
      );
    if (this.trellis && this.trellis._mounted) {
      return this.trellis.exports.svgString();
    }
    return this.ctx.exports.getSvgString(scale);
  }
  /**
   * Triggers a CSV download of the chart's data.
   * Requires the Exports feature: `import 'apexcharts/features/exports'`.
   *
   * @param {{ series?: any, fileName?: string, columnDelimiter?: string, lineDelimiter?: string }} [options]
   */
  exportToCSV(options2 = {}) {
    if (!this.ctx.exports)
      throw new Error(
        "apexcharts: Exports feature is not registered. Import apexcharts/features/exports."
      );
    if (this.trellis && this.trellis._mounted) {
      return this.trellis.exports.download("csv");
    }
    return this.ctx.exports.exportToCSV(options2);
  }
  /**
   * Trellis (#22, P3): expand one panel to the grid's full width (what
   * clicking its header does). No-op on a chart that is not a trellis host.
   * @param {string} key the panel's facet key
   * @returns {Promise<void>}
   */
  promotePanel(key) {
    return this.trellis && this.trellis._mounted ? this.trellis.promote(key) : Promise.resolve();
  }
  /**
   * Trellis (#22, P3): restore the grid from a panel promotion.
   * @returns {Promise<void>}
   */
  restorePanels() {
    return this.trellis && this.trellis._mounted ? this.trellis.restorePromotion() : Promise.resolve();
  }
  paper() {
    return this.w.dom.Paper;
  }
  /**
   * Returns the active series renderer for the last render: `'svg'` (default)
   * or `'canvas'` (Strata #2). `'auto'`/`'canvas'` resolve to `'svg'` unless the
   * canvas renderer feature is bundled and no canvas-unsupported feature is in
   * use. See `chart.renderer` / `chart.rendererThreshold`.
   *
   * @returns {'svg' | 'canvas' | 'gpu'}
   */
  getActiveRenderer() {
    return this.rendererController ? this.rendererController.getActiveKind() : "svg";
  }
  /**
   * Facet (#13): re-resolve the `--apx-*` design tokens and re-render.
   *
   * Tokens are read from the CSS cascade once per render, so a runtime change
   * that is NOT an OS color-scheme flip (e.g. the host app swaps its own
   * design-system theme by toggling a class or setting style properties) is
   * invisible until the next render, and `updateOptions({})` is memoized away.
   * This busts the memo and re-renders, picking up the current token values.
   * @returns {Promise<any>}
   */
  refreshTokens() {
    this.lastUpdateOptions = null;
    return this.update();
  }
  /**
   * Drills into the child level referenced by `id` (a `chart.drilldown.series` entry).
   * Requires the Drilldown feature: `import 'apexcharts/features/drilldown'`.
   *
   * @param {string|number} id - The drilldown series id to navigate into.
   * @returns {Promise<ApexCharts>}
   */
  drillDown(id) {
    if (!this.ctx.drilldown)
      throw new Error(
        "apexcharts: Drilldown feature is not registered. Import apexcharts/features/drilldown."
      );
    return this.ctx.drilldown.drillDown(id);
  }
  /**
   * Navigates back one drilldown level.
   * Requires the Drilldown feature: `import 'apexcharts/features/drilldown'`.
   *
   * @returns {Promise<ApexCharts>}
   */
  drillUp() {
    if (!this.ctx.drilldown)
      throw new Error(
        "apexcharts: Drilldown feature is not registered. Import apexcharts/features/drilldown."
      );
    return this.ctx.drilldown.drillUp();
  }
  /**
   * Navigates back to the root drilldown level.
   * Requires the Drilldown feature: `import 'apexcharts/features/drilldown'`.
   *
   * @returns {Promise<ApexCharts>}
   */
  drillToRoot() {
    if (!this.ctx.drilldown)
      throw new Error(
        "apexcharts: Drilldown feature is not registered. Import apexcharts/features/drilldown."
      );
    return this.ctx.drilldown.drillToRoot();
  }
  /**
   * Drops levels cached from `drilldown.onDrillDown`, so the next drill re-runs
   * the resolver. Call it when the data behind an already-drilled chart changes.
   * Requires the Drilldown feature: `import 'apexcharts/features/drilldown'`.
   *
   * @param {string|number} [id] - A single level id, or every level when omitted.
   * @returns {ApexCharts}
   */
  clearDrilldownCache(id) {
    if (!this.ctx.drilldown)
      throw new Error(
        "apexcharts: Drilldown feature is not registered. Import apexcharts/features/drilldown."
      );
    return this.ctx.drilldown.clearCache(id);
  }
  // ─── Slice write-back stubs ─────────────────────────────────────────────────
  /**
   * Copy own DATA properties of a parse-state slice onto a live w.* slice.
   * Never Object.assign here: several w.* fields (and, historically, snapshot
   * fields) are lazy accessors, and [[Get]]-ing an accessor while copying
   * forces its deferred computation (a deep initialSeries clone plus O(n)
   * stacked-totals passes on every render/update) and can replace the live
   * accessor with a materialized value for the life of the instance.
   * @param {any} target
   * @param {any} slice
   */
  static _writeDataProps(target, slice) {
    for (const key of Object.keys(slice)) {
      const d = Object.getOwnPropertyDescriptor(slice, key);
      if (d && "value" in d) target[key] = d.value;
    }
  }
  /**
   * @param {Partial<import('./types/internal').SeriesData>} slice
   */
  _writeParsedSeriesData(slice) {
    _ApexCharts._writeDataProps(this.w.seriesData, slice);
  }
  /**
   * @param {Partial<import('./types/internal').RangeData>} slice
   */
  _writeParsedRangeData(slice) {
    _ApexCharts._writeDataProps(this.w.rangeData, slice);
  }
  /**
   * @param {Partial<import('./types/internal').CandleData>} slice
   */
  _writeParsedCandleData(slice) {
    _ApexCharts._writeDataProps(this.w.candleData, slice);
  }
  /**
   * @param {Partial<import('./types/internal').LabelData>} slice
   */
  _writeParsedLabelData(slice) {
    _ApexCharts._writeDataProps(this.w.labelData, slice);
  }
  /**
   * @param {Partial<import('./types/internal').AxisFlags>} slice
   */
  _writeParsedAxisFlags(slice) {
    _ApexCharts._writeDataProps(this.w.axisFlags, slice);
  }
  /**
   * @param {Partial<import('./types/internal').LayoutCoords>} slice
   */
  _writeLayoutCoords(slice) {
    _ApexCharts._writeDataProps(this.w.layout, slice);
  }
  _parentResizeCallback() {
    if (this.w.globals.animationEnded && this.w.config.chart.redrawOnParentResize) {
      this._windowResize();
    }
  }
  /**
   * Handle window resize and re-draw the whole chart.
   */
  _windowResize() {
    this.w.globals.resizeTimer = window.setTimeout(() => {
      const gl = this.w.globals;
      if (this.core && gl.lastResizeSignature) {
        const sig = this.core.getResizeSignature();
        if (sig.w === gl.lastResizeSignature.w && sig.h === gl.lastResizeSignature.h && sig.iw === gl.lastResizeSignature.iw) {
          return;
        }
      }
      gl.resized = true;
      gl.dataChanged = false;
      this.ctx.update();
    }, 150);
  }
  _windowResizeHandler() {
    var _a;
    clearTimeout((_a = this.w.globals.resizeTimer) != null ? _a : void 0);
    let { redrawOnWindowResize: redraw } = this.w.config.chart;
    if (typeof redraw === "function") {
      redraw = /** @type {any} */
      redraw();
    }
    redraw && this._windowResize();
  }
};
/**
 * Static Perspectives helpers (decode/fromURL), populated by the perspectives
 * feature when imported (`import 'apexcharts/features/perspectives'`); null
 * otherwise. Declared here as a placeholder so core stays free of the
 * Perspectives module while the assignment in the feature file type-checks.
 * @type {any}
 */
__publicField(_ApexCharts, "perspectives", null);
let ApexCharts = _ApexCharts;
export {
  Animations as __apex_Animations,
  applyAnimationPolicy as __apex_Animations_applyAnimationPolicy,
  applyProgressiveReveal as __apex_Animations_applyProgressiveReveal,
  computeStagger as __apex_Animations_computeStagger,
  prefersReducedMotion as __apex_Animations_prefersReducedMotion,
  Base as __apex_Base,
  BrowserAPIs as __apex_BrowserAPIs_BrowserAPIs,
  getChartClass as __apex_ChartFactory_getChartClass,
  isCustom as __apex_ChartFactory_isCustom,
  register as __apex_ChartFactory_register,
  Config as __apex_Config,
  LINE_HEIGHT_RATIO as __apex_Constants_LINE_HEIGHT_RATIO,
  NICE_SCALE_ALLOWED_MAG_MSD as __apex_Constants_NICE_SCALE_ALLOWED_MAG_MSD,
  NICE_SCALE_DEFAULT_TICKS as __apex_Constants_NICE_SCALE_DEFAULT_TICKS,
  Core as __apex_Core,
  CoreUtils as __apex_CoreUtils,
  Crosshairs as __apex_Crosshairs,
  SSRClassList as __apex_DOMShim_SSRClassList,
  SSRDOMShim as __apex_DOMShim_SSRDOMShim,
  SSRElement as __apex_DOMShim_SSRElement,
  Data as __apex_Data,
  DataLabels as __apex_DataLabels,
  DateTime as __apex_DateTime,
  Defaults as __apex_Defaults,
  Environment as __apex_Environment_Environment,
  Events as __apex_Events,
  Fill as __apex_Fill,
  Filters as __apex_Filters,
  Formatters as __apex_Formatters,
  Globals as __apex_Globals,
  Graphics as __apex_Graphics,
  Markers as __apex_Markers,
  Options as __apex_Options,
  arrayToPath as __apex_PathMorphing_arrayToPath,
  morphPaths as __apex_PathMorphing_morphPaths,
  parsePath as __apex_PathMorphing_parsePath,
  pathBbox as __apex_PathMorphing_pathBbox,
  PerformanceCache as __apex_PerformanceCache,
  Range as __apex_Range,
  addResizeListener as __apex_Resize_addResizeListener,
  removeResizeListener as __apex_Resize_removeResizeListener,
  Responsive as __apex_Responsive,
  SVGAnimationRunner as __apex_SVGAnimation_SVGAnimationRunner,
  installAnimationMethods as __apex_SVGAnimation_installAnimationMethods,
  SVGContainer as __apex_SVGContainer,
  installDraggable as __apex_SVGDraggable_installDraggable,
  SVGElement as __apex_SVGElement,
  FilterBuilder as __apex_SVGFilter_FilterBuilder,
  SVGFilter as __apex_SVGFilter_SVGFilter,
  installFilterMethods as __apex_SVGFilter_installFilterMethods,
  SVGGradient as __apex_SVGGradient_SVGGradient,
  SVGPattern as __apex_SVGPattern_SVGPattern,
  installSelectable as __apex_SVGSelectable_installSelectable,
  Scales as __apex_Scales,
  Series as __apex_Series,
  Theme as __apex_Theme,
  getThemePalettes as __apex_ThemePalettes_getThemePalettes,
  TimeScale as __apex_TimeScale,
  TitleSubtitle as __apex_TitleSubtitle,
  Utils$1 as __apex_Utils,
  Axes as __apex_axes_Axes,
  AxesUtils as __apex_axes_AxesUtils,
  Grid as __apex_axes_Grid,
  XAxis as __apex_axes_XAxis,
  YAxis as __apex_axes_YAxis,
  Scatter as __apex_charts_Scatter,
  Dimensions as __apex_dimensions_Dimensions,
  DimGrid as __apex_dimensions_Grid,
  Helpers as __apex_dimensions_Helpers,
  DimXAxis as __apex_dimensions_XAxis,
  DimYAxis as __apex_dimensions_YAxis,
  Destroy as __apex_helpers_Destroy,
  InitCtxVariables as __apex_helpers_InitCtxVariables,
  Localization as __apex_helpers_Localization,
  UpdateHelpers as __apex_helpers_UpdateHelpers,
  Box as __apex_index_Box,
  SVG as __apex_index_SVG,
  Box as __apex_math_Box,
  Matrix as __apex_math_Matrix,
  Point as __apex_math_Point,
  SVGNS$1 as __apex_math_SVGNS,
  AxesTooltip as __apex_tooltip_AxesTooltip,
  Intersect as __apex_tooltip_Intersect,
  Labels as __apex_tooltip_Labels,
  Marker as __apex_tooltip_Marker,
  Position as __apex_tooltip_Position,
  Tooltip as __apex_tooltip_Tooltip,
  Utils2 as __apex_tooltip_Utils,
  ApexCharts as default
};