Explorar o código

Merge pull request #3730 from BlackDex/update-admin-interface

Update admin interface
Daniel García %!s(int64=2) %!d(string=hai) anos
pai
achega
66bff73ebf

+ 36 - 7
src/api/web.rs

@@ -14,11 +14,17 @@ use crate::{
 pub fn routes() -> Vec<Route> {
     // If addding more routes here, consider also adding them to
     // crate::utils::LOGGED_ROUTES to make sure they appear in the log
+    let mut routes = routes![attachments, alive, alive_head, static_files];
     if CONFIG.web_vault_enabled() {
-        routes![web_index, web_index_head, app_id, web_files, attachments, alive, alive_head, static_files]
-    } else {
-        routes![attachments, alive, alive_head, static_files]
+        routes.append(&mut routes![web_index, web_index_head, app_id, web_files]);
+    }
+
+    #[cfg(debug_assertions)]
+    if CONFIG.reload_templates() {
+        routes.append(&mut routes![_static_files_dev]);
     }
+
+    routes
 }
 
 pub fn catchers() -> Vec<Catcher> {
@@ -116,7 +122,30 @@ fn alive_head(_conn: DbConn) -> EmptyResult {
     Ok(())
 }
 
-#[get("/vw_static/<filename>")]
+// This endpoint/function is used during development and development only.
+// It allows to easily develop the admin interface by always loading the files from disk instead from a slice of bytes
+// This will only be active during a debug build and only when `RELOAD_TEMPLATES` is set to `true`
+// NOTE: Do not forget to add any new files added to the `static_files` function below!
+#[cfg(debug_assertions)]
+#[get("/vw_static/<filename>", rank = 1)]
+pub async fn _static_files_dev(filename: PathBuf) -> Option<NamedFile> {
+    warn!("LOADING STATIC FILES FROM DISK");
+    let file = filename.to_str().unwrap_or_default();
+    let ext = filename.extension().unwrap_or_default();
+
+    let path = if ext == "png" || ext == "svg" {
+        tokio::fs::canonicalize(Path::new(file!()).parent().unwrap().join("../static/images/").join(file)).await
+    } else {
+        tokio::fs::canonicalize(Path::new(file!()).parent().unwrap().join("../static/scripts/").join(file)).await
+    };
+
+    if let Ok(path) = path {
+        return NamedFile::open(path).await.ok();
+    };
+    None
+}
+
+#[get("/vw_static/<filename>", rank = 2)]
 pub fn static_files(filename: &str) -> Result<(ContentType, &'static [u8]), Error> {
     match filename {
         "404.png" => Ok((ContentType::PNG, include_bytes!("../static/images/404.png"))),
@@ -138,12 +167,12 @@ pub fn static_files(filename: &str) -> Result<(ContentType, &'static [u8]), Erro
             Ok((ContentType::JavaScript, include_bytes!("../static/scripts/admin_diagnostics.js")))
         }
         "bootstrap.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/bootstrap.css"))),
-        "bootstrap-native.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js"))),
+        "bootstrap.bundle.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap.bundle.js"))),
         "jdenticon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jdenticon.js"))),
         "datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
         "datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
-        "jquery-3.6.4.slim.js" => {
-            Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.4.slim.js")))
+        "jquery-3.7.0.slim.js" => {
+            Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.7.0.slim.js")))
         }
         _ => err!(format!("Static file not found: {filename}")),
     }

+ 78 - 7
src/static/scripts/admin.js

@@ -37,36 +37,107 @@ function _post(url, successMsg, errMsg, body, reload_page = true) {
         mode: "same-origin",
         credentials: "same-origin",
         headers: { "Content-Type": "application/json" }
-    }).then( resp => {
+    }).then(resp => {
         if (resp.ok) {
             msg(successMsg, reload_page);
             // Abuse the catch handler by setting error to false and continue
-            return Promise.reject({error: false});
+            return Promise.reject({ error: false });
         }
         respStatus = resp.status;
         respStatusText = resp.statusText;
         return resp.text();
-    }).then( respText => {
+    }).then(respText => {
         try {
             const respJson = JSON.parse(respText);
             if (respJson.ErrorModel && respJson.ErrorModel.Message) {
                 return respJson.ErrorModel.Message;
             } else {
-                return Promise.reject({body:`${respStatus} - ${respStatusText}\n\nUnknown error`, error: true});
+                return Promise.reject({ body: `${respStatus} - ${respStatusText}\n\nUnknown error`, error: true });
             }
         } catch (e) {
-            return Promise.reject({body:`${respStatus} - ${respStatusText}\n\n[Catch] ${e}`, error: true});
+            return Promise.reject({ body: `${respStatus} - ${respStatusText}\n\n[Catch] ${e}`, error: true });
         }
-    }).then( apiMsg => {
+    }).then(apiMsg => {
         msg(`${errMsg}\n${apiMsg}`, reload_page);
-    }).catch( e => {
+    }).catch(e => {
         if (e.error === false) { return true; }
         else { msg(`${errMsg}\n${e.body}`, reload_page); }
     });
 }
 
+// Bootstrap Theme Selector
+const getStoredTheme = () => localStorage.getItem("theme");
+const setStoredTheme = theme => localStorage.setItem("theme", theme);
+
+const getPreferredTheme = () => {
+    const storedTheme = getStoredTheme();
+    if (storedTheme) {
+        return storedTheme;
+    }
+
+    return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+};
+
+const setTheme = theme => {
+    if (theme === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches) {
+        document.documentElement.setAttribute("data-bs-theme", "dark");
+    } else {
+        document.documentElement.setAttribute("data-bs-theme", theme);
+    }
+};
+
+setTheme(getPreferredTheme());
+
+const showActiveTheme = (theme, focus = false) => {
+    const themeSwitcher = document.querySelector("#bd-theme");
+
+    if (!themeSwitcher) {
+        return;
+    }
+
+    const themeSwitcherText = document.querySelector("#bd-theme-text");
+    const activeThemeIcon = document.querySelector(".theme-icon-active use");
+    const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`);
+    const svgOfActiveBtn = btnToActive.querySelector("span use").innerText;
+
+    document.querySelectorAll("[data-bs-theme-value]").forEach(element => {
+        element.classList.remove("active");
+        element.setAttribute("aria-pressed", "false");
+    });
+
+    btnToActive.classList.add("active");
+    btnToActive.setAttribute("aria-pressed", "true");
+    activeThemeIcon.innerText = svgOfActiveBtn;
+    const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`;
+    themeSwitcher.setAttribute("aria-label", themeSwitcherLabel);
+
+    if (focus) {
+        themeSwitcher.focus();
+    }
+};
+
+window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
+    const storedTheme = getStoredTheme();
+    if (storedTheme !== "light" && storedTheme !== "dark") {
+        setTheme(getPreferredTheme());
+    }
+});
+
+
 // onLoad events
 document.addEventListener("DOMContentLoaded", (/*event*/) => {
+    showActiveTheme(getPreferredTheme());
+
+    document.querySelectorAll("[data-bs-theme-value]")
+        .forEach(toggle => {
+            toggle.addEventListener("click", () => {
+                const theme = toggle.getAttribute("data-bs-theme-value");
+                setStoredTheme(theme);
+                setTheme(theme);
+                showActiveTheme(theme, true);
+            });
+        });
+
     // get current URL path and assign "active" class to the correct nav-item
     const pathname = window.location.pathname;
     if (pathname === "") return;

+ 2 - 2
src/static/scripts/admin_diagnostics.js

@@ -1,6 +1,6 @@
 "use strict";
 /* eslint-env es2017, browser */
-/* global BASE_URL:readable, BSN:readable */
+/* global BASE_URL:readable, bootstrap:readable */
 
 var dnsCheck = false;
 var timeCheck = false;
@@ -135,7 +135,7 @@ function copyToClipboard(event) {
     document.execCommand("copy");
     tmpCopyEl.remove();
 
-    new BSN.Toast("#toastClipboardCopy").show();
+    new bootstrap.Toast("#toastClipboardCopy").show();
 }
 
 function checkTimeDrift(utcTimeA, utcTimeB, statusPrefix) {

+ 9 - 5
src/static/scripts/admin_users.js

@@ -141,19 +141,20 @@ function resendUserInvite (event) {
 const ORG_TYPES = {
     "0": {
         "name": "Owner",
-        "color": "orange"
+        "bg": "orange",
+        "font": "black"
     },
     "1": {
         "name": "Admin",
-        "color": "blueviolet"
+        "bg": "blueviolet"
     },
     "2": {
         "name": "User",
-        "color": "blue"
+        "bg": "blue"
     },
     "3": {
         "name": "Manager",
-        "color": "green"
+        "bg": "green"
     },
 };
 
@@ -227,7 +228,10 @@ function initUserTable() {
     // Color all the org buttons per type
     document.querySelectorAll("button[data-vw-org-type]").forEach(function(e) {
         const orgType = ORG_TYPES[e.dataset.vwOrgType];
-        e.style.backgroundColor = orgType.color;
+        e.style.backgroundColor = orgType.bg;
+        if (orgType.font !== undefined) {
+            e.style.color = orgType.font;
+        }
         e.title = orgType.name;
     });
 

+ 0 - 5991
src/static/scripts/bootstrap-native.js

@@ -1,5991 +0,0 @@
-/*!
-  * Native JavaScript for Bootstrap v4.2.0 (https://thednp.github.io/bootstrap.native/)
-  * Copyright 2015-2022 © dnp_theme
-  * Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
-  */
-(function (global, factory) {
-  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
-  typeof define === 'function' && define.amd ? define(factory) :
-  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BSN = factory());
-})(this, (function () { 'use strict';
-
-  /** @type {Record<string, any>} */
-  const EventRegistry = {};
-
-  /**
-   * The global event listener.
-   *
-   * @type {EventListener}
-   * @this {EventTarget}
-   */
-  function globalListener(e) {
-    const that = this;
-    const { type } = e;
-
-    [...EventRegistry[type]].forEach((elementsMap) => {
-      const [element, listenersMap] = elementsMap;
-      /* istanbul ignore else */
-      if (element === that) {
-        [...listenersMap].forEach((listenerMap) => {
-          const [listener, options] = listenerMap;
-          listener.apply(element, [e]);
-
-          if (options && options.once) {
-            removeListener(element, type, listener, options);
-          }
-        });
-      }
-    });
-  }
-
-  /**
-   * Register a new listener with its options and attach the `globalListener`
-   * to the target if this is the first listener.
-   *
-   * @type {Listener.ListenerAction<EventTarget>}
-   */
-  const addListener = (element, eventType, listener, options) => {
-    // get element listeners first
-    if (!EventRegistry[eventType]) {
-      EventRegistry[eventType] = new Map();
-    }
-    const oneEventMap = EventRegistry[eventType];
-
-    if (!oneEventMap.has(element)) {
-      oneEventMap.set(element, new Map());
-    }
-    const oneElementMap = oneEventMap.get(element);
-
-    // get listeners size
-    const { size } = oneElementMap;
-
-    // register listener with its options
-    oneElementMap.set(listener, options);
-
-    // add listener last
-    if (!size) {
-      element.addEventListener(eventType, globalListener, options);
-    }
-  };
-
-  /**
-   * Remove a listener from registry and detach the `globalListener`
-   * if no listeners are found in the registry.
-   *
-   * @type {Listener.ListenerAction<EventTarget>}
-   */
-  const removeListener = (element, eventType, listener, options) => {
-    // get listener first
-    const oneEventMap = EventRegistry[eventType];
-    const oneElementMap = oneEventMap && oneEventMap.get(element);
-    const savedOptions = oneElementMap && oneElementMap.get(listener);
-
-    // also recover initial options
-    const { options: eventOptions } = savedOptions !== undefined
-      ? savedOptions
-      : { options };
-
-    // unsubscribe second, remove from registry
-    if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
-    if (oneEventMap && (!oneElementMap || !oneElementMap.size)) oneEventMap.delete(element);
-    if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
-
-    // remove listener last
-    /* istanbul ignore else */
-    if (!oneElementMap || !oneElementMap.size) {
-      element.removeEventListener(eventType, globalListener, eventOptions);
-    }
-  };
-
-  /**
-   * Advanced event listener based on subscribe / publish pattern.
-   * @see https://www.patterns.dev/posts/classic-design-patterns/#observerpatternjavascript
-   * @see https://gist.github.com/shystruk/d16c0ee7ac7d194da9644e5d740c8338#file-subpub-js
-   * @see https://hackernoon.com/do-you-still-register-window-event-listeners-in-each-component-react-in-example-31a4b1f6f1c8
-   */
-  const Listener = {
-    on: addListener,
-    off: removeListener,
-    globalListener,
-    registry: EventRegistry,
-  };
-
-  /**
-   * A global namespace for `click` event.
-   * @type {string}
-   */
-  const mouseclickEvent = 'click';
-
-  /**
-   * A global namespace for 'transitionend' string.
-   * @type {string}
-   */
-  const transitionEndEvent = 'transitionend';
-
-  /**
-   * A global namespace for 'transitionDelay' string.
-   * @type {string}
-   */
-  const transitionDelay = 'transitionDelay';
-
-  /**
-   * A global namespace for `transitionProperty` string for modern browsers.
-   *
-   * @type {string}
-   */
-  const transitionProperty = 'transitionProperty';
-
-  /**
-   * Shortcut for `window.getComputedStyle(element).propertyName`
-   * static method.
-   *
-   * * If `element` parameter is not an `HTMLElement`, `getComputedStyle`
-   * throws a `ReferenceError`.
-   *
-   * @param {HTMLElement} element target
-   * @param {string} property the css property
-   * @return {string} the css property value
-   */
-  function getElementStyle(element, property) {
-    const computedStyle = getComputedStyle(element);
-
-    // must use camelcase strings,
-    // or non-camelcase strings with `getPropertyValue`
-    return property.includes('--')
-      ? computedStyle.getPropertyValue(property)
-      : computedStyle[property];
-  }
-
-  /**
-   * Utility to get the computed `transitionDelay`
-   * from Element in miliseconds.
-   *
-   * @param {HTMLElement} element target
-   * @return {number} the value in miliseconds
-   */
-  function getElementTransitionDelay(element) {
-    const propertyValue = getElementStyle(element, transitionProperty);
-    const delayValue = getElementStyle(element, transitionDelay);
-    const delayScale = delayValue.includes('ms') ? /* istanbul ignore next */1 : 1000;
-    const duration = propertyValue && propertyValue !== 'none'
-      ? parseFloat(delayValue) * delayScale : 0;
-
-    return !Number.isNaN(duration) ? duration : /* istanbul ignore next */0;
-  }
-
-  /**
-   * A global namespace for 'transitionDuration' string.
-   * @type {string}
-   */
-  const transitionDuration = 'transitionDuration';
-
-  /**
-   * Utility to get the computed `transitionDuration`
-   * from Element in miliseconds.
-   *
-   * @param {HTMLElement} element target
-   * @return {number} the value in miliseconds
-   */
-  function getElementTransitionDuration(element) {
-    const propertyValue = getElementStyle(element, transitionProperty);
-    const durationValue = getElementStyle(element, transitionDuration);
-    const durationScale = durationValue.includes('ms') ? /* istanbul ignore next */1 : 1000;
-    const duration = propertyValue && propertyValue !== 'none'
-      ? parseFloat(durationValue) * durationScale : 0;
-
-    return !Number.isNaN(duration) ? duration : /* istanbul ignore next */0;
-  }
-
-  /**
-   * Shortcut for the `Element.dispatchEvent(Event)` method.
-   *
-   * @param {HTMLElement} element is the target
-   * @param {Event} event is the `Event` object
-   */
-  const dispatchEvent = (element, event) => element.dispatchEvent(event);
-
-  /**
-   * Utility to make sure callbacks are consistently
-   * called when transition ends.
-   *
-   * @param {HTMLElement} element target
-   * @param {EventListener} handler `transitionend` callback
-   */
-  function emulateTransitionEnd(element, handler) {
-    let called = 0;
-    const endEvent = new Event(transitionEndEvent);
-    const duration = getElementTransitionDuration(element);
-    const delay = getElementTransitionDelay(element);
-
-    if (duration) {
-      /**
-       * Wrap the handler in on -> off callback
-       * @type {EventListener} e Event object
-       */
-      const transitionEndWrapper = (e) => {
-        /* istanbul ignore else */
-        if (e.target === element) {
-          handler.apply(element, [e]);
-          element.removeEventListener(transitionEndEvent, transitionEndWrapper);
-          called = 1;
-        }
-      };
-      element.addEventListener(transitionEndEvent, transitionEndWrapper);
-      setTimeout(() => {
-        /* istanbul ignore next */
-        if (!called) dispatchEvent(element, endEvent);
-      }, duration + delay + 17);
-    } else {
-      handler.apply(element, [endEvent]);
-    }
-  }
-
-  /**
-   * Checks if an object is a `Node`.
-   *
-   * @param {any} node the target object
-   * @returns {boolean} the query result
-   */
-  const isNode = (element) => (element && [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
-    .some((x) => +element.nodeType === x)) || false;
-
-  /**
-   * Check if a target object is `Window`.
-   * => equivalent to `object instanceof Window`
-   *
-   * @param {any} object the target object
-   * @returns {boolean} the query result
-   */
-  const isWindow = (object) => (object && object.constructor.name === 'Window') || false;
-
-  /**
-   * Checks if an object is a `Document`.
-   * @see https://dom.spec.whatwg.org/#node
-   *
-   * @param {any} object the target object
-   * @returns {boolean} the query result
-   */
-  const isDocument = (object) => (object && object.nodeType === 9) || false;
-
-  /**
-   * Returns the `document` or the `#document` element.
-   * @see https://github.com/floating-ui/floating-ui
-   * @param {(Node | Window)=} node
-   * @returns {Document}
-   */
-  function getDocument(node) {
-    // node instanceof Document
-    if (isDocument(node)) return node;
-    // node instanceof Node
-    if (isNode(node)) return node.ownerDocument;
-    // node instanceof Window
-    if (isWindow(node)) return node.document;
-    // node is undefined | NULL
-    return window.document;
-  }
-
-  /**
-   * Utility to check if target is typeof `HTMLElement`, `Element`, `Node`
-   * or find one that matches a selector.
-   *
-   * @param {Node | string} selector the input selector or target element
-   * @param {ParentNode=} parent optional node to look into
-   * @return {HTMLElement?} the `HTMLElement` or `querySelector` result
-   */
-  function querySelector(selector, parent) {
-    if (isNode(selector)) {
-      return selector;
-    }
-    const lookUp = isNode(parent) ? parent : getDocument();
-
-    return lookUp.querySelector(selector);
-  }
-
-  /**
-   * Shortcut for `HTMLElement.closest` method which also works
-   * with children of `ShadowRoot`. The order of the parameters
-   * is intentional since they're both required.
-   *
-   * @see https://stackoverflow.com/q/54520554/803358
-   *
-   * @param {HTMLElement} element Element to look into
-   * @param {string} selector the selector name
-   * @return {HTMLElement?} the query result
-   */
-  function closest(element, selector) {
-    return element ? (element.closest(selector)
-      // break out of `ShadowRoot`
-      || closest(element.getRootNode().host, selector)) : null;
-  }
-
-  /**
-   * Shortcut for `Object.assign()` static method.
-   * @param  {Record<string, any>} obj a target object
-   * @param  {Record<string, any>} source a source object
-   */
-  const ObjectAssign = (obj, source) => Object.assign(obj, source);
-
-  /**
-   * Check class in `HTMLElement.classList`.
-   *
-   * @param {HTMLElement} element target
-   * @param {string} classNAME to check
-   * @returns {boolean}
-   */
-  function hasClass(element, classNAME) {
-    return element.classList.contains(classNAME);
-  }
-
-  /**
-   * Remove class from `HTMLElement.classList`.
-   *
-   * @param {HTMLElement} element target
-   * @param {string} classNAME to remove
-   * @returns {void}
-   */
-  function removeClass(element, classNAME) {
-    element.classList.remove(classNAME);
-  }
-
-  /**
-   * Checks if an element is an `HTMLElement`.
-   * @see https://dom.spec.whatwg.org/#node
-   *
-   * @param {any} element the target object
-   * @returns {boolean} the query result
-   */
-  const isHTMLElement = (element) => (element && element.nodeType === 1) || false;
-
-  /** @type {Map<string, Map<HTMLElement, Record<string, any>>>} */
-  const componentData = new Map();
-  /**
-   * An interface for web components background data.
-   * @see https://github.com/thednp/bootstrap.native/blob/master/src/components/base-component.js
-   */
-  const Data = {
-    /**
-     * Sets web components data.
-     * @param {HTMLElement} element target element
-     * @param {string} component the component's name or a unique key
-     * @param {Record<string, any>} instance the component instance
-     */
-    set: (element, component, instance) => {
-      if (!isHTMLElement(element)) return;
-
-      /* istanbul ignore else */
-      if (!componentData.has(component)) {
-        componentData.set(component, new Map());
-      }
-
-      const instanceMap = componentData.get(component);
-      // not undefined, but defined right above
-      instanceMap.set(element, instance);
-    },
-
-    /**
-     * Returns all instances for specified component.
-     * @param {string} component the component's name or a unique key
-     * @returns {Map<HTMLElement, Record<string, any>>?} all the component instances
-     */
-    getAllFor: (component) => {
-      const instanceMap = componentData.get(component);
-
-      return instanceMap || null;
-    },
-
-    /**
-     * Returns the instance associated with the target.
-     * @param {HTMLElement} element target element
-     * @param {string} component the component's name or a unique key
-     * @returns {Record<string, any>?} the instance
-     */
-    get: (element, component) => {
-      if (!isHTMLElement(element) || !component) return null;
-      const allForC = Data.getAllFor(component);
-      const instance = element && allForC && allForC.get(element);
-
-      return instance || null;
-    },
-
-    /**
-     * Removes web components data.
-     * @param {HTMLElement} element target element
-     * @param {string} component the component's name or a unique key
-     */
-    remove: (element, component) => {
-      const instanceMap = componentData.get(component);
-      if (!instanceMap || !isHTMLElement(element)) return;
-
-      instanceMap.delete(element);
-
-      /* istanbul ignore else */
-      if (instanceMap.size === 0) {
-        componentData.delete(component);
-      }
-    },
-  };
-
-  /**
-   * An alias for `Data.get()`.
-   * @type {SHORTY.getInstance<any>}
-   */
-  const getInstance = (target, component) => Data.get(target, component);
-
-  /**
-   * Checks if an object is an `Object`.
-   *
-   * @param {any} obj the target object
-   * @returns {boolean} the query result
-   */
-  const isObject = (obj) => (typeof obj === 'object') || false;
-
-  /**
-   * Returns a namespaced `CustomEvent` specific to each component.
-   * @param {string} EventType Event.type
-   * @param {Record<string, any>=} config Event.options | Event.properties
-   * @returns {SHORTY.OriginalEvent} a new namespaced event
-   */
-  function OriginalEvent(EventType, config) {
-    const OriginalCustomEvent = new CustomEvent(EventType, {
-      cancelable: true, bubbles: true,
-    });
-
-    /* istanbul ignore else */
-    if (isObject(config)) {
-      ObjectAssign(OriginalCustomEvent, config);
-    }
-    return OriginalCustomEvent;
-  }
-
-  /**
-   * Global namespace for most components `fade` class.
-   */
-  const fadeClass = 'fade';
-
-  /**
-   * Global namespace for most components `show` class.
-   */
-  const showClass = 'show';
-
-  /**
-   * Global namespace for most components `dismiss` option.
-   */
-  const dataBsDismiss = 'data-bs-dismiss';
-
-  /** @type {string} */
-  const alertString = 'alert';
-
-  /** @type {string} */
-  const alertComponent = 'Alert';
-
-  /**
-   * Shortcut for `HTMLElement.getAttribute()` method.
-   * @param {HTMLElement} element target element
-   * @param {string} attribute attribute name
-   * @returns {string?} attribute value
-   */
-  const getAttribute = (element, attribute) => element.getAttribute(attribute);
-
-  /**
-   * The raw value or a given component option.
-   *
-   * @typedef {string | HTMLElement | Function | number | boolean | null} niceValue
-   */
-
-  /**
-   * Utility to normalize component options
-   *
-   * @param {any} value the input value
-   * @return {niceValue} the normalized value
-   */
-  function normalizeValue(value) {
-    if (['true', true].includes(value)) { // boolean
-    // if ('true' === value) { // boolean
-      return true;
-    }
-
-    if (['false', false].includes(value)) { // boolean
-    // if ('false' === value) { // boolean
-      return false;
-    }
-
-    if (value === '' || value === 'null') { // null
-      return null;
-    }
-
-    if (value !== '' && !Number.isNaN(+value)) { // number
-      return +value;
-    }
-
-    // string / function / HTMLElement / object
-    return value;
-  }
-
-  /**
-   * Shortcut for `Object.keys()` static method.
-   * @param  {Record<string, any>} obj a target object
-   * @returns {string[]}
-   */
-  const ObjectKeys = (obj) => Object.keys(obj);
-
-  /**
-   * Shortcut for `String.toLowerCase()`.
-   *
-   * @param {string} source input string
-   * @returns {string} lowercase output string
-   */
-  const toLowerCase = (source) => source.toLowerCase();
-
-  /**
-   * Utility to normalize component options.
-   *
-   * @param {HTMLElement} element target
-   * @param {Record<string, any>} defaultOps component default options
-   * @param {Record<string, any>} inputOps component instance options
-   * @param {string=} ns component namespace
-   * @return {Record<string, any>} normalized component options object
-   */
-  function normalizeOptions(element, defaultOps, inputOps, ns) {
-    const data = { ...element.dataset };
-    /** @type {Record<string, any>} */
-    const normalOps = {};
-    /** @type {Record<string, any>} */
-    const dataOps = {};
-    const title = 'title';
-
-    ObjectKeys(data).forEach((k) => {
-      const key = ns && k.includes(ns)
-        ? k.replace(ns, '').replace(/[A-Z]/, (match) => toLowerCase(match))
-        : k;
-
-      dataOps[key] = normalizeValue(data[k]);
-    });
-
-    ObjectKeys(inputOps).forEach((k) => {
-      inputOps[k] = normalizeValue(inputOps[k]);
-    });
-
-    ObjectKeys(defaultOps).forEach((k) => {
-      /* istanbul ignore else */
-      if (k in inputOps) {
-        normalOps[k] = inputOps[k];
-      } else if (k in dataOps) {
-        normalOps[k] = dataOps[k];
-      } else {
-        normalOps[k] = k === title
-          ? getAttribute(element, title)
-          : defaultOps[k];
-      }
-    });
-
-    return normalOps;
-  }
-
-  var version = "4.2.0";
-
-  const Version = version;
-
-  /* Native JavaScript for Bootstrap 5 | Base Component
-  ----------------------------------------------------- */
-
-  /** Returns a new `BaseComponent` instance. */
-  class BaseComponent {
-    /**
-     * @param {HTMLElement | string} target `Element` or selector string
-     * @param {BSN.ComponentOptions=} config component instance options
-     */
-    constructor(target, config) {
-      const self = this;
-      const element = querySelector(target);
-
-      if (!element) {
-        throw Error(`${self.name} Error: "${target}" is not a valid selector.`);
-      }
-
-      /** @static @type {BSN.ComponentOptions} */
-      self.options = {};
-
-      const prevInstance = Data.get(element, self.name);
-      if (prevInstance) prevInstance.dispose();
-
-      /** @type {HTMLElement} */
-      self.element = element;
-
-      /* istanbul ignore else */
-      if (self.defaults && ObjectKeys(self.defaults).length) {
-        self.options = normalizeOptions(element, self.defaults, (config || {}), 'bs');
-      }
-
-      Data.set(element, self.name, self);
-    }
-
-    /* eslint-disable */
-    /* istanbul ignore next */
-    /** @static */
-    get version() { return Version; }
-
-    /* eslint-enable */
-    /* istanbul ignore next */
-    /** @static */
-    get name() { return this.constructor.name; }
-
-    /* istanbul ignore next */
-    /** @static */
-    get defaults() { return this.constructor.defaults; }
-
-    /**
-     * Removes component from target element;
-     */
-    dispose() {
-      const self = this;
-      Data.remove(self.element, self.name);
-      ObjectKeys(self).forEach((prop) => { self[prop] = null; });
-    }
-  }
-
-  /* Native JavaScript for Bootstrap 5 | Alert
-  -------------------------------------------- */
-
-  // ALERT PRIVATE GC
-  // ================
-  const alertSelector = `.${alertString}`;
-  const alertDismissSelector = `[${dataBsDismiss}="${alertString}"]`;
-
-  /**
-   * Static method which returns an existing `Alert` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Alert>}
-   */
-  const getAlertInstance = (element) => getInstance(element, alertComponent);
-
-  /**
-  * An `Alert` initialization callback.
-  * @type {BSN.InitCallback<Alert>}
-  */
-  const alertInitCallback = (element) => new Alert(element);
-
-  // ALERT CUSTOM EVENTS
-  // ===================
-  const closeAlertEvent = OriginalEvent(`close.bs.${alertString}`);
-  const closedAlertEvent = OriginalEvent(`closed.bs.${alertString}`);
-
-  // ALERT EVENT HANDLER
-  // ===================
-  /**
-   * Alert `transitionend` callback.
-   * @param {Alert} self target Alert instance
-   */
-  function alertTransitionEnd(self) {
-    const { element } = self;
-    toggleAlertHandler(self);
-
-    dispatchEvent(element, closedAlertEvent);
-
-    self.dispose();
-    element.remove();
-  }
-
-  // ALERT PRIVATE METHOD
-  // ====================
-  /**
-   * Toggle on / off the `click` event listener.
-   * @param {Alert} self the target alert instance
-   * @param {boolean=} add when `true`, event listener is added
-   */
-  function toggleAlertHandler(self, add) {
-    const action = add ? addListener : removeListener;
-    const { dismiss } = self;
-    /* istanbul ignore else */
-    if (dismiss) action(dismiss, mouseclickEvent, self.close);
-  }
-
-  // ALERT DEFINITION
-  // ================
-  /** Creates a new Alert instance. */
-  class Alert extends BaseComponent {
-    /** @param {HTMLElement | string} target element or selector */
-    constructor(target) {
-      super(target);
-      // bind
-      const self = this;
-
-      // initialization element
-      const { element } = self;
-
-      // the dismiss button
-      /** @static @type {HTMLElement?} */
-      self.dismiss = querySelector(alertDismissSelector, element);
-
-      // add event listener
-      toggleAlertHandler(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return alertComponent; }
-    /* eslint-enable */
-
-    // ALERT PUBLIC METHODS
-    // ====================
-    /**
-     * Public method that hides the `.alert` element from the user,
-     * disposes the instance once animation is complete, then
-     * removes the element from the DOM.
-     *
-     * @param {Event=} e most likely the `click` event
-     * @this {Alert} the `Alert` instance or `EventTarget`
-     */
-    close(e) {
-      const self = e ? getAlertInstance(closest(this, alertSelector)) : this;
-      const { element } = self;
-
-      /* istanbul ignore else */
-      if (element && hasClass(element, showClass)) {
-        dispatchEvent(element, closeAlertEvent);
-        if (closeAlertEvent.defaultPrevented) return;
-
-        removeClass(element, showClass);
-
-        if (hasClass(element, fadeClass)) {
-          emulateTransitionEnd(element, () => alertTransitionEnd(self));
-        } else alertTransitionEnd(self);
-      }
-    }
-
-    /** Remove the component from target element. */
-    dispose() {
-      toggleAlertHandler(this);
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Alert, {
-    selector: alertSelector,
-    init: alertInitCallback,
-    getInstance: getAlertInstance,
-  });
-
-  /**
-   * A global namespace for aria-pressed.
-   * @type {string}
-   */
-  const ariaPressed = 'aria-pressed';
-
-  /**
-   * Shortcut for `HTMLElement.setAttribute()` method.
-   * @param  {HTMLElement} element target element
-   * @param  {string} attribute attribute name
-   * @param  {string} value attribute value
-   * @returns {void}
-   */
-  const setAttribute = (element, attribute, value) => element.setAttribute(attribute, value);
-
-  /**
-   * Add class to `HTMLElement.classList`.
-   *
-   * @param {HTMLElement} element target
-   * @param {string} classNAME to add
-   * @returns {void}
-   */
-  function addClass(element, classNAME) {
-    element.classList.add(classNAME);
-  }
-
-  /**
-   * Global namespace for most components active class.
-   */
-  const activeClass = 'active';
-
-  /**
-   * Global namespace for most components `toggle` option.
-   */
-  const dataBsToggle = 'data-bs-toggle';
-
-  /** @type {string} */
-  const buttonString = 'button';
-
-  /** @type {string} */
-  const buttonComponent = 'Button';
-
-  /* Native JavaScript for Bootstrap 5 | Button
-  ---------------------------------------------*/
-
-  // BUTTON PRIVATE GC
-  // =================
-  const buttonSelector = `[${dataBsToggle}="${buttonString}"]`;
-
-  /**
-   * Static method which returns an existing `Button` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Button>}
-   */
-  const getButtonInstance = (element) => getInstance(element, buttonComponent);
-
-  /**
-   * A `Button` initialization callback.
-   * @type {BSN.InitCallback<Button>}
-   */
-  const buttonInitCallback = (element) => new Button(element);
-
-  // BUTTON PRIVATE METHOD
-  // =====================
-  /**
-   * Toggles on/off the `click` event listener.
-   * @param {Button} self the `Button` instance
-   * @param {boolean=} add when `true`, event listener is added
-   */
-  function toggleButtonHandler(self, add) {
-    const action = add ? addListener : removeListener;
-    action(self.element, mouseclickEvent, self.toggle);
-  }
-
-  // BUTTON DEFINITION
-  // =================
-  /** Creates a new `Button` instance. */
-  class Button extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target usually a `.btn` element
-     */
-    constructor(target) {
-      super(target);
-      const self = this;
-
-      // initialization element
-      const { element } = self;
-
-      // set initial state
-      /** @type {boolean} */
-      self.isActive = hasClass(element, activeClass);
-      setAttribute(element, ariaPressed, `${!!self.isActive}`);
-
-      // add event listener
-      toggleButtonHandler(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return buttonComponent; }
-    /* eslint-enable */
-
-    // BUTTON PUBLIC METHODS
-    // =====================
-    /**
-     * Toggles the state of the target button.
-     * @param {MouseEvent} e usually `click` Event object
-     */
-    toggle(e) {
-      if (e) e.preventDefault();
-      const self = e ? getButtonInstance(this) : this;
-      if (!self.element) return;
-      const { element, isActive } = self;
-
-      if (hasClass(element, 'disabled')) return;
-
-      const action = isActive ? removeClass : addClass;
-      action(element, activeClass);
-      setAttribute(element, ariaPressed, isActive ? 'false' : 'true');
-      self.isActive = hasClass(element, activeClass);
-    }
-
-    /** Removes the `Button` component from the target element. */
-    dispose() {
-      toggleButtonHandler(this);
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Button, {
-    selector: buttonSelector,
-    init: buttonInitCallback,
-    getInstance: getButtonInstance,
-  });
-
-  /**
-   * A global namespace for `mouseenter` event.
-   * @type {string}
-   */
-  const mouseenterEvent = 'mouseenter';
-
-  /**
-   * A global namespace for `mouseleave` event.
-   * @type {string}
-   */
-  const mouseleaveEvent = 'mouseleave';
-
-  /**
-   * A global namespace for `keydown` event.
-   * @type {string}
-   */
-  const keydownEvent = 'keydown';
-
-  /**
-   * A global namespace for `ArrowLeft` key.
-   * @type {string} e.which = 37 equivalent
-   */
-  const keyArrowLeft = 'ArrowLeft';
-
-  /**
-   * A global namespace for `ArrowRight` key.
-   * @type {string} e.which = 39 equivalent
-   */
-  const keyArrowRight = 'ArrowRight';
-
-  /**
-   * A global namespace for `pointerdown` event.
-   * @type {string}
-   */
-  const pointerdownEvent = 'pointerdown';
-
-  /**
-   * A global namespace for `pointermove` event.
-   * @type {string}
-   */
-  const pointermoveEvent = 'pointermove';
-
-  /**
-   * A global namespace for `pointerup` event.
-   * @type {string}
-   */
-  const pointerupEvent = 'pointerup';
-
-  /**
-   * Returns the bounding client rect of a target `HTMLElement`.
-   *
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {HTMLElement} element event.target
-   * @param {boolean=} includeScale when *true*, the target scale is also computed
-   * @returns {SHORTY.BoundingClientRect} the bounding client rect object
-   */
-  function getBoundingClientRect(element, includeScale) {
-    const {
-      width, height, top, right, bottom, left,
-    } = element.getBoundingClientRect();
-    let scaleX = 1;
-    let scaleY = 1;
-
-    if (includeScale && isHTMLElement(element)) {
-      const { offsetWidth, offsetHeight } = element;
-      scaleX = offsetWidth > 0 ? Math.round(width) / offsetWidth
-        : /* istanbul ignore next */1;
-      scaleY = offsetHeight > 0 ? Math.round(height) / offsetHeight
-        : /* istanbul ignore next */1;
-    }
-
-    return {
-      width: width / scaleX,
-      height: height / scaleY,
-      top: top / scaleY,
-      right: right / scaleX,
-      bottom: bottom / scaleY,
-      left: left / scaleX,
-      x: left / scaleX,
-      y: top / scaleY,
-    };
-  }
-
-  /**
-   * Returns the `document.documentElement` or the `<html>` element.
-   *
-   * @param {(Node | Window)=} node
-   * @returns {HTMLHtmlElement}
-   */
-  function getDocumentElement(node) {
-    return getDocument(node).documentElement;
-  }
-
-  /**
-   * Utility to determine if an `HTMLElement`
-   * is partially visible in viewport.
-   *
-   * @param {HTMLElement} element target
-   * @return {boolean} the query result
-   */
-  const isElementInScrollRange = (element) => {
-    if (!element || !isNode(element)) return false;
-
-    const { top, bottom } = getBoundingClientRect(element);
-    const { clientHeight } = getDocumentElement(element);
-    return top <= clientHeight && bottom >= 0;
-  };
-
-  /**
-   * Checks if a page is Right To Left.
-   * @param {HTMLElement=} node the target
-   * @returns {boolean} the query result
-   */
-  const isRTL = (node) => getDocumentElement(node).dir === 'rtl';
-
-  /**
-   * A shortcut for `(document|Element).querySelectorAll`.
-   *
-   * @param {string} selector the input selector
-   * @param {ParentNode=} parent optional node to look into
-   * @return {NodeListOf<HTMLElement>} the query result
-   */
-  function querySelectorAll(selector, parent) {
-    const lookUp = isNode(parent) ? parent : getDocument();
-    return lookUp.querySelectorAll(selector);
-  }
-
-  /**
-   * Shortcut for `HTMLElement.getElementsByClassName` method. Some `Node` elements
-   * like `ShadowRoot` do not support `getElementsByClassName`.
-   *
-   * @param {string} selector the class name
-   * @param {ParentNode=} parent optional Element to look into
-   * @return {HTMLCollectionOf<HTMLElement>} the 'HTMLCollection'
-   */
-  function getElementsByClassName(selector, parent) {
-    const lookUp = isNode(parent) ? parent : getDocument();
-    return lookUp.getElementsByClassName(selector);
-  }
-
-  /** @type {Map<HTMLElement, any>} */
-  const TimeCache = new Map();
-  /**
-   * An interface for one or more `TimerHandler`s per `Element`.
-   * @see https://github.com/thednp/navbar.js/
-   */
-  const Timer = {
-    /**
-     * Sets a new timeout timer for an element, or element -> key association.
-     * @param {HTMLElement} element target element
-     * @param {ReturnType<TimerHandler>} callback the callback
-     * @param {number} delay the execution delay
-     * @param {string=} key a unique key
-     */
-    set: (element, callback, delay, key) => {
-      if (!isHTMLElement(element)) return;
-
-      /* istanbul ignore else */
-      if (key && key.length) {
-        /* istanbul ignore else */
-        if (!TimeCache.has(element)) {
-          TimeCache.set(element, new Map());
-        }
-        const keyTimers = TimeCache.get(element);
-        keyTimers.set(key, setTimeout(callback, delay));
-      } else {
-        TimeCache.set(element, setTimeout(callback, delay));
-      }
-    },
-
-    /**
-     * Returns the timer associated with the target.
-     * @param {HTMLElement} element target element
-     * @param {string=} key a unique
-     * @returns {number?} the timer
-     */
-    get: (element, key) => {
-      if (!isHTMLElement(element)) return null;
-      const keyTimers = TimeCache.get(element);
-
-      if (key && key.length && keyTimers && keyTimers.get) {
-        return keyTimers.get(key) || /* istanbul ignore next */null;
-      }
-      return keyTimers || null;
-    },
-
-    /**
-     * Clears the element's timer.
-     * @param {HTMLElement} element target element
-     * @param {string=} key a unique key
-     */
-    clear: (element, key) => {
-      if (!isHTMLElement(element)) return;
-
-      if (key && key.length) {
-        const keyTimers = TimeCache.get(element);
-        /* istanbul ignore else */
-        if (keyTimers && keyTimers.get) {
-          clearTimeout(keyTimers.get(key));
-          keyTimers.delete(key);
-          /* istanbul ignore else */
-          if (keyTimers.size === 0) {
-            TimeCache.delete(element);
-          }
-        }
-      } else {
-        clearTimeout(TimeCache.get(element));
-        TimeCache.delete(element);
-      }
-    },
-  };
-
-  /**
-   * Utility to force re-paint of an `HTMLElement` target.
-   *
-   * @param {HTMLElement} element is the target
-   * @return {number} the `Element.offsetHeight` value
-   */
-  const reflow = (element) => element.offsetHeight;
-
-  /**
-   * A global namespace for most scroll event listeners.
-   * @type {Partial<AddEventListenerOptions>}
-   */
-  const passiveHandler = { passive: true };
-
-  /**
-   * Global namespace for most components `target` option.
-   */
-  const dataBsTarget = 'data-bs-target';
-
-  /** @type {string} */
-  const carouselString = 'carousel';
-
-  /** @type {string} */
-  const carouselComponent = 'Carousel';
-
-  /**
-   * Global namespace for most components `parent` option.
-   */
-  const dataBsParent = 'data-bs-parent';
-
-  /**
-   * Global namespace for most components `container` option.
-   */
-  const dataBsContainer = 'data-bs-container';
-
-  /**
-   * Returns the `Element` that THIS one targets
-   * via `data-bs-target`, `href`, `data-bs-parent` or `data-bs-container`.
-   *
-   * @param {HTMLElement} element the target element
-   * @returns {HTMLElement?} the query result
-   */
-  function getTargetElement(element) {
-    const targetAttr = [dataBsTarget, dataBsParent, dataBsContainer, 'href'];
-    const doc = getDocument(element);
-
-    return targetAttr.map((att) => {
-      const attValue = getAttribute(element, att);
-      if (attValue) {
-        return att === dataBsParent ? closest(element, attValue) : querySelector(attValue, doc);
-      }
-      return null;
-    }).filter((x) => x)[0];
-  }
-
-  /* Native JavaScript for Bootstrap 5 | Carousel
-  ----------------------------------------------- */
-
-  // CAROUSEL PRIVATE GC
-  // ===================
-  const carouselSelector = `[data-bs-ride="${carouselString}"]`;
-  const carouselItem = `${carouselString}-item`;
-  const dataBsSlideTo = 'data-bs-slide-to';
-  const dataBsSlide = 'data-bs-slide';
-  const pausedClass = 'paused';
-
-  const carouselDefaults = {
-    pause: 'hover',
-    keyboard: false,
-    touch: true,
-    interval: 5000,
-  };
-
-  /**
-   * Static method which returns an existing `Carousel` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Carousel>}
-   */
-  const getCarouselInstance = (element) => getInstance(element, carouselComponent);
-
-  /**
-   * A `Carousel` initialization callback.
-   * @type {BSN.InitCallback<Carousel>}
-   */
-  const carouselInitCallback = (element) => new Carousel(element);
-
-  let startX = 0;
-  let currentX = 0;
-  let endX = 0;
-
-  // CAROUSEL CUSTOM EVENTS
-  // ======================
-  const carouselSlideEvent = OriginalEvent(`slide.bs.${carouselString}`);
-  const carouselSlidEvent = OriginalEvent(`slid.bs.${carouselString}`);
-
-  // CAROUSEL EVENT HANDLERS
-  // =======================
-  /**
-   * The `transitionend` event listener of the `Carousel`.
-   * @param {Carousel} self the `Carousel` instance
-   */
-  function carouselTransitionEndHandler(self) {
-    const {
-      index, direction, element, slides, options,
-    } = self;
-
-    // discontinue disposed instances
-    /* istanbul ignore else */
-    if (self.isAnimating && getCarouselInstance(element)) {
-      const activeItem = getActiveIndex(self);
-      const orientation = direction === 'left' ? 'next' : 'prev';
-      const directionClass = direction === 'left' ? 'start' : 'end';
-
-      addClass(slides[index], activeClass);
-      removeClass(slides[index], `${carouselItem}-${orientation}`);
-      removeClass(slides[index], `${carouselItem}-${directionClass}`);
-
-      removeClass(slides[activeItem], activeClass);
-      removeClass(slides[activeItem], `${carouselItem}-${directionClass}`);
-
-      dispatchEvent(element, carouselSlidEvent);
-      Timer.clear(element, dataBsSlide);
-
-      // check for element, might have been disposed
-      if (!getDocument(element).hidden && options.interval
-        && !self.isPaused) {
-        self.cycle();
-      }
-    }
-  }
-
-  /**
-   * Handles the `mouseenter` events when *options.pause*
-   * is set to `hover`.
-   *
-   * @this {HTMLElement}
-   */
-  function carouselPauseHandler() {
-    const element = this;
-    const self = getCarouselInstance(element);
-    /* istanbul ignore else */
-    if (self && !self.isPaused && !Timer.get(element, pausedClass)) {
-      addClass(element, pausedClass);
-    }
-  }
-
-  /**
-   * Handles the `mouseleave` events when *options.pause*
-   * is set to `hover`.
-   *
-   * @this {HTMLElement}
-   */
-  function carouselResumeHandler() {
-    const element = this;
-    const self = getCarouselInstance(element);
-    /* istanbul ignore else */
-    if (self && self.isPaused && !Timer.get(element, pausedClass)) {
-      self.cycle();
-    }
-  }
-
-  /**
-   * Handles the `click` event for the `Carousel` indicators.
-   *
-   * @this {HTMLElement}
-   * @param {MouseEvent} e the `Event` object
-   */
-  function carouselIndicatorHandler(e) {
-    e.preventDefault();
-    const indicator = this;
-    const element = closest(indicator, carouselSelector) || getTargetElement(indicator);
-    const self = getCarouselInstance(element);
-
-    if (!self || self.isAnimating) return;
-
-    const newIndex = +getAttribute(indicator, dataBsSlideTo);
-
-    if (indicator && !hasClass(indicator, activeClass) // event target is not active
-      && !Number.isNaN(newIndex)) { // AND has the specific attribute
-      self.to(newIndex); // do the slide
-    }
-  }
-
-  /**
-   * Handles the `click` event for the `Carousel` arrows.
-   *
-   * @this {HTMLElement}
-   * @param {MouseEvent} e the `Event` object
-   */
-  function carouselControlsHandler(e) {
-    e.preventDefault();
-    const control = this;
-    const element = closest(control, carouselSelector) || getTargetElement(control);
-    const self = getCarouselInstance(element);
-
-    if (!self || self.isAnimating) return;
-    const orientation = getAttribute(control, dataBsSlide);
-
-    /* istanbul ignore else */
-    if (orientation === 'next') {
-      self.next();
-    } else if (orientation === 'prev') {
-      self.prev();
-    }
-  }
-
-  /**
-   * Handles the keyboard `keydown` event for the visible `Carousel` elements.
-   *
-   * @param {KeyboardEvent} e the `Event` object
-   */
-  function carouselKeyHandler({ code, target }) {
-    const doc = getDocument(target);
-    const [element] = [...querySelectorAll(carouselSelector, doc)]
-      .filter((x) => isElementInScrollRange(x));
-    const self = getCarouselInstance(element);
-
-    /* istanbul ignore next */
-    if (!self || self.isAnimating || /textarea|input/i.test(target.tagName)) return;
-    const RTL = isRTL(element);
-    const arrowKeyNext = !RTL ? keyArrowRight : keyArrowLeft;
-    const arrowKeyPrev = !RTL ? keyArrowLeft : keyArrowRight;
-
-    /* istanbul ignore else */
-    if (code === arrowKeyPrev) self.prev();
-    else if (code === arrowKeyNext) self.next();
-  }
-
-  // CAROUSEL TOUCH HANDLERS
-  // =======================
-  /**
-   * Handles the `pointerdown` event for the `Carousel` element.
-   *
-   * @this {HTMLElement}
-   * @param {PointerEvent} e the `Event` object
-   */
-  function carouselPointerDownHandler(e) {
-    const element = this;
-    const { target } = e;
-    const self = getCarouselInstance(element);
-
-    // filter pointer event on controls & indicators
-    const { controls, indicators } = self;
-    if ([...controls, ...indicators].some((el) => (el === target || el.contains(target)))) {
-      return;
-    }
-
-    if (!self || self.isAnimating || self.isTouch) { return; }
-
-    startX = e.pageX;
-
-    /* istanbul ignore else */
-    if (element.contains(target)) {
-      self.isTouch = true;
-      toggleCarouselTouchHandlers(self, true);
-    }
-  }
-
-  /**
-   * Handles the `pointermove` event for the `Carousel` element.
-   *
-   * @this {HTMLElement}
-   * @param {PointerEvent} e
-   */
-  function carouselPointerMoveHandler(e) {
-    // const self = getCarouselInstance(this);
-
-    // if (!self || !self.isTouch) { return; }
-
-    currentX = e.pageX;
-  }
-
-  /**
-   * Handles the `pointerup` event for the `Carousel` element.
-   *
-   * @this {HTMLElement}
-
-   * @param {PointerEvent} e
-   */
-  function carouselPointerUpHandler(e) {
-    const { target } = e;
-    const doc = getDocument(target);
-    const self = [...querySelectorAll(carouselSelector, doc)]
-      .map((c) => getCarouselInstance(c)).find((i) => i.isTouch);
-
-    // impossible to satisfy
-    /* istanbul ignore next */
-    if (!self) { return; }
-
-    const { element, index } = self;
-    const RTL = isRTL(target);
-
-    self.isTouch = false;
-    toggleCarouselTouchHandlers(self);
-
-    if (doc.getSelection().toString().length) {
-      // reset pointer position
-      startX = 0; currentX = 0; endX = 0;
-      return;
-    }
-
-    endX = e.pageX;
-
-    // the event target is outside the carousel context
-    // OR swipe distance is less than 120px
-    /* istanbul ignore else */
-    if (!element.contains(target) || Math.abs(startX - endX) < 120) {
-      // reset pointer position
-      startX = 0; currentX = 0; endX = 0;
-      return;
-    }
-    // OR determine next index to slide to
-    /* istanbul ignore else */
-    if (currentX < startX) {
-      self.to(index + (RTL ? -1 : 1));
-    } else if (currentX > startX) {
-      self.to(index + (RTL ? 1 : -1));
-    }
-    // reset pointer position
-    startX = 0; currentX = 0; endX = 0;
-  }
-
-  // CAROUSEL PRIVATE METHODS
-  // ========================
-  /**
-   * Sets active indicator for the `Carousel` instance.
-   * @param {Carousel} self the `Carousel` instance
-   * @param {number} pageIndex the index of the new active indicator
-   */
-  function activateCarouselIndicator(self, pageIndex) {
-    const { indicators } = self;
-    [...indicators].forEach((x) => removeClass(x, activeClass));
-
-    /* istanbul ignore else */
-    if (self.indicators[pageIndex]) addClass(indicators[pageIndex], activeClass);
-  }
-
-  /**
-   * Toggles the pointer event listeners for a given `Carousel` instance.
-   * @param {Carousel} self the `Carousel` instance
-   * @param {boolean=} add when `TRUE` event listeners are added
-   */
-  function toggleCarouselTouchHandlers(self, add) {
-    const { element } = self;
-    const action = add ? addListener : removeListener;
-    action(getDocument(element), pointermoveEvent, carouselPointerMoveHandler, passiveHandler);
-    action(getDocument(element), pointerupEvent, carouselPointerUpHandler, passiveHandler);
-  }
-
-  /**
-   * Toggles all event listeners for a given `Carousel` instance.
-   * @param {Carousel} self the `Carousel` instance
-   * @param {boolean=} add when `TRUE` event listeners are added
-   */
-  function toggleCarouselHandlers(self, add) {
-    const {
-      element, options, slides, controls, indicators,
-    } = self;
-    const {
-      touch, pause, interval, keyboard,
-    } = options;
-    const action = add ? addListener : removeListener;
-
-    if (pause && interval) {
-      action(element, mouseenterEvent, carouselPauseHandler);
-      action(element, mouseleaveEvent, carouselResumeHandler);
-    }
-
-    if (touch && slides.length > 2) {
-      action(element, pointerdownEvent, carouselPointerDownHandler, passiveHandler);
-    }
-
-    /* istanbul ignore else */
-    if (controls.length) {
-      controls.forEach((arrow) => {
-        /* istanbul ignore else */
-        if (arrow) action(arrow, mouseclickEvent, carouselControlsHandler);
-      });
-    }
-
-    /* istanbul ignore else */
-    if (indicators.length) {
-      indicators.forEach((indicator) => {
-        action(indicator, mouseclickEvent, carouselIndicatorHandler);
-      });
-    }
-
-    if (keyboard) action(getDocument(element), keydownEvent, carouselKeyHandler);
-  }
-
-  /**
-   * Returns the index of the current active item.
-   * @param {Carousel} self the `Carousel` instance
-   * @returns {number} the query result
-   */
-  function getActiveIndex(self) {
-    const { slides, element } = self;
-    const activeItem = querySelector(`.${carouselItem}.${activeClass}`, element);
-    return [...slides].indexOf(activeItem);
-  }
-
-  // CAROUSEL DEFINITION
-  // ===================
-  /** Creates a new `Carousel` instance. */
-  class Carousel extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target mostly a `.carousel` element
-     * @param {BSN.Options.Carousel=} config instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-      // bind
-      const self = this;
-      // initialization element
-      const { element } = self;
-
-      // additional properties
-      /** @type {string} */
-      self.direction = isRTL(element) ? 'right' : 'left';
-      /** @type {number} */
-      self.index = 0;
-      /** @type {boolean} */
-      self.isTouch = false;
-
-      // carousel elements
-      // a LIVE collection is prefferable
-      self.slides = getElementsByClassName(carouselItem, element);
-      const { slides } = self;
-
-      // invalidate when not enough items
-      // no need to go further
-      if (slides.length < 2) { return; }
-      // external controls must be within same document context
-      const doc = getDocument(element);
-
-      self.controls = [
-        ...querySelectorAll(`[${dataBsSlide}]`, element),
-        ...querySelectorAll(`[${dataBsSlide}][${dataBsTarget}="#${element.id}"]`, doc),
-      ];
-
-      /** @type {HTMLElement?} */
-      self.indicator = querySelector(`.${carouselString}-indicators`, element);
-
-      // a LIVE collection is prefferable
-      /** @type {HTMLElement[]} */
-      self.indicators = [
-        ...(self.indicator ? querySelectorAll(`[${dataBsSlideTo}]`, self.indicator) : []),
-        ...querySelectorAll(`[${dataBsSlideTo}][${dataBsTarget}="#${element.id}"]`, doc),
-      ];
-
-      // set JavaScript and DATA API options
-      const { options } = self;
-
-      // don't use TRUE as interval, it's actually 0, use the default 5000ms better
-      self.options.interval = options.interval === true
-        ? carouselDefaults.interval
-        : options.interval;
-
-      // set first slide active if none
-      /* istanbul ignore else */
-      if (getActiveIndex(self) < 0) {
-        addClass(slides[0], activeClass);
-        /* istanbul ignore else */
-        if (self.indicators.length) activateCarouselIndicator(self, 0);
-      }
-
-      // attach event handlers
-      toggleCarouselHandlers(self, true);
-
-      // start to cycle if interval is set
-      if (options.interval) self.cycle();
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return carouselComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return carouselDefaults; }
-    /* eslint-enable */
-
-    /**
-     * Check if instance is paused.
-     * @returns {boolean}
-    */
-    get isPaused() {
-      return hasClass(this.element, pausedClass);
-    }
-
-    /**
-     * Check if instance is animating.
-     * @returns {boolean}
-    */
-    get isAnimating() {
-      return querySelector(`.${carouselItem}-next,.${carouselItem}-prev`, this.element) !== null;
-    }
-
-    // CAROUSEL PUBLIC METHODS
-    // =======================
-    /** Slide automatically through items. */
-    cycle() {
-      const self = this;
-      const {
-        element, options, isPaused, index,
-      } = self;
-
-      Timer.clear(element, carouselString);
-      if (isPaused) {
-        Timer.clear(element, pausedClass);
-        removeClass(element, pausedClass);
-      }
-
-      Timer.set(element, () => {
-        // it's very important to check self.element
-        // where instance might have been disposed
-        /* istanbul ignore else */
-        if (self.element && !self.isPaused && !self.isTouch
-          && isElementInScrollRange(element)) {
-          self.to(index + 1);
-        }
-      }, options.interval, carouselString);
-    }
-
-    /** Pause the automatic cycle. */
-    pause() {
-      const self = this;
-      const { element, options } = self;
-      /* istanbul ignore else */
-      if (!self.isPaused && options.interval) {
-        addClass(element, pausedClass);
-        Timer.set(element, () => {}, 1, pausedClass);
-      }
-    }
-
-    /** Slide to the next item. */
-    next() {
-      const self = this;
-      /* istanbul ignore else */
-      if (!self.isAnimating) { self.to(self.index + 1); }
-    }
-
-    /** Slide to the previous item. */
-    prev() {
-      const self = this;
-      /* istanbul ignore else */
-      if (!self.isAnimating) { self.to(self.index - 1); }
-    }
-
-    /**
-     * Jump to the item with the `idx` index.
-     * @param {number} idx the index of the item to jump to
-     */
-    to(idx) {
-      const self = this;
-      const {
-        element, slides, options,
-      } = self;
-      const activeItem = getActiveIndex(self);
-      const RTL = isRTL(element);
-      let next = idx;
-
-      // when controled via methods, make sure to check again
-      // first return if we're on the same item #227
-      // `to()` must be SPAM protected by Timer
-      if (self.isAnimating || activeItem === next || Timer.get(element, dataBsSlide)) return;
-
-      // determine transition direction
-      /* istanbul ignore else */
-      if ((activeItem < next) || (activeItem === 0 && next === slides.length - 1)) {
-        self.direction = RTL ? 'right' : 'left'; // next
-      } else if ((activeItem > next) || (activeItem === slides.length - 1 && next === 0)) {
-        self.direction = RTL ? 'left' : 'right'; // prev
-      }
-      const { direction } = self;
-
-      // find the right next index
-      if (next < 0) { next = slides.length - 1; } else if (next >= slides.length) { next = 0; }
-
-      // orientation, class name, eventProperties
-      const orientation = direction === 'left' ? 'next' : 'prev';
-      const directionClass = direction === 'left' ? 'start' : 'end';
-
-      const eventProperties = {
-        relatedTarget: slides[next],
-        from: activeItem,
-        to: next,
-        direction,
-      };
-
-      // update event properties
-      ObjectAssign(carouselSlideEvent, eventProperties);
-      ObjectAssign(carouselSlidEvent, eventProperties);
-
-      // discontinue when prevented
-      dispatchEvent(element, carouselSlideEvent);
-      if (carouselSlideEvent.defaultPrevented) return;
-
-      // update index
-      self.index = next;
-      activateCarouselIndicator(self, next);
-
-      if (getElementTransitionDuration(slides[next]) && hasClass(element, 'slide')) {
-        Timer.set(element, () => {
-          addClass(slides[next], `${carouselItem}-${orientation}`);
-          reflow(slides[next]);
-          addClass(slides[next], `${carouselItem}-${directionClass}`);
-          addClass(slides[activeItem], `${carouselItem}-${directionClass}`);
-
-          emulateTransitionEnd(slides[next], () => carouselTransitionEndHandler(self));
-        }, 0, dataBsSlide);
-      } else {
-        addClass(slides[next], activeClass);
-        removeClass(slides[activeItem], activeClass);
-
-        Timer.set(element, () => {
-          Timer.clear(element, dataBsSlide);
-          // check for element, might have been disposed
-          /* istanbul ignore else */
-          if (element && options.interval && !self.isPaused) {
-            self.cycle();
-          }
-
-          dispatchEvent(element, carouselSlidEvent);
-        }, 0, dataBsSlide);
-      }
-    }
-
-    /** Remove `Carousel` component from target. */
-    dispose() {
-      const self = this;
-      const { slides } = self;
-      const itemClasses = ['start', 'end', 'prev', 'next'];
-
-      [...slides].forEach((slide, idx) => {
-        if (hasClass(slide, activeClass)) activateCarouselIndicator(self, idx);
-        itemClasses.forEach((c) => removeClass(slide, `${carouselItem}-${c}`));
-      });
-
-      toggleCarouselHandlers(self);
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Carousel, {
-    selector: carouselSelector,
-    init: carouselInitCallback,
-    getInstance: getCarouselInstance,
-  });
-
-  /**
-   * A global namespace for aria-expanded.
-   * @type {string}
-   */
-  const ariaExpanded = 'aria-expanded';
-
-  /**
-   * Shortcut for `Object.entries()` static method.
-   * @param  {Record<string, any>} obj a target object
-   * @returns {[string, any][]}
-   */
-  const ObjectEntries = (obj) => Object.entries(obj);
-
-  /**
-   * Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
-   * @param  {HTMLElement} element target element
-   * @param  {Partial<CSSStyleDeclaration>} styles attribute value
-   */
-  const setElementStyle = (element, styles) => {
-    ObjectEntries(styles).forEach(([key, value]) => {
-      if (key.includes('--')) {
-        element.style.setProperty(key, value);
-      } else {
-        const propObject = {}; propObject[key] = value;
-        ObjectAssign(element.style, propObject);
-      }
-    });
-  };
-
-  /**
-   * Global namespace for most components `collapsing` class.
-   * As used by `Collapse` / `Tab`.
-   */
-  const collapsingClass = 'collapsing';
-
-  /** @type {string} */
-  const collapseString = 'collapse';
-
-  /** @type {string} */
-  const collapseComponent = 'Collapse';
-
-  /* Native JavaScript for Bootstrap 5 | Collapse
-  ----------------------------------------------- */
-
-  // COLLAPSE GC
-  // ===========
-  const collapseSelector = `.${collapseString}`;
-  const collapseToggleSelector = `[${dataBsToggle}="${collapseString}"]`;
-  const collapseDefaults = { parent: null };
-
-  /**
-   * Static method which returns an existing `Collapse` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Collapse>}
-   */
-  const getCollapseInstance = (element) => getInstance(element, collapseComponent);
-
-  /**
-   * A `Collapse` initialization callback.
-   * @type {BSN.InitCallback<Collapse>}
-   */
-  const collapseInitCallback = (element) => new Collapse(element);
-
-  // COLLAPSE CUSTOM EVENTS
-  // ======================
-  const showCollapseEvent = OriginalEvent(`show.bs.${collapseString}`);
-  const shownCollapseEvent = OriginalEvent(`shown.bs.${collapseString}`);
-  const hideCollapseEvent = OriginalEvent(`hide.bs.${collapseString}`);
-  const hiddenCollapseEvent = OriginalEvent(`hidden.bs.${collapseString}`);
-
-  // COLLAPSE PRIVATE METHODS
-  // ========================
-  /**
-   * Expand the designated `Element`.
-   * @param {Collapse} self the `Collapse` instance
-   */
-  function expandCollapse(self) {
-    const {
-      element, parent, triggers,
-    } = self;
-
-    dispatchEvent(element, showCollapseEvent);
-    if (showCollapseEvent.defaultPrevented) return;
-
-    Timer.set(element, () => {}, 17);
-    if (parent) Timer.set(parent, () => {}, 17);
-
-    addClass(element, collapsingClass);
-    removeClass(element, collapseString);
-
-    setElementStyle(element, { height: `${element.scrollHeight}px` });
-
-    emulateTransitionEnd(element, () => {
-      Timer.clear(element);
-      if (parent) Timer.clear(parent);
-
-      triggers.forEach((btn) => setAttribute(btn, ariaExpanded, 'true'));
-
-      removeClass(element, collapsingClass);
-      addClass(element, collapseString);
-      addClass(element, showClass);
-
-      setElementStyle(element, { height: '' });
-
-      dispatchEvent(element, shownCollapseEvent);
-    });
-  }
-
-  /**
-   * Collapse the designated `Element`.
-   * @param {Collapse} self the `Collapse` instance
-   */
-  function collapseContent(self) {
-    const {
-      element, parent, triggers,
-    } = self;
-
-    dispatchEvent(element, hideCollapseEvent);
-
-    if (hideCollapseEvent.defaultPrevented) return;
-
-    Timer.set(element, () => {}, 17);
-    if (parent) Timer.set(parent, () => {}, 17);
-
-    setElementStyle(element, { height: `${element.scrollHeight}px` });
-
-    removeClass(element, collapseString);
-    removeClass(element, showClass);
-    addClass(element, collapsingClass);
-
-    reflow(element);
-    setElementStyle(element, { height: '0px' });
-
-    emulateTransitionEnd(element, () => {
-      Timer.clear(element);
-      /* istanbul ignore else */
-      if (parent) Timer.clear(parent);
-
-      triggers.forEach((btn) => setAttribute(btn, ariaExpanded, 'false'));
-
-      removeClass(element, collapsingClass);
-      addClass(element, collapseString);
-
-      setElementStyle(element, { height: '' });
-
-      dispatchEvent(element, hiddenCollapseEvent);
-    });
-  }
-
-  /**
-   * Toggles on/off the event listener(s) of the `Collapse` instance.
-   * @param {Collapse} self the `Collapse` instance
-   * @param {boolean=} add when `true`, the event listener is added
-   */
-  function toggleCollapseHandler(self, add) {
-    const action = add ? addListener : removeListener;
-    const { triggers } = self;
-
-    /* istanbul ignore else */
-    if (triggers.length) {
-      triggers.forEach((btn) => action(btn, mouseclickEvent, collapseClickHandler));
-    }
-  }
-
-  // COLLAPSE EVENT HANDLER
-  // ======================
-  /**
-   * Handles the `click` event for the `Collapse` instance.
-   * @param {MouseEvent} e the `Event` object
-   */
-  function collapseClickHandler(e) {
-    const { target } = e; // our target is `HTMLElement`
-    const trigger = target && closest(target, collapseToggleSelector);
-    const element = trigger && getTargetElement(trigger);
-    const self = element && getCollapseInstance(element);
-    /* istanbul ignore else */
-    if (self) self.toggle();
-
-    // event target is anchor link #398
-    if (trigger && trigger.tagName === 'A') e.preventDefault();
-  }
-
-  // COLLAPSE DEFINITION
-  // ===================
-
-  /** Returns a new `Colapse` instance. */
-  class Collapse extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target and `Element` that matches the selector
-     * @param {BSN.Options.Collapse=} config instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-      // bind
-      const self = this;
-
-      // initialization element
-      const { element, options } = self;
-      const doc = getDocument(element);
-
-      // set triggering elements
-      /** @type {HTMLElement[]} */
-      self.triggers = [...querySelectorAll(collapseToggleSelector, doc)]
-        .filter((btn) => getTargetElement(btn) === element);
-
-      // set parent accordion
-      /** @type {HTMLElement?} */
-      self.parent = querySelector(options.parent, doc)
-        || getTargetElement(element) || null;
-
-      // add event listeners
-      toggleCollapseHandler(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return collapseComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return collapseDefaults; }
-    /* eslint-enable */
-
-    // COLLAPSE PUBLIC METHODS
-    // =======================
-    /** Toggles the visibility of the collapse. */
-    toggle() {
-      const self = this;
-      if (!hasClass(self.element, showClass)) self.show();
-      else self.hide();
-    }
-
-    /** Hides the collapse. */
-    hide() {
-      const self = this;
-      const { triggers, element } = self;
-      if (Timer.get(element)) return;
-
-      collapseContent(self);
-      /* istanbul ignore else */
-      if (triggers.length) {
-        triggers.forEach((btn) => addClass(btn, `${collapseString}d`));
-      }
-    }
-
-    /** Shows the collapse. */
-    show() {
-      const self = this;
-      const {
-        element, parent, triggers,
-      } = self;
-      let activeCollapse;
-      let activeCollapseInstance;
-
-      if (parent) {
-        activeCollapse = [...querySelectorAll(`.${collapseString}.${showClass}`, parent)]
-          .find((i) => getCollapseInstance(i));
-        activeCollapseInstance = activeCollapse && getCollapseInstance(activeCollapse);
-      }
-
-      if ((!parent || !Timer.get(parent)) && !Timer.get(element)) {
-        if (activeCollapseInstance && activeCollapse !== element) {
-          collapseContent(activeCollapseInstance);
-          activeCollapseInstance.triggers.forEach((btn) => {
-            addClass(btn, `${collapseString}d`);
-          });
-        }
-
-        expandCollapse(self);
-        /* istanbul ignore else */
-        if (triggers.length) {
-          triggers.forEach((btn) => removeClass(btn, `${collapseString}d`));
-        }
-      }
-    }
-
-    /** Remove the `Collapse` component from the target `Element`. */
-    dispose() {
-      const self = this;
-      toggleCollapseHandler(self);
-
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Collapse, {
-    selector: collapseSelector,
-    init: collapseInitCallback,
-    getInstance: getCollapseInstance,
-  });
-
-  /**
-   * A global namespace for `focus` event.
-   * @type {string}
-   */
-  const focusEvent = 'focus';
-
-  /**
-   * A global namespace for `keyup` event.
-   * @type {string}
-   */
-  const keyupEvent = 'keyup';
-
-  /**
-   * A global namespace for `scroll` event.
-   * @type {string}
-   */
-  const scrollEvent = 'scroll';
-
-  /**
-   * A global namespace for `resize` event.
-   * @type {string}
-   */
-  const resizeEvent = 'resize';
-
-  /**
-   * A global namespace for `ArrowUp` key.
-   * @type {string} e.which = 38 equivalent
-   */
-  const keyArrowUp = 'ArrowUp';
-
-  /**
-   * A global namespace for `ArrowDown` key.
-   * @type {string} e.which = 40 equivalent
-   */
-  const keyArrowDown = 'ArrowDown';
-
-  /**
-   * A global namespace for `Escape` key.
-   * @type {string} e.which = 27 equivalent
-   */
-  const keyEscape = 'Escape';
-
-  /**
-   * Shortcut for `HTMLElement.hasAttribute()` method.
-   * @param  {HTMLElement} element target element
-   * @param  {string} attribute attribute name
-   * @returns {boolean} the query result
-   */
-  const hasAttribute = (element, attribute) => element.hasAttribute(attribute);
-
-  /**
-   * Utility to focus an `HTMLElement` target.
-   *
-   * @param {HTMLElement} element is the target
-   */
-  const focus = (element) => element.focus();
-
-  /**
-   * Returns the `Window` object of a target node.
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {(Node | Window)=} node target node
-   * @returns {Window} the `Window` object
-   */
-  function getWindow(node) {
-    // node is undefined | NULL
-    if (!node) return window;
-    // node instanceof Document
-    if (isDocument(node)) return node.defaultView;
-    // node instanceof Node
-    if (isNode(node)) return node.ownerDocument.defaultView;
-    // node is instanceof Window
-    return node;
-  }
-
-  /**
-   * Global namespace for `Dropdown` types / classes.
-   */
-  const dropdownMenuClasses = ['dropdown', 'dropup', 'dropstart', 'dropend'];
-
-  /** @type {string} */
-  const dropdownComponent = 'Dropdown';
-
-  /**
-   * Global namespace for `.dropdown-menu`.
-   */
-  const dropdownMenuClass = 'dropdown-menu';
-
-  /**
-   * Checks if an *event.target* or its parent has an `href="#"` value.
-   * We need to prevent jumping around onclick, don't we?
-   *
-   * @param {Node} element the target element
-   * @returns {boolean} the query result
-   */
-  function isEmptyAnchor(element) {
-    // `EventTarget` must be `HTMLElement`
-    const parentAnchor = closest(element, 'A');
-    return isHTMLElement(element)
-      // anchor href starts with #
-      && ((hasAttribute(element, 'href') && element.href.slice(-1) === '#')
-      // OR a child of an anchor with href starts with #
-      || (parentAnchor && hasAttribute(parentAnchor, 'href')
-      && parentAnchor.href.slice(-1) === '#'));
-  }
-
-  /* Native JavaScript for Bootstrap 5 | Dropdown
-  ----------------------------------------------- */
-
-  // DROPDOWN PRIVATE GC
-  // ===================
-  const [
-    dropdownString,
-    dropupString,
-    dropstartString,
-    dropendString,
-  ] = dropdownMenuClasses;
-  const dropdownSelector = `[${dataBsToggle}="${dropdownString}"]`;
-
-  /**
-   * Static method which returns an existing `Dropdown` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Dropdown>}
-   */
-  const getDropdownInstance = (element) => getInstance(element, dropdownComponent);
-
-  /**
-   * A `Dropdown` initialization callback.
-   * @type {BSN.InitCallback<Dropdown>}
-   */
-  const dropdownInitCallback = (element) => new Dropdown(element);
-
-  // DROPDOWN PRIVATE GC
-  // ===================
-  // const dropdownMenuStartClass = `${dropdownMenuClass}-start`;
-  const dropdownMenuEndClass = `${dropdownMenuClass}-end`;
-  const verticalClass = [dropdownString, dropupString];
-  const horizontalClass = [dropstartString, dropendString];
-  const menuFocusTags = ['A', 'BUTTON'];
-
-  const dropdownDefaults = {
-    offset: 5, // [number] 5(px)
-    display: 'dynamic', // [dynamic|static]
-  };
-
-  // DROPDOWN CUSTOM EVENTS
-  // ======================
-  const showDropdownEvent = OriginalEvent(`show.bs.${dropdownString}`);
-  const shownDropdownEvent = OriginalEvent(`shown.bs.${dropdownString}`);
-  const hideDropdownEvent = OriginalEvent(`hide.bs.${dropdownString}`);
-  const hiddenDropdownEvent = OriginalEvent(`hidden.bs.${dropdownString}`);
-
-  // DROPDOWN PRIVATE METHODS
-  // ========================
-  /**
-   * Apply specific style or class names to a `.dropdown-menu` to automatically
-   * accomodate the layout and the page scroll.
-   *
-   * @param {Dropdown} self the `Dropdown` instance
-   */
-  function styleDropdown(self) {
-    const {
-      element, menu, parentElement, options,
-    } = self;
-    const { offset } = options;
-
-    // don't apply any style on mobile view
-    /* istanbul ignore next: this test requires a navbar */
-    if (getElementStyle(menu, 'position') === 'static') return;
-
-    const RTL = isRTL(element);
-    // const menuStart = hasClass(menu, dropdownMenuStartClass);
-    const menuEnd = hasClass(menu, dropdownMenuEndClass);
-
-    // reset menu offset and position
-    const resetProps = ['margin', 'top', 'bottom', 'left', 'right'];
-    resetProps.forEach((p) => { menu.style[p] = ''; });
-
-    // set initial position class
-    // take into account .btn-group parent as .dropdown
-    // this requires navbar/btn-group/input-group
-    let positionClass = dropdownMenuClasses.find((c) => hasClass(parentElement, c))
-      || /* istanbul ignore next: fallback position */ dropdownString;
-
-    /** @type {Record<string, Record<string, any>>} */
-    let dropdownMargin = {
-      dropdown: [offset, 0, 0],
-      dropup: [0, 0, offset],
-      dropstart: RTL ? [-1, 0, 0, offset] : [-1, offset, 0],
-      dropend: RTL ? [-1, offset, 0] : [-1, 0, 0, offset],
-    };
-
-    /** @type {Record<string, Record<string, any>>} */
-    const dropdownPosition = {
-      dropdown: { top: '100%' },
-      dropup: { top: 'auto', bottom: '100%' },
-      dropstart: RTL ? { left: '100%', right: 'auto' } : { left: 'auto', right: '100%' },
-      dropend: RTL ? { left: 'auto', right: '100%' } : { left: '100%', right: 'auto' },
-      menuStart: RTL ? { right: 0, left: 'auto' } : { right: 'auto', left: 0 },
-      menuEnd: RTL ? { right: 'auto', left: 0 } : { right: 0, left: 'auto' },
-    };
-
-    const { offsetWidth: menuWidth, offsetHeight: menuHeight } = menu;
-
-    const { clientWidth, clientHeight } = getDocumentElement(element);
-    const {
-      left: targetLeft, top: targetTop,
-      width: targetWidth, height: targetHeight,
-    } = getBoundingClientRect(element);
-
-    // dropstart | dropend
-    const leftFullExceed = targetLeft - menuWidth - offset < 0;
-    // dropend
-    const rightFullExceed = targetLeft + menuWidth + targetWidth + offset >= clientWidth;
-    // dropstart | dropend
-    const bottomExceed = targetTop + menuHeight + offset >= clientHeight;
-    // dropdown
-    const bottomFullExceed = targetTop + menuHeight + targetHeight + offset >= clientHeight;
-    // dropup
-    const topExceed = targetTop - menuHeight - offset < 0;
-    // dropdown / dropup
-    const leftExceed = ((!RTL && menuEnd) || (RTL && !menuEnd))
-      && targetLeft + targetWidth - menuWidth < 0;
-    const rightExceed = ((RTL && menuEnd) || (!RTL && !menuEnd))
-      && targetLeft + menuWidth >= clientWidth;
-
-    // recompute position
-    // handle RTL as well
-    if (horizontalClass.includes(positionClass) && leftFullExceed && rightFullExceed) {
-      positionClass = dropdownString;
-    }
-    if (positionClass === dropstartString && (!RTL ? leftFullExceed : rightFullExceed)) {
-      positionClass = dropendString;
-    }
-    if (positionClass === dropendString && (RTL ? leftFullExceed : rightFullExceed)) {
-      positionClass = dropstartString;
-    }
-    if (positionClass === dropupString && topExceed && !bottomFullExceed) {
-      positionClass = dropdownString;
-    }
-    if (positionClass === dropdownString && bottomFullExceed && !topExceed) {
-      positionClass = dropupString;
-    }
-
-    // override position for horizontal classes
-    if (horizontalClass.includes(positionClass) && bottomExceed) {
-      ObjectAssign(dropdownPosition[positionClass], {
-        top: 'auto', bottom: 0,
-      });
-    }
-
-    // override position for vertical classes
-    if (verticalClass.includes(positionClass) && (leftExceed || rightExceed)) {
-      // don't realign when menu is wider than window
-      // in both RTL and non-RTL readability is KING
-      let posAjust;
-      if (!leftExceed && rightExceed && !RTL) posAjust = { left: 'auto', right: 0 };
-      if (leftExceed && !rightExceed && RTL) posAjust = { left: 0, right: 'auto' };
-      if (posAjust) ObjectAssign(dropdownPosition[positionClass], posAjust);
-    }
-
-    dropdownMargin = dropdownMargin[positionClass];
-    setElementStyle(menu, {
-      ...dropdownPosition[positionClass],
-      margin: `${dropdownMargin.map((x) => (x ? `${x}px` : x)).join(' ')}`,
-    });
-
-    // override dropdown-menu-start | dropdown-menu-end
-    if (verticalClass.includes(positionClass) && menuEnd) {
-      /* istanbul ignore else */
-      if (menuEnd) {
-        const endAdjust = (!RTL && leftExceed) || (RTL && rightExceed)
-          ? 'menuStart' : /* istanbul ignore next */'menuEnd';
-        setElementStyle(menu, dropdownPosition[endAdjust]);
-      }
-    }
-  }
-
-  /**
-   * Returns an `Array` of focusable items in the given dropdown-menu.
-   * @param {HTMLElement} menu
-   * @returns {HTMLElement[]}
-   */
-  function getMenuItems(menu) {
-    return [...menu.children].map((c) => {
-      if (c && menuFocusTags.includes(c.tagName)) return c;
-      const { firstElementChild } = c;
-      if (firstElementChild && menuFocusTags.includes(firstElementChild.tagName)) {
-        return firstElementChild;
-      }
-      return null;
-    }).filter((c) => c);
-  }
-
-  /**
-   * Toggles on/off the listeners for the events that close the dropdown
-   * as well as event that request a new position for the dropdown.
-   *
-   * @param {Dropdown} self the `Dropdown` instance
-   */
-  function toggleDropdownDismiss(self) {
-    const { element, options } = self;
-    const action = self.open ? addListener : removeListener;
-    const doc = getDocument(element);
-
-    action(doc, mouseclickEvent, dropdownDismissHandler);
-    action(doc, focusEvent, dropdownDismissHandler);
-    action(doc, keydownEvent, dropdownPreventScroll);
-    action(doc, keyupEvent, dropdownKeyHandler);
-
-    /* istanbul ignore else */
-    if (options.display === 'dynamic') {
-      [scrollEvent, resizeEvent].forEach((ev) => {
-        action(getWindow(element), ev, dropdownLayoutHandler, passiveHandler);
-      });
-    }
-  }
-
-  /**
-   * Toggles on/off the `click` event listener of the `Dropdown`.
-   *
-   * @param {Dropdown} self the `Dropdown` instance
-   * @param {boolean=} add when `true`, it will add the event listener
-   */
-  function toggleDropdownHandler(self, add) {
-    const action = add ? addListener : removeListener;
-    action(self.element, mouseclickEvent, dropdownClickHandler);
-  }
-
-  /**
-   * Returns the currently open `.dropdown` element.
-   *
-   * @param {(Node | Window)=} element target
-   * @returns {HTMLElement?} the query result
-   */
-  function getCurrentOpenDropdown(element) {
-    const currentParent = [...dropdownMenuClasses, 'btn-group', 'input-group']
-      .map((c) => getElementsByClassName(`${c} ${showClass}`, getDocument(element)))
-      .find((x) => x.length);
-
-    if (currentParent && currentParent.length) {
-      return [...currentParent[0].children]
-        .find((x) => hasAttribute(x, dataBsToggle));
-    }
-    return null;
-  }
-
-  // DROPDOWN EVENT HANDLERS
-  // =======================
-  /**
-   * Handles the `click` event for the `Dropdown` instance.
-   *
-   * @param {MouseEvent} e event object
-   * @this {Document}
-   */
-  function dropdownDismissHandler(e) {
-    const { target, type } = e;
-
-    /* istanbul ignore next: impossible to satisfy */
-    if (!target || !target.closest) return; // some weird FF bug #409
-
-    const element = getCurrentOpenDropdown(target);
-    const self = getDropdownInstance(element);
-
-    /* istanbul ignore next */
-    if (!self) return;
-
-    const { parentElement, menu } = self;
-
-    const hasData = closest(target, dropdownSelector) !== null;
-    const isForm = parentElement && parentElement.contains(target)
-      && (target.tagName === 'form' || closest(target, 'form') !== null);
-
-    if (type === mouseclickEvent && isEmptyAnchor(target)) {
-      e.preventDefault();
-    }
-    if (type === focusEvent
-      && (target === element || target === menu || menu.contains(target))) {
-      return;
-    }
-
-    /* istanbul ignore else */
-    if (isForm || hasData) ; else if (self) {
-      self.hide();
-    }
-  }
-
-  /**
-   * Handles `click` event listener for `Dropdown`.
-   * @this {HTMLElement}
-   * @param {MouseEvent} e event object
-   */
-  function dropdownClickHandler(e) {
-    const element = this;
-    const { target } = e;
-    const self = getDropdownInstance(element);
-
-    /* istanbul ignore else */
-    if (self) {
-      self.toggle();
-      /* istanbul ignore else */
-      if (target && isEmptyAnchor(target)) e.preventDefault();
-    }
-  }
-
-  /**
-   * Prevents scroll when dropdown-menu is visible.
-   * @param {KeyboardEvent} e event object
-   */
-  function dropdownPreventScroll(e) {
-    /* istanbul ignore else */
-    if ([keyArrowDown, keyArrowUp].includes(e.code)) e.preventDefault();
-  }
-
-  /**
-   * Handles keyboard `keydown` events for `Dropdown`.
-   * @param {KeyboardEvent} e keyboard key
-   * @this {Document}
-   */
-  function dropdownKeyHandler(e) {
-    const { code } = e;
-    const element = getCurrentOpenDropdown(this);
-    const self = element && getDropdownInstance(element);
-    const { activeElement } = element && getDocument(element);
-    /* istanbul ignore next: impossible to satisfy */
-    if (!self || !activeElement) return;
-    const { menu, open } = self;
-    const menuItems = getMenuItems(menu);
-
-    // arrow up & down
-    if (menuItems && menuItems.length && [keyArrowDown, keyArrowUp].includes(code)) {
-      let idx = menuItems.indexOf(activeElement);
-      /* istanbul ignore else */
-      if (activeElement === element) {
-        idx = 0;
-      } else if (code === keyArrowUp) {
-        idx = idx > 1 ? idx - 1 : 0;
-      } else if (code === keyArrowDown) {
-        idx = idx < menuItems.length - 1 ? idx + 1 : idx;
-      }
-      /* istanbul ignore else */
-      if (menuItems[idx]) focus(menuItems[idx]);
-    }
-
-    if (keyEscape === code && open) {
-      self.toggle();
-      focus(element);
-    }
-  }
-
-  /**
-   * @this {globalThis}
-   * @returns {void}
-   */
-  function dropdownLayoutHandler() {
-    const element = getCurrentOpenDropdown(this);
-    const self = element && getDropdownInstance(element);
-
-    /* istanbul ignore else */
-    if (self && self.open) styleDropdown(self);
-  }
-
-  // DROPDOWN DEFINITION
-  // ===================
-  /** Returns a new Dropdown instance. */
-  class Dropdown extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target Element or string selector
-     * @param {BSN.Options.Dropdown=} config the instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-      // bind
-      const self = this;
-
-      // initialization element
-      const { element } = self;
-      const { parentElement } = element;
-
-      // set targets
-      /** @type {(Element | HTMLElement)} */
-      self.parentElement = parentElement;
-      /** @type {(Element | HTMLElement)} */
-      self.menu = querySelector(`.${dropdownMenuClass}`, parentElement);
-
-      // set initial state to closed
-      /** @type {boolean} */
-      self.open = false;
-
-      // add event listener
-      toggleDropdownHandler(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return dropdownComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return dropdownDefaults; }
-    /* eslint-enable */
-
-    // DROPDOWN PUBLIC METHODS
-    // =======================
-    /** Shows/hides the dropdown menu to the user. */
-    toggle() {
-      const self = this;
-
-      if (self.open) self.hide();
-      else self.show();
-    }
-
-    /** Shows the dropdown menu to the user. */
-    show() {
-      const self = this;
-      const {
-        element, open, menu, parentElement,
-      } = self;
-
-      /* istanbul ignore next */
-      if (open) return;
-
-      const currentElement = getCurrentOpenDropdown(element);
-      const currentInstance = currentElement && getDropdownInstance(currentElement);
-      if (currentInstance) currentInstance.hide();
-
-      // dispatch event
-      [showDropdownEvent, shownDropdownEvent].forEach((e) => {
-        e.relatedTarget = element;
-      });
-      dispatchEvent(parentElement, showDropdownEvent);
-      if (showDropdownEvent.defaultPrevented) return;
-
-      addClass(menu, showClass);
-      addClass(parentElement, showClass);
-      setAttribute(element, ariaExpanded, 'true');
-
-      // change menu position
-      styleDropdown(self);
-
-      self.open = !open;
-
-      focus(element); // focus the element
-      toggleDropdownDismiss(self);
-      dispatchEvent(parentElement, shownDropdownEvent);
-    }
-
-    /** Hides the dropdown menu from the user. */
-    hide() {
-      const self = this;
-      const {
-        element, open, menu, parentElement,
-      } = self;
-
-      /* istanbul ignore next */
-      if (!open) return;
-
-      [hideDropdownEvent, hiddenDropdownEvent].forEach((e) => {
-        e.relatedTarget = element;
-      });
-      dispatchEvent(parentElement, hideDropdownEvent);
-      if (hideDropdownEvent.defaultPrevented) return;
-
-      removeClass(menu, showClass);
-      removeClass(parentElement, showClass);
-      setAttribute(element, ariaExpanded, 'false');
-
-      self.open = !open;
-      // only re-attach handler if the instance is not disposed
-      toggleDropdownDismiss(self);
-      dispatchEvent(parentElement, hiddenDropdownEvent);
-    }
-
-    /** Removes the `Dropdown` component from the target element. */
-    dispose() {
-      const self = this;
-      if (self.open) self.hide();
-
-      toggleDropdownHandler(self);
-
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Dropdown, {
-    selector: dropdownSelector,
-    init: dropdownInitCallback,
-    getInstance: getDropdownInstance,
-  });
-
-  /**
-   * A global namespace for aria-hidden.
-   * @type {string}
-   */
-  const ariaHidden = 'aria-hidden';
-
-  /**
-   * A global namespace for aria-modal.
-   * @type {string}
-   */
-  const ariaModal = 'aria-modal';
-
-  /**
-   * Shortcut for `HTMLElement.removeAttribute()` method.
-   * @param  {HTMLElement} element target element
-   * @param  {string} attribute attribute name
-   * @returns {void}
-   */
-  const removeAttribute = (element, attribute) => element.removeAttribute(attribute);
-
-  /**
-   * Returns the `document.body` or the `<body>` element.
-   *
-   * @param {(Node | Window)=} node
-   * @returns {HTMLBodyElement}
-   */
-  function getDocumentBody(node) {
-    return getDocument(node).body;
-  }
-
-  /** @type {string} */
-  const modalString = 'modal';
-
-  /** @type {string} */
-  const modalComponent = 'Modal';
-
-  /**
-   * Check if target is a `ShadowRoot`.
-   *
-   * @param {any} element target
-   * @returns {boolean} the query result
-   */
-  const isShadowRoot = (element) => (element && element.constructor.name === 'ShadowRoot')
-    || false;
-
-  /**
-   * Returns the `parentNode` also going through `ShadowRoot`.
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {Node} node the target node
-   * @returns {Node} the apropriate parent node
-   */
-  function getParentNode(node) {
-    if (node.nodeName === 'HTML') {
-      return node;
-    }
-
-    // this is a quicker (but less type safe) way to save quite some bytes from the bundle
-    return (
-      node.assignedSlot // step into the shadow DOM of the parent of a slotted node
-      || node.parentNode // DOM Element detected
-      || (isShadowRoot(node) && node.host) // ShadowRoot detected
-      || getDocumentElement(node) // fallback
-    );
-  }
-
-  /**
-   * Check if a target element is a `<table>`, `<td>` or `<th>`.
-   * This specific check is important for determining
-   * the `offsetParent` of a given element.
-   *
-   * @param {any} element the target element
-   * @returns {boolean} the query result
-   */
-  const isTableElement = (element) => (element && ['TABLE', 'TD', 'TH'].includes(element.tagName))
-    || false;
-
-  /**
-   * Returns an `HTMLElement` to be used as default value for *options.container*
-   * for `Tooltip` / `Popover` components.
-   *
-   * When `getOffset` is *true*, it returns the `offsetParent` for tooltip/popover
-   * offsets computation similar to **floating-ui**.
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {HTMLElement} element the target
-   * @param {boolean=} getOffset when *true* it will return an `offsetParent`
-   * @returns {ParentNode | Window} the query result
-   */
-  function getElementContainer(element, getOffset) {
-    const majorBlockTags = ['HTML', 'BODY'];
-
-    if (getOffset) {
-      /** @type {any} */
-      let { offsetParent } = element;
-      const win = getWindow(element);
-
-      while (offsetParent && (isTableElement(offsetParent)
-        || (isHTMLElement(offsetParent)
-          // we must count for both fixed & sticky
-          && !['sticky', 'fixed'].includes(getElementStyle(offsetParent, 'position'))))) {
-        offsetParent = offsetParent.offsetParent;
-      }
-
-      if (!offsetParent || (majorBlockTags.includes(offsetParent.tagName)
-          || getElementStyle(offsetParent, 'position') === 'static')) {
-        offsetParent = win;
-      }
-      return offsetParent;
-    }
-
-    /** @type {ParentNode[]} */
-    const containers = [];
-    /** @type {ParentNode} */
-    let { parentNode } = element;
-
-    while (parentNode && !majorBlockTags.includes(parentNode.nodeName)) {
-      parentNode = getParentNode(parentNode);
-      /* istanbul ignore else */
-      if (!(isShadowRoot(parentNode) || !!parentNode.shadowRoot
-        || isTableElement(parentNode))) {
-        containers.push(parentNode);
-      }
-    }
-
-    return containers.find((c, i) => {
-      if (getElementStyle(c, 'position') !== 'relative'
-        && containers.slice(i + 1).every((r) => getElementStyle(r, 'position') === 'static')) {
-        return c;
-      }
-      return null;
-    }) || getDocumentBody(element);
-  }
-
-  /**
-   * Global namespace for components `fixed-top` class.
-   */
-  const fixedTopClass = 'fixed-top';
-
-  /**
-   * Global namespace for components `fixed-bottom` class.
-   */
-  const fixedBottomClass = 'fixed-bottom';
-
-  /**
-   * Global namespace for components `sticky-top` class.
-   */
-  const stickyTopClass = 'sticky-top';
-
-  /**
-   * Global namespace for components `position-sticky` class.
-   */
-  const positionStickyClass = 'position-sticky';
-
-  /** @param {(HTMLElement | Document)=} parent */
-  const getFixedItems = (parent) => [
-    ...getElementsByClassName(fixedTopClass, parent),
-    ...getElementsByClassName(fixedBottomClass, parent),
-    ...getElementsByClassName(stickyTopClass, parent),
-    ...getElementsByClassName(positionStickyClass, parent),
-    ...getElementsByClassName('is-fixed', parent),
-  ];
-
-  /**
-   * Removes *padding* and *overflow* from the `<body>`
-   * and all spacing from fixed items.
-   * @param {HTMLElement=} element the target modal/offcanvas
-   */
-  function resetScrollbar(element) {
-    const bd = getDocumentBody(element);
-    setElementStyle(bd, {
-      paddingRight: '',
-      overflow: '',
-    });
-
-    const fixedItems = getFixedItems(bd);
-
-    if (fixedItems.length) {
-      fixedItems.forEach((fixed) => {
-        setElementStyle(fixed, {
-          paddingRight: '',
-          marginRight: '',
-        });
-      });
-    }
-  }
-
-  /**
-   * Returns the scrollbar width if the body does overflow
-   * the window.
-   * @param {HTMLElement=} element
-   * @returns {number} the value
-   */
-  function measureScrollbar(element) {
-    const { clientWidth } = getDocumentElement(element);
-    const { innerWidth } = getWindow(element);
-    return Math.abs(innerWidth - clientWidth);
-  }
-
-  /**
-   * Sets the `<body>` and fixed items style when modal / offcanvas
-   * is shown to the user.
-   *
-   * @param {HTMLElement} element the target modal/offcanvas
-   * @param {boolean=} overflow body does overflow or not
-   */
-  function setScrollbar(element, overflow) {
-    const bd = getDocumentBody(element);
-    const bodyPad = parseInt(getElementStyle(bd, 'paddingRight'), 10);
-    const isOpen = getElementStyle(bd, 'overflow') === 'hidden';
-    const sbWidth = isOpen && bodyPad ? 0 : measureScrollbar(element);
-    const fixedItems = getFixedItems(bd);
-
-    /* istanbul ignore else */
-    if (overflow) {
-      setElementStyle(bd, {
-        overflow: 'hidden',
-        paddingRight: `${bodyPad + sbWidth}px`,
-      });
-
-      /* istanbul ignore else */
-      if (fixedItems.length) {
-        fixedItems.forEach((fixed) => {
-          const itemPadValue = getElementStyle(fixed, 'paddingRight');
-          fixed.style.paddingRight = `${parseInt(itemPadValue, 10) + sbWidth}px`;
-          /* istanbul ignore else */
-          if ([stickyTopClass, positionStickyClass].some((c) => hasClass(fixed, c))) {
-            const itemMValue = getElementStyle(fixed, 'marginRight');
-            fixed.style.marginRight = `${parseInt(itemMValue, 10) - sbWidth}px`;
-          }
-        });
-      }
-    }
-  }
-
-  /**
-   * This is a shortie for `document.createElement` method
-   * which allows you to create a new `HTMLElement` for a given `tagName`
-   * or based on an object with specific non-readonly attributes:
-   * `id`, `className`, `textContent`, `style`, etc.
-   * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
-   *
-   * @param {Record<string, string> | string} param `tagName` or object
-   * @return {HTMLElement} a new `HTMLElement` or `Element`
-   */
-  function createElement(param) {
-    if (!param) return null;
-
-    if (typeof param === 'string') {
-      return getDocument().createElement(param);
-    }
-
-    const { tagName } = param;
-    const attr = { ...param };
-    const newElement = createElement(tagName);
-    delete attr.tagName;
-    ObjectAssign(newElement, attr);
-    return newElement;
-  }
-
-  /** @type {string} */
-  const offcanvasString = 'offcanvas';
-
-  const backdropString = 'backdrop';
-  const modalBackdropClass = `${modalString}-${backdropString}`;
-  const offcanvasBackdropClass = `${offcanvasString}-${backdropString}`;
-  const modalActiveSelector = `.${modalString}.${showClass}`;
-  const offcanvasActiveSelector = `.${offcanvasString}.${showClass}`;
-
-  // any document would suffice
-  const overlay = createElement('div');
-
-  /**
-   * Returns the current active modal / offcancas element.
-   * @param {HTMLElement=} element the context element
-   * @returns {HTMLElement?} the requested element
-   */
-  function getCurrentOpen(element) {
-    return querySelector(`${modalActiveSelector},${offcanvasActiveSelector}`, getDocument(element));
-  }
-
-  /**
-   * Toogles from a Modal overlay to an Offcanvas, or vice-versa.
-   * @param {boolean=} isModal
-   */
-  function toggleOverlayType(isModal) {
-    const targetClass = isModal ? modalBackdropClass : offcanvasBackdropClass;
-    [modalBackdropClass, offcanvasBackdropClass].forEach((c) => {
-      removeClass(overlay, c);
-    });
-    addClass(overlay, targetClass);
-  }
-
-  /**
-   * Append the overlay to DOM.
-   * @param {HTMLElement} container
-   * @param {boolean} hasFade
-   * @param {boolean=} isModal
-   */
-  function appendOverlay(container, hasFade, isModal) {
-    toggleOverlayType(isModal);
-    container.append(overlay);
-    if (hasFade) addClass(overlay, fadeClass);
-  }
-
-  /**
-   * Shows the overlay to the user.
-   */
-  function showOverlay() {
-    if (!hasClass(overlay, showClass)) {
-      addClass(overlay, showClass);
-      reflow(overlay);
-    }
-  }
-
-  /**
-   * Hides the overlay from the user.
-   */
-  function hideOverlay() {
-    removeClass(overlay, showClass);
-  }
-
-  /**
-   * Removes the overlay from DOM.
-   * @param {HTMLElement=} element
-   */
-  function removeOverlay(element) {
-    if (!getCurrentOpen(element)) {
-      removeClass(overlay, fadeClass);
-      overlay.remove();
-      resetScrollbar(element);
-    }
-  }
-
-  /**
-   * @param {HTMLElement} element target
-   * @returns {boolean}
-   */
-  function isVisible(element) {
-    return isHTMLElement(element)
-      && getElementStyle(element, 'visibility') !== 'hidden'
-      && element.offsetParent !== null;
-  }
-
-  /* Native JavaScript for Bootstrap 5 | Modal
-  -------------------------------------------- */
-
-  // MODAL PRIVATE GC
-  // ================
-  const modalSelector = `.${modalString}`;
-  const modalToggleSelector = `[${dataBsToggle}="${modalString}"]`;
-  const modalDismissSelector = `[${dataBsDismiss}="${modalString}"]`;
-  const modalStaticClass = `${modalString}-static`;
-
-  const modalDefaults = {
-    backdrop: true, // boolean|string
-    keyboard: true, // boolean
-  };
-
-  /**
-   * Static method which returns an existing `Modal` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Modal>}
-   */
-  const getModalInstance = (element) => getInstance(element, modalComponent);
-
-  /**
-   * A `Modal` initialization callback.
-   * @type {BSN.InitCallback<Modal>}
-   */
-  const modalInitCallback = (element) => new Modal(element);
-
-  // MODAL CUSTOM EVENTS
-  // ===================
-  const showModalEvent = OriginalEvent(`show.bs.${modalString}`);
-  const shownModalEvent = OriginalEvent(`shown.bs.${modalString}`);
-  const hideModalEvent = OriginalEvent(`hide.bs.${modalString}`);
-  const hiddenModalEvent = OriginalEvent(`hidden.bs.${modalString}`);
-
-  // MODAL PRIVATE METHODS
-  // =====================
-  /**
-   * Applies special style for the `<body>` and fixed elements
-   * when a modal instance is shown to the user.
-   *
-   * @param {Modal} self the `Modal` instance
-   */
-  function setModalScrollbar(self) {
-    const { element } = self;
-    const scrollbarWidth = measureScrollbar(element);
-    const { clientHeight, scrollHeight } = getDocumentElement(element);
-    const { clientHeight: modalHeight, scrollHeight: modalScrollHeight } = element;
-    const modalOverflow = modalHeight !== modalScrollHeight;
-
-    /* istanbul ignore else */
-    if (!modalOverflow && scrollbarWidth) {
-      const pad = !isRTL(element) ? 'paddingRight' : /* istanbul ignore next */'paddingLeft';
-      const padStyle = {};
-      padStyle[pad] = `${scrollbarWidth}px`;
-      setElementStyle(element, padStyle);
-    }
-    setScrollbar(element, (modalOverflow || clientHeight !== scrollHeight));
-  }
-
-  /**
-   * Toggles on/off the listeners of events that close the modal.
-   *
-   * @param {Modal} self the `Modal` instance
-   * @param {boolean=} add when `true`, event listeners are added
-   */
-  function toggleModalDismiss(self, add) {
-    const action = add ? addListener : removeListener;
-    const { element } = self;
-    action(element, mouseclickEvent, modalDismissHandler);
-    action(getWindow(element), resizeEvent, self.update, passiveHandler);
-    action(getDocument(element), keydownEvent, modalKeyHandler);
-  }
-
-  /**
-   * Toggles on/off the `click` event listener of the `Modal` instance.
-   * @param {Modal} self the `Modal` instance
-   * @param {boolean=} add when `true`, event listener is added
-   */
-  function toggleModalHandler(self, add) {
-    const action = add ? addListener : removeListener;
-    const { triggers } = self;
-
-    /* istanbul ignore else */
-    if (triggers.length) {
-      triggers.forEach((btn) => action(btn, mouseclickEvent, modalClickHandler));
-    }
-  }
-
-  /**
-   * Executes after a modal is hidden to the user.
-   * @param {Modal} self the `Modal` instance
-   * @param {Function} callback the `Modal` instance
-   */
-  function afterModalHide(self, callback) {
-    const { triggers, element, relatedTarget } = self;
-    removeOverlay(element);
-    setElementStyle(element, { paddingRight: '', display: '' });
-    toggleModalDismiss(self);
-
-    const focusElement = showModalEvent.relatedTarget || triggers.find(isVisible);
-    /* istanbul ignore else */
-    if (focusElement) focus(focusElement);
-
-    /* istanbul ignore else */
-    if (callback) callback();
-
-    hiddenModalEvent.relatedTarget = relatedTarget;
-    dispatchEvent(element, hiddenModalEvent);
-  }
-
-  /**
-   * Executes after a modal is shown to the user.
-   * @param {Modal} self the `Modal` instance
-   */
-  function afterModalShow(self) {
-    const { element, relatedTarget } = self;
-    focus(element);
-    toggleModalDismiss(self, true);
-
-    shownModalEvent.relatedTarget = relatedTarget;
-    dispatchEvent(element, shownModalEvent);
-  }
-
-  /**
-   * Executes before a modal is shown to the user.
-   * @param {Modal} self the `Modal` instance
-   */
-  function beforeModalShow(self) {
-    const { element, hasFade } = self;
-    setElementStyle(element, { display: 'block' });
-
-    setModalScrollbar(self);
-    /* istanbul ignore else */
-    if (!getCurrentOpen(element)) {
-      setElementStyle(getDocumentBody(element), { overflow: 'hidden' });
-    }
-
-    addClass(element, showClass);
-    removeAttribute(element, ariaHidden);
-    setAttribute(element, ariaModal, 'true');
-
-    if (hasFade) emulateTransitionEnd(element, () => afterModalShow(self));
-    else afterModalShow(self);
-  }
-
-  /**
-   * Executes before a modal is hidden to the user.
-   * @param {Modal} self the `Modal` instance
-   * @param {Function=} callback when `true` skip animation
-   */
-  function beforeModalHide(self, callback) {
-    const {
-      element, options, hasFade,
-    } = self;
-
-    // callback can also be the transitionEvent object, we wanna make sure it's not
-    // call is not forced and overlay is visible
-    if (options.backdrop && !callback && hasFade && hasClass(overlay, showClass)
-      && !getCurrentOpen(element)) { // AND no modal is visible
-      hideOverlay();
-      emulateTransitionEnd(overlay, () => afterModalHide(self));
-    } else {
-      afterModalHide(self, callback);
-    }
-  }
-
-  // MODAL EVENT HANDLERS
-  // ====================
-  /**
-   * Handles the `click` event listener for modal.
-   * @param {MouseEvent} e the `Event` object
-   */
-  function modalClickHandler(e) {
-    const { target } = e;
-
-    const trigger = target && closest(target, modalToggleSelector);
-    const element = trigger && getTargetElement(trigger);
-    const self = element && getModalInstance(element);
-
-    /* istanbul ignore else */
-    if (trigger && trigger.tagName === 'A') e.preventDefault();
-    self.relatedTarget = trigger;
-    self.toggle();
-  }
-
-  /**
-   * Handles the `keydown` event listener for modal
-   * to hide the modal when user type the `ESC` key.
-   *
-   * @param {KeyboardEvent} e the `Event` object
-   */
-  function modalKeyHandler({ code, target }) {
-    const element = querySelector(modalActiveSelector, getDocument(target));
-    const self = element && getModalInstance(element);
-
-    const { options } = self;
-    /* istanbul ignore else */
-    if (options.keyboard && code === keyEscape // the keyboard option is enabled and the key is 27
-      && hasClass(element, showClass)) { // the modal is not visible
-      self.relatedTarget = null;
-      self.hide();
-    }
-  }
-
-  /**
-   * Handles the `click` event listeners that hide the modal.
-   *
-   * @this {HTMLElement}
-   * @param {MouseEvent} e the `Event` object
-   */
-  function modalDismissHandler(e) {
-    const element = this;
-    const self = getModalInstance(element);
-
-    // this timer is needed
-    /* istanbul ignore next: must have a filter */
-    if (!self || Timer.get(element)) return;
-
-    const { options, isStatic, modalDialog } = self;
-    const { backdrop } = options;
-    const { target } = e;
-
-    const selectedText = getDocument(element).getSelection().toString().length;
-    const targetInsideDialog = modalDialog.contains(target);
-    const dismiss = target && closest(target, modalDismissSelector);
-
-    /* istanbul ignore else */
-    if (isStatic && !targetInsideDialog) {
-      Timer.set(element, () => {
-        addClass(element, modalStaticClass);
-        emulateTransitionEnd(modalDialog, () => staticTransitionEnd(self));
-      }, 17);
-    } else if (dismiss || (!selectedText && !isStatic && !targetInsideDialog && backdrop)) {
-      self.relatedTarget = dismiss || null;
-      self.hide();
-      e.preventDefault();
-    }
-  }
-
-  /**
-   * Handles the `transitionend` event listeners for `Modal`.
-   *
-   * @param {Modal} self the `Modal` instance
-   */
-  function staticTransitionEnd(self) {
-    const { element, modalDialog } = self;
-    const duration = getElementTransitionDuration(modalDialog) + 17;
-    removeClass(element, modalStaticClass);
-    // user must wait for zoom out transition
-    Timer.set(element, () => Timer.clear(element), duration);
-  }
-
-  // MODAL DEFINITION
-  // ================
-  /** Returns a new `Modal` instance. */
-  class Modal extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target usually the `.modal` element
-     * @param {BSN.Options.Modal=} config instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-
-      // bind
-      const self = this;
-
-      // the modal
-      const { element } = self;
-
-      // the modal-dialog
-      /** @type {(HTMLElement)} */
-      self.modalDialog = querySelector(`.${modalString}-dialog`, element);
-
-      // modal can have multiple triggering elements
-      /** @type {HTMLElement[]} */
-      self.triggers = [...querySelectorAll(modalToggleSelector, getDocument(element))]
-        .filter((btn) => getTargetElement(btn) === element);
-
-      // additional internals
-      /** @type {boolean} */
-      self.isStatic = self.options.backdrop === 'static';
-      /** @type {boolean} */
-      self.hasFade = hasClass(element, fadeClass);
-      /** @type {HTMLElement?} */
-      self.relatedTarget = null;
-      /** @type {HTMLBodyElement | HTMLElement} */
-      self.container = getElementContainer(element);
-
-      // attach event listeners
-      toggleModalHandler(self, true);
-
-      // bind
-      self.update = self.update.bind(self);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return modalComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return modalDefaults; }
-    /* eslint-enable */
-
-    // MODAL PUBLIC METHODS
-    // ====================
-    /** Toggles the visibility of the modal. */
-    toggle() {
-      const self = this;
-      if (hasClass(self.element, showClass)) self.hide();
-      else self.show();
-    }
-
-    /** Shows the modal to the user. */
-    show() {
-      const self = this;
-      const {
-        element, options, hasFade, relatedTarget, container,
-      } = self;
-      const { backdrop } = options;
-      let overlayDelay = 0;
-
-      if (hasClass(element, showClass)) return;
-
-      showModalEvent.relatedTarget = relatedTarget || null;
-      dispatchEvent(element, showModalEvent);
-      if (showModalEvent.defaultPrevented) return;
-
-      // we elegantly hide any opened modal/offcanvas
-      const currentOpen = getCurrentOpen(element);
-      if (currentOpen && currentOpen !== element) {
-        const this1 = getModalInstance(currentOpen);
-        const that1 = this1
-          || /* istanbul ignore next */getInstance(currentOpen, 'Offcanvas');
-        that1.hide();
-      }
-
-      if (backdrop) {
-        if (!container.contains(overlay)) {
-          appendOverlay(container, hasFade, true);
-        } else {
-          toggleOverlayType(true);
-        }
-
-        overlayDelay = getElementTransitionDuration(overlay);
-
-        showOverlay();
-        setTimeout(() => beforeModalShow(self), overlayDelay);
-      } else {
-        beforeModalShow(self);
-        /* istanbul ignore else */
-        if (currentOpen && hasClass(overlay, showClass)) {
-          hideOverlay();
-        }
-      }
-    }
-
-    /**
-     * Hide the modal from the user.
-     * @param {Function=} callback when defined it will skip animation
-     */
-    hide(callback) {
-      const self = this;
-      const {
-        element, hasFade, relatedTarget,
-      } = self;
-
-      if (!hasClass(element, showClass)) return;
-
-      hideModalEvent.relatedTarget = relatedTarget || null;
-      dispatchEvent(element, hideModalEvent);
-      if (hideModalEvent.defaultPrevented) return;
-      removeClass(element, showClass);
-      setAttribute(element, ariaHidden, 'true');
-      removeAttribute(element, ariaModal);
-
-      // if (hasFade && callback) {
-      /* istanbul ignore else */
-      if (hasFade) {
-        emulateTransitionEnd(element, () => beforeModalHide(self, callback));
-      } else {
-        beforeModalHide(self, callback);
-      }
-    }
-
-    /**
-     * Updates the modal layout.
-     * @this {Modal} the modal instance
-     */
-    update() {
-      const self = this;
-      /* istanbul ignore else */
-      if (hasClass(self.element, showClass)) setModalScrollbar(self);
-    }
-
-    /** Removes the `Modal` component from target element. */
-    dispose() {
-      const self = this;
-      toggleModalHandler(self);
-      // use callback
-      self.hide(() => super.dispose());
-    }
-  }
-
-  ObjectAssign(Modal, {
-    selector: modalSelector,
-    init: modalInitCallback,
-    getInstance: getModalInstance,
-  });
-
-  /** @type {string} */
-  const offcanvasComponent = 'Offcanvas';
-
-  /* Native JavaScript for Bootstrap 5 | OffCanvas
-  ------------------------------------------------ */
-
-  // OFFCANVAS PRIVATE GC
-  // ====================
-  const offcanvasSelector = `.${offcanvasString}`;
-  const offcanvasToggleSelector = `[${dataBsToggle}="${offcanvasString}"]`;
-  const offcanvasDismissSelector = `[${dataBsDismiss}="${offcanvasString}"]`;
-  const offcanvasTogglingClass = `${offcanvasString}-toggling`;
-
-  const offcanvasDefaults = {
-    backdrop: true, // boolean
-    keyboard: true, // boolean
-    scroll: false, // boolean
-  };
-
-  /**
-   * Static method which returns an existing `Offcanvas` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Offcanvas>}
-   */
-  const getOffcanvasInstance = (element) => getInstance(element, offcanvasComponent);
-
-  /**
-   * An `Offcanvas` initialization callback.
-   * @type {BSN.InitCallback<Offcanvas>}
-   */
-  const offcanvasInitCallback = (element) => new Offcanvas(element);
-
-  // OFFCANVAS CUSTOM EVENTS
-  // =======================
-  const showOffcanvasEvent = OriginalEvent(`show.bs.${offcanvasString}`);
-  const shownOffcanvasEvent = OriginalEvent(`shown.bs.${offcanvasString}`);
-  const hideOffcanvasEvent = OriginalEvent(`hide.bs.${offcanvasString}`);
-  const hiddenOffcanvasEvent = OriginalEvent(`hidden.bs.${offcanvasString}`);
-
-  // OFFCANVAS PRIVATE METHODS
-  // =========================
-  /**
-   * Sets additional style for the `<body>` and other elements
-   * when showing an offcanvas to the user.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   */
-  function setOffCanvasScrollbar(self) {
-    const { element } = self;
-    const { clientHeight, scrollHeight } = getDocumentElement(element);
-    setScrollbar(element, clientHeight !== scrollHeight);
-  }
-
-  /**
-   * Toggles on/off the `click` event listeners.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   * @param {boolean=} add when *true*, listeners are added
-   */
-  function toggleOffcanvasEvents(self, add) {
-    const action = add ? addListener : removeListener;
-    self.triggers.forEach((btn) => action(btn, mouseclickEvent, offcanvasTriggerHandler));
-  }
-
-  /**
-   * Toggles on/off the listeners of the events that close the offcanvas.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   * @param {boolean=} add when *true* listeners are added
-   */
-  function toggleOffCanvasDismiss(self, add) {
-    const action = add ? addListener : removeListener;
-    const doc = getDocument(self.element);
-    action(doc, keydownEvent, offcanvasKeyDismissHandler);
-    action(doc, mouseclickEvent, offcanvasDismissHandler);
-  }
-
-  /**
-   * Executes before showing the offcanvas.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   */
-  function beforeOffcanvasShow(self) {
-    const { element, options } = self;
-
-    /* istanbul ignore else */
-    if (!options.scroll) {
-      setOffCanvasScrollbar(self);
-      setElementStyle(getDocumentBody(element), { overflow: 'hidden' });
-    }
-
-    addClass(element, offcanvasTogglingClass);
-    addClass(element, showClass);
-    setElementStyle(element, { visibility: 'visible' });
-
-    emulateTransitionEnd(element, () => showOffcanvasComplete(self));
-  }
-
-  /**
-   * Executes before hiding the offcanvas.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   * @param {Function=} callback the hide callback
-   */
-  function beforeOffcanvasHide(self, callback) {
-    const { element, options } = self;
-    const currentOpen = getCurrentOpen(element);
-
-    element.blur();
-
-    if (!currentOpen && options.backdrop && hasClass(overlay, showClass)) {
-      hideOverlay();
-      emulateTransitionEnd(overlay, () => hideOffcanvasComplete(self, callback));
-    } else hideOffcanvasComplete(self, callback);
-  }
-
-  // OFFCANVAS EVENT HANDLERS
-  // ========================
-  /**
-   * Handles the `click` event listeners.
-   *
-   * @this {HTMLElement}
-   * @param {MouseEvent} e the `Event` object
-   */
-  function offcanvasTriggerHandler(e) {
-    const trigger = closest(this, offcanvasToggleSelector);
-    const element = trigger && getTargetElement(trigger);
-    const self = element && getOffcanvasInstance(element);
-
-    /* istanbul ignore else */
-    if (self) {
-      self.relatedTarget = trigger;
-      self.toggle();
-      /* istanbul ignore else */
-      if (trigger && trigger.tagName === 'A') {
-        e.preventDefault();
-      }
-    }
-  }
-
-  /**
-   * Handles the event listeners that close the offcanvas.
-   *
-   * @param {MouseEvent} e the `Event` object
-   */
-  function offcanvasDismissHandler(e) {
-    const { target } = e;
-    const element = querySelector(offcanvasActiveSelector, getDocument(target));
-    const offCanvasDismiss = querySelector(offcanvasDismissSelector, element);
-    const self = getOffcanvasInstance(element);
-
-    /* istanbul ignore next: must have a filter */
-    if (!self) return;
-
-    const { options, triggers } = self;
-    const { backdrop } = options;
-    const trigger = closest(target, offcanvasToggleSelector);
-    const selection = getDocument(element).getSelection();
-
-    if (overlay.contains(target) && backdrop === 'static') return;
-
-    /* istanbul ignore else */
-    if (!(selection && selection.toString().length)
-      && ((!element.contains(target) && backdrop
-      && /* istanbul ignore next */(!trigger || triggers.includes(target)))
-      || (offCanvasDismiss && offCanvasDismiss.contains(target)))) {
-      self.relatedTarget = offCanvasDismiss && offCanvasDismiss.contains(target)
-        ? offCanvasDismiss : null;
-      self.hide();
-    }
-
-    /* istanbul ignore next */
-    if (trigger && trigger.tagName === 'A') e.preventDefault();
-  }
-
-  /**
-   * Handles the `keydown` event listener for offcanvas
-   * to hide it when user type the `ESC` key.
-   *
-   * @param {KeyboardEvent} e the `Event` object
-   */
-  function offcanvasKeyDismissHandler({ code, target }) {
-    const element = querySelector(offcanvasActiveSelector, getDocument(target));
-
-    const self = getOffcanvasInstance(element);
-
-    /* istanbul ignore next: must filter */
-    if (!self) return;
-
-    /* istanbul ignore else */
-    if (self.options.keyboard && code === keyEscape) {
-      self.relatedTarget = null;
-      self.hide();
-    }
-  }
-
-  /**
-   * Handles the `transitionend` when showing the offcanvas.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   */
-  function showOffcanvasComplete(self) {
-    const { element } = self;
-    removeClass(element, offcanvasTogglingClass);
-
-    removeAttribute(element, ariaHidden);
-    setAttribute(element, ariaModal, 'true');
-    setAttribute(element, 'role', 'dialog');
-
-    dispatchEvent(element, shownOffcanvasEvent);
-
-    toggleOffCanvasDismiss(self, true);
-    focus(element);
-  }
-
-  /**
-   * Handles the `transitionend` when hiding the offcanvas.
-   *
-   * @param {Offcanvas} self the `Offcanvas` instance
-   * @param {Function} callback the hide callback
-   */
-  function hideOffcanvasComplete(self, callback) {
-    const { element, triggers } = self;
-
-    setAttribute(element, ariaHidden, 'true');
-    removeAttribute(element, ariaModal);
-    removeAttribute(element, 'role');
-    setElementStyle(element, { visibility: '' });
-
-    const visibleTrigger = showOffcanvasEvent.relatedTarget || triggers.find((x) => isVisible(x));
-    /* istanbul ignore else */
-    if (visibleTrigger) focus(visibleTrigger);
-
-    removeOverlay(element);
-
-    dispatchEvent(element, hiddenOffcanvasEvent);
-    removeClass(element, offcanvasTogglingClass);
-
-    // must check for open instances
-    if (!getCurrentOpen(element)) {
-      toggleOffCanvasDismiss(self);
-    }
-    // callback
-    if (callback) callback();
-  }
-
-  // OFFCANVAS DEFINITION
-  // ====================
-  /** Returns a new `Offcanvas` instance. */
-  class Offcanvas extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target usually an `.offcanvas` element
-     * @param {BSN.Options.Offcanvas=} config instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-      const self = this;
-
-      // instance element
-      const { element } = self;
-
-      // all the triggering buttons
-      /** @type {HTMLElement[]} */
-      self.triggers = [...querySelectorAll(offcanvasToggleSelector, getDocument(element))]
-        .filter((btn) => getTargetElement(btn) === element);
-
-      // additional instance property
-      /** @type {HTMLBodyElement | HTMLElement} */
-      self.container = getElementContainer(element);
-      /** @type {HTMLElement?} */
-      self.relatedTarget = null;
-
-      // attach event listeners
-      toggleOffcanvasEvents(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return offcanvasComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return offcanvasDefaults; }
-    /* eslint-enable */
-
-    // OFFCANVAS PUBLIC METHODS
-    // ========================
-    /** Shows or hides the offcanvas from the user. */
-    toggle() {
-      const self = this;
-      if (hasClass(self.element, showClass)) self.hide();
-      else self.show();
-    }
-
-    /** Shows the offcanvas to the user. */
-    show() {
-      const self = this;
-      const {
-        element, options, container, relatedTarget,
-      } = self;
-      let overlayDelay = 0;
-
-      if (hasClass(element, showClass)) return;
-
-      showOffcanvasEvent.relatedTarget = relatedTarget;
-      shownOffcanvasEvent.relatedTarget = relatedTarget;
-      dispatchEvent(element, showOffcanvasEvent);
-      if (showOffcanvasEvent.defaultPrevented) return;
-
-      // we elegantly hide any opened modal/offcanvas
-      const currentOpen = getCurrentOpen(element);
-      if (currentOpen && currentOpen !== element) {
-        const this1 = getOffcanvasInstance(currentOpen);
-        const that1 = this1
-          || /* istanbul ignore next */getInstance(currentOpen, 'Modal');
-        that1.hide();
-      }
-
-      if (options.backdrop) {
-        if (!container.contains(overlay)) {
-          appendOverlay(container, true);
-        } else {
-          toggleOverlayType();
-        }
-
-        overlayDelay = getElementTransitionDuration(overlay);
-        showOverlay();
-
-        setTimeout(() => beforeOffcanvasShow(self), overlayDelay);
-      } else {
-        beforeOffcanvasShow(self);
-        /* istanbul ignore else */
-        if (currentOpen && hasClass(overlay, showClass)) {
-          hideOverlay();
-        }
-      }
-    }
-
-    /**
-     * Hides the offcanvas from the user.
-     * @param {Function=} callback when `true` it will skip animation
-     */
-    hide(callback) {
-      const self = this;
-      const { element, relatedTarget } = self;
-
-      if (!hasClass(element, showClass)) return;
-
-      hideOffcanvasEvent.relatedTarget = relatedTarget;
-      hiddenOffcanvasEvent.relatedTarget = relatedTarget;
-      dispatchEvent(element, hideOffcanvasEvent);
-      if (hideOffcanvasEvent.defaultPrevented) return;
-
-      addClass(element, offcanvasTogglingClass);
-      removeClass(element, showClass);
-
-      if (!callback) {
-        emulateTransitionEnd(element, () => beforeOffcanvasHide(self, callback));
-      } else beforeOffcanvasHide(self, callback);
-    }
-
-    /** Removes the `Offcanvas` from the target element. */
-    dispose() {
-      const self = this;
-      toggleOffcanvasEvents(self);
-      self.hide(() => super.dispose());
-    }
-  }
-
-  ObjectAssign(Offcanvas, {
-    selector: offcanvasSelector,
-    init: offcanvasInitCallback,
-    getInstance: getOffcanvasInstance,
-  });
-
-  /** @type {string} */
-  const popoverString = 'popover';
-
-  /** @type {string} */
-  const popoverComponent = 'Popover';
-
-  /** @type {string} */
-  const tooltipString = 'tooltip';
-
-  /**
-   * Returns a template for Popover / Tooltip.
-   *
-   * @param {string} tipType the expected markup type
-   * @returns {string} the template markup
-   */
-  function getTipTemplate(tipType) {
-    const isTooltip = tipType === tooltipString;
-    const bodyClass = isTooltip ? `${tipType}-inner` : `${tipType}-body`;
-    const header = !isTooltip ? `<h3 class="${tipType}-header"></h3>` : '';
-    const arrow = `<div class="${tipType}-arrow"></div>`;
-    const body = `<div class="${bodyClass}"></div>`;
-    return `<div class="${tipType}" role="${tooltipString}">${header + arrow + body}</div>`;
-  }
-
-  /**
-   * Checks if an element is an `<svg>` (or any type of SVG element),
-   * `<img>` or `<video>`.
-   *
-   * *Tooltip* / *Popover* works different with media elements.
-   * @param {any} element the target element
-   * @returns {boolean} the query result
-   */
-
-  const isMedia = (element) => (
-    element
-    && element.nodeType === 1
-    && ['SVG', 'Image', 'Video'].some((s) => element.constructor.name.includes(s))) || false;
-
-  /**
-   * Returns an `{x,y}` object with the target
-   * `HTMLElement` / `Node` scroll position.
-   *
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {HTMLElement | Window} element target node / element
-   * @returns {{x: number, y: number}} the scroll tuple
-   */
-  function getNodeScroll(element) {
-    const isWin = 'scrollX' in element;
-    const x = isWin ? element.scrollX : element.scrollLeft;
-    const y = isWin ? element.scrollY : element.scrollTop;
-
-    return { x, y };
-  }
-
-  /**
-   * Checks if a target `HTMLElement` is affected by scale.
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {HTMLElement} element target
-   * @returns {boolean} the query result
-   */
-  function isScaledElement(element) {
-    if (!element || !isHTMLElement(element)) return false;
-    const { width, height } = getBoundingClientRect(element);
-    const { offsetWidth, offsetHeight } = element;
-    return Math.round(width) !== offsetWidth
-      || Math.round(height) !== offsetHeight;
-  }
-
-  /**
-   * Returns the rect relative to an offset parent.
-   * @see https://github.com/floating-ui/floating-ui
-   *
-   * @param {HTMLElement} element target
-   * @param {ParentNode | Window} offsetParent the container / offset parent
-   * @param {{x: number, y: number}} scroll the offsetParent scroll position
-   * @returns {SHORTY.OffsetRect}
-   */
-  function getRectRelativeToOffsetParent(element, offsetParent, scroll) {
-    const isParentAnElement = isHTMLElement(offsetParent);
-    const rect = getBoundingClientRect(element, isParentAnElement && isScaledElement(offsetParent));
-    const offsets = { x: 0, y: 0 };
-
-    /* istanbul ignore next */
-    if (isParentAnElement) {
-      const offsetRect = getBoundingClientRect(offsetParent, true);
-      offsets.x = offsetRect.x + offsetParent.clientLeft;
-      offsets.y = offsetRect.y + offsetParent.clientTop;
-    }
-
-    return {
-      x: rect.left + scroll.x - offsets.x,
-      y: rect.top + scroll.y - offsets.y,
-      width: rect.width,
-      height: rect.height,
-    };
-  }
-
-  /** @type {Record<string, string>} */
-  const tipClassPositions = {
-    top: 'top',
-    bottom: 'bottom',
-    left: 'start',
-    right: 'end',
-  };
-
-  /**
-   * Style popovers and tooltips.
-   * @param {BSN.Tooltip | BSN.Popover} self the `Popover` / `Tooltip` instance
-   * @param {PointerEvent=} e event object
-   */
-  function styleTip(self, e) {
-    const tipClasses = /\b(top|bottom|start|end)+/;
-    const {
-      element, tooltip, options, arrow, offsetParent,
-    } = self;
-    const tipPositions = { ...tipClassPositions };
-
-    const RTL = isRTL(element);
-    if (RTL) {
-      tipPositions.left = 'end';
-      tipPositions.right = 'start';
-    }
-
-    // reset tooltip style (top: 0, left: 0 works best)
-    setElementStyle(tooltip, {
-      // top: '0px', left: '0px', right: '', bottom: '',
-      top: '', left: '', right: '', bottom: '',
-    });
-    const isPopover = self.name === popoverComponent;
-    const {
-      offsetWidth: tipWidth, offsetHeight: tipHeight,
-    } = tooltip;
-    const {
-      clientWidth: htmlcw, clientHeight: htmlch,
-    } = getDocumentElement(element);
-    const { container } = options;
-    let { placement } = options;
-    const {
-      left: parentLeft, right: parentRight, top: parentTop,
-    } = getBoundingClientRect(container, true);
-    const {
-      clientWidth: parentCWidth, offsetWidth: parentOWidth,
-    } = container;
-    const scrollbarWidth = Math.abs(parentCWidth - parentOWidth);
-    // const tipAbsolute = getElementStyle(tooltip, 'position') === 'absolute';
-    const parentPosition = getElementStyle(container, 'position');
-    // const absoluteParent = parentPosition === 'absolute';
-    const fixedParent = parentPosition === 'fixed';
-    const staticParent = parentPosition === 'static';
-    const stickyParent = parentPosition === 'sticky';
-    const isSticky = stickyParent && parentTop === parseFloat(getElementStyle(container, 'top'));
-    // const absoluteTarget = getElementStyle(element, 'position') === 'absolute';
-    // const stickyFixedParent = ['sticky', 'fixed'].includes(parentPosition);
-    const leftBoundry = RTL && fixedParent ? scrollbarWidth : 0;
-    const rightBoundry = fixedParent ? parentCWidth + parentLeft + (RTL ? scrollbarWidth : 0)
-      : parentCWidth + parentLeft + (htmlcw - parentRight) - 1;
-    const {
-      width: elemWidth,
-      height: elemHeight,
-      left: elemRectLeft,
-      right: elemRectRight,
-      top: elemRectTop,
-    } = getBoundingClientRect(element, true);
-
-    const scroll = getNodeScroll(offsetParent);
-    const { x, y } = getRectRelativeToOffsetParent(element, offsetParent, scroll);
-    // reset arrow style
-    setElementStyle(arrow, {
-      top: '', left: '', right: '', bottom: '',
-    });
-    let topPosition;
-    let leftPosition;
-    let rightPosition;
-    let arrowTop;
-    let arrowLeft;
-    let arrowRight;
-
-    const arrowWidth = arrow.offsetWidth || 0;
-    const arrowHeight = arrow.offsetHeight || 0;
-    const arrowAdjust = arrowWidth / 2;
-
-    // check placement
-    let topExceed = elemRectTop - tipHeight - arrowHeight < 0;
-    let bottomExceed = elemRectTop + tipHeight + elemHeight
-      + arrowHeight >= htmlch;
-    let leftExceed = elemRectLeft - tipWidth - arrowWidth < leftBoundry;
-    let rightExceed = elemRectLeft + tipWidth + elemWidth
-      + arrowWidth >= rightBoundry;
-
-    const horizontal = ['left', 'right'];
-    const vertical = ['top', 'bottom'];
-
-    topExceed = horizontal.includes(placement)
-      ? elemRectTop + elemHeight / 2 - tipHeight / 2 - arrowHeight < 0
-      : topExceed;
-    bottomExceed = horizontal.includes(placement)
-      ? elemRectTop + tipHeight / 2 + elemHeight / 2 + arrowHeight >= htmlch
-      : bottomExceed;
-    leftExceed = vertical.includes(placement)
-      ? elemRectLeft + elemWidth / 2 - tipWidth / 2 < leftBoundry
-      : leftExceed;
-    rightExceed = vertical.includes(placement)
-      ? elemRectLeft + tipWidth / 2 + elemWidth / 2 >= rightBoundry
-      : rightExceed;
-
-    // first remove side positions if both left and right limits are exceeded
-    // we usually fall back to top|bottom
-    placement = (horizontal.includes(placement)) && leftExceed && rightExceed ? 'top' : placement;
-    // second, recompute placement
-    placement = placement === 'top' && topExceed ? 'bottom' : placement;
-    placement = placement === 'bottom' && bottomExceed ? 'top' : placement;
-    placement = placement === 'left' && leftExceed ? 'right' : placement;
-    placement = placement === 'right' && rightExceed ? 'left' : placement;
-
-    // update tooltip/popover class
-    if (!tooltip.className.includes(placement)) {
-      tooltip.className = tooltip.className.replace(tipClasses, tipPositions[placement]);
-    }
-
-    // compute tooltip / popover coordinates
-    /* istanbul ignore else */
-    if (horizontal.includes(placement)) { // secondary|side positions
-      if (placement === 'left') { // LEFT
-        leftPosition = x - tipWidth - (isPopover ? arrowWidth : 0);
-      } else { // RIGHT
-        leftPosition = x + elemWidth + (isPopover ? arrowWidth : 0);
-      }
-
-      // adjust top and arrow
-      if (topExceed) {
-        topPosition = y;
-        topPosition += (isSticky ? -parentTop - scroll.y : 0);
-
-        arrowTop = elemHeight / 2 - arrowWidth;
-      } else if (bottomExceed) {
-        topPosition = y - tipHeight + elemHeight;
-        topPosition += (isSticky ? -parentTop - scroll.y : 0);
-
-        arrowTop = tipHeight - elemHeight / 2 - arrowWidth;
-      } else {
-        topPosition = y - tipHeight / 2 + elemHeight / 2;
-        topPosition += (isSticky ? -parentTop - scroll.y : 0);
-
-        arrowTop = tipHeight / 2 - arrowHeight / 2;
-      }
-    } else if (vertical.includes(placement)) {
-      if (e && isMedia(element)) {
-        let eX = 0;
-        let eY = 0;
-        if (staticParent) {
-          eX = e.pageX;
-          eY = e.pageY;
-        } else { // fixedParent | stickyParent
-          eX = e.clientX - parentLeft + (fixedParent ? scroll.x : 0);
-          eY = e.clientY - parentTop + (fixedParent ? scroll.y : 0);
-        }
-
-        // some weird RTL bug
-        eX -= RTL && fixedParent && scrollbarWidth ? scrollbarWidth : 0;
-
-        if (placement === 'top') {
-          topPosition = eY - tipHeight - arrowWidth;
-        } else {
-          topPosition = eY + arrowWidth;
-        }
-
-        // adjust (left | right) and also the arrow
-        if (e.clientX - tipWidth / 2 < leftBoundry) {
-          leftPosition = 0;
-          arrowLeft = eX - arrowAdjust;
-        } else if (e.clientX + tipWidth / 2 > rightBoundry) {
-          leftPosition = 'auto';
-          rightPosition = 0;
-          arrowRight = rightBoundry - eX - arrowAdjust;
-          arrowRight -= fixedParent ? parentLeft + (RTL ? scrollbarWidth : 0) : 0;
-
-        // normal top/bottom
-        } else {
-          leftPosition = eX - tipWidth / 2;
-          arrowLeft = tipWidth / 2 - arrowAdjust;
-        }
-      } else {
-        if (placement === 'top') {
-          topPosition = y - tipHeight - (isPopover ? arrowHeight : 0);
-        } else { // BOTTOM
-          topPosition = y + elemHeight + (isPopover ? arrowHeight : 0);
-        }
-
-        // adjust left | right and also the arrow
-        if (leftExceed) {
-          leftPosition = 0;
-          arrowLeft = x + elemWidth / 2 - arrowAdjust;
-        } else if (rightExceed) {
-          leftPosition = 'auto';
-          rightPosition = 0;
-          arrowRight = elemWidth / 2 + rightBoundry - elemRectRight - arrowAdjust;
-        } else {
-          leftPosition = x - tipWidth / 2 + elemWidth / 2;
-          arrowLeft = tipWidth / 2 - arrowAdjust;
-        }
-      }
-    }
-
-    // apply style to tooltip/popover
-    setElementStyle(tooltip, {
-      top: `${topPosition}px`,
-      left: leftPosition === 'auto' ? leftPosition : `${leftPosition}px`,
-      right: rightPosition !== undefined ? `${rightPosition}px` : '',
-    });
-
-    // update arrow placement
-    /* istanbul ignore else */
-    if (isHTMLElement(arrow)) {
-      if (arrowTop !== undefined) {
-        arrow.style.top = `${arrowTop}px`;
-      }
-      if (arrowLeft !== undefined) {
-        arrow.style.left = `${arrowLeft}px`;
-      } else if (arrowRight !== undefined) {
-        arrow.style.right = `${arrowRight}px`;
-      }
-    }
-  }
-
-  const tooltipDefaults = {
-    /** @type {string} */
-    template: getTipTemplate(tooltipString),
-    /** @type {string?} */
-    title: null, // string
-    /** @type {string?} */
-    customClass: null, // string | null
-    /** @type {string} */
-    trigger: 'hover focus',
-    /** @type {string?} */
-    placement: 'top', // string
-    /** @type {((c:string)=>string)?} */
-    sanitizeFn: null, // function
-    /** @type {boolean} */
-    animation: true, // bool
-    /** @type {number} */
-    delay: 200, // number
-    /** @type {HTMLElement?} */
-    container: null,
-  };
-
-  /**
-   * A global namespace for aria-describedby.
-   * @type {string}
-   */
-  const ariaDescribedBy = 'aria-describedby';
-
-  /**
-   * A global namespace for `mousedown` event.
-   * @type {string}
-   */
-  const mousedownEvent = 'mousedown';
-
-  /**
-   * A global namespace for `mousemove` event.
-   * @type {string}
-   */
-  const mousemoveEvent = 'mousemove';
-
-  /**
-   * A global namespace for `focusin` event.
-   * @type {string}
-   */
-  const focusinEvent = 'focusin';
-
-  /**
-   * A global namespace for `focusout` event.
-   * @type {string}
-   */
-  const focusoutEvent = 'focusout';
-
-  /**
-   * A global namespace for `hover` event.
-   * @type {string}
-   */
-  const mousehoverEvent = 'hover';
-
-  /**
-   * A global namespace for `touchstart` event.
-   * @type {string}
-   */
-  const touchstartEvent = 'touchstart';
-
-  let elementUID = 0;
-  let elementMapUID = 0;
-  const elementIDMap = new Map();
-
-  /**
-   * Returns a unique identifier for popover, tooltip, scrollspy.
-   *
-   * @param {HTMLElement} element target element
-   * @param {string=} key predefined key
-   * @returns {number} an existing or new unique ID
-   */
-  function getUID(element, key) {
-    let result = key ? elementUID : elementMapUID;
-
-    if (key) {
-      const elID = getUID(element);
-      const elMap = elementIDMap.get(elID) || new Map();
-      if (!elementIDMap.has(elID)) {
-        elementIDMap.set(elID, elMap);
-      }
-      if (!elMap.has(key)) {
-        elMap.set(key, result);
-        elementUID += 1;
-      } else result = elMap.get(key);
-    } else {
-      const elkey = element.id || element;
-
-      if (!elementIDMap.has(elkey)) {
-        elementIDMap.set(elkey, result);
-        elementMapUID += 1;
-      } else result = elementIDMap.get(elkey);
-    }
-    return result;
-  }
-
-  /**
-   * Checks if an object is a `Function`.
-   *
-   * @param {any} fn the target object
-   * @returns {boolean} the query result
-   */
-  const isFunction = (fn) => (fn && fn.constructor.name === 'Function') || false;
-
-  const { userAgentData: uaDATA } = navigator;
-
-  /**
-   * A global namespace for `userAgentData` object.
-   */
-  const userAgentData = uaDATA;
-
-  const { userAgent: userAgentString } = navigator;
-
-  /**
-   * A global namespace for `navigator.userAgent` string.
-   */
-  const userAgent = userAgentString;
-
-  const appleBrands = /(iPhone|iPod|iPad)/;
-
-  /**
-   * A global `boolean` for Apple browsers.
-   * @type {boolean}
-   */
-  const isApple = userAgentData ? userAgentData.brands.some((x) => appleBrands.test(x.brand))
-    : /* istanbul ignore next */appleBrands.test(userAgent);
-
-  /**
-   * Global namespace for `data-bs-title` attribute.
-   */
-  const dataOriginalTitle = 'data-original-title';
-
-  /** @type {string} */
-  const tooltipComponent = 'Tooltip';
-
-  /**
-   * Checks if an object is a `NodeList`.
-   * => equivalent to `object instanceof NodeList`
-   *
-   * @param {any} object the target object
-   * @returns {boolean} the query result
-   */
-  const isNodeList = (object) => (object && object.constructor.name === 'NodeList') || false;
-
-  /**
-   * Shortcut for `typeof SOMETHING === "string"`.
-   *
-   * @param  {any} str input value
-   * @returns {boolean} the query result
-   */
-  const isString = (str) => typeof str === 'string';
-
-  /**
-   * Shortcut for `Array.isArray()` static method.
-   *
-   * @param  {any} arr array-like iterable object
-   * @returns {boolean} the query result
-   */
-  const isArray = (arr) => Array.isArray(arr);
-
-  /**
-   * Append an existing `Element` to Popover / Tooltip component or HTML
-   * markup string to be parsed & sanitized to be used as popover / tooltip content.
-   *
-   * @param {HTMLElement} element target
-   * @param {Node | string} content the `Element` to append / string
-   * @param {ReturnType<any>} sanitizeFn a function to sanitize string content
-   */
-  function setHtml(element, content, sanitizeFn) {
-    /* istanbul ignore next */
-    if (!isHTMLElement(element) || (isString(content) && !content.length)) return;
-
-    /* istanbul ignore else */
-    if (isString(content)) {
-      let dirty = content.trim(); // fixing #233
-      if (isFunction(sanitizeFn)) dirty = sanitizeFn(dirty);
-
-      const win = getWindow(element);
-      const domParser = new win.DOMParser();
-      const tempDocument = domParser.parseFromString(dirty, 'text/html');
-      element.append(...[...tempDocument.body.childNodes]);
-    } else if (isHTMLElement(content)) {
-      element.append(content);
-    } else if (isNodeList(content)
-      || (isArray(content) && content.every(isNode))) {
-      element.append(...[...content]);
-    }
-  }
-
-  /**
-   * Creates a new tooltip / popover.
-   *
-   * @param {BSN.Popover | BSN.Tooltip} self the `Tooltip` / `Popover` instance
-   */
-  function createTip(self) {
-    const { id, element, options } = self;
-    const {
-      animation, customClass, sanitizeFn, placement, dismissible,
-      title, content, template, btnClose,
-    } = options;
-    const isTooltip = self.name === tooltipComponent;
-    const tipString = isTooltip ? tooltipString : popoverString;
-    const tipPositions = { ...tipClassPositions };
-    let titleParts = [];
-    let contentParts = [];
-
-    if (isRTL(element)) {
-      tipPositions.left = 'end';
-      tipPositions.right = 'start';
-    }
-
-    // set initial popover class
-    const placementClass = `bs-${tipString}-${tipPositions[placement]}`;
-
-    // load template
-    /** @type {HTMLElement?} */
-    let tooltipTemplate;
-    if (isHTMLElement(template)) {
-      tooltipTemplate = template;
-    } else {
-      const htmlMarkup = createElement('div');
-      setHtml(htmlMarkup, template, sanitizeFn);
-      tooltipTemplate = htmlMarkup.firstChild;
-    }
-
-    // set popover markup
-    self.tooltip = isHTMLElement(tooltipTemplate) && tooltipTemplate.cloneNode(true);
-
-    const { tooltip } = self;
-
-    // set id and role attributes
-    setAttribute(tooltip, 'id', id);
-    setAttribute(tooltip, 'role', tooltipString);
-
-    const bodyClass = isTooltip ? `${tooltipString}-inner` : `${popoverString}-body`;
-    const tooltipHeader = isTooltip ? null : querySelector(`.${popoverString}-header`, tooltip);
-    const tooltipBody = querySelector(`.${bodyClass}`, tooltip);
-
-    // set arrow and enable access for styleTip
-    self.arrow = querySelector(`.${tipString}-arrow`, tooltip);
-    const { arrow } = self;
-
-    if (isHTMLElement(title)) titleParts = [title.cloneNode(true)];
-    else {
-      const tempTitle = createElement('div');
-      setHtml(tempTitle, title, sanitizeFn);
-      titleParts = [...[...tempTitle.childNodes]];
-    }
-
-    if (isHTMLElement(content)) contentParts = [content.cloneNode(true)];
-    else {
-      const tempContent = createElement('div');
-      setHtml(tempContent, content, sanitizeFn);
-      contentParts = [...[...tempContent.childNodes]];
-    }
-
-    // set dismissible button
-    if (dismissible) {
-      if (title) {
-        if (isHTMLElement(btnClose)) titleParts = [...titleParts, btnClose.cloneNode(true)];
-        else {
-          const tempBtn = createElement('div');
-          setHtml(tempBtn, btnClose, sanitizeFn);
-          titleParts = [...titleParts, tempBtn.firstChild];
-        }
-      } else {
-        /* istanbul ignore else */
-        if (tooltipHeader) tooltipHeader.remove();
-        if (isHTMLElement(btnClose)) contentParts = [...contentParts, btnClose.cloneNode(true)];
-        else {
-          const tempBtn = createElement('div');
-          setHtml(tempBtn, btnClose, sanitizeFn);
-          contentParts = [...contentParts, tempBtn.firstChild];
-        }
-      }
-    }
-
-    // fill the template with content from options / data attributes
-    // also sanitize title && content
-    /* istanbul ignore else */
-    if (!isTooltip) {
-      /* istanbul ignore else */
-      if (title && tooltipHeader) setHtml(tooltipHeader, titleParts, sanitizeFn);
-      /* istanbul ignore else */
-      if (content && tooltipBody) setHtml(tooltipBody, contentParts, sanitizeFn);
-      // set btn
-      self.btn = querySelector('.btn-close', tooltip);
-    } else if (title && tooltipBody) setHtml(tooltipBody, title, sanitizeFn);
-
-    // Bootstrap 5.2.x
-    addClass(tooltip, 'position-absolute');
-    addClass(arrow, 'position-absolute');
-
-    // set popover animation and placement
-    /* istanbul ignore else */
-    if (!hasClass(tooltip, tipString)) addClass(tooltip, tipString);
-    /* istanbul ignore else */
-    if (animation && !hasClass(tooltip, fadeClass)) addClass(tooltip, fadeClass);
-    /* istanbul ignore else */
-    if (customClass && !hasClass(tooltip, customClass)) {
-      addClass(tooltip, customClass);
-    }
-    /* istanbul ignore else */
-    if (!hasClass(tooltip, placementClass)) addClass(tooltip, placementClass);
-  }
-
-  /**
-   * @param {HTMLElement} tip target
-   * @param {ParentNode} container parent container
-   * @returns {boolean}
-   */
-  function isVisibleTip(tip, container) {
-    return isHTMLElement(tip) && container.contains(tip);
-  }
-
-  /* Native JavaScript for Bootstrap 5 | Tooltip
-  ---------------------------------------------- */
-
-  // TOOLTIP PRIVATE GC
-  // ==================
-  const tooltipSelector = `[${dataBsToggle}="${tooltipString}"],[data-tip="${tooltipString}"]`;
-  const titleAttr = 'title';
-
-  /**
-   * Static method which returns an existing `Tooltip` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Tooltip>}
-   */
-  let getTooltipInstance = (element) => getInstance(element, tooltipComponent);
-
-  /**
-   * A `Tooltip` initialization callback.
-   * @type {BSN.InitCallback<Tooltip>}
-   */
-  const tooltipInitCallback = (element) => new Tooltip(element);
-
-  // TOOLTIP PRIVATE METHODS
-  // =======================
-  /**
-   * Removes the tooltip from the DOM.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   */
-  function removeTooltip(self) {
-    const { element, tooltip } = self;
-    removeAttribute(element, ariaDescribedBy);
-    tooltip.remove();
-  }
-
-  /**
-   * Executes after the instance has been disposed.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   * @param {Function=} callback the parent dispose callback
-   */
-  function disposeTooltipComplete(self, callback) {
-    const { element } = self;
-    toggleTooltipHandlers(self);
-
-    /* istanbul ignore else */
-    if (hasAttribute(element, dataOriginalTitle) && self.name === tooltipComponent) {
-      toggleTooltipTitle(self);
-    }
-    /* istanbul ignore else */
-    if (callback) callback();
-  }
-
-  /**
-   * Toggles on/off the special `Tooltip` event listeners.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   * @param {boolean=} add when `true`, event listeners are added
-   */
-  function toggleTooltipAction(self, add) {
-    const action = add ? addListener : removeListener;
-    const { element } = self;
-
-    action(getDocument(element), touchstartEvent, self.handleTouch, passiveHandler);
-
-    /* istanbul ignore else */
-    if (!isMedia(element)) {
-      [scrollEvent, resizeEvent].forEach((ev) => {
-        action(getWindow(element), ev, self.update, passiveHandler);
-      });
-    }
-  }
-
-  /**
-   * Executes after the tooltip was shown to the user.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   */
-  function tooltipShownAction(self) {
-    const { element } = self;
-    const shownTooltipEvent = OriginalEvent(`shown.bs.${toLowerCase(self.name)}`);
-
-    toggleTooltipAction(self, true);
-    dispatchEvent(element, shownTooltipEvent);
-    Timer.clear(element, 'in');
-  }
-
-  /**
-   * Executes after the tooltip was hidden to the user.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   * @param {Function=} callback the dispose callback
-   */
-  function tooltipHiddenAction(self, callback) {
-    const { element } = self;
-    const hiddenTooltipEvent = OriginalEvent(`hidden.bs.${toLowerCase(self.name)}`);
-
-    toggleTooltipAction(self);
-    removeTooltip(self);
-    dispatchEvent(element, hiddenTooltipEvent);
-    if (isFunction(callback)) callback();
-    Timer.clear(element, 'out');
-  }
-
-  /**
-   * Toggles on/off the `Tooltip` event listeners.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   * @param {boolean=} add when `true`, event listeners are added
-   */
-  function toggleTooltipHandlers(self, add) {
-    const action = add ? addListener : removeListener;
-    // btn is only for dismissible popover
-    const { element, options, btn } = self;
-    const { trigger, dismissible } = options;
-
-    if (trigger.includes('manual')) return;
-
-    self.enabled = !!add;
-
-    /** @type {string[]} */
-    const triggerOptions = trigger.split(' ');
-    const elemIsMedia = isMedia(element);
-
-    if (elemIsMedia) {
-      action(element, mousemoveEvent, self.update, passiveHandler);
-    }
-
-    triggerOptions.forEach((tr) => {
-      /* istanbul ignore else */
-      if (elemIsMedia || tr === mousehoverEvent) {
-        action(element, mousedownEvent, self.show);
-        action(element, mouseenterEvent, self.show);
-
-        /* istanbul ignore else */
-        if (dismissible && btn) {
-          action(btn, mouseclickEvent, self.hide);
-        } else {
-          action(element, mouseleaveEvent, self.hide);
-          action(getDocument(element), touchstartEvent, self.handleTouch, passiveHandler);
-        }
-      } else if (tr === mouseclickEvent) {
-        action(element, tr, (!dismissible ? self.toggle : self.show));
-      } else if (tr === focusEvent) {
-        action(element, focusinEvent, self.show);
-        /* istanbul ignore else */
-        if (!dismissible) action(element, focusoutEvent, self.hide);
-        /* istanbul ignore else */
-        if (isApple) {
-          action(element, mouseclickEvent, () => focus(element));
-        }
-      }
-    });
-  }
-
-  /**
-   * Toggles on/off the `Tooltip` event listeners that hide/update the tooltip.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   * @param {boolean=} add when `true`, event listeners are added
-   */
-  function toggleTooltipOpenHandlers(self, add) {
-    const action = add ? addListener : removeListener;
-    const { element, options, offsetParent } = self;
-    const { container } = options;
-    const { offsetHeight, scrollHeight } = container;
-    const parentModal = closest(element, `.${modalString}`);
-    const parentOffcanvas = closest(element, `.${offcanvasString}`);
-
-    /* istanbul ignore else */
-    if (!isMedia(element)) {
-      const win = getWindow(element);
-      const overflow = offsetHeight !== scrollHeight;
-      const scrollTarget = overflow || offsetParent !== win ? container : win;
-      action(win, resizeEvent, self.update, passiveHandler);
-      action(scrollTarget, scrollEvent, self.update, passiveHandler);
-    }
-
-    // dismiss tooltips inside modal / offcanvas
-    if (parentModal) action(parentModal, `hide.bs.${modalString}`, self.hide);
-    if (parentOffcanvas) action(parentOffcanvas, `hide.bs.${offcanvasString}`, self.hide);
-  }
-
-  /**
-   * Toggles the `title` and `data-original-title` attributes.
-   *
-   * @param {Tooltip} self the `Tooltip` instance
-   * @param {string=} content when `true`, event listeners are added
-   */
-  function toggleTooltipTitle(self, content) {
-    // [0 - add, 1 - remove] | [0 - remove, 1 - add]
-    const titleAtt = [dataOriginalTitle, titleAttr];
-    const { element } = self;
-
-    setAttribute(element, titleAtt[content ? 0 : 1],
-      (content || getAttribute(element, titleAtt[0])));
-    removeAttribute(element, titleAtt[content ? 1 : 0]);
-  }
-
-  // TOOLTIP DEFINITION
-  // ==================
-  /** Creates a new `Tooltip` instance. */
-  class Tooltip extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target the target element
-     * @param {BSN.Options.Tooltip=} config the instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-
-      // bind
-      const self = this;
-      const { element } = self;
-      const isTooltip = self.name === tooltipComponent;
-      const tipString = isTooltip ? tooltipString : popoverString;
-      const tipComponent = isTooltip ? tooltipComponent : popoverComponent;
-
-      /* istanbul ignore next: this is to set Popover too */
-      getTooltipInstance = (elem) => getInstance(elem, tipComponent);
-
-      // additional properties
-      /** @type {any} */
-      self.tooltip = {};
-      if (!isTooltip) {
-        /** @type {any?} */
-        self.btn = null;
-      }
-      /** @type {any} */
-      self.arrow = {};
-      /** @type {any} */
-      self.offsetParent = {};
-      /** @type {boolean} */
-      self.enabled = true;
-      /** @type {string} Set unique ID for `aria-describedby`. */
-      self.id = `${tipString}-${getUID(element, tipString)}`;
-
-      // instance options
-      const { options } = self;
-
-      // invalidate
-      if ((!options.title && isTooltip) || (!isTooltip && !options.content)) {
-        // throw Error(`${this.name} Error: target has no content set.`);
-        return;
-      }
-
-      const container = querySelector(options.container, getDocument(element));
-      const idealContainer = getElementContainer(element);
-
-      // bypass container option when its position is static/relative
-      self.options.container = !container || (container
-        && ['static', 'relative'].includes(getElementStyle(container, 'position')))
-        ? idealContainer
-        : /* istanbul ignore next */container || getDocumentBody(element);
-
-      // reset default options
-      tooltipDefaults[titleAttr] = null;
-
-      // all functions bind
-      self.handleTouch = self.handleTouch.bind(self);
-      self.update = self.update.bind(self);
-      self.show = self.show.bind(self);
-      self.hide = self.hide.bind(self);
-      self.toggle = self.toggle.bind(self);
-
-      // set title attributes and add event listeners
-      /* istanbul ignore else */
-      if (hasAttribute(element, titleAttr) && isTooltip) {
-        toggleTooltipTitle(self, options.title);
-      }
-
-      // create tooltip here
-      createTip(self);
-
-      // attach events
-      toggleTooltipHandlers(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return tooltipComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return tooltipDefaults; }
-    /* eslint-enable */
-
-    // TOOLTIP PUBLIC METHODS
-    // ======================
-    /**
-     * Shows the tooltip.
-     *
-     * @param {Event=} e the `Event` object
-     * @this {Tooltip}
-     */
-    show(e) {
-      const self = this;
-      const {
-        options, tooltip, element, id,
-      } = self;
-      const { container, animation } = options;
-      const outTimer = Timer.get(element, 'out');
-
-      Timer.clear(element, 'out');
-
-      if (tooltip && !outTimer && !isVisibleTip(tooltip, container)) {
-        Timer.set(element, () => {
-          const showTooltipEvent = OriginalEvent(`show.bs.${toLowerCase(self.name)}`);
-          dispatchEvent(element, showTooltipEvent);
-          if (showTooltipEvent.defaultPrevented) return;
-
-          // append to container
-          container.append(tooltip);
-          setAttribute(element, ariaDescribedBy, `#${id}`);
-          // set offsetParent
-          self.offsetParent = getElementContainer(tooltip, true);
-
-          self.update(e);
-          toggleTooltipOpenHandlers(self, true);
-
-          /* istanbul ignore else */
-          if (!hasClass(tooltip, showClass)) addClass(tooltip, showClass);
-          /* istanbul ignore else */
-          if (animation) emulateTransitionEnd(tooltip, () => tooltipShownAction(self));
-          else tooltipShownAction(self);
-        }, 17, 'in');
-      }
-    }
-
-    /**
-     * Hides the tooltip.
-     *
-     * @this {Tooltip} the Tooltip instance
-     * @param {Function=} callback the dispose callback
-     */
-    hide(callback) {
-      const self = this;
-      const { options, tooltip, element } = self;
-      const { container, animation, delay } = options;
-
-      Timer.clear(element, 'in');
-
-      /* istanbul ignore else */
-      if (tooltip && isVisibleTip(tooltip, container)) {
-        Timer.set(element, () => {
-          const hideTooltipEvent = OriginalEvent(`hide.bs.${toLowerCase(self.name)}`);
-          dispatchEvent(element, hideTooltipEvent);
-
-          if (hideTooltipEvent.defaultPrevented) return;
-
-          removeClass(tooltip, showClass);
-          toggleTooltipOpenHandlers(self);
-
-          /* istanbul ignore else */
-          if (animation) emulateTransitionEnd(tooltip, () => tooltipHiddenAction(self, callback));
-          else tooltipHiddenAction(self, callback);
-        }, delay + 17, 'out');
-      }
-    }
-
-    /**
-     * Updates the tooltip position.
-     *
-     * @param {Event=} e the `Event` object
-     * @this {Tooltip} the `Tooltip` instance
-     */
-    update(e) {
-      styleTip(this, e);
-    }
-
-    /**
-     * Toggles the tooltip visibility.
-     *
-     * @param {Event=} e the `Event` object
-     * @this {Tooltip} the instance
-     */
-    toggle(e) {
-      const self = this;
-      const { tooltip, options } = self;
-
-      if (!isVisibleTip(tooltip, options.container)) self.show(e);
-      else self.hide();
-    }
-
-    /** Enables the tooltip. */
-    enable() {
-      const self = this;
-      const { enabled } = self;
-      /* istanbul ignore else */
-      if (!enabled) {
-        toggleTooltipHandlers(self, true);
-        self.enabled = !enabled;
-      }
-    }
-
-    /** Disables the tooltip. */
-    disable() {
-      const self = this;
-      const {
-        tooltip, options, enabled,
-      } = self;
-      const { animation, container } = options;
-      /* istanbul ignore else */
-      if (enabled) {
-        if (isVisibleTip(tooltip, container) && animation) {
-          self.hide(() => toggleTooltipHandlers(self));
-        } else {
-          toggleTooltipHandlers(self);
-        }
-        self.enabled = !enabled;
-      }
-    }
-
-    /** Toggles the `disabled` property. */
-    toggleEnabled() {
-      const self = this;
-      if (!self.enabled) self.enable();
-      else self.disable();
-    }
-
-    /**
-     * Handles the `touchstart` event listener for `Tooltip`
-     * @this {Tooltip}
-     * @param {TouchEvent} e the `Event` object
-     */
-    handleTouch({ target }) {
-      const { tooltip, element } = this;
-
-      /* istanbul ignore next */
-      if (tooltip.contains(target) || target === element
-        || (target && element.contains(target))) ; else {
-        this.hide();
-      }
-    }
-
-    /** Removes the `Tooltip` from the target element. */
-    dispose() {
-      const self = this;
-      const { tooltip, options } = self;
-      const callback = () => disposeTooltipComplete(self, () => super.dispose());
-
-      if (options.animation && isVisibleTip(tooltip, options.container)) {
-        self.options.delay = 0; // reset delay
-        self.hide(callback);
-      } else {
-        callback();
-      }
-    }
-  }
-
-  ObjectAssign(Tooltip, {
-    selector: tooltipSelector,
-    init: tooltipInitCallback,
-    getInstance: getTooltipInstance,
-    styleTip,
-  });
-
-  /* Native JavaScript for Bootstrap 5 | Popover
-  ---------------------------------------------- */
-
-  // POPOVER PRIVATE GC
-  // ==================
-  const popoverSelector = `[${dataBsToggle}="${popoverString}"],[data-tip="${popoverString}"]`;
-
-  const popoverDefaults = {
-    ...tooltipDefaults,
-    /** @type {string} */
-    template: getTipTemplate(popoverString),
-    /** @type {string} */
-    btnClose: '<button class="btn-close" aria-label="Close"></button>',
-    /** @type {boolean} */
-    dismissible: false,
-    /** @type {string?} */
-    content: null,
-  };
-
-  // POPOVER DEFINITION
-  // ==================
-  /** Returns a new `Popover` instance. */
-  class Popover extends Tooltip {
-    /* eslint-disable -- we want to specify Popover Options */
-    /**
-     * @param {HTMLElement | string} target the target element
-     * @param {BSN.Options.Popover=} config the instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-    }
-    /**
-     * Returns component name string.
-     */ 
-    get name() { return popoverComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return popoverDefaults; }
-    /* eslint-enable */
-
-    /* extend original `show()` */
-    show() {
-      super.show();
-      // btn only exists within dismissible popover
-      const { options, btn } = this;
-      /* istanbul ignore else */
-      if (options.dismissible && btn) setTimeout(() => focus(btn), 17);
-    }
-  }
-
-  /**
-   * Static method which returns an existing `Popover` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Popover>}
-   */
-  const getPopoverInstance = (element) => getInstance(element, popoverComponent);
-
-  /**
-   * A `Popover` initialization callback.
-   * @type {BSN.InitCallback<Popover>}
-   */
-  const popoverInitCallback = (element) => new Popover(element);
-
-  ObjectAssign(Popover, {
-    selector: popoverSelector,
-    init: popoverInitCallback,
-    getInstance: getPopoverInstance,
-    styleTip,
-  });
-
-  /**
-   * Shortcut for `HTMLElement.getElementsByTagName` method. Some `Node` elements
-   * like `ShadowRoot` do not support `getElementsByTagName`.
-   *
-   * @param {string} selector the tag name
-   * @param {ParentNode=} parent optional Element to look into
-   * @return {HTMLCollectionOf<HTMLElement>} the 'HTMLCollection'
-   */
-  function getElementsByTagName(selector, parent) {
-    const lookUp = isNode(parent) ? parent : getDocument();
-    return lookUp.getElementsByTagName(selector);
-  }
-
-  /** @type {string} */
-  const scrollspyString = 'scrollspy';
-
-  /** @type {string} */
-  const scrollspyComponent = 'ScrollSpy';
-
-  /* Native JavaScript for Bootstrap 5 | ScrollSpy
-  ------------------------------------------------ */
-
-  // SCROLLSPY PRIVATE GC
-  // ====================
-  const scrollspySelector = '[data-bs-spy="scroll"]';
-
-  const scrollspyDefaults = {
-    offset: 10,
-    target: null,
-  };
-
-  /**
-   * Static method which returns an existing `ScrollSpy` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<ScrollSpy>}
-   */
-  const getScrollSpyInstance = (element) => getInstance(element, scrollspyComponent);
-
-  /**
-   * A `ScrollSpy` initialization callback.
-   * @type {BSN.InitCallback<ScrollSpy>}
-   */
-  const scrollspyInitCallback = (element) => new ScrollSpy(element);
-
-  // SCROLLSPY CUSTOM EVENT
-  // ======================
-  const activateScrollSpy = OriginalEvent(`activate.bs.${scrollspyString}`);
-
-  // SCROLLSPY PRIVATE METHODS
-  // =========================
-  /**
-   * Update the state of all items.
-   * @param {ScrollSpy} self the `ScrollSpy` instance
-   */
-  function updateSpyTargets(self) {
-    const {
-      target, scrollTarget, options, itemsLength, scrollHeight, element,
-    } = self;
-    const { offset } = options;
-    const isWin = isWindow(scrollTarget);
-
-    const links = target && getElementsByTagName('A', target);
-    const scrollHEIGHT = scrollTarget && getScrollHeight(scrollTarget);
-
-    self.scrollTop = isWin ? scrollTarget.scrollY : scrollTarget.scrollTop;
-
-    // only update items/offsets once or with each mutation
-    /* istanbul ignore else */
-    if (links && (itemsLength !== links.length || scrollHEIGHT !== scrollHeight)) {
-      let href;
-      let targetItem;
-      let rect;
-
-      // reset arrays & update
-      self.items = [];
-      self.offsets = [];
-      self.scrollHeight = scrollHEIGHT;
-      self.maxScroll = self.scrollHeight - getOffsetHeight(self);
-
-      [...links].forEach((link) => {
-        href = getAttribute(link, 'href');
-        targetItem = href && href.charAt(0) === '#' && href.slice(-1) !== '#'
-          && querySelector(href, getDocument(element));
-
-        if (targetItem) {
-          self.items.push(link);
-          rect = getBoundingClientRect(targetItem);
-          self.offsets.push((isWin ? rect.top + self.scrollTop : targetItem.offsetTop) - offset);
-        }
-      });
-      self.itemsLength = self.items.length;
-    }
-  }
-
-  /**
-   * Returns the `scrollHeight` property of the scrolling element.
-   * @param {Node | Window} scrollTarget the `ScrollSpy` instance
-   * @return {number} `scrollTarget` height
-   */
-  function getScrollHeight(scrollTarget) {
-    return isHTMLElement(scrollTarget)
-      ? scrollTarget.scrollHeight
-      : getDocumentElement(scrollTarget).scrollHeight;
-  }
-
-  /**
-   * Returns the height property of the scrolling element.
-   * @param {ScrollSpy} params the `ScrollSpy` instance
-   * @returns {number}
-   */
-  function getOffsetHeight({ element, scrollTarget }) {
-    return (isWindow(scrollTarget))
-      ? scrollTarget.innerHeight
-      : getBoundingClientRect(element).height;
-  }
-
-  /**
-   * Clear all items of the target.
-   * @param {HTMLElement} target a single item
-   */
-  function clear(target) {
-    [...getElementsByTagName('A', target)].forEach((item) => {
-      if (hasClass(item, activeClass)) removeClass(item, activeClass);
-    });
-  }
-
-  /**
-   * Activates a new item.
-   * @param {ScrollSpy} self the `ScrollSpy` instance
-   * @param {HTMLElement} item a single item
-   */
-  function activate(self, item) {
-    const { target, element } = self;
-    clear(target);
-    self.activeItem = item;
-    addClass(item, activeClass);
-
-    // activate all parents
-    const parents = [];
-    let parentItem = item;
-    while (parentItem !== getDocumentBody(element)) {
-      parentItem = parentItem.parentElement;
-      if (hasClass(parentItem, 'nav') || hasClass(parentItem, 'dropdown-menu')) parents.push(parentItem);
-    }
-
-    parents.forEach((menuItem) => {
-      /** @type {HTMLElement?} */
-      const parentLink = menuItem.previousElementSibling;
-
-      /* istanbul ignore else */
-      if (parentLink && !hasClass(parentLink, activeClass)) {
-        addClass(parentLink, activeClass);
-      }
-    });
-
-    // dispatch
-    activateScrollSpy.relatedTarget = item;
-    dispatchEvent(element, activateScrollSpy);
-  }
-
-  /**
-   * Toggles on/off the component event listener.
-   * @param {ScrollSpy} self the `ScrollSpy` instance
-   * @param {boolean=} add when `true`, listener is added
-   */
-  function toggleSpyHandlers(self, add) {
-    const action = add ? addListener : removeListener;
-    action(self.scrollTarget, scrollEvent, self.refresh, passiveHandler);
-  }
-
-  // SCROLLSPY DEFINITION
-  // ====================
-  /** Returns a new `ScrollSpy` instance. */
-  class ScrollSpy extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target the target element
-     * @param {BSN.Options.ScrollSpy=} config the instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-      // bind
-      const self = this;
-
-      // initialization element & options
-      const { element, options } = self;
-
-      // additional properties
-      /** @type {HTMLElement?} */
-      self.target = querySelector(options.target, getDocument(element));
-
-      // invalidate
-      if (!self.target) return;
-
-      // set initial state
-      /** @type {HTMLElement | Window} */
-      self.scrollTarget = element.clientHeight < element.scrollHeight
-        ? element : getWindow(element);
-      /** @type {number} */
-      self.scrollTop = 0;
-      /** @type {number} */
-      self.maxScroll = 0;
-      /** @type {number} */
-      self.scrollHeight = 0;
-      /** @type {HTMLElement?} */
-      self.activeItem = null;
-      /** @type {HTMLElement[]} */
-      self.items = [];
-      /** @type {number} */
-      self.itemsLength = 0;
-      /** @type {number[]} */
-      self.offsets = [];
-
-      // bind events
-      self.refresh = self.refresh.bind(self);
-
-      // add event handlers
-      toggleSpyHandlers(self, true);
-
-      self.refresh();
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */
-    get name() { return scrollspyComponent; }
-    /**
-     * Returns component default options.
-     */
-    get defaults() { return scrollspyDefaults; }
-    /* eslint-enable */
-
-    // SCROLLSPY PUBLIC METHODS
-    // ========================
-    /** Updates all items. */
-    refresh() {
-      const self = this;
-      const { target } = self;
-
-      // check if target is visible and invalidate
-      /* istanbul ignore next */
-      if (target.offsetHeight === 0) return;
-
-      updateSpyTargets(self);
-
-      const {
-        scrollTop, maxScroll, itemsLength, items, activeItem,
-      } = self;
-
-      if (scrollTop >= maxScroll) {
-        const newActiveItem = items[itemsLength - 1];
-
-        /* istanbul ignore else */
-        if (activeItem !== newActiveItem) {
-          activate(self, newActiveItem);
-        }
-        return;
-      }
-
-      const { offsets } = self;
-
-      if (activeItem && scrollTop < offsets[0] && offsets[0] > 0) {
-        self.activeItem = null;
-        clear(target);
-        return;
-      }
-
-      items.forEach((item, i) => {
-        if (activeItem !== item && scrollTop >= offsets[i]
-          && (typeof offsets[i + 1] === 'undefined' || scrollTop < offsets[i + 1])) {
-          activate(self, item);
-        }
-      });
-    }
-
-    /** Removes `ScrollSpy` from the target element. */
-    dispose() {
-      toggleSpyHandlers(this);
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(ScrollSpy, {
-    selector: scrollspySelector,
-    init: scrollspyInitCallback,
-    getInstance: getScrollSpyInstance,
-  });
-
-  /**
-   * A global namespace for aria-selected.
-   * @type {string}
-   */
-  const ariaSelected = 'aria-selected';
-
-  /** @type {string} */
-  const tabString = 'tab';
-
-  /** @type {string} */
-  const tabComponent = 'Tab';
-
-  /* Native JavaScript for Bootstrap 5 | Tab
-  ------------------------------------------ */
-
-  // TAB PRIVATE GC
-  // ================
-  const tabSelector = `[${dataBsToggle}="${tabString}"]`;
-
-  /**
-   * Static method which returns an existing `Tab` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Tab>}
-   */
-  const getTabInstance = (element) => getInstance(element, tabComponent);
-
-  /**
-   * A `Tab` initialization callback.
-   * @type {BSN.InitCallback<Tab>}
-   */
-  const tabInitCallback = (element) => new Tab(element);
-
-  // TAB CUSTOM EVENTS
-  // =================
-  const showTabEvent = OriginalEvent(`show.bs.${tabString}`);
-  const shownTabEvent = OriginalEvent(`shown.bs.${tabString}`);
-  const hideTabEvent = OriginalEvent(`hide.bs.${tabString}`);
-  const hiddenTabEvent = OriginalEvent(`hidden.bs.${tabString}`);
-
-  /**
-   * Stores the current active tab and its content
-   * for a given `.nav` element.
-   * @type {Map<HTMLElement, any>}
-   */
-  const tabPrivate = new Map();
-
-  // TAB PRIVATE METHODS
-  // ===================
-  /**
-   * Executes after tab transition has finished.
-   * @param {Tab} self the `Tab` instance
-   */
-  function triggerTabEnd(self) {
-    const { tabContent, nav } = self;
-
-    /* istanbul ignore else */
-    if (tabContent && hasClass(tabContent, collapsingClass)) {
-      tabContent.style.height = '';
-      removeClass(tabContent, collapsingClass);
-    }
-
-    /* istanbul ignore else */
-    if (nav) Timer.clear(nav);
-  }
-
-  /**
-   * Executes before showing the tab content.
-   * @param {Tab} self the `Tab` instance
-   */
-  function triggerTabShow(self) {
-    const {
-      element, tabContent, content: nextContent, nav,
-    } = self;
-    const { tab } = nav && tabPrivate.get(nav);
-
-    /* istanbul ignore else */
-    if (tabContent && hasClass(nextContent, fadeClass)) {
-      const { currentHeight, nextHeight } = tabPrivate.get(element);
-      if (currentHeight === nextHeight) {
-        triggerTabEnd(self);
-      } else {
-        // enables height animation
-        setTimeout(() => {
-          tabContent.style.height = `${nextHeight}px`;
-          reflow(tabContent);
-          emulateTransitionEnd(tabContent, () => triggerTabEnd(self));
-        }, 50);
-      }
-    } else if (nav) Timer.clear(nav);
-
-    shownTabEvent.relatedTarget = tab;
-    dispatchEvent(element, shownTabEvent);
-  }
-
-  /**
-   * Executes before hiding the tab.
-   * @param {Tab} self the `Tab` instance
-   */
-  function triggerTabHide(self) {
-    const {
-      element, content: nextContent, tabContent, nav,
-    } = self;
-    const { tab, content } = nav && tabPrivate.get(nav);
-    let currentHeight = 0;
-
-    /* istanbul ignore else */
-    if (tabContent && hasClass(nextContent, fadeClass)) {
-      [content, nextContent].forEach((c) => {
-        addClass(c, 'overflow-hidden');
-      });
-      currentHeight = content.scrollHeight || /* istanbul ignore next */0;
-    }
-
-    // update relatedTarget and dispatch event
-    showTabEvent.relatedTarget = tab;
-    hiddenTabEvent.relatedTarget = element;
-    dispatchEvent(element, showTabEvent);
-    if (showTabEvent.defaultPrevented) return;
-
-    addClass(nextContent, activeClass);
-    removeClass(content, activeClass);
-
-    /* istanbul ignore else */
-    if (tabContent && hasClass(nextContent, fadeClass)) {
-      const nextHeight = nextContent.scrollHeight;
-      tabPrivate.set(element, { currentHeight, nextHeight });
-
-      addClass(tabContent, collapsingClass);
-      tabContent.style.height = `${currentHeight}px`;
-      reflow(tabContent);
-      [content, nextContent].forEach((c) => {
-        removeClass(c, 'overflow-hidden');
-      });
-    }
-
-    if (nextContent && hasClass(nextContent, fadeClass)) {
-      setTimeout(() => {
-        addClass(nextContent, showClass);
-        emulateTransitionEnd(nextContent, () => {
-          triggerTabShow(self);
-        });
-      }, 1);
-    } else {
-      addClass(nextContent, showClass);
-      triggerTabShow(self);
-    }
-
-    dispatchEvent(tab, hiddenTabEvent);
-  }
-
-  /**
-   * Returns the current active tab and its target content.
-   * @param {Tab} self the `Tab` instance
-   * @returns {Record<string, any>} the query result
-   */
-  function getActiveTab(self) {
-    const { nav } = self;
-
-    const activeTabs = getElementsByClassName(activeClass, nav);
-    /** @type {(HTMLElement)=} */
-    let tab;
-    /* istanbul ignore else */
-    if (activeTabs.length === 1
-      && !dropdownMenuClasses.some((c) => hasClass(activeTabs[0].parentElement, c))) {
-      [tab] = activeTabs;
-    } else if (activeTabs.length > 1) {
-      tab = activeTabs[activeTabs.length - 1];
-    }
-    const content = tab ? getTargetElement(tab) : null;
-    return { tab, content };
-  }
-
-  /**
-   * Returns a parent dropdown.
-   * @param {HTMLElement} element the `Tab` element
-   * @returns {HTMLElement?} the parent dropdown
-   */
-  function getParentDropdown(element) {
-    const dropdown = closest(element, `.${dropdownMenuClasses.join(',.')}`);
-    return dropdown ? querySelector(`.${dropdownMenuClasses[0]}-toggle`, dropdown) : null;
-  }
-
-  /**
-   * Toggles on/off the `click` event listener.
-   * @param {Tab} self the `Tab` instance
-   * @param {boolean=} add when `true`, event listener is added
-   */
-  function toggleTabHandler(self, add) {
-    const action = add ? addListener : removeListener;
-    action(self.element, mouseclickEvent, tabClickHandler);
-  }
-
-  // TAB EVENT HANDLER
-  // =================
-  /**
-   * Handles the `click` event listener.
-   * @this {HTMLElement}
-   * @param {MouseEvent} e the `Event` object
-   */
-  function tabClickHandler(e) {
-    const self = getTabInstance(this);
-    /* istanbul ignore next: must filter */
-    if (!self) return;
-    e.preventDefault();
-
-    self.show();
-  }
-
-  // TAB DEFINITION
-  // ==============
-  /** Creates a new `Tab` instance. */
-  class Tab extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target the target element
-     */
-    constructor(target) {
-      super(target);
-      // bind
-      const self = this;
-
-      // initialization element
-      const { element } = self;
-      const content = getTargetElement(element);
-
-      // no point initializing a tab without a corresponding content
-      if (!content) return;
-
-      const nav = closest(element, '.nav');
-      const container = closest(content, '.tab-content');
-
-      /** @type {HTMLElement?} */
-      self.nav = nav;
-      /** @type {HTMLElement} */
-      self.content = content;
-      /** @type {HTMLElement?} */
-      self.tabContent = container;
-
-      // event targets
-      /** @type {HTMLElement?} */
-      self.dropdown = getParentDropdown(element);
-
-      // show first Tab instance of none is shown
-      // suggested on #432
-      const { tab } = getActiveTab(self);
-      if (nav && !tab) {
-        const firstTab = querySelector(tabSelector, nav);
-        const firstTabContent = firstTab && getTargetElement(firstTab);
-
-        /* istanbul ignore else */
-        if (firstTabContent) {
-          addClass(firstTab, activeClass);
-          addClass(firstTabContent, showClass);
-          addClass(firstTabContent, activeClass);
-          setAttribute(element, ariaSelected, 'true');
-        }
-      }
-
-      // add event listener
-      toggleTabHandler(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */  
-    get name() { return tabComponent; }
-    /* eslint-enable */
-
-    // TAB PUBLIC METHODS
-    // ==================
-    /** Shows the tab to the user. */
-    show() {
-      const self = this;
-      const {
-        element, content: nextContent, nav, dropdown,
-      } = self;
-
-      /* istanbul ignore else */
-      if (!(nav && Timer.get(nav)) && !hasClass(element, activeClass)) {
-        const { tab, content } = getActiveTab(self);
-
-        /* istanbul ignore else */
-        if (nav) tabPrivate.set(nav, { tab, content });
-
-        // update relatedTarget and dispatch
-        hideTabEvent.relatedTarget = element;
-
-        dispatchEvent(tab, hideTabEvent);
-        if (hideTabEvent.defaultPrevented) return;
-
-        addClass(element, activeClass);
-        setAttribute(element, ariaSelected, 'true');
-
-        const activeDropdown = getParentDropdown(tab);
-        if (activeDropdown && hasClass(activeDropdown, activeClass)) {
-          removeClass(activeDropdown, activeClass);
-        }
-
-        /* istanbul ignore else */
-        if (nav) {
-          const toggleTab = () => {
-            removeClass(tab, activeClass);
-            setAttribute(tab, ariaSelected, 'false');
-            if (dropdown && !hasClass(dropdown, activeClass)) addClass(dropdown, activeClass);
-          };
-
-          if (hasClass(content, fadeClass) || hasClass(nextContent, fadeClass)) {
-            Timer.set(nav, toggleTab, 1);
-          } else toggleTab();
-        }
-
-        removeClass(content, showClass);
-        if (hasClass(content, fadeClass)) {
-          emulateTransitionEnd(content, () => triggerTabHide(self));
-        } else {
-          triggerTabHide(self);
-        }
-      }
-    }
-
-    /** Removes the `Tab` component from the target element. */
-    dispose() {
-      toggleTabHandler(this);
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Tab, {
-    selector: tabSelector,
-    init: tabInitCallback,
-    getInstance: getTabInstance,
-  });
-
-  /** @type {string} */
-  const toastString = 'toast';
-
-  /** @type {string} */
-  const toastComponent = 'Toast';
-
-  /* Native JavaScript for Bootstrap 5 | Toast
-  -------------------------------------------- */
-
-  // TOAST PRIVATE GC
-  // ================
-  const toastSelector = `.${toastString}`;
-  const toastDismissSelector = `[${dataBsDismiss}="${toastString}"]`;
-  const toastToggleSelector = `[${dataBsToggle}="${toastString}"]`;
-  const showingClass = 'showing';
-  /** @deprecated */
-  const hideClass = 'hide';
-
-  const toastDefaults = {
-    animation: true,
-    autohide: true,
-    delay: 5000,
-  };
-
-  /**
-   * Static method which returns an existing `Toast` instance associated
-   * to a target `Element`.
-   *
-   * @type {BSN.GetInstance<Toast>}
-   */
-  const getToastInstance = (element) => getInstance(element, toastComponent);
-
-  /**
-   * A `Toast` initialization callback.
-   * @type {BSN.InitCallback<Toast>}
-   */
-  const toastInitCallback = (element) => new Toast(element);
-
-  // TOAST CUSTOM EVENTS
-  // ===================
-  const showToastEvent = OriginalEvent(`show.bs.${toastString}`);
-  const shownToastEvent = OriginalEvent(`shown.bs.${toastString}`);
-  const hideToastEvent = OriginalEvent(`hide.bs.${toastString}`);
-  const hiddenToastEvent = OriginalEvent(`hidden.bs.${toastString}`);
-
-  // TOAST PRIVATE METHODS
-  // =====================
-  /**
-   * Executes after the toast is shown to the user.
-   * @param {Toast} self the `Toast` instance
-   */
-  function showToastComplete(self) {
-    const { element, options } = self;
-    removeClass(element, showingClass);
-    Timer.clear(element, showingClass);
-
-    dispatchEvent(element, shownToastEvent);
-    /* istanbul ignore else */
-    if (options.autohide) {
-      Timer.set(element, () => self.hide(), options.delay, toastString);
-    }
-  }
-
-  /**
-   * Executes after the toast is hidden to the user.
-   * @param {Toast} self the `Toast` instance
-   */
-  function hideToastComplete(self) {
-    const { element } = self;
-    removeClass(element, showingClass);
-    removeClass(element, showClass);
-    addClass(element, hideClass); // B/C
-    Timer.clear(element, toastString);
-    dispatchEvent(element, hiddenToastEvent);
-  }
-
-  /**
-   * Executes before hiding the toast.
-   * @param {Toast} self the `Toast` instance
-   */
-  function hideToast(self) {
-    const { element, options } = self;
-    addClass(element, showingClass);
-
-    if (options.animation) {
-      reflow(element);
-      emulateTransitionEnd(element, () => hideToastComplete(self));
-    } else {
-      hideToastComplete(self);
-    }
-  }
-
-  /**
-   * Executes before showing the toast.
-   * @param {Toast} self the `Toast` instance
-   */
-  function showToast(self) {
-    const { element, options } = self;
-    Timer.set(element, () => {
-      removeClass(element, hideClass); // B/C
-      reflow(element);
-      addClass(element, showClass);
-      addClass(element, showingClass);
-
-      if (options.animation) {
-        emulateTransitionEnd(element, () => showToastComplete(self));
-      } else {
-        showToastComplete(self);
-      }
-    }, 17, showingClass);
-  }
-
-  /**
-   * Toggles on/off the `click` event listener.
-   * @param {Toast} self the `Toast` instance
-   * @param {boolean=} add when `true`, it will add the listener
-   */
-  function toggleToastHandlers(self, add) {
-    const action = add ? addListener : removeListener;
-    const {
-      element, triggers, dismiss, options,
-    } = self;
-
-    /* istanbul ignore else */
-    if (dismiss) {
-      action(dismiss, mouseclickEvent, self.hide);
-    }
-
-    /* istanbul ignore else */
-    if (options.autohide) {
-      [focusinEvent, focusoutEvent, mouseenterEvent, mouseleaveEvent]
-        .forEach((e) => action(element, e, interactiveToastHandler));
-    }
-    /* istanbul ignore else */
-    if (triggers.length) {
-      triggers.forEach((btn) => action(btn, mouseclickEvent, toastClickHandler));
-    }
-  }
-
-  // TOAST EVENT HANDLERS
-  // ====================
-  /**
-   * Executes after the instance has been disposed.
-   * @param {Toast} self the `Toast` instance
-   */
-  function completeDisposeToast(self) {
-    Timer.clear(self.element, toastString);
-    toggleToastHandlers(self);
-  }
-
-  /**
-   * Handles the `click` event listener for toast.
-   * @param {MouseEvent} e the `Event` object
-   */
-  function toastClickHandler(e) {
-    const { target } = e;
-
-    const trigger = target && closest(target, toastToggleSelector);
-    const element = trigger && getTargetElement(trigger);
-    const self = element && getToastInstance(element);
-
-    /* istanbul ignore else */
-    if (trigger && trigger.tagName === 'A') e.preventDefault();
-    self.relatedTarget = trigger;
-    self.show();
-  }
-
-  /**
-   * Executes when user interacts with the toast without closing it,
-   * usually by hovering or focusing it.
-   *
-   * @this {HTMLElement}
-   * @param {MouseEvent} e the `Toast` instance
-   */
-  function interactiveToastHandler(e) {
-    const element = this;
-    const self = getToastInstance(element);
-    const { type, relatedTarget } = e;
-
-    /* istanbul ignore next: a solid filter is required */
-    if (!self || (element === relatedTarget || element.contains(relatedTarget))) return;
-
-    if ([mouseenterEvent, focusinEvent].includes(type)) {
-      Timer.clear(element, toastString);
-    } else {
-      Timer.set(element, () => self.hide(), self.options.delay, toastString);
-    }
-  }
-
-  // TOAST DEFINITION
-  // ================
-  /** Creates a new `Toast` instance. */
-  class Toast extends BaseComponent {
-    /**
-     * @param {HTMLElement | string} target the target `.toast` element
-     * @param {BSN.Options.Toast=} config the instance options
-     */
-    constructor(target, config) {
-      super(target, config);
-      // bind
-      const self = this;
-      const { element, options } = self;
-
-      // set fadeClass, the options.animation will override the markup
-      if (options.animation && !hasClass(element, fadeClass)) addClass(element, fadeClass);
-      else if (!options.animation && hasClass(element, fadeClass)) removeClass(element, fadeClass);
-
-      // dismiss button
-      /** @type {HTMLElement?} */
-      self.dismiss = querySelector(toastDismissSelector, element);
-
-      // toast can have multiple triggering elements
-      /** @type {HTMLElement[]} */
-      self.triggers = [...querySelectorAll(toastToggleSelector, getDocument(element))]
-        .filter((btn) => getTargetElement(btn) === element);
-
-      // bind
-      self.show = self.show.bind(self);
-      self.hide = self.hide.bind(self);
-
-      // add event listener
-      toggleToastHandlers(self, true);
-    }
-
-    /* eslint-disable */
-    /**
-     * Returns component name string.
-     */  
-    get name() { return toastComponent; }
-    /**
-     * Returns component default options.
-     */  
-    get defaults() { return toastDefaults; }
-    /* eslint-enable */
-
-    /**
-     * Returns *true* when toast is visible.
-     */
-    get isShown() { return hasClass(this.element, showClass); }
-
-    // TOAST PUBLIC METHODS
-    // ====================
-    /** Shows the toast. */
-    show() {
-      const self = this;
-      const { element, isShown } = self;
-
-      /* istanbul ignore else */
-      if (element && !isShown) {
-        dispatchEvent(element, showToastEvent);
-        if (showToastEvent.defaultPrevented) return;
-
-        showToast(self);
-      }
-    }
-
-    /** Hides the toast. */
-    hide() {
-      const self = this;
-      const { element, isShown } = self;
-
-      /* istanbul ignore else */
-      if (element && isShown) {
-        dispatchEvent(element, hideToastEvent);
-        if (hideToastEvent.defaultPrevented) return;
-        hideToast(self);
-      }
-    }
-
-    /** Removes the `Toast` component from the target element. */
-    dispose() {
-      const self = this;
-      const { element, isShown } = self;
-
-      /* istanbul ignore else */
-      if (isShown) {
-        removeClass(element, showClass);
-      }
-
-      completeDisposeToast(self);
-
-      super.dispose();
-    }
-  }
-
-  ObjectAssign(Toast, {
-    selector: toastSelector,
-    init: toastInitCallback,
-    getInstance: getToastInstance,
-  });
-
-  /**
-   * Check if element matches a CSS selector.
-   *
-   * @param {HTMLElement} target
-   * @param {string} selector
-   * @returns {boolean}
-   */
-  function matches(target, selector) {
-    return target.matches(selector);
-  }
-
-  /** @type {Record<string, any>} */
-  const componentsList = {
-    Alert,
-    Button,
-    Carousel,
-    Collapse,
-    Dropdown,
-    Modal,
-    Offcanvas,
-    Popover,
-    ScrollSpy,
-    Tab,
-    Toast,
-    Tooltip,
-  };
-
-  /**
-   * Initialize all matched `Element`s for one component.
-   * @param {BSN.InitCallback<any>} callback
-   * @param {NodeList | Node[]} collection
-   */
-  function initComponentDataAPI(callback, collection) {
-    [...collection].forEach((x) => callback(x));
-  }
-
-  /**
-   * Remove one component from a target container element or all in the page.
-   * @param {string} component the component name
-   * @param {ParentNode} context parent `Node`
-   */
-  function removeComponentDataAPI(component, context) {
-    const compData = Data.getAllFor(component);
-
-    if (compData) {
-      [...compData].forEach((x) => {
-        const [element, instance] = x;
-        if (context.contains(element)) instance.dispose();
-      });
-    }
-  }
-
-  /**
-   * Initialize all BSN components for a target container.
-   * @param {ParentNode=} context parent `Node`
-   */
-  function initCallback(context) {
-    const lookUp = context && context.nodeName ? context : document;
-    const elemCollection = [...getElementsByTagName('*', lookUp)];
-
-    ObjectKeys(componentsList).forEach((comp) => {
-      const { init, selector } = componentsList[comp];
-      initComponentDataAPI(init, elemCollection.filter((item) => matches(item, selector)));
-    });
-  }
-
-  /**
-   * Remove all BSN components for a target container.
-   * @param {ParentNode=} context parent `Node`
-   */
-  function removeDataAPI(context) {
-    const lookUp = context && context.nodeName ? context : document;
-
-    ObjectKeys(componentsList).forEach((comp) => {
-      removeComponentDataAPI(comp, lookUp);
-    });
-  }
-
-  // bulk initialize all components
-  if (document.body) initCallback();
-  else {
-    addListener(document, 'DOMContentLoaded', () => initCallback(), { once: true });
-  }
-
-  const BSN = {
-    Alert,
-    Button,
-    Carousel,
-    Collapse,
-    Dropdown,
-    Modal,
-    Offcanvas,
-    Popover,
-    ScrollSpy,
-    Tab,
-    Toast,
-    Tooltip,
-
-    initCallback,
-    removeDataAPI,
-    Version,
-    EventListener: Listener,
-  };
-
-  return BSN;
-
-}));

+ 6313 - 0
src/static/scripts/bootstrap.bundle.js

@@ -0,0 +1,6313 @@
+/*!
+  * Bootstrap v5.3.1 (https://getbootstrap.com/)
+  * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+  */
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory());
+})(this, (function () { 'use strict';
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap dom/data.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  /**
+   * Constants
+   */
+
+  const elementMap = new Map();
+  const Data = {
+    set(element, key, instance) {
+      if (!elementMap.has(element)) {
+        elementMap.set(element, new Map());
+      }
+      const instanceMap = elementMap.get(element);
+
+      // make it clear we only want one instance per element
+      // can be removed later when multiple key/instances are fine to be used
+      if (!instanceMap.has(key) && instanceMap.size !== 0) {
+        // eslint-disable-next-line no-console
+        console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);
+        return;
+      }
+      instanceMap.set(key, instance);
+    },
+    get(element, key) {
+      if (elementMap.has(element)) {
+        return elementMap.get(element).get(key) || null;
+      }
+      return null;
+    },
+    remove(element, key) {
+      if (!elementMap.has(element)) {
+        return;
+      }
+      const instanceMap = elementMap.get(element);
+      instanceMap.delete(key);
+
+      // free up element references if there are no instances left for an element
+      if (instanceMap.size === 0) {
+        elementMap.delete(element);
+      }
+    }
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/index.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  const MAX_UID = 1000000;
+  const MILLISECONDS_MULTIPLIER = 1000;
+  const TRANSITION_END = 'transitionend';
+
+  /**
+   * Properly escape IDs selectors to handle weird IDs
+   * @param {string} selector
+   * @returns {string}
+   */
+  const parseSelector = selector => {
+    if (selector && window.CSS && window.CSS.escape) {
+      // document.querySelector needs escaping to handle IDs (html5+) containing for instance /
+      selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`);
+    }
+    return selector;
+  };
+
+  // Shout-out Angus Croll (https://goo.gl/pxwQGp)
+  const toType = object => {
+    if (object === null || object === undefined) {
+      return `${object}`;
+    }
+    return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase();
+  };
+
+  /**
+   * Public Util API
+   */
+
+  const getUID = prefix => {
+    do {
+      prefix += Math.floor(Math.random() * MAX_UID);
+    } while (document.getElementById(prefix));
+    return prefix;
+  };
+  const getTransitionDurationFromElement = element => {
+    if (!element) {
+      return 0;
+    }
+
+    // Get transition-duration of the element
+    let {
+      transitionDuration,
+      transitionDelay
+    } = window.getComputedStyle(element);
+    const floatTransitionDuration = Number.parseFloat(transitionDuration);
+    const floatTransitionDelay = Number.parseFloat(transitionDelay);
+
+    // Return 0 if element or transition duration is not found
+    if (!floatTransitionDuration && !floatTransitionDelay) {
+      return 0;
+    }
+
+    // If multiple durations are defined, take the first
+    transitionDuration = transitionDuration.split(',')[0];
+    transitionDelay = transitionDelay.split(',')[0];
+    return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
+  };
+  const triggerTransitionEnd = element => {
+    element.dispatchEvent(new Event(TRANSITION_END));
+  };
+  const isElement$1 = object => {
+    if (!object || typeof object !== 'object') {
+      return false;
+    }
+    if (typeof object.jquery !== 'undefined') {
+      object = object[0];
+    }
+    return typeof object.nodeType !== 'undefined';
+  };
+  const getElement = object => {
+    // it's a jQuery object or a node element
+    if (isElement$1(object)) {
+      return object.jquery ? object[0] : object;
+    }
+    if (typeof object === 'string' && object.length > 0) {
+      return document.querySelector(parseSelector(object));
+    }
+    return null;
+  };
+  const isVisible = element => {
+    if (!isElement$1(element) || element.getClientRects().length === 0) {
+      return false;
+    }
+    const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';
+    // Handle `details` element as its content may falsie appear visible when it is closed
+    const closedDetails = element.closest('details:not([open])');
+    if (!closedDetails) {
+      return elementIsVisible;
+    }
+    if (closedDetails !== element) {
+      const summary = element.closest('summary');
+      if (summary && summary.parentNode !== closedDetails) {
+        return false;
+      }
+      if (summary === null) {
+        return false;
+      }
+    }
+    return elementIsVisible;
+  };
+  const isDisabled = element => {
+    if (!element || element.nodeType !== Node.ELEMENT_NODE) {
+      return true;
+    }
+    if (element.classList.contains('disabled')) {
+      return true;
+    }
+    if (typeof element.disabled !== 'undefined') {
+      return element.disabled;
+    }
+    return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
+  };
+  const findShadowRoot = element => {
+    if (!document.documentElement.attachShadow) {
+      return null;
+    }
+
+    // Can find the shadow root otherwise it'll return the document
+    if (typeof element.getRootNode === 'function') {
+      const root = element.getRootNode();
+      return root instanceof ShadowRoot ? root : null;
+    }
+    if (element instanceof ShadowRoot) {
+      return element;
+    }
+
+    // when we don't find a shadow root
+    if (!element.parentNode) {
+      return null;
+    }
+    return findShadowRoot(element.parentNode);
+  };
+  const noop = () => {};
+
+  /**
+   * Trick to restart an element's animation
+   *
+   * @param {HTMLElement} element
+   * @return void
+   *
+   * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
+   */
+  const reflow = element => {
+    element.offsetHeight; // eslint-disable-line no-unused-expressions
+  };
+
+  const getjQuery = () => {
+    if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
+      return window.jQuery;
+    }
+    return null;
+  };
+  const DOMContentLoadedCallbacks = [];
+  const onDOMContentLoaded = callback => {
+    if (document.readyState === 'loading') {
+      // add listener on the first call when the document is in loading state
+      if (!DOMContentLoadedCallbacks.length) {
+        document.addEventListener('DOMContentLoaded', () => {
+          for (const callback of DOMContentLoadedCallbacks) {
+            callback();
+          }
+        });
+      }
+      DOMContentLoadedCallbacks.push(callback);
+    } else {
+      callback();
+    }
+  };
+  const isRTL = () => document.documentElement.dir === 'rtl';
+  const defineJQueryPlugin = plugin => {
+    onDOMContentLoaded(() => {
+      const $ = getjQuery();
+      /* istanbul ignore if */
+      if ($) {
+        const name = plugin.NAME;
+        const JQUERY_NO_CONFLICT = $.fn[name];
+        $.fn[name] = plugin.jQueryInterface;
+        $.fn[name].Constructor = plugin;
+        $.fn[name].noConflict = () => {
+          $.fn[name] = JQUERY_NO_CONFLICT;
+          return plugin.jQueryInterface;
+        };
+      }
+    });
+  };
+  const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
+    return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;
+  };
+  const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
+    if (!waitForTransition) {
+      execute(callback);
+      return;
+    }
+    const durationPadding = 5;
+    const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
+    let called = false;
+    const handler = ({
+      target
+    }) => {
+      if (target !== transitionElement) {
+        return;
+      }
+      called = true;
+      transitionElement.removeEventListener(TRANSITION_END, handler);
+      execute(callback);
+    };
+    transitionElement.addEventListener(TRANSITION_END, handler);
+    setTimeout(() => {
+      if (!called) {
+        triggerTransitionEnd(transitionElement);
+      }
+    }, emulatedDuration);
+  };
+
+  /**
+   * Return the previous/next element of a list.
+   *
+   * @param {array} list    The list of elements
+   * @param activeElement   The active element
+   * @param shouldGetNext   Choose to get next or previous element
+   * @param isCycleAllowed
+   * @return {Element|elem} The proper element
+   */
+  const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
+    const listLength = list.length;
+    let index = list.indexOf(activeElement);
+
+    // if the element does not exist in the list return an element
+    // depending on the direction and if cycle is allowed
+    if (index === -1) {
+      return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];
+    }
+    index += shouldGetNext ? 1 : -1;
+    if (isCycleAllowed) {
+      index = (index + listLength) % listLength;
+    }
+    return list[Math.max(0, Math.min(index, listLength - 1))];
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap dom/event-handler.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const namespaceRegex = /[^.]*(?=\..*)\.|.*/;
+  const stripNameRegex = /\..*/;
+  const stripUidRegex = /::\d+$/;
+  const eventRegistry = {}; // Events storage
+  let uidEvent = 1;
+  const customEvents = {
+    mouseenter: 'mouseover',
+    mouseleave: 'mouseout'
+  };
+  const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']);
+
+  /**
+   * Private methods
+   */
+
+  function makeEventUid(element, uid) {
+    return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;
+  }
+  function getElementEvents(element) {
+    const uid = makeEventUid(element);
+    element.uidEvent = uid;
+    eventRegistry[uid] = eventRegistry[uid] || {};
+    return eventRegistry[uid];
+  }
+  function bootstrapHandler(element, fn) {
+    return function handler(event) {
+      hydrateObj(event, {
+        delegateTarget: element
+      });
+      if (handler.oneOff) {
+        EventHandler.off(element, event.type, fn);
+      }
+      return fn.apply(element, [event]);
+    };
+  }
+  function bootstrapDelegationHandler(element, selector, fn) {
+    return function handler(event) {
+      const domElements = element.querySelectorAll(selector);
+      for (let {
+        target
+      } = event; target && target !== this; target = target.parentNode) {
+        for (const domElement of domElements) {
+          if (domElement !== target) {
+            continue;
+          }
+          hydrateObj(event, {
+            delegateTarget: target
+          });
+          if (handler.oneOff) {
+            EventHandler.off(element, event.type, selector, fn);
+          }
+          return fn.apply(target, [event]);
+        }
+      }
+    };
+  }
+  function findHandler(events, callable, delegationSelector = null) {
+    return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector);
+  }
+  function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
+    const isDelegated = typeof handler === 'string';
+    // TODO: tooltip passes `false` instead of selector, so we need to check
+    const callable = isDelegated ? delegationFunction : handler || delegationFunction;
+    let typeEvent = getTypeEvent(originalTypeEvent);
+    if (!nativeEvents.has(typeEvent)) {
+      typeEvent = originalTypeEvent;
+    }
+    return [isDelegated, callable, typeEvent];
+  }
+  function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
+    if (typeof originalTypeEvent !== 'string' || !element) {
+      return;
+    }
+    let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);
+
+    // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
+    // this prevents the handler from being dispatched the same way as mouseover or mouseout does
+    if (originalTypeEvent in customEvents) {
+      const wrapFunction = fn => {
+        return function (event) {
+          if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {
+            return fn.call(this, event);
+          }
+        };
+      };
+      callable = wrapFunction(callable);
+    }
+    const events = getElementEvents(element);
+    const handlers = events[typeEvent] || (events[typeEvent] = {});
+    const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);
+    if (previousFunction) {
+      previousFunction.oneOff = previousFunction.oneOff && oneOff;
+      return;
+    }
+    const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));
+    const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable);
+    fn.delegationSelector = isDelegated ? handler : null;
+    fn.callable = callable;
+    fn.oneOff = oneOff;
+    fn.uidEvent = uid;
+    handlers[uid] = fn;
+    element.addEventListener(typeEvent, fn, isDelegated);
+  }
+  function removeHandler(element, events, typeEvent, handler, delegationSelector) {
+    const fn = findHandler(events[typeEvent], handler, delegationSelector);
+    if (!fn) {
+      return;
+    }
+    element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));
+    delete events[typeEvent][fn.uidEvent];
+  }
+  function removeNamespacedHandlers(element, events, typeEvent, namespace) {
+    const storeElementEvent = events[typeEvent] || {};
+    for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
+      if (handlerKey.includes(namespace)) {
+        removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
+      }
+    }
+  }
+  function getTypeEvent(event) {
+    // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
+    event = event.replace(stripNameRegex, '');
+    return customEvents[event] || event;
+  }
+  const EventHandler = {
+    on(element, event, handler, delegationFunction) {
+      addHandler(element, event, handler, delegationFunction, false);
+    },
+    one(element, event, handler, delegationFunction) {
+      addHandler(element, event, handler, delegationFunction, true);
+    },
+    off(element, originalTypeEvent, handler, delegationFunction) {
+      if (typeof originalTypeEvent !== 'string' || !element) {
+        return;
+      }
+      const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);
+      const inNamespace = typeEvent !== originalTypeEvent;
+      const events = getElementEvents(element);
+      const storeElementEvent = events[typeEvent] || {};
+      const isNamespace = originalTypeEvent.startsWith('.');
+      if (typeof callable !== 'undefined') {
+        // Simplest case: handler is passed, remove that listener ONLY.
+        if (!Object.keys(storeElementEvent).length) {
+          return;
+        }
+        removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);
+        return;
+      }
+      if (isNamespace) {
+        for (const elementEvent of Object.keys(events)) {
+          removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));
+        }
+      }
+      for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
+        const handlerKey = keyHandlers.replace(stripUidRegex, '');
+        if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
+          removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
+        }
+      }
+    },
+    trigger(element, event, args) {
+      if (typeof event !== 'string' || !element) {
+        return null;
+      }
+      const $ = getjQuery();
+      const typeEvent = getTypeEvent(event);
+      const inNamespace = event !== typeEvent;
+      let jQueryEvent = null;
+      let bubbles = true;
+      let nativeDispatch = true;
+      let defaultPrevented = false;
+      if (inNamespace && $) {
+        jQueryEvent = $.Event(event, args);
+        $(element).trigger(jQueryEvent);
+        bubbles = !jQueryEvent.isPropagationStopped();
+        nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
+        defaultPrevented = jQueryEvent.isDefaultPrevented();
+      }
+      const evt = hydrateObj(new Event(event, {
+        bubbles,
+        cancelable: true
+      }), args);
+      if (defaultPrevented) {
+        evt.preventDefault();
+      }
+      if (nativeDispatch) {
+        element.dispatchEvent(evt);
+      }
+      if (evt.defaultPrevented && jQueryEvent) {
+        jQueryEvent.preventDefault();
+      }
+      return evt;
+    }
+  };
+  function hydrateObj(obj, meta = {}) {
+    for (const [key, value] of Object.entries(meta)) {
+      try {
+        obj[key] = value;
+      } catch (_unused) {
+        Object.defineProperty(obj, key, {
+          configurable: true,
+          get() {
+            return value;
+          }
+        });
+      }
+    }
+    return obj;
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap dom/manipulator.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  function normalizeData(value) {
+    if (value === 'true') {
+      return true;
+    }
+    if (value === 'false') {
+      return false;
+    }
+    if (value === Number(value).toString()) {
+      return Number(value);
+    }
+    if (value === '' || value === 'null') {
+      return null;
+    }
+    if (typeof value !== 'string') {
+      return value;
+    }
+    try {
+      return JSON.parse(decodeURIComponent(value));
+    } catch (_unused) {
+      return value;
+    }
+  }
+  function normalizeDataKey(key) {
+    return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);
+  }
+  const Manipulator = {
+    setDataAttribute(element, key, value) {
+      element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);
+    },
+    removeDataAttribute(element, key) {
+      element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);
+    },
+    getDataAttributes(element) {
+      if (!element) {
+        return {};
+      }
+      const attributes = {};
+      const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));
+      for (const key of bsKeys) {
+        let pureKey = key.replace(/^bs/, '');
+        pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);
+        attributes[pureKey] = normalizeData(element.dataset[key]);
+      }
+      return attributes;
+    },
+    getDataAttribute(element, key) {
+      return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));
+    }
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/config.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Class definition
+   */
+
+  class Config {
+    // Getters
+    static get Default() {
+      return {};
+    }
+    static get DefaultType() {
+      return {};
+    }
+    static get NAME() {
+      throw new Error('You have to implement the static method "NAME", for each component!');
+    }
+    _getConfig(config) {
+      config = this._mergeConfigObj(config);
+      config = this._configAfterMerge(config);
+      this._typeCheckConfig(config);
+      return config;
+    }
+    _configAfterMerge(config) {
+      return config;
+    }
+    _mergeConfigObj(config, element) {
+      const jsonConfig = isElement$1(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse
+
+      return {
+        ...this.constructor.Default,
+        ...(typeof jsonConfig === 'object' ? jsonConfig : {}),
+        ...(isElement$1(element) ? Manipulator.getDataAttributes(element) : {}),
+        ...(typeof config === 'object' ? config : {})
+      };
+    }
+    _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
+      for (const [property, expectedTypes] of Object.entries(configTypes)) {
+        const value = config[property];
+        const valueType = isElement$1(value) ? 'element' : toType(value);
+        if (!new RegExp(expectedTypes).test(valueType)) {
+          throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
+        }
+      }
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap base-component.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const VERSION = '5.3.1';
+
+  /**
+   * Class definition
+   */
+
+  class BaseComponent extends Config {
+    constructor(element, config) {
+      super();
+      element = getElement(element);
+      if (!element) {
+        return;
+      }
+      this._element = element;
+      this._config = this._getConfig(config);
+      Data.set(this._element, this.constructor.DATA_KEY, this);
+    }
+
+    // Public
+    dispose() {
+      Data.remove(this._element, this.constructor.DATA_KEY);
+      EventHandler.off(this._element, this.constructor.EVENT_KEY);
+      for (const propertyName of Object.getOwnPropertyNames(this)) {
+        this[propertyName] = null;
+      }
+    }
+    _queueCallback(callback, element, isAnimated = true) {
+      executeAfterTransition(callback, element, isAnimated);
+    }
+    _getConfig(config) {
+      config = this._mergeConfigObj(config, this._element);
+      config = this._configAfterMerge(config);
+      this._typeCheckConfig(config);
+      return config;
+    }
+
+    // Static
+    static getInstance(element) {
+      return Data.get(getElement(element), this.DATA_KEY);
+    }
+    static getOrCreateInstance(element, config = {}) {
+      return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);
+    }
+    static get VERSION() {
+      return VERSION;
+    }
+    static get DATA_KEY() {
+      return `bs.${this.NAME}`;
+    }
+    static get EVENT_KEY() {
+      return `.${this.DATA_KEY}`;
+    }
+    static eventName(name) {
+      return `${name}${this.EVENT_KEY}`;
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap dom/selector-engine.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  const getSelector = element => {
+    let selector = element.getAttribute('data-bs-target');
+    if (!selector || selector === '#') {
+      let hrefAttribute = element.getAttribute('href');
+
+      // The only valid content that could double as a selector are IDs or classes,
+      // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
+      // `document.querySelector` will rightfully complain it is invalid.
+      // See https://github.com/twbs/bootstrap/issues/32273
+      if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {
+        return null;
+      }
+
+      // Just in case some CMS puts out a full URL with the anchor appended
+      if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
+        hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
+      }
+      selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
+    }
+    return parseSelector(selector);
+  };
+  const SelectorEngine = {
+    find(selector, element = document.documentElement) {
+      return [].concat(...Element.prototype.querySelectorAll.call(element, selector));
+    },
+    findOne(selector, element = document.documentElement) {
+      return Element.prototype.querySelector.call(element, selector);
+    },
+    children(element, selector) {
+      return [].concat(...element.children).filter(child => child.matches(selector));
+    },
+    parents(element, selector) {
+      const parents = [];
+      let ancestor = element.parentNode.closest(selector);
+      while (ancestor) {
+        parents.push(ancestor);
+        ancestor = ancestor.parentNode.closest(selector);
+      }
+      return parents;
+    },
+    prev(element, selector) {
+      let previous = element.previousElementSibling;
+      while (previous) {
+        if (previous.matches(selector)) {
+          return [previous];
+        }
+        previous = previous.previousElementSibling;
+      }
+      return [];
+    },
+    // TODO: this is now unused; remove later along with prev()
+    next(element, selector) {
+      let next = element.nextElementSibling;
+      while (next) {
+        if (next.matches(selector)) {
+          return [next];
+        }
+        next = next.nextElementSibling;
+      }
+      return [];
+    },
+    focusableChildren(element) {
+      const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(',');
+      return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));
+    },
+    getSelectorFromElement(element) {
+      const selector = getSelector(element);
+      if (selector) {
+        return SelectorEngine.findOne(selector) ? selector : null;
+      }
+      return null;
+    },
+    getElementFromSelector(element) {
+      const selector = getSelector(element);
+      return selector ? SelectorEngine.findOne(selector) : null;
+    },
+    getMultipleElementsFromSelector(element) {
+      const selector = getSelector(element);
+      return selector ? SelectorEngine.find(selector) : [];
+    }
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/component-functions.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  const enableDismissTrigger = (component, method = 'hide') => {
+    const clickEvent = `click.dismiss${component.EVENT_KEY}`;
+    const name = component.NAME;
+    EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
+      if (['A', 'AREA'].includes(this.tagName)) {
+        event.preventDefault();
+      }
+      if (isDisabled(this)) {
+        return;
+      }
+      const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);
+      const instance = component.getOrCreateInstance(target);
+
+      // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
+      instance[method]();
+    });
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap alert.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$f = 'alert';
+  const DATA_KEY$a = 'bs.alert';
+  const EVENT_KEY$b = `.${DATA_KEY$a}`;
+  const EVENT_CLOSE = `close${EVENT_KEY$b}`;
+  const EVENT_CLOSED = `closed${EVENT_KEY$b}`;
+  const CLASS_NAME_FADE$5 = 'fade';
+  const CLASS_NAME_SHOW$8 = 'show';
+
+  /**
+   * Class definition
+   */
+
+  class Alert extends BaseComponent {
+    // Getters
+    static get NAME() {
+      return NAME$f;
+    }
+
+    // Public
+    close() {
+      const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);
+      if (closeEvent.defaultPrevented) {
+        return;
+      }
+      this._element.classList.remove(CLASS_NAME_SHOW$8);
+      const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5);
+      this._queueCallback(() => this._destroyElement(), this._element, isAnimated);
+    }
+
+    // Private
+    _destroyElement() {
+      this._element.remove();
+      EventHandler.trigger(this._element, EVENT_CLOSED);
+      this.dispose();
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Alert.getOrCreateInstance(this);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config](this);
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  enableDismissTrigger(Alert, 'close');
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Alert);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap button.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$e = 'button';
+  const DATA_KEY$9 = 'bs.button';
+  const EVENT_KEY$a = `.${DATA_KEY$9}`;
+  const DATA_API_KEY$6 = '.data-api';
+  const CLASS_NAME_ACTIVE$3 = 'active';
+  const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]';
+  const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;
+
+  /**
+   * Class definition
+   */
+
+  class Button extends BaseComponent {
+    // Getters
+    static get NAME() {
+      return NAME$e;
+    }
+
+    // Public
+    toggle() {
+      // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
+      this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3));
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Button.getOrCreateInstance(this);
+        if (config === 'toggle') {
+          data[config]();
+        }
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => {
+    event.preventDefault();
+    const button = event.target.closest(SELECTOR_DATA_TOGGLE$5);
+    const data = Button.getOrCreateInstance(button);
+    data.toggle();
+  });
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Button);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/swipe.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$d = 'swipe';
+  const EVENT_KEY$9 = '.bs.swipe';
+  const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`;
+  const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`;
+  const EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`;
+  const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`;
+  const EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`;
+  const POINTER_TYPE_TOUCH = 'touch';
+  const POINTER_TYPE_PEN = 'pen';
+  const CLASS_NAME_POINTER_EVENT = 'pointer-event';
+  const SWIPE_THRESHOLD = 40;
+  const Default$c = {
+    endCallback: null,
+    leftCallback: null,
+    rightCallback: null
+  };
+  const DefaultType$c = {
+    endCallback: '(function|null)',
+    leftCallback: '(function|null)',
+    rightCallback: '(function|null)'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Swipe extends Config {
+    constructor(element, config) {
+      super();
+      this._element = element;
+      if (!element || !Swipe.isSupported()) {
+        return;
+      }
+      this._config = this._getConfig(config);
+      this._deltaX = 0;
+      this._supportPointerEvents = Boolean(window.PointerEvent);
+      this._initEvents();
+    }
+
+    // Getters
+    static get Default() {
+      return Default$c;
+    }
+    static get DefaultType() {
+      return DefaultType$c;
+    }
+    static get NAME() {
+      return NAME$d;
+    }
+
+    // Public
+    dispose() {
+      EventHandler.off(this._element, EVENT_KEY$9);
+    }
+
+    // Private
+    _start(event) {
+      if (!this._supportPointerEvents) {
+        this._deltaX = event.touches[0].clientX;
+        return;
+      }
+      if (this._eventIsPointerPenTouch(event)) {
+        this._deltaX = event.clientX;
+      }
+    }
+    _end(event) {
+      if (this._eventIsPointerPenTouch(event)) {
+        this._deltaX = event.clientX - this._deltaX;
+      }
+      this._handleSwipe();
+      execute(this._config.endCallback);
+    }
+    _move(event) {
+      this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;
+    }
+    _handleSwipe() {
+      const absDeltaX = Math.abs(this._deltaX);
+      if (absDeltaX <= SWIPE_THRESHOLD) {
+        return;
+      }
+      const direction = absDeltaX / this._deltaX;
+      this._deltaX = 0;
+      if (!direction) {
+        return;
+      }
+      execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);
+    }
+    _initEvents() {
+      if (this._supportPointerEvents) {
+        EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));
+        EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));
+        this._element.classList.add(CLASS_NAME_POINTER_EVENT);
+      } else {
+        EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));
+        EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));
+        EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));
+      }
+    }
+    _eventIsPointerPenTouch(event) {
+      return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);
+    }
+
+    // Static
+    static isSupported() {
+      return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap carousel.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$c = 'carousel';
+  const DATA_KEY$8 = 'bs.carousel';
+  const EVENT_KEY$8 = `.${DATA_KEY$8}`;
+  const DATA_API_KEY$5 = '.data-api';
+  const ARROW_LEFT_KEY$1 = 'ArrowLeft';
+  const ARROW_RIGHT_KEY$1 = 'ArrowRight';
+  const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
+
+  const ORDER_NEXT = 'next';
+  const ORDER_PREV = 'prev';
+  const DIRECTION_LEFT = 'left';
+  const DIRECTION_RIGHT = 'right';
+  const EVENT_SLIDE = `slide${EVENT_KEY$8}`;
+  const EVENT_SLID = `slid${EVENT_KEY$8}`;
+  const EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`;
+  const EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`;
+  const EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`;
+  const EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`;
+  const EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;
+  const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;
+  const CLASS_NAME_CAROUSEL = 'carousel';
+  const CLASS_NAME_ACTIVE$2 = 'active';
+  const CLASS_NAME_SLIDE = 'slide';
+  const CLASS_NAME_END = 'carousel-item-end';
+  const CLASS_NAME_START = 'carousel-item-start';
+  const CLASS_NAME_NEXT = 'carousel-item-next';
+  const CLASS_NAME_PREV = 'carousel-item-prev';
+  const SELECTOR_ACTIVE = '.active';
+  const SELECTOR_ITEM = '.carousel-item';
+  const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;
+  const SELECTOR_ITEM_IMG = '.carousel-item img';
+  const SELECTOR_INDICATORS = '.carousel-indicators';
+  const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';
+  const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]';
+  const KEY_TO_DIRECTION = {
+    [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT,
+    [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT
+  };
+  const Default$b = {
+    interval: 5000,
+    keyboard: true,
+    pause: 'hover',
+    ride: false,
+    touch: true,
+    wrap: true
+  };
+  const DefaultType$b = {
+    interval: '(number|boolean)',
+    // TODO:v6 remove boolean support
+    keyboard: 'boolean',
+    pause: '(string|boolean)',
+    ride: '(boolean|string)',
+    touch: 'boolean',
+    wrap: 'boolean'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Carousel extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+      this._interval = null;
+      this._activeElement = null;
+      this._isSliding = false;
+      this.touchTimeout = null;
+      this._swipeHelper = null;
+      this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);
+      this._addEventListeners();
+      if (this._config.ride === CLASS_NAME_CAROUSEL) {
+        this.cycle();
+      }
+    }
+
+    // Getters
+    static get Default() {
+      return Default$b;
+    }
+    static get DefaultType() {
+      return DefaultType$b;
+    }
+    static get NAME() {
+      return NAME$c;
+    }
+
+    // Public
+    next() {
+      this._slide(ORDER_NEXT);
+    }
+    nextWhenVisible() {
+      // FIXME TODO use `document.visibilityState`
+      // Don't call next when the page isn't visible
+      // or the carousel or its parent isn't visible
+      if (!document.hidden && isVisible(this._element)) {
+        this.next();
+      }
+    }
+    prev() {
+      this._slide(ORDER_PREV);
+    }
+    pause() {
+      if (this._isSliding) {
+        triggerTransitionEnd(this._element);
+      }
+      this._clearInterval();
+    }
+    cycle() {
+      this._clearInterval();
+      this._updateInterval();
+      this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);
+    }
+    _maybeEnableCycle() {
+      if (!this._config.ride) {
+        return;
+      }
+      if (this._isSliding) {
+        EventHandler.one(this._element, EVENT_SLID, () => this.cycle());
+        return;
+      }
+      this.cycle();
+    }
+    to(index) {
+      const items = this._getItems();
+      if (index > items.length - 1 || index < 0) {
+        return;
+      }
+      if (this._isSliding) {
+        EventHandler.one(this._element, EVENT_SLID, () => this.to(index));
+        return;
+      }
+      const activeIndex = this._getItemIndex(this._getActive());
+      if (activeIndex === index) {
+        return;
+      }
+      const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;
+      this._slide(order, items[index]);
+    }
+    dispose() {
+      if (this._swipeHelper) {
+        this._swipeHelper.dispose();
+      }
+      super.dispose();
+    }
+
+    // Private
+    _configAfterMerge(config) {
+      config.defaultInterval = config.interval;
+      return config;
+    }
+    _addEventListeners() {
+      if (this._config.keyboard) {
+        EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event));
+      }
+      if (this._config.pause === 'hover') {
+        EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause());
+        EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle());
+      }
+      if (this._config.touch && Swipe.isSupported()) {
+        this._addTouchEventListeners();
+      }
+    }
+    _addTouchEventListeners() {
+      for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {
+        EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());
+      }
+      const endCallBack = () => {
+        if (this._config.pause !== 'hover') {
+          return;
+        }
+
+        // If it's a touch-enabled device, mouseenter/leave are fired as
+        // part of the mouse compatibility events on first tap - the carousel
+        // would stop cycling until user tapped out of it;
+        // here, we listen for touchend, explicitly pause the carousel
+        // (as if it's the second time we tap on it, mouseenter compat event
+        // is NOT fired) and after a timeout (to allow for mouse compatibility
+        // events to fire) we explicitly restart cycling
+
+        this.pause();
+        if (this.touchTimeout) {
+          clearTimeout(this.touchTimeout);
+        }
+        this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);
+      };
+      const swipeConfig = {
+        leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),
+        rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),
+        endCallback: endCallBack
+      };
+      this._swipeHelper = new Swipe(this._element, swipeConfig);
+    }
+    _keydown(event) {
+      if (/input|textarea/i.test(event.target.tagName)) {
+        return;
+      }
+      const direction = KEY_TO_DIRECTION[event.key];
+      if (direction) {
+        event.preventDefault();
+        this._slide(this._directionToOrder(direction));
+      }
+    }
+    _getItemIndex(element) {
+      return this._getItems().indexOf(element);
+    }
+    _setActiveIndicatorElement(index) {
+      if (!this._indicatorsElement) {
+        return;
+      }
+      const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
+      activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2);
+      activeIndicator.removeAttribute('aria-current');
+      const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement);
+      if (newActiveIndicator) {
+        newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2);
+        newActiveIndicator.setAttribute('aria-current', 'true');
+      }
+    }
+    _updateInterval() {
+      const element = this._activeElement || this._getActive();
+      if (!element) {
+        return;
+      }
+      const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);
+      this._config.interval = elementInterval || this._config.defaultInterval;
+    }
+    _slide(order, element = null) {
+      if (this._isSliding) {
+        return;
+      }
+      const activeElement = this._getActive();
+      const isNext = order === ORDER_NEXT;
+      const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);
+      if (nextElement === activeElement) {
+        return;
+      }
+      const nextElementIndex = this._getItemIndex(nextElement);
+      const triggerEvent = eventName => {
+        return EventHandler.trigger(this._element, eventName, {
+          relatedTarget: nextElement,
+          direction: this._orderToDirection(order),
+          from: this._getItemIndex(activeElement),
+          to: nextElementIndex
+        });
+      };
+      const slideEvent = triggerEvent(EVENT_SLIDE);
+      if (slideEvent.defaultPrevented) {
+        return;
+      }
+      if (!activeElement || !nextElement) {
+        // Some weirdness is happening, so we bail
+        // TODO: change tests that use empty divs to avoid this check
+        return;
+      }
+      const isCycling = Boolean(this._interval);
+      this.pause();
+      this._isSliding = true;
+      this._setActiveIndicatorElement(nextElementIndex);
+      this._activeElement = nextElement;
+      const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
+      const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
+      nextElement.classList.add(orderClassName);
+      reflow(nextElement);
+      activeElement.classList.add(directionalClassName);
+      nextElement.classList.add(directionalClassName);
+      const completeCallBack = () => {
+        nextElement.classList.remove(directionalClassName, orderClassName);
+        nextElement.classList.add(CLASS_NAME_ACTIVE$2);
+        activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName);
+        this._isSliding = false;
+        triggerEvent(EVENT_SLID);
+      };
+      this._queueCallback(completeCallBack, activeElement, this._isAnimated());
+      if (isCycling) {
+        this.cycle();
+      }
+    }
+    _isAnimated() {
+      return this._element.classList.contains(CLASS_NAME_SLIDE);
+    }
+    _getActive() {
+      return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);
+    }
+    _getItems() {
+      return SelectorEngine.find(SELECTOR_ITEM, this._element);
+    }
+    _clearInterval() {
+      if (this._interval) {
+        clearInterval(this._interval);
+        this._interval = null;
+      }
+    }
+    _directionToOrder(direction) {
+      if (isRTL()) {
+        return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;
+      }
+      return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;
+    }
+    _orderToDirection(order) {
+      if (isRTL()) {
+        return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;
+      }
+      return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Carousel.getOrCreateInstance(this, config);
+        if (typeof config === 'number') {
+          data.to(config);
+          return;
+        }
+        if (typeof config === 'string') {
+          if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+            throw new TypeError(`No method named "${config}"`);
+          }
+          data[config]();
+        }
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) {
+    const target = SelectorEngine.getElementFromSelector(this);
+    if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
+      return;
+    }
+    event.preventDefault();
+    const carousel = Carousel.getOrCreateInstance(target);
+    const slideIndex = this.getAttribute('data-bs-slide-to');
+    if (slideIndex) {
+      carousel.to(slideIndex);
+      carousel._maybeEnableCycle();
+      return;
+    }
+    if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
+      carousel.next();
+      carousel._maybeEnableCycle();
+      return;
+    }
+    carousel.prev();
+    carousel._maybeEnableCycle();
+  });
+  EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {
+    const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);
+    for (const carousel of carousels) {
+      Carousel.getOrCreateInstance(carousel);
+    }
+  });
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Carousel);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap collapse.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$b = 'collapse';
+  const DATA_KEY$7 = 'bs.collapse';
+  const EVENT_KEY$7 = `.${DATA_KEY$7}`;
+  const DATA_API_KEY$4 = '.data-api';
+  const EVENT_SHOW$6 = `show${EVENT_KEY$7}`;
+  const EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`;
+  const EVENT_HIDE$6 = `hide${EVENT_KEY$7}`;
+  const EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`;
+  const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;
+  const CLASS_NAME_SHOW$7 = 'show';
+  const CLASS_NAME_COLLAPSE = 'collapse';
+  const CLASS_NAME_COLLAPSING = 'collapsing';
+  const CLASS_NAME_COLLAPSED = 'collapsed';
+  const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;
+  const CLASS_NAME_HORIZONTAL = 'collapse-horizontal';
+  const WIDTH = 'width';
+  const HEIGHT = 'height';
+  const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';
+  const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]';
+  const Default$a = {
+    parent: null,
+    toggle: true
+  };
+  const DefaultType$a = {
+    parent: '(null|element)',
+    toggle: 'boolean'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Collapse extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+      this._isTransitioning = false;
+      this._triggerArray = [];
+      const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4);
+      for (const elem of toggleList) {
+        const selector = SelectorEngine.getSelectorFromElement(elem);
+        const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);
+        if (selector !== null && filterElement.length) {
+          this._triggerArray.push(elem);
+        }
+      }
+      this._initializeChildren();
+      if (!this._config.parent) {
+        this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());
+      }
+      if (this._config.toggle) {
+        this.toggle();
+      }
+    }
+
+    // Getters
+    static get Default() {
+      return Default$a;
+    }
+    static get DefaultType() {
+      return DefaultType$a;
+    }
+    static get NAME() {
+      return NAME$b;
+    }
+
+    // Public
+    toggle() {
+      if (this._isShown()) {
+        this.hide();
+      } else {
+        this.show();
+      }
+    }
+    show() {
+      if (this._isTransitioning || this._isShown()) {
+        return;
+      }
+      let activeChildren = [];
+
+      // find active children
+      if (this._config.parent) {
+        activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {
+          toggle: false
+        }));
+      }
+      if (activeChildren.length && activeChildren[0]._isTransitioning) {
+        return;
+      }
+      const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6);
+      if (startEvent.defaultPrevented) {
+        return;
+      }
+      for (const activeInstance of activeChildren) {
+        activeInstance.hide();
+      }
+      const dimension = this._getDimension();
+      this._element.classList.remove(CLASS_NAME_COLLAPSE);
+      this._element.classList.add(CLASS_NAME_COLLAPSING);
+      this._element.style[dimension] = 0;
+      this._addAriaAndCollapsedClass(this._triggerArray, true);
+      this._isTransitioning = true;
+      const complete = () => {
+        this._isTransitioning = false;
+        this._element.classList.remove(CLASS_NAME_COLLAPSING);
+        this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);
+        this._element.style[dimension] = '';
+        EventHandler.trigger(this._element, EVENT_SHOWN$6);
+      };
+      const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
+      const scrollSize = `scroll${capitalizedDimension}`;
+      this._queueCallback(complete, this._element, true);
+      this._element.style[dimension] = `${this._element[scrollSize]}px`;
+    }
+    hide() {
+      if (this._isTransitioning || !this._isShown()) {
+        return;
+      }
+      const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6);
+      if (startEvent.defaultPrevented) {
+        return;
+      }
+      const dimension = this._getDimension();
+      this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;
+      reflow(this._element);
+      this._element.classList.add(CLASS_NAME_COLLAPSING);
+      this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);
+      for (const trigger of this._triggerArray) {
+        const element = SelectorEngine.getElementFromSelector(trigger);
+        if (element && !this._isShown(element)) {
+          this._addAriaAndCollapsedClass([trigger], false);
+        }
+      }
+      this._isTransitioning = true;
+      const complete = () => {
+        this._isTransitioning = false;
+        this._element.classList.remove(CLASS_NAME_COLLAPSING);
+        this._element.classList.add(CLASS_NAME_COLLAPSE);
+        EventHandler.trigger(this._element, EVENT_HIDDEN$6);
+      };
+      this._element.style[dimension] = '';
+      this._queueCallback(complete, this._element, true);
+    }
+    _isShown(element = this._element) {
+      return element.classList.contains(CLASS_NAME_SHOW$7);
+    }
+
+    // Private
+    _configAfterMerge(config) {
+      config.toggle = Boolean(config.toggle); // Coerce string values
+      config.parent = getElement(config.parent);
+      return config;
+    }
+    _getDimension() {
+      return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;
+    }
+    _initializeChildren() {
+      if (!this._config.parent) {
+        return;
+      }
+      const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4);
+      for (const element of children) {
+        const selected = SelectorEngine.getElementFromSelector(element);
+        if (selected) {
+          this._addAriaAndCollapsedClass([element], this._isShown(selected));
+        }
+      }
+    }
+    _getFirstLevelChildren(selector) {
+      const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);
+      // remove children if greater depth
+      return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));
+    }
+    _addAriaAndCollapsedClass(triggerArray, isOpen) {
+      if (!triggerArray.length) {
+        return;
+      }
+      for (const element of triggerArray) {
+        element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);
+        element.setAttribute('aria-expanded', isOpen);
+      }
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      const _config = {};
+      if (typeof config === 'string' && /show|hide/.test(config)) {
+        _config.toggle = false;
+      }
+      return this.each(function () {
+        const data = Collapse.getOrCreateInstance(this, _config);
+        if (typeof config === 'string') {
+          if (typeof data[config] === 'undefined') {
+            throw new TypeError(`No method named "${config}"`);
+          }
+          data[config]();
+        }
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) {
+    // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
+    if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {
+      event.preventDefault();
+    }
+    for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {
+      Collapse.getOrCreateInstance(element, {
+        toggle: false
+      }).toggle();
+    }
+  });
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Collapse);
+
+  var top = 'top';
+  var bottom = 'bottom';
+  var right = 'right';
+  var left = 'left';
+  var auto = 'auto';
+  var basePlacements = [top, bottom, right, left];
+  var start = 'start';
+  var end = 'end';
+  var clippingParents = 'clippingParents';
+  var viewport = 'viewport';
+  var popper = 'popper';
+  var reference = 'reference';
+  var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {
+    return acc.concat([placement + "-" + start, placement + "-" + end]);
+  }, []);
+  var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {
+    return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
+  }, []); // modifiers that need to read the DOM
+
+  var beforeRead = 'beforeRead';
+  var read = 'read';
+  var afterRead = 'afterRead'; // pure-logic modifiers
+
+  var beforeMain = 'beforeMain';
+  var main = 'main';
+  var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)
+
+  var beforeWrite = 'beforeWrite';
+  var write = 'write';
+  var afterWrite = 'afterWrite';
+  var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
+
+  function getNodeName(element) {
+    return element ? (element.nodeName || '').toLowerCase() : null;
+  }
+
+  function getWindow(node) {
+    if (node == null) {
+      return window;
+    }
+
+    if (node.toString() !== '[object Window]') {
+      var ownerDocument = node.ownerDocument;
+      return ownerDocument ? ownerDocument.defaultView || window : window;
+    }
+
+    return node;
+  }
+
+  function isElement(node) {
+    var OwnElement = getWindow(node).Element;
+    return node instanceof OwnElement || node instanceof Element;
+  }
+
+  function isHTMLElement(node) {
+    var OwnElement = getWindow(node).HTMLElement;
+    return node instanceof OwnElement || node instanceof HTMLElement;
+  }
+
+  function isShadowRoot(node) {
+    // IE 11 has no ShadowRoot
+    if (typeof ShadowRoot === 'undefined') {
+      return false;
+    }
+
+    var OwnElement = getWindow(node).ShadowRoot;
+    return node instanceof OwnElement || node instanceof ShadowRoot;
+  }
+
+  // and applies them to the HTMLElements such as popper and arrow
+
+  function applyStyles(_ref) {
+    var state = _ref.state;
+    Object.keys(state.elements).forEach(function (name) {
+      var style = state.styles[name] || {};
+      var attributes = state.attributes[name] || {};
+      var element = state.elements[name]; // arrow is optional + virtual elements
+
+      if (!isHTMLElement(element) || !getNodeName(element)) {
+        return;
+      } // Flow doesn't support to extend this property, but it's the most
+      // effective way to apply styles to an HTMLElement
+      // $FlowFixMe[cannot-write]
+
+
+      Object.assign(element.style, style);
+      Object.keys(attributes).forEach(function (name) {
+        var value = attributes[name];
+
+        if (value === false) {
+          element.removeAttribute(name);
+        } else {
+          element.setAttribute(name, value === true ? '' : value);
+        }
+      });
+    });
+  }
+
+  function effect$2(_ref2) {
+    var state = _ref2.state;
+    var initialStyles = {
+      popper: {
+        position: state.options.strategy,
+        left: '0',
+        top: '0',
+        margin: '0'
+      },
+      arrow: {
+        position: 'absolute'
+      },
+      reference: {}
+    };
+    Object.assign(state.elements.popper.style, initialStyles.popper);
+    state.styles = initialStyles;
+
+    if (state.elements.arrow) {
+      Object.assign(state.elements.arrow.style, initialStyles.arrow);
+    }
+
+    return function () {
+      Object.keys(state.elements).forEach(function (name) {
+        var element = state.elements[name];
+        var attributes = state.attributes[name] || {};
+        var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them
+
+        var style = styleProperties.reduce(function (style, property) {
+          style[property] = '';
+          return style;
+        }, {}); // arrow is optional + virtual elements
+
+        if (!isHTMLElement(element) || !getNodeName(element)) {
+          return;
+        }
+
+        Object.assign(element.style, style);
+        Object.keys(attributes).forEach(function (attribute) {
+          element.removeAttribute(attribute);
+        });
+      });
+    };
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const applyStyles$1 = {
+    name: 'applyStyles',
+    enabled: true,
+    phase: 'write',
+    fn: applyStyles,
+    effect: effect$2,
+    requires: ['computeStyles']
+  };
+
+  function getBasePlacement(placement) {
+    return placement.split('-')[0];
+  }
+
+  var max = Math.max;
+  var min = Math.min;
+  var round = Math.round;
+
+  function getUAString() {
+    var uaData = navigator.userAgentData;
+
+    if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {
+      return uaData.brands.map(function (item) {
+        return item.brand + "/" + item.version;
+      }).join(' ');
+    }
+
+    return navigator.userAgent;
+  }
+
+  function isLayoutViewport() {
+    return !/^((?!chrome|android).)*safari/i.test(getUAString());
+  }
+
+  function getBoundingClientRect(element, includeScale, isFixedStrategy) {
+    if (includeScale === void 0) {
+      includeScale = false;
+    }
+
+    if (isFixedStrategy === void 0) {
+      isFixedStrategy = false;
+    }
+
+    var clientRect = element.getBoundingClientRect();
+    var scaleX = 1;
+    var scaleY = 1;
+
+    if (includeScale && isHTMLElement(element)) {
+      scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
+      scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
+    }
+
+    var _ref = isElement(element) ? getWindow(element) : window,
+        visualViewport = _ref.visualViewport;
+
+    var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;
+    var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;
+    var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;
+    var width = clientRect.width / scaleX;
+    var height = clientRect.height / scaleY;
+    return {
+      width: width,
+      height: height,
+      top: y,
+      right: x + width,
+      bottom: y + height,
+      left: x,
+      x: x,
+      y: y
+    };
+  }
+
+  // means it doesn't take into account transforms.
+
+  function getLayoutRect(element) {
+    var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.
+    // Fixes https://github.com/popperjs/popper-core/issues/1223
+
+    var width = element.offsetWidth;
+    var height = element.offsetHeight;
+
+    if (Math.abs(clientRect.width - width) <= 1) {
+      width = clientRect.width;
+    }
+
+    if (Math.abs(clientRect.height - height) <= 1) {
+      height = clientRect.height;
+    }
+
+    return {
+      x: element.offsetLeft,
+      y: element.offsetTop,
+      width: width,
+      height: height
+    };
+  }
+
+  function contains(parent, child) {
+    var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method
+
+    if (parent.contains(child)) {
+      return true;
+    } // then fallback to custom implementation with Shadow DOM support
+    else if (rootNode && isShadowRoot(rootNode)) {
+        var next = child;
+
+        do {
+          if (next && parent.isSameNode(next)) {
+            return true;
+          } // $FlowFixMe[prop-missing]: need a better way to handle this...
+
+
+          next = next.parentNode || next.host;
+        } while (next);
+      } // Give up, the result is false
+
+
+    return false;
+  }
+
+  function getComputedStyle$1(element) {
+    return getWindow(element).getComputedStyle(element);
+  }
+
+  function isTableElement(element) {
+    return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
+  }
+
+  function getDocumentElement(element) {
+    // $FlowFixMe[incompatible-return]: assume body is always available
+    return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
+    element.document) || window.document).documentElement;
+  }
+
+  function getParentNode(element) {
+    if (getNodeName(element) === 'html') {
+      return element;
+    }
+
+    return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
+      // $FlowFixMe[incompatible-return]
+      // $FlowFixMe[prop-missing]
+      element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
+      element.parentNode || ( // DOM Element detected
+      isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
+      // $FlowFixMe[incompatible-call]: HTMLElement is a Node
+      getDocumentElement(element) // fallback
+
+    );
+  }
+
+  function getTrueOffsetParent(element) {
+    if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
+    getComputedStyle$1(element).position === 'fixed') {
+      return null;
+    }
+
+    return element.offsetParent;
+  } // `.offsetParent` reports `null` for fixed elements, while absolute elements
+  // return the containing block
+
+
+  function getContainingBlock(element) {
+    var isFirefox = /firefox/i.test(getUAString());
+    var isIE = /Trident/i.test(getUAString());
+
+    if (isIE && isHTMLElement(element)) {
+      // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
+      var elementCss = getComputedStyle$1(element);
+
+      if (elementCss.position === 'fixed') {
+        return null;
+      }
+    }
+
+    var currentNode = getParentNode(element);
+
+    if (isShadowRoot(currentNode)) {
+      currentNode = currentNode.host;
+    }
+
+    while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
+      var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that
+      // create a containing block.
+      // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
+
+      if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
+        return currentNode;
+      } else {
+        currentNode = currentNode.parentNode;
+      }
+    }
+
+    return null;
+  } // Gets the closest ancestor positioned element. Handles some edge cases,
+  // such as table ancestors and cross browser bugs.
+
+
+  function getOffsetParent(element) {
+    var window = getWindow(element);
+    var offsetParent = getTrueOffsetParent(element);
+
+    while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') {
+      offsetParent = getTrueOffsetParent(offsetParent);
+    }
+
+    if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) {
+      return window;
+    }
+
+    return offsetParent || getContainingBlock(element) || window;
+  }
+
+  function getMainAxisFromPlacement(placement) {
+    return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';
+  }
+
+  function within(min$1, value, max$1) {
+    return max(min$1, min(value, max$1));
+  }
+  function withinMaxClamp(min, value, max) {
+    var v = within(min, value, max);
+    return v > max ? max : v;
+  }
+
+  function getFreshSideObject() {
+    return {
+      top: 0,
+      right: 0,
+      bottom: 0,
+      left: 0
+    };
+  }
+
+  function mergePaddingObject(paddingObject) {
+    return Object.assign({}, getFreshSideObject(), paddingObject);
+  }
+
+  function expandToHashMap(value, keys) {
+    return keys.reduce(function (hashMap, key) {
+      hashMap[key] = value;
+      return hashMap;
+    }, {});
+  }
+
+  var toPaddingObject = function toPaddingObject(padding, state) {
+    padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {
+      placement: state.placement
+    })) : padding;
+    return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+  };
+
+  function arrow(_ref) {
+    var _state$modifiersData$;
+
+    var state = _ref.state,
+        name = _ref.name,
+        options = _ref.options;
+    var arrowElement = state.elements.arrow;
+    var popperOffsets = state.modifiersData.popperOffsets;
+    var basePlacement = getBasePlacement(state.placement);
+    var axis = getMainAxisFromPlacement(basePlacement);
+    var isVertical = [left, right].indexOf(basePlacement) >= 0;
+    var len = isVertical ? 'height' : 'width';
+
+    if (!arrowElement || !popperOffsets) {
+      return;
+    }
+
+    var paddingObject = toPaddingObject(options.padding, state);
+    var arrowRect = getLayoutRect(arrowElement);
+    var minProp = axis === 'y' ? top : left;
+    var maxProp = axis === 'y' ? bottom : right;
+    var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];
+    var startDiff = popperOffsets[axis] - state.rects.reference[axis];
+    var arrowOffsetParent = getOffsetParent(arrowElement);
+    var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
+    var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is
+    // outside of the popper bounds
+
+    var min = paddingObject[minProp];
+    var max = clientSize - arrowRect[len] - paddingObject[maxProp];
+    var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
+    var offset = within(min, center, max); // Prevents breaking syntax highlighting...
+
+    var axisProp = axis;
+    state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);
+  }
+
+  function effect$1(_ref2) {
+    var state = _ref2.state,
+        options = _ref2.options;
+    var _options$element = options.element,
+        arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;
+
+    if (arrowElement == null) {
+      return;
+    } // CSS selector
+
+
+    if (typeof arrowElement === 'string') {
+      arrowElement = state.elements.popper.querySelector(arrowElement);
+
+      if (!arrowElement) {
+        return;
+      }
+    }
+
+    if (!contains(state.elements.popper, arrowElement)) {
+      return;
+    }
+
+    state.elements.arrow = arrowElement;
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const arrow$1 = {
+    name: 'arrow',
+    enabled: true,
+    phase: 'main',
+    fn: arrow,
+    effect: effect$1,
+    requires: ['popperOffsets'],
+    requiresIfExists: ['preventOverflow']
+  };
+
+  function getVariation(placement) {
+    return placement.split('-')[1];
+  }
+
+  var unsetSides = {
+    top: 'auto',
+    right: 'auto',
+    bottom: 'auto',
+    left: 'auto'
+  }; // Round the offsets to the nearest suitable subpixel based on the DPR.
+  // Zooming can change the DPR, but it seems to report a value that will
+  // cleanly divide the values into the appropriate subpixels.
+
+  function roundOffsetsByDPR(_ref, win) {
+    var x = _ref.x,
+        y = _ref.y;
+    var dpr = win.devicePixelRatio || 1;
+    return {
+      x: round(x * dpr) / dpr || 0,
+      y: round(y * dpr) / dpr || 0
+    };
+  }
+
+  function mapToStyles(_ref2) {
+    var _Object$assign2;
+
+    var popper = _ref2.popper,
+        popperRect = _ref2.popperRect,
+        placement = _ref2.placement,
+        variation = _ref2.variation,
+        offsets = _ref2.offsets,
+        position = _ref2.position,
+        gpuAcceleration = _ref2.gpuAcceleration,
+        adaptive = _ref2.adaptive,
+        roundOffsets = _ref2.roundOffsets,
+        isFixed = _ref2.isFixed;
+    var _offsets$x = offsets.x,
+        x = _offsets$x === void 0 ? 0 : _offsets$x,
+        _offsets$y = offsets.y,
+        y = _offsets$y === void 0 ? 0 : _offsets$y;
+
+    var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({
+      x: x,
+      y: y
+    }) : {
+      x: x,
+      y: y
+    };
+
+    x = _ref3.x;
+    y = _ref3.y;
+    var hasX = offsets.hasOwnProperty('x');
+    var hasY = offsets.hasOwnProperty('y');
+    var sideX = left;
+    var sideY = top;
+    var win = window;
+
+    if (adaptive) {
+      var offsetParent = getOffsetParent(popper);
+      var heightProp = 'clientHeight';
+      var widthProp = 'clientWidth';
+
+      if (offsetParent === getWindow(popper)) {
+        offsetParent = getDocumentElement(popper);
+
+        if (getComputedStyle$1(offsetParent).position !== 'static' && position === 'absolute') {
+          heightProp = 'scrollHeight';
+          widthProp = 'scrollWidth';
+        }
+      } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
+
+
+      offsetParent = offsetParent;
+
+      if (placement === top || (placement === left || placement === right) && variation === end) {
+        sideY = bottom;
+        var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]
+        offsetParent[heightProp];
+        y -= offsetY - popperRect.height;
+        y *= gpuAcceleration ? 1 : -1;
+      }
+
+      if (placement === left || (placement === top || placement === bottom) && variation === end) {
+        sideX = right;
+        var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]
+        offsetParent[widthProp];
+        x -= offsetX - popperRect.width;
+        x *= gpuAcceleration ? 1 : -1;
+      }
+    }
+
+    var commonStyles = Object.assign({
+      position: position
+    }, adaptive && unsetSides);
+
+    var _ref4 = roundOffsets === true ? roundOffsetsByDPR({
+      x: x,
+      y: y
+    }, getWindow(popper)) : {
+      x: x,
+      y: y
+    };
+
+    x = _ref4.x;
+    y = _ref4.y;
+
+    if (gpuAcceleration) {
+      var _Object$assign;
+
+      return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
+    }
+
+    return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
+  }
+
+  function computeStyles(_ref5) {
+    var state = _ref5.state,
+        options = _ref5.options;
+    var _options$gpuAccelerat = options.gpuAcceleration,
+        gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
+        _options$adaptive = options.adaptive,
+        adaptive = _options$adaptive === void 0 ? true : _options$adaptive,
+        _options$roundOffsets = options.roundOffsets,
+        roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
+    var commonStyles = {
+      placement: getBasePlacement(state.placement),
+      variation: getVariation(state.placement),
+      popper: state.elements.popper,
+      popperRect: state.rects.popper,
+      gpuAcceleration: gpuAcceleration,
+      isFixed: state.options.strategy === 'fixed'
+    };
+
+    if (state.modifiersData.popperOffsets != null) {
+      state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
+        offsets: state.modifiersData.popperOffsets,
+        position: state.options.strategy,
+        adaptive: adaptive,
+        roundOffsets: roundOffsets
+      })));
+    }
+
+    if (state.modifiersData.arrow != null) {
+      state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
+        offsets: state.modifiersData.arrow,
+        position: 'absolute',
+        adaptive: false,
+        roundOffsets: roundOffsets
+      })));
+    }
+
+    state.attributes.popper = Object.assign({}, state.attributes.popper, {
+      'data-popper-placement': state.placement
+    });
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const computeStyles$1 = {
+    name: 'computeStyles',
+    enabled: true,
+    phase: 'beforeWrite',
+    fn: computeStyles,
+    data: {}
+  };
+
+  var passive = {
+    passive: true
+  };
+
+  function effect(_ref) {
+    var state = _ref.state,
+        instance = _ref.instance,
+        options = _ref.options;
+    var _options$scroll = options.scroll,
+        scroll = _options$scroll === void 0 ? true : _options$scroll,
+        _options$resize = options.resize,
+        resize = _options$resize === void 0 ? true : _options$resize;
+    var window = getWindow(state.elements.popper);
+    var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
+
+    if (scroll) {
+      scrollParents.forEach(function (scrollParent) {
+        scrollParent.addEventListener('scroll', instance.update, passive);
+      });
+    }
+
+    if (resize) {
+      window.addEventListener('resize', instance.update, passive);
+    }
+
+    return function () {
+      if (scroll) {
+        scrollParents.forEach(function (scrollParent) {
+          scrollParent.removeEventListener('scroll', instance.update, passive);
+        });
+      }
+
+      if (resize) {
+        window.removeEventListener('resize', instance.update, passive);
+      }
+    };
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const eventListeners = {
+    name: 'eventListeners',
+    enabled: true,
+    phase: 'write',
+    fn: function fn() {},
+    effect: effect,
+    data: {}
+  };
+
+  var hash$1 = {
+    left: 'right',
+    right: 'left',
+    bottom: 'top',
+    top: 'bottom'
+  };
+  function getOppositePlacement(placement) {
+    return placement.replace(/left|right|bottom|top/g, function (matched) {
+      return hash$1[matched];
+    });
+  }
+
+  var hash = {
+    start: 'end',
+    end: 'start'
+  };
+  function getOppositeVariationPlacement(placement) {
+    return placement.replace(/start|end/g, function (matched) {
+      return hash[matched];
+    });
+  }
+
+  function getWindowScroll(node) {
+    var win = getWindow(node);
+    var scrollLeft = win.pageXOffset;
+    var scrollTop = win.pageYOffset;
+    return {
+      scrollLeft: scrollLeft,
+      scrollTop: scrollTop
+    };
+  }
+
+  function getWindowScrollBarX(element) {
+    // If <html> has a CSS width greater than the viewport, then this will be
+    // incorrect for RTL.
+    // Popper 1 is broken in this case and never had a bug report so let's assume
+    // it's not an issue. I don't think anyone ever specifies width on <html>
+    // anyway.
+    // Browsers where the left scrollbar doesn't cause an issue report `0` for
+    // this (e.g. Edge 2019, IE11, Safari)
+    return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
+  }
+
+  function getViewportRect(element, strategy) {
+    var win = getWindow(element);
+    var html = getDocumentElement(element);
+    var visualViewport = win.visualViewport;
+    var width = html.clientWidth;
+    var height = html.clientHeight;
+    var x = 0;
+    var y = 0;
+
+    if (visualViewport) {
+      width = visualViewport.width;
+      height = visualViewport.height;
+      var layoutViewport = isLayoutViewport();
+
+      if (layoutViewport || !layoutViewport && strategy === 'fixed') {
+        x = visualViewport.offsetLeft;
+        y = visualViewport.offsetTop;
+      }
+    }
+
+    return {
+      width: width,
+      height: height,
+      x: x + getWindowScrollBarX(element),
+      y: y
+    };
+  }
+
+  // of the `<html>` and `<body>` rect bounds if horizontally scrollable
+
+  function getDocumentRect(element) {
+    var _element$ownerDocumen;
+
+    var html = getDocumentElement(element);
+    var winScroll = getWindowScroll(element);
+    var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
+    var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
+    var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
+    var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
+    var y = -winScroll.scrollTop;
+
+    if (getComputedStyle$1(body || html).direction === 'rtl') {
+      x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
+    }
+
+    return {
+      width: width,
+      height: height,
+      x: x,
+      y: y
+    };
+  }
+
+  function isScrollParent(element) {
+    // Firefox wants us to check `-x` and `-y` variations as well
+    var _getComputedStyle = getComputedStyle$1(element),
+        overflow = _getComputedStyle.overflow,
+        overflowX = _getComputedStyle.overflowX,
+        overflowY = _getComputedStyle.overflowY;
+
+    return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
+  }
+
+  function getScrollParent(node) {
+    if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
+      // $FlowFixMe[incompatible-return]: assume body is always available
+      return node.ownerDocument.body;
+    }
+
+    if (isHTMLElement(node) && isScrollParent(node)) {
+      return node;
+    }
+
+    return getScrollParent(getParentNode(node));
+  }
+
+  /*
+  given a DOM element, return the list of all scroll parents, up the list of ancesors
+  until we get to the top window object. This list is what we attach scroll listeners
+  to, because if any of these parent elements scroll, we'll need to re-calculate the
+  reference element's position.
+  */
+
+  function listScrollParents(element, list) {
+    var _element$ownerDocumen;
+
+    if (list === void 0) {
+      list = [];
+    }
+
+    var scrollParent = getScrollParent(element);
+    var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
+    var win = getWindow(scrollParent);
+    var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
+    var updatedList = list.concat(target);
+    return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
+    updatedList.concat(listScrollParents(getParentNode(target)));
+  }
+
+  function rectToClientRect(rect) {
+    return Object.assign({}, rect, {
+      left: rect.x,
+      top: rect.y,
+      right: rect.x + rect.width,
+      bottom: rect.y + rect.height
+    });
+  }
+
+  function getInnerBoundingClientRect(element, strategy) {
+    var rect = getBoundingClientRect(element, false, strategy === 'fixed');
+    rect.top = rect.top + element.clientTop;
+    rect.left = rect.left + element.clientLeft;
+    rect.bottom = rect.top + element.clientHeight;
+    rect.right = rect.left + element.clientWidth;
+    rect.width = element.clientWidth;
+    rect.height = element.clientHeight;
+    rect.x = rect.left;
+    rect.y = rect.top;
+    return rect;
+  }
+
+  function getClientRectFromMixedType(element, clippingParent, strategy) {
+    return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
+  } // A "clipping parent" is an overflowable container with the characteristic of
+  // clipping (or hiding) overflowing elements with a position different from
+  // `initial`
+
+
+  function getClippingParents(element) {
+    var clippingParents = listScrollParents(getParentNode(element));
+    var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0;
+    var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
+
+    if (!isElement(clipperElement)) {
+      return [];
+    } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414
+
+
+    return clippingParents.filter(function (clippingParent) {
+      return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
+    });
+  } // Gets the maximum area that the element is visible in due to any number of
+  // clipping parents
+
+
+  function getClippingRect(element, boundary, rootBoundary, strategy) {
+    var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
+    var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
+    var firstClippingParent = clippingParents[0];
+    var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
+      var rect = getClientRectFromMixedType(element, clippingParent, strategy);
+      accRect.top = max(rect.top, accRect.top);
+      accRect.right = min(rect.right, accRect.right);
+      accRect.bottom = min(rect.bottom, accRect.bottom);
+      accRect.left = max(rect.left, accRect.left);
+      return accRect;
+    }, getClientRectFromMixedType(element, firstClippingParent, strategy));
+    clippingRect.width = clippingRect.right - clippingRect.left;
+    clippingRect.height = clippingRect.bottom - clippingRect.top;
+    clippingRect.x = clippingRect.left;
+    clippingRect.y = clippingRect.top;
+    return clippingRect;
+  }
+
+  function computeOffsets(_ref) {
+    var reference = _ref.reference,
+        element = _ref.element,
+        placement = _ref.placement;
+    var basePlacement = placement ? getBasePlacement(placement) : null;
+    var variation = placement ? getVariation(placement) : null;
+    var commonX = reference.x + reference.width / 2 - element.width / 2;
+    var commonY = reference.y + reference.height / 2 - element.height / 2;
+    var offsets;
+
+    switch (basePlacement) {
+      case top:
+        offsets = {
+          x: commonX,
+          y: reference.y - element.height
+        };
+        break;
+
+      case bottom:
+        offsets = {
+          x: commonX,
+          y: reference.y + reference.height
+        };
+        break;
+
+      case right:
+        offsets = {
+          x: reference.x + reference.width,
+          y: commonY
+        };
+        break;
+
+      case left:
+        offsets = {
+          x: reference.x - element.width,
+          y: commonY
+        };
+        break;
+
+      default:
+        offsets = {
+          x: reference.x,
+          y: reference.y
+        };
+    }
+
+    var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
+
+    if (mainAxis != null) {
+      var len = mainAxis === 'y' ? 'height' : 'width';
+
+      switch (variation) {
+        case start:
+          offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);
+          break;
+
+        case end:
+          offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);
+          break;
+      }
+    }
+
+    return offsets;
+  }
+
+  function detectOverflow(state, options) {
+    if (options === void 0) {
+      options = {};
+    }
+
+    var _options = options,
+        _options$placement = _options.placement,
+        placement = _options$placement === void 0 ? state.placement : _options$placement,
+        _options$strategy = _options.strategy,
+        strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,
+        _options$boundary = _options.boundary,
+        boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,
+        _options$rootBoundary = _options.rootBoundary,
+        rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,
+        _options$elementConte = _options.elementContext,
+        elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,
+        _options$altBoundary = _options.altBoundary,
+        altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,
+        _options$padding = _options.padding,
+        padding = _options$padding === void 0 ? 0 : _options$padding;
+    var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+    var altContext = elementContext === popper ? reference : popper;
+    var popperRect = state.rects.popper;
+    var element = state.elements[altBoundary ? altContext : elementContext];
+    var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);
+    var referenceClientRect = getBoundingClientRect(state.elements.reference);
+    var popperOffsets = computeOffsets({
+      reference: referenceClientRect,
+      element: popperRect,
+      strategy: 'absolute',
+      placement: placement
+    });
+    var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));
+    var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect
+    // 0 or negative = within the clipping rect
+
+    var overflowOffsets = {
+      top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
+      bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
+      left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
+      right: elementClientRect.right - clippingClientRect.right + paddingObject.right
+    };
+    var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element
+
+    if (elementContext === popper && offsetData) {
+      var offset = offsetData[placement];
+      Object.keys(overflowOffsets).forEach(function (key) {
+        var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
+        var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
+        overflowOffsets[key] += offset[axis] * multiply;
+      });
+    }
+
+    return overflowOffsets;
+  }
+
+  function computeAutoPlacement(state, options) {
+    if (options === void 0) {
+      options = {};
+    }
+
+    var _options = options,
+        placement = _options.placement,
+        boundary = _options.boundary,
+        rootBoundary = _options.rootBoundary,
+        padding = _options.padding,
+        flipVariations = _options.flipVariations,
+        _options$allowedAutoP = _options.allowedAutoPlacements,
+        allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;
+    var variation = getVariation(placement);
+    var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {
+      return getVariation(placement) === variation;
+    }) : basePlacements;
+    var allowedPlacements = placements$1.filter(function (placement) {
+      return allowedAutoPlacements.indexOf(placement) >= 0;
+    });
+
+    if (allowedPlacements.length === 0) {
+      allowedPlacements = placements$1;
+    } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...
+
+
+    var overflows = allowedPlacements.reduce(function (acc, placement) {
+      acc[placement] = detectOverflow(state, {
+        placement: placement,
+        boundary: boundary,
+        rootBoundary: rootBoundary,
+        padding: padding
+      })[getBasePlacement(placement)];
+      return acc;
+    }, {});
+    return Object.keys(overflows).sort(function (a, b) {
+      return overflows[a] - overflows[b];
+    });
+  }
+
+  function getExpandedFallbackPlacements(placement) {
+    if (getBasePlacement(placement) === auto) {
+      return [];
+    }
+
+    var oppositePlacement = getOppositePlacement(placement);
+    return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
+  }
+
+  function flip(_ref) {
+    var state = _ref.state,
+        options = _ref.options,
+        name = _ref.name;
+
+    if (state.modifiersData[name]._skip) {
+      return;
+    }
+
+    var _options$mainAxis = options.mainAxis,
+        checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+        _options$altAxis = options.altAxis,
+        checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,
+        specifiedFallbackPlacements = options.fallbackPlacements,
+        padding = options.padding,
+        boundary = options.boundary,
+        rootBoundary = options.rootBoundary,
+        altBoundary = options.altBoundary,
+        _options$flipVariatio = options.flipVariations,
+        flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,
+        allowedAutoPlacements = options.allowedAutoPlacements;
+    var preferredPlacement = state.options.placement;
+    var basePlacement = getBasePlacement(preferredPlacement);
+    var isBasePlacement = basePlacement === preferredPlacement;
+    var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
+    var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {
+      return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {
+        placement: placement,
+        boundary: boundary,
+        rootBoundary: rootBoundary,
+        padding: padding,
+        flipVariations: flipVariations,
+        allowedAutoPlacements: allowedAutoPlacements
+      }) : placement);
+    }, []);
+    var referenceRect = state.rects.reference;
+    var popperRect = state.rects.popper;
+    var checksMap = new Map();
+    var makeFallbackChecks = true;
+    var firstFittingPlacement = placements[0];
+
+    for (var i = 0; i < placements.length; i++) {
+      var placement = placements[i];
+
+      var _basePlacement = getBasePlacement(placement);
+
+      var isStartVariation = getVariation(placement) === start;
+      var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;
+      var len = isVertical ? 'width' : 'height';
+      var overflow = detectOverflow(state, {
+        placement: placement,
+        boundary: boundary,
+        rootBoundary: rootBoundary,
+        altBoundary: altBoundary,
+        padding: padding
+      });
+      var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;
+
+      if (referenceRect[len] > popperRect[len]) {
+        mainVariationSide = getOppositePlacement(mainVariationSide);
+      }
+
+      var altVariationSide = getOppositePlacement(mainVariationSide);
+      var checks = [];
+
+      if (checkMainAxis) {
+        checks.push(overflow[_basePlacement] <= 0);
+      }
+
+      if (checkAltAxis) {
+        checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
+      }
+
+      if (checks.every(function (check) {
+        return check;
+      })) {
+        firstFittingPlacement = placement;
+        makeFallbackChecks = false;
+        break;
+      }
+
+      checksMap.set(placement, checks);
+    }
+
+    if (makeFallbackChecks) {
+      // `2` may be desired in some cases – research later
+      var numberOfChecks = flipVariations ? 3 : 1;
+
+      var _loop = function _loop(_i) {
+        var fittingPlacement = placements.find(function (placement) {
+          var checks = checksMap.get(placement);
+
+          if (checks) {
+            return checks.slice(0, _i).every(function (check) {
+              return check;
+            });
+          }
+        });
+
+        if (fittingPlacement) {
+          firstFittingPlacement = fittingPlacement;
+          return "break";
+        }
+      };
+
+      for (var _i = numberOfChecks; _i > 0; _i--) {
+        var _ret = _loop(_i);
+
+        if (_ret === "break") break;
+      }
+    }
+
+    if (state.placement !== firstFittingPlacement) {
+      state.modifiersData[name]._skip = true;
+      state.placement = firstFittingPlacement;
+      state.reset = true;
+    }
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const flip$1 = {
+    name: 'flip',
+    enabled: true,
+    phase: 'main',
+    fn: flip,
+    requiresIfExists: ['offset'],
+    data: {
+      _skip: false
+    }
+  };
+
+  function getSideOffsets(overflow, rect, preventedOffsets) {
+    if (preventedOffsets === void 0) {
+      preventedOffsets = {
+        x: 0,
+        y: 0
+      };
+    }
+
+    return {
+      top: overflow.top - rect.height - preventedOffsets.y,
+      right: overflow.right - rect.width + preventedOffsets.x,
+      bottom: overflow.bottom - rect.height + preventedOffsets.y,
+      left: overflow.left - rect.width - preventedOffsets.x
+    };
+  }
+
+  function isAnySideFullyClipped(overflow) {
+    return [top, right, bottom, left].some(function (side) {
+      return overflow[side] >= 0;
+    });
+  }
+
+  function hide(_ref) {
+    var state = _ref.state,
+        name = _ref.name;
+    var referenceRect = state.rects.reference;
+    var popperRect = state.rects.popper;
+    var preventedOffsets = state.modifiersData.preventOverflow;
+    var referenceOverflow = detectOverflow(state, {
+      elementContext: 'reference'
+    });
+    var popperAltOverflow = detectOverflow(state, {
+      altBoundary: true
+    });
+    var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
+    var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
+    var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
+    var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
+    state.modifiersData[name] = {
+      referenceClippingOffsets: referenceClippingOffsets,
+      popperEscapeOffsets: popperEscapeOffsets,
+      isReferenceHidden: isReferenceHidden,
+      hasPopperEscaped: hasPopperEscaped
+    };
+    state.attributes.popper = Object.assign({}, state.attributes.popper, {
+      'data-popper-reference-hidden': isReferenceHidden,
+      'data-popper-escaped': hasPopperEscaped
+    });
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const hide$1 = {
+    name: 'hide',
+    enabled: true,
+    phase: 'main',
+    requiresIfExists: ['preventOverflow'],
+    fn: hide
+  };
+
+  function distanceAndSkiddingToXY(placement, rects, offset) {
+    var basePlacement = getBasePlacement(placement);
+    var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
+
+    var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {
+      placement: placement
+    })) : offset,
+        skidding = _ref[0],
+        distance = _ref[1];
+
+    skidding = skidding || 0;
+    distance = (distance || 0) * invertDistance;
+    return [left, right].indexOf(basePlacement) >= 0 ? {
+      x: distance,
+      y: skidding
+    } : {
+      x: skidding,
+      y: distance
+    };
+  }
+
+  function offset(_ref2) {
+    var state = _ref2.state,
+        options = _ref2.options,
+        name = _ref2.name;
+    var _options$offset = options.offset,
+        offset = _options$offset === void 0 ? [0, 0] : _options$offset;
+    var data = placements.reduce(function (acc, placement) {
+      acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
+      return acc;
+    }, {});
+    var _data$state$placement = data[state.placement],
+        x = _data$state$placement.x,
+        y = _data$state$placement.y;
+
+    if (state.modifiersData.popperOffsets != null) {
+      state.modifiersData.popperOffsets.x += x;
+      state.modifiersData.popperOffsets.y += y;
+    }
+
+    state.modifiersData[name] = data;
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const offset$1 = {
+    name: 'offset',
+    enabled: true,
+    phase: 'main',
+    requires: ['popperOffsets'],
+    fn: offset
+  };
+
+  function popperOffsets(_ref) {
+    var state = _ref.state,
+        name = _ref.name;
+    // Offsets are the actual position the popper needs to have to be
+    // properly positioned near its reference element
+    // This is the most basic placement, and will be adjusted by
+    // the modifiers in the next step
+    state.modifiersData[name] = computeOffsets({
+      reference: state.rects.reference,
+      element: state.rects.popper,
+      strategy: 'absolute',
+      placement: state.placement
+    });
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const popperOffsets$1 = {
+    name: 'popperOffsets',
+    enabled: true,
+    phase: 'read',
+    fn: popperOffsets,
+    data: {}
+  };
+
+  function getAltAxis(axis) {
+    return axis === 'x' ? 'y' : 'x';
+  }
+
+  function preventOverflow(_ref) {
+    var state = _ref.state,
+        options = _ref.options,
+        name = _ref.name;
+    var _options$mainAxis = options.mainAxis,
+        checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+        _options$altAxis = options.altAxis,
+        checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
+        boundary = options.boundary,
+        rootBoundary = options.rootBoundary,
+        altBoundary = options.altBoundary,
+        padding = options.padding,
+        _options$tether = options.tether,
+        tether = _options$tether === void 0 ? true : _options$tether,
+        _options$tetherOffset = options.tetherOffset,
+        tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
+    var overflow = detectOverflow(state, {
+      boundary: boundary,
+      rootBoundary: rootBoundary,
+      padding: padding,
+      altBoundary: altBoundary
+    });
+    var basePlacement = getBasePlacement(state.placement);
+    var variation = getVariation(state.placement);
+    var isBasePlacement = !variation;
+    var mainAxis = getMainAxisFromPlacement(basePlacement);
+    var altAxis = getAltAxis(mainAxis);
+    var popperOffsets = state.modifiersData.popperOffsets;
+    var referenceRect = state.rects.reference;
+    var popperRect = state.rects.popper;
+    var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {
+      placement: state.placement
+    })) : tetherOffset;
+    var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {
+      mainAxis: tetherOffsetValue,
+      altAxis: tetherOffsetValue
+    } : Object.assign({
+      mainAxis: 0,
+      altAxis: 0
+    }, tetherOffsetValue);
+    var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;
+    var data = {
+      x: 0,
+      y: 0
+    };
+
+    if (!popperOffsets) {
+      return;
+    }
+
+    if (checkMainAxis) {
+      var _offsetModifierState$;
+
+      var mainSide = mainAxis === 'y' ? top : left;
+      var altSide = mainAxis === 'y' ? bottom : right;
+      var len = mainAxis === 'y' ? 'height' : 'width';
+      var offset = popperOffsets[mainAxis];
+      var min$1 = offset + overflow[mainSide];
+      var max$1 = offset - overflow[altSide];
+      var additive = tether ? -popperRect[len] / 2 : 0;
+      var minLen = variation === start ? referenceRect[len] : popperRect[len];
+      var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
+      // outside the reference bounds
+
+      var arrowElement = state.elements.arrow;
+      var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
+        width: 0,
+        height: 0
+      };
+      var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
+      var arrowPaddingMin = arrowPaddingObject[mainSide];
+      var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
+      // to include its full size in the calculation. If the reference is small
+      // and near the edge of a boundary, the popper can overflow even if the
+      // reference is not overflowing as well (e.g. virtual elements with no
+      // width or height)
+
+      var arrowLen = within(0, referenceRect[len], arrowRect[len]);
+      var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;
+      var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;
+      var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
+      var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
+      var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;
+      var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;
+      var tetherMax = offset + maxOffset - offsetModifierValue;
+      var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1);
+      popperOffsets[mainAxis] = preventedOffset;
+      data[mainAxis] = preventedOffset - offset;
+    }
+
+    if (checkAltAxis) {
+      var _offsetModifierState$2;
+
+      var _mainSide = mainAxis === 'x' ? top : left;
+
+      var _altSide = mainAxis === 'x' ? bottom : right;
+
+      var _offset = popperOffsets[altAxis];
+
+      var _len = altAxis === 'y' ? 'height' : 'width';
+
+      var _min = _offset + overflow[_mainSide];
+
+      var _max = _offset - overflow[_altSide];
+
+      var isOriginSide = [top, left].indexOf(basePlacement) !== -1;
+
+      var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;
+
+      var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;
+
+      var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;
+
+      var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);
+
+      popperOffsets[altAxis] = _preventedOffset;
+      data[altAxis] = _preventedOffset - _offset;
+    }
+
+    state.modifiersData[name] = data;
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  const preventOverflow$1 = {
+    name: 'preventOverflow',
+    enabled: true,
+    phase: 'main',
+    fn: preventOverflow,
+    requiresIfExists: ['offset']
+  };
+
+  function getHTMLElementScroll(element) {
+    return {
+      scrollLeft: element.scrollLeft,
+      scrollTop: element.scrollTop
+    };
+  }
+
+  function getNodeScroll(node) {
+    if (node === getWindow(node) || !isHTMLElement(node)) {
+      return getWindowScroll(node);
+    } else {
+      return getHTMLElementScroll(node);
+    }
+  }
+
+  function isElementScaled(element) {
+    var rect = element.getBoundingClientRect();
+    var scaleX = round(rect.width) / element.offsetWidth || 1;
+    var scaleY = round(rect.height) / element.offsetHeight || 1;
+    return scaleX !== 1 || scaleY !== 1;
+  } // Returns the composite rect of an element relative to its offsetParent.
+  // Composite means it takes into account transforms as well as layout.
+
+
+  function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
+    if (isFixed === void 0) {
+      isFixed = false;
+    }
+
+    var isOffsetParentAnElement = isHTMLElement(offsetParent);
+    var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);
+    var documentElement = getDocumentElement(offsetParent);
+    var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);
+    var scroll = {
+      scrollLeft: 0,
+      scrollTop: 0
+    };
+    var offsets = {
+      x: 0,
+      y: 0
+    };
+
+    if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
+      if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
+      isScrollParent(documentElement)) {
+        scroll = getNodeScroll(offsetParent);
+      }
+
+      if (isHTMLElement(offsetParent)) {
+        offsets = getBoundingClientRect(offsetParent, true);
+        offsets.x += offsetParent.clientLeft;
+        offsets.y += offsetParent.clientTop;
+      } else if (documentElement) {
+        offsets.x = getWindowScrollBarX(documentElement);
+      }
+    }
+
+    return {
+      x: rect.left + scroll.scrollLeft - offsets.x,
+      y: rect.top + scroll.scrollTop - offsets.y,
+      width: rect.width,
+      height: rect.height
+    };
+  }
+
+  function order(modifiers) {
+    var map = new Map();
+    var visited = new Set();
+    var result = [];
+    modifiers.forEach(function (modifier) {
+      map.set(modifier.name, modifier);
+    }); // On visiting object, check for its dependencies and visit them recursively
+
+    function sort(modifier) {
+      visited.add(modifier.name);
+      var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
+      requires.forEach(function (dep) {
+        if (!visited.has(dep)) {
+          var depModifier = map.get(dep);
+
+          if (depModifier) {
+            sort(depModifier);
+          }
+        }
+      });
+      result.push(modifier);
+    }
+
+    modifiers.forEach(function (modifier) {
+      if (!visited.has(modifier.name)) {
+        // check for visited object
+        sort(modifier);
+      }
+    });
+    return result;
+  }
+
+  function orderModifiers(modifiers) {
+    // order based on dependencies
+    var orderedModifiers = order(modifiers); // order based on phase
+
+    return modifierPhases.reduce(function (acc, phase) {
+      return acc.concat(orderedModifiers.filter(function (modifier) {
+        return modifier.phase === phase;
+      }));
+    }, []);
+  }
+
+  function debounce(fn) {
+    var pending;
+    return function () {
+      if (!pending) {
+        pending = new Promise(function (resolve) {
+          Promise.resolve().then(function () {
+            pending = undefined;
+            resolve(fn());
+          });
+        });
+      }
+
+      return pending;
+    };
+  }
+
+  function mergeByName(modifiers) {
+    var merged = modifiers.reduce(function (merged, current) {
+      var existing = merged[current.name];
+      merged[current.name] = existing ? Object.assign({}, existing, current, {
+        options: Object.assign({}, existing.options, current.options),
+        data: Object.assign({}, existing.data, current.data)
+      }) : current;
+      return merged;
+    }, {}); // IE11 does not support Object.values
+
+    return Object.keys(merged).map(function (key) {
+      return merged[key];
+    });
+  }
+
+  var DEFAULT_OPTIONS = {
+    placement: 'bottom',
+    modifiers: [],
+    strategy: 'absolute'
+  };
+
+  function areValidElements() {
+    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
+
+    return !args.some(function (element) {
+      return !(element && typeof element.getBoundingClientRect === 'function');
+    });
+  }
+
+  function popperGenerator(generatorOptions) {
+    if (generatorOptions === void 0) {
+      generatorOptions = {};
+    }
+
+    var _generatorOptions = generatorOptions,
+        _generatorOptions$def = _generatorOptions.defaultModifiers,
+        defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,
+        _generatorOptions$def2 = _generatorOptions.defaultOptions,
+        defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
+    return function createPopper(reference, popper, options) {
+      if (options === void 0) {
+        options = defaultOptions;
+      }
+
+      var state = {
+        placement: 'bottom',
+        orderedModifiers: [],
+        options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
+        modifiersData: {},
+        elements: {
+          reference: reference,
+          popper: popper
+        },
+        attributes: {},
+        styles: {}
+      };
+      var effectCleanupFns = [];
+      var isDestroyed = false;
+      var instance = {
+        state: state,
+        setOptions: function setOptions(setOptionsAction) {
+          var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;
+          cleanupModifierEffects();
+          state.options = Object.assign({}, defaultOptions, state.options, options);
+          state.scrollParents = {
+            reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],
+            popper: listScrollParents(popper)
+          }; // Orders the modifiers based on their dependencies and `phase`
+          // properties
+
+          var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers
+
+          state.orderedModifiers = orderedModifiers.filter(function (m) {
+            return m.enabled;
+          });
+          runModifierEffects();
+          return instance.update();
+        },
+        // Sync update – it will always be executed, even if not necessary. This
+        // is useful for low frequency updates where sync behavior simplifies the
+        // logic.
+        // For high frequency updates (e.g. `resize` and `scroll` events), always
+        // prefer the async Popper#update method
+        forceUpdate: function forceUpdate() {
+          if (isDestroyed) {
+            return;
+          }
+
+          var _state$elements = state.elements,
+              reference = _state$elements.reference,
+              popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements
+          // anymore
+
+          if (!areValidElements(reference, popper)) {
+            return;
+          } // Store the reference and popper rects to be read by modifiers
+
+
+          state.rects = {
+            reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),
+            popper: getLayoutRect(popper)
+          }; // Modifiers have the ability to reset the current update cycle. The
+          // most common use case for this is the `flip` modifier changing the
+          // placement, which then needs to re-run all the modifiers, because the
+          // logic was previously ran for the previous placement and is therefore
+          // stale/incorrect
+
+          state.reset = false;
+          state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier
+          // is filled with the initial data specified by the modifier. This means
+          // it doesn't persist and is fresh on each update.
+          // To ensure persistent data, use `${name}#persistent`
+
+          state.orderedModifiers.forEach(function (modifier) {
+            return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
+          });
+
+          for (var index = 0; index < state.orderedModifiers.length; index++) {
+            if (state.reset === true) {
+              state.reset = false;
+              index = -1;
+              continue;
+            }
+
+            var _state$orderedModifie = state.orderedModifiers[index],
+                fn = _state$orderedModifie.fn,
+                _state$orderedModifie2 = _state$orderedModifie.options,
+                _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,
+                name = _state$orderedModifie.name;
+
+            if (typeof fn === 'function') {
+              state = fn({
+                state: state,
+                options: _options,
+                name: name,
+                instance: instance
+              }) || state;
+            }
+          }
+        },
+        // Async and optimistically optimized update – it will not be executed if
+        // not necessary (debounced to run at most once-per-tick)
+        update: debounce(function () {
+          return new Promise(function (resolve) {
+            instance.forceUpdate();
+            resolve(state);
+          });
+        }),
+        destroy: function destroy() {
+          cleanupModifierEffects();
+          isDestroyed = true;
+        }
+      };
+
+      if (!areValidElements(reference, popper)) {
+        return instance;
+      }
+
+      instance.setOptions(options).then(function (state) {
+        if (!isDestroyed && options.onFirstUpdate) {
+          options.onFirstUpdate(state);
+        }
+      }); // Modifiers have the ability to execute arbitrary code before the first
+      // update cycle runs. They will be executed in the same order as the update
+      // cycle. This is useful when a modifier adds some persistent data that
+      // other modifiers need to use, but the modifier is run after the dependent
+      // one.
+
+      function runModifierEffects() {
+        state.orderedModifiers.forEach(function (_ref) {
+          var name = _ref.name,
+              _ref$options = _ref.options,
+              options = _ref$options === void 0 ? {} : _ref$options,
+              effect = _ref.effect;
+
+          if (typeof effect === 'function') {
+            var cleanupFn = effect({
+              state: state,
+              name: name,
+              instance: instance,
+              options: options
+            });
+
+            var noopFn = function noopFn() {};
+
+            effectCleanupFns.push(cleanupFn || noopFn);
+          }
+        });
+      }
+
+      function cleanupModifierEffects() {
+        effectCleanupFns.forEach(function (fn) {
+          return fn();
+        });
+        effectCleanupFns = [];
+      }
+
+      return instance;
+    };
+  }
+  var createPopper$2 = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules
+
+  var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1];
+  var createPopper$1 = /*#__PURE__*/popperGenerator({
+    defaultModifiers: defaultModifiers$1
+  }); // eslint-disable-next-line import/no-unused-modules
+
+  var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1];
+  var createPopper = /*#__PURE__*/popperGenerator({
+    defaultModifiers: defaultModifiers
+  }); // eslint-disable-next-line import/no-unused-modules
+
+  const Popper = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
+    __proto__: null,
+    afterMain,
+    afterRead,
+    afterWrite,
+    applyStyles: applyStyles$1,
+    arrow: arrow$1,
+    auto,
+    basePlacements,
+    beforeMain,
+    beforeRead,
+    beforeWrite,
+    bottom,
+    clippingParents,
+    computeStyles: computeStyles$1,
+    createPopper,
+    createPopperBase: createPopper$2,
+    createPopperLite: createPopper$1,
+    detectOverflow,
+    end,
+    eventListeners,
+    flip: flip$1,
+    hide: hide$1,
+    left,
+    main,
+    modifierPhases,
+    offset: offset$1,
+    placements,
+    popper,
+    popperGenerator,
+    popperOffsets: popperOffsets$1,
+    preventOverflow: preventOverflow$1,
+    read,
+    reference,
+    right,
+    start,
+    top,
+    variationPlacements,
+    viewport,
+    write
+  }, Symbol.toStringTag, { value: 'Module' }));
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap dropdown.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$a = 'dropdown';
+  const DATA_KEY$6 = 'bs.dropdown';
+  const EVENT_KEY$6 = `.${DATA_KEY$6}`;
+  const DATA_API_KEY$3 = '.data-api';
+  const ESCAPE_KEY$2 = 'Escape';
+  const TAB_KEY$1 = 'Tab';
+  const ARROW_UP_KEY$1 = 'ArrowUp';
+  const ARROW_DOWN_KEY$1 = 'ArrowDown';
+  const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button
+
+  const EVENT_HIDE$5 = `hide${EVENT_KEY$6}`;
+  const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`;
+  const EVENT_SHOW$5 = `show${EVENT_KEY$6}`;
+  const EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`;
+  const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;
+  const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;
+  const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;
+  const CLASS_NAME_SHOW$6 = 'show';
+  const CLASS_NAME_DROPUP = 'dropup';
+  const CLASS_NAME_DROPEND = 'dropend';
+  const CLASS_NAME_DROPSTART = 'dropstart';
+  const CLASS_NAME_DROPUP_CENTER = 'dropup-center';
+  const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';
+  const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)';
+  const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;
+  const SELECTOR_MENU = '.dropdown-menu';
+  const SELECTOR_NAVBAR = '.navbar';
+  const SELECTOR_NAVBAR_NAV = '.navbar-nav';
+  const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';
+  const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';
+  const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';
+  const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';
+  const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';
+  const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';
+  const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';
+  const PLACEMENT_TOPCENTER = 'top';
+  const PLACEMENT_BOTTOMCENTER = 'bottom';
+  const Default$9 = {
+    autoClose: true,
+    boundary: 'clippingParents',
+    display: 'dynamic',
+    offset: [0, 2],
+    popperConfig: null,
+    reference: 'toggle'
+  };
+  const DefaultType$9 = {
+    autoClose: '(boolean|string)',
+    boundary: '(string|element)',
+    display: 'string',
+    offset: '(array|string|function)',
+    popperConfig: '(null|object|function)',
+    reference: '(string|element|object)'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Dropdown extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+      this._popper = null;
+      this._parent = this._element.parentNode; // dropdown wrapper
+      // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
+      this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);
+      this._inNavbar = this._detectNavbar();
+    }
+
+    // Getters
+    static get Default() {
+      return Default$9;
+    }
+    static get DefaultType() {
+      return DefaultType$9;
+    }
+    static get NAME() {
+      return NAME$a;
+    }
+
+    // Public
+    toggle() {
+      return this._isShown() ? this.hide() : this.show();
+    }
+    show() {
+      if (isDisabled(this._element) || this._isShown()) {
+        return;
+      }
+      const relatedTarget = {
+        relatedTarget: this._element
+      };
+      const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget);
+      if (showEvent.defaultPrevented) {
+        return;
+      }
+      this._createPopper();
+
+      // If this is a touch-enabled device we add extra
+      // empty mouseover listeners to the body's immediate children;
+      // only needed because of broken event delegation on iOS
+      // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+      if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
+        for (const element of [].concat(...document.body.children)) {
+          EventHandler.on(element, 'mouseover', noop);
+        }
+      }
+      this._element.focus();
+      this._element.setAttribute('aria-expanded', true);
+      this._menu.classList.add(CLASS_NAME_SHOW$6);
+      this._element.classList.add(CLASS_NAME_SHOW$6);
+      EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget);
+    }
+    hide() {
+      if (isDisabled(this._element) || !this._isShown()) {
+        return;
+      }
+      const relatedTarget = {
+        relatedTarget: this._element
+      };
+      this._completeHide(relatedTarget);
+    }
+    dispose() {
+      if (this._popper) {
+        this._popper.destroy();
+      }
+      super.dispose();
+    }
+    update() {
+      this._inNavbar = this._detectNavbar();
+      if (this._popper) {
+        this._popper.update();
+      }
+    }
+
+    // Private
+    _completeHide(relatedTarget) {
+      const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget);
+      if (hideEvent.defaultPrevented) {
+        return;
+      }
+
+      // If this is a touch-enabled device we remove the extra
+      // empty mouseover listeners we added for iOS support
+      if ('ontouchstart' in document.documentElement) {
+        for (const element of [].concat(...document.body.children)) {
+          EventHandler.off(element, 'mouseover', noop);
+        }
+      }
+      if (this._popper) {
+        this._popper.destroy();
+      }
+      this._menu.classList.remove(CLASS_NAME_SHOW$6);
+      this._element.classList.remove(CLASS_NAME_SHOW$6);
+      this._element.setAttribute('aria-expanded', 'false');
+      Manipulator.removeDataAttribute(this._menu, 'popper');
+      EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);
+    }
+    _getConfig(config) {
+      config = super._getConfig(config);
+      if (typeof config.reference === 'object' && !isElement$1(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {
+        // Popper virtual elements require a getBoundingClientRect method
+        throw new TypeError(`${NAME$a.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);
+      }
+      return config;
+    }
+    _createPopper() {
+      if (typeof Popper === 'undefined') {
+        throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)');
+      }
+      let referenceElement = this._element;
+      if (this._config.reference === 'parent') {
+        referenceElement = this._parent;
+      } else if (isElement$1(this._config.reference)) {
+        referenceElement = getElement(this._config.reference);
+      } else if (typeof this._config.reference === 'object') {
+        referenceElement = this._config.reference;
+      }
+      const popperConfig = this._getPopperConfig();
+      this._popper = createPopper(referenceElement, this._menu, popperConfig);
+    }
+    _isShown() {
+      return this._menu.classList.contains(CLASS_NAME_SHOW$6);
+    }
+    _getPlacement() {
+      const parentDropdown = this._parent;
+      if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
+        return PLACEMENT_RIGHT;
+      }
+      if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
+        return PLACEMENT_LEFT;
+      }
+      if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
+        return PLACEMENT_TOPCENTER;
+      }
+      if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
+        return PLACEMENT_BOTTOMCENTER;
+      }
+
+      // We need to trim the value because custom properties can also include spaces
+      const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';
+      if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
+        return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;
+      }
+      return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;
+    }
+    _detectNavbar() {
+      return this._element.closest(SELECTOR_NAVBAR) !== null;
+    }
+    _getOffset() {
+      const {
+        offset
+      } = this._config;
+      if (typeof offset === 'string') {
+        return offset.split(',').map(value => Number.parseInt(value, 10));
+      }
+      if (typeof offset === 'function') {
+        return popperData => offset(popperData, this._element);
+      }
+      return offset;
+    }
+    _getPopperConfig() {
+      const defaultBsPopperConfig = {
+        placement: this._getPlacement(),
+        modifiers: [{
+          name: 'preventOverflow',
+          options: {
+            boundary: this._config.boundary
+          }
+        }, {
+          name: 'offset',
+          options: {
+            offset: this._getOffset()
+          }
+        }]
+      };
+
+      // Disable Popper if we have a static display or Dropdown is in Navbar
+      if (this._inNavbar || this._config.display === 'static') {
+        Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove
+        defaultBsPopperConfig.modifiers = [{
+          name: 'applyStyles',
+          enabled: false
+        }];
+      }
+      return {
+        ...defaultBsPopperConfig,
+        ...execute(this._config.popperConfig, [defaultBsPopperConfig])
+      };
+    }
+    _selectMenuItem({
+      key,
+      target
+    }) {
+      const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element));
+      if (!items.length) {
+        return;
+      }
+
+      // if target isn't included in items (e.g. when expanding the dropdown)
+      // allow cycling to get the last item in case key equals ARROW_UP_KEY
+      getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Dropdown.getOrCreateInstance(this, config);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (typeof data[config] === 'undefined') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config]();
+      });
+    }
+    static clearMenus(event) {
+      if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {
+        return;
+      }
+      const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);
+      for (const toggle of openToggles) {
+        const context = Dropdown.getInstance(toggle);
+        if (!context || context._config.autoClose === false) {
+          continue;
+        }
+        const composedPath = event.composedPath();
+        const isMenuTarget = composedPath.includes(context._menu);
+        if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {
+          continue;
+        }
+
+        // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
+        if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) {
+          continue;
+        }
+        const relatedTarget = {
+          relatedTarget: context._element
+        };
+        if (event.type === 'click') {
+          relatedTarget.clickEvent = event;
+        }
+        context._completeHide(relatedTarget);
+      }
+    }
+    static dataApiKeydownHandler(event) {
+      // If not an UP | DOWN | ESCAPE key => not a dropdown command
+      // If input/textarea && if key is other than ESCAPE => not a dropdown command
+
+      const isInput = /input|textarea/i.test(event.target.tagName);
+      const isEscapeEvent = event.key === ESCAPE_KEY$2;
+      const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key);
+      if (!isUpOrDownEvent && !isEscapeEvent) {
+        return;
+      }
+      if (isInput && !isEscapeEvent) {
+        return;
+      }
+      event.preventDefault();
+
+      // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
+      const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode);
+      const instance = Dropdown.getOrCreateInstance(getToggleButton);
+      if (isUpOrDownEvent) {
+        event.stopPropagation();
+        instance.show();
+        instance._selectMenuItem(event);
+        return;
+      }
+      if (instance._isShown()) {
+        // else is escape and we check if it is shown
+        event.stopPropagation();
+        instance.hide();
+        getToggleButton.focus();
+      }
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler);
+  EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);
+  EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus);
+  EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);
+  EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {
+    event.preventDefault();
+    Dropdown.getOrCreateInstance(this).toggle();
+  });
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Dropdown);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/backdrop.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$9 = 'backdrop';
+  const CLASS_NAME_FADE$4 = 'fade';
+  const CLASS_NAME_SHOW$5 = 'show';
+  const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`;
+  const Default$8 = {
+    className: 'modal-backdrop',
+    clickCallback: null,
+    isAnimated: false,
+    isVisible: true,
+    // if false, we use the backdrop helper without adding any element to the dom
+    rootElement: 'body' // give the choice to place backdrop under different elements
+  };
+
+  const DefaultType$8 = {
+    className: 'string',
+    clickCallback: '(function|null)',
+    isAnimated: 'boolean',
+    isVisible: 'boolean',
+    rootElement: '(element|string)'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Backdrop extends Config {
+    constructor(config) {
+      super();
+      this._config = this._getConfig(config);
+      this._isAppended = false;
+      this._element = null;
+    }
+
+    // Getters
+    static get Default() {
+      return Default$8;
+    }
+    static get DefaultType() {
+      return DefaultType$8;
+    }
+    static get NAME() {
+      return NAME$9;
+    }
+
+    // Public
+    show(callback) {
+      if (!this._config.isVisible) {
+        execute(callback);
+        return;
+      }
+      this._append();
+      const element = this._getElement();
+      if (this._config.isAnimated) {
+        reflow(element);
+      }
+      element.classList.add(CLASS_NAME_SHOW$5);
+      this._emulateAnimation(() => {
+        execute(callback);
+      });
+    }
+    hide(callback) {
+      if (!this._config.isVisible) {
+        execute(callback);
+        return;
+      }
+      this._getElement().classList.remove(CLASS_NAME_SHOW$5);
+      this._emulateAnimation(() => {
+        this.dispose();
+        execute(callback);
+      });
+    }
+    dispose() {
+      if (!this._isAppended) {
+        return;
+      }
+      EventHandler.off(this._element, EVENT_MOUSEDOWN);
+      this._element.remove();
+      this._isAppended = false;
+    }
+
+    // Private
+    _getElement() {
+      if (!this._element) {
+        const backdrop = document.createElement('div');
+        backdrop.className = this._config.className;
+        if (this._config.isAnimated) {
+          backdrop.classList.add(CLASS_NAME_FADE$4);
+        }
+        this._element = backdrop;
+      }
+      return this._element;
+    }
+    _configAfterMerge(config) {
+      // use getElement() with the default "body" to get a fresh Element on each instantiation
+      config.rootElement = getElement(config.rootElement);
+      return config;
+    }
+    _append() {
+      if (this._isAppended) {
+        return;
+      }
+      const element = this._getElement();
+      this._config.rootElement.append(element);
+      EventHandler.on(element, EVENT_MOUSEDOWN, () => {
+        execute(this._config.clickCallback);
+      });
+      this._isAppended = true;
+    }
+    _emulateAnimation(callback) {
+      executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/focustrap.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$8 = 'focustrap';
+  const DATA_KEY$5 = 'bs.focustrap';
+  const EVENT_KEY$5 = `.${DATA_KEY$5}`;
+  const EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`;
+  const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`;
+  const TAB_KEY = 'Tab';
+  const TAB_NAV_FORWARD = 'forward';
+  const TAB_NAV_BACKWARD = 'backward';
+  const Default$7 = {
+    autofocus: true,
+    trapElement: null // The element to trap focus inside of
+  };
+
+  const DefaultType$7 = {
+    autofocus: 'boolean',
+    trapElement: 'element'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class FocusTrap extends Config {
+    constructor(config) {
+      super();
+      this._config = this._getConfig(config);
+      this._isActive = false;
+      this._lastTabNavDirection = null;
+    }
+
+    // Getters
+    static get Default() {
+      return Default$7;
+    }
+    static get DefaultType() {
+      return DefaultType$7;
+    }
+    static get NAME() {
+      return NAME$8;
+    }
+
+    // Public
+    activate() {
+      if (this._isActive) {
+        return;
+      }
+      if (this._config.autofocus) {
+        this._config.trapElement.focus();
+      }
+      EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop
+      EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event));
+      EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
+      this._isActive = true;
+    }
+    deactivate() {
+      if (!this._isActive) {
+        return;
+      }
+      this._isActive = false;
+      EventHandler.off(document, EVENT_KEY$5);
+    }
+
+    // Private
+    _handleFocusin(event) {
+      const {
+        trapElement
+      } = this._config;
+      if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
+        return;
+      }
+      const elements = SelectorEngine.focusableChildren(trapElement);
+      if (elements.length === 0) {
+        trapElement.focus();
+      } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
+        elements[elements.length - 1].focus();
+      } else {
+        elements[0].focus();
+      }
+    }
+    _handleKeydown(event) {
+      if (event.key !== TAB_KEY) {
+        return;
+      }
+      this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/scrollBar.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
+  const SELECTOR_STICKY_CONTENT = '.sticky-top';
+  const PROPERTY_PADDING = 'padding-right';
+  const PROPERTY_MARGIN = 'margin-right';
+
+  /**
+   * Class definition
+   */
+
+  class ScrollBarHelper {
+    constructor() {
+      this._element = document.body;
+    }
+
+    // Public
+    getWidth() {
+      // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
+      const documentWidth = document.documentElement.clientWidth;
+      return Math.abs(window.innerWidth - documentWidth);
+    }
+    hide() {
+      const width = this.getWidth();
+      this._disableOverFlow();
+      // give padding to element to balance the hidden scrollbar width
+      this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
+      // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
+      this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
+      this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);
+    }
+    reset() {
+      this._resetElementAttributes(this._element, 'overflow');
+      this._resetElementAttributes(this._element, PROPERTY_PADDING);
+      this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
+      this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
+    }
+    isOverflowing() {
+      return this.getWidth() > 0;
+    }
+
+    // Private
+    _disableOverFlow() {
+      this._saveInitialAttribute(this._element, 'overflow');
+      this._element.style.overflow = 'hidden';
+    }
+    _setElementAttributes(selector, styleProperty, callback) {
+      const scrollbarWidth = this.getWidth();
+      const manipulationCallBack = element => {
+        if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
+          return;
+        }
+        this._saveInitialAttribute(element, styleProperty);
+        const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);
+        element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);
+      };
+      this._applyManipulationCallback(selector, manipulationCallBack);
+    }
+    _saveInitialAttribute(element, styleProperty) {
+      const actualValue = element.style.getPropertyValue(styleProperty);
+      if (actualValue) {
+        Manipulator.setDataAttribute(element, styleProperty, actualValue);
+      }
+    }
+    _resetElementAttributes(selector, styleProperty) {
+      const manipulationCallBack = element => {
+        const value = Manipulator.getDataAttribute(element, styleProperty);
+        // We only want to remove the property if the value is `null`; the value can also be zero
+        if (value === null) {
+          element.style.removeProperty(styleProperty);
+          return;
+        }
+        Manipulator.removeDataAttribute(element, styleProperty);
+        element.style.setProperty(styleProperty, value);
+      };
+      this._applyManipulationCallback(selector, manipulationCallBack);
+    }
+    _applyManipulationCallback(selector, callBack) {
+      if (isElement$1(selector)) {
+        callBack(selector);
+        return;
+      }
+      for (const sel of SelectorEngine.find(selector, this._element)) {
+        callBack(sel);
+      }
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap modal.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$7 = 'modal';
+  const DATA_KEY$4 = 'bs.modal';
+  const EVENT_KEY$4 = `.${DATA_KEY$4}`;
+  const DATA_API_KEY$2 = '.data-api';
+  const ESCAPE_KEY$1 = 'Escape';
+  const EVENT_HIDE$4 = `hide${EVENT_KEY$4}`;
+  const EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`;
+  const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`;
+  const EVENT_SHOW$4 = `show${EVENT_KEY$4}`;
+  const EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`;
+  const EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`;
+  const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`;
+  const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`;
+  const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`;
+  const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;
+  const CLASS_NAME_OPEN = 'modal-open';
+  const CLASS_NAME_FADE$3 = 'fade';
+  const CLASS_NAME_SHOW$4 = 'show';
+  const CLASS_NAME_STATIC = 'modal-static';
+  const OPEN_SELECTOR$1 = '.modal.show';
+  const SELECTOR_DIALOG = '.modal-dialog';
+  const SELECTOR_MODAL_BODY = '.modal-body';
+  const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]';
+  const Default$6 = {
+    backdrop: true,
+    focus: true,
+    keyboard: true
+  };
+  const DefaultType$6 = {
+    backdrop: '(boolean|string)',
+    focus: 'boolean',
+    keyboard: 'boolean'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Modal extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+      this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element);
+      this._backdrop = this._initializeBackDrop();
+      this._focustrap = this._initializeFocusTrap();
+      this._isShown = false;
+      this._isTransitioning = false;
+      this._scrollBar = new ScrollBarHelper();
+      this._addEventListeners();
+    }
+
+    // Getters
+    static get Default() {
+      return Default$6;
+    }
+    static get DefaultType() {
+      return DefaultType$6;
+    }
+    static get NAME() {
+      return NAME$7;
+    }
+
+    // Public
+    toggle(relatedTarget) {
+      return this._isShown ? this.hide() : this.show(relatedTarget);
+    }
+    show(relatedTarget) {
+      if (this._isShown || this._isTransitioning) {
+        return;
+      }
+      const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, {
+        relatedTarget
+      });
+      if (showEvent.defaultPrevented) {
+        return;
+      }
+      this._isShown = true;
+      this._isTransitioning = true;
+      this._scrollBar.hide();
+      document.body.classList.add(CLASS_NAME_OPEN);
+      this._adjustDialog();
+      this._backdrop.show(() => this._showElement(relatedTarget));
+    }
+    hide() {
+      if (!this._isShown || this._isTransitioning) {
+        return;
+      }
+      const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4);
+      if (hideEvent.defaultPrevented) {
+        return;
+      }
+      this._isShown = false;
+      this._isTransitioning = true;
+      this._focustrap.deactivate();
+      this._element.classList.remove(CLASS_NAME_SHOW$4);
+      this._queueCallback(() => this._hideModal(), this._element, this._isAnimated());
+    }
+    dispose() {
+      EventHandler.off(window, EVENT_KEY$4);
+      EventHandler.off(this._dialog, EVENT_KEY$4);
+      this._backdrop.dispose();
+      this._focustrap.deactivate();
+      super.dispose();
+    }
+    handleUpdate() {
+      this._adjustDialog();
+    }
+
+    // Private
+    _initializeBackDrop() {
+      return new Backdrop({
+        isVisible: Boolean(this._config.backdrop),
+        // 'static' option will be translated to true, and booleans will keep their value,
+        isAnimated: this._isAnimated()
+      });
+    }
+    _initializeFocusTrap() {
+      return new FocusTrap({
+        trapElement: this._element
+      });
+    }
+    _showElement(relatedTarget) {
+      // try to append dynamic modal
+      if (!document.body.contains(this._element)) {
+        document.body.append(this._element);
+      }
+      this._element.style.display = 'block';
+      this._element.removeAttribute('aria-hidden');
+      this._element.setAttribute('aria-modal', true);
+      this._element.setAttribute('role', 'dialog');
+      this._element.scrollTop = 0;
+      const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog);
+      if (modalBody) {
+        modalBody.scrollTop = 0;
+      }
+      reflow(this._element);
+      this._element.classList.add(CLASS_NAME_SHOW$4);
+      const transitionComplete = () => {
+        if (this._config.focus) {
+          this._focustrap.activate();
+        }
+        this._isTransitioning = false;
+        EventHandler.trigger(this._element, EVENT_SHOWN$4, {
+          relatedTarget
+        });
+      };
+      this._queueCallback(transitionComplete, this._dialog, this._isAnimated());
+    }
+    _addEventListeners() {
+      EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => {
+        if (event.key !== ESCAPE_KEY$1) {
+          return;
+        }
+        if (this._config.keyboard) {
+          this.hide();
+          return;
+        }
+        this._triggerBackdropTransition();
+      });
+      EventHandler.on(window, EVENT_RESIZE$1, () => {
+        if (this._isShown && !this._isTransitioning) {
+          this._adjustDialog();
+        }
+      });
+      EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {
+        // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks
+        EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {
+          if (this._element !== event.target || this._element !== event2.target) {
+            return;
+          }
+          if (this._config.backdrop === 'static') {
+            this._triggerBackdropTransition();
+            return;
+          }
+          if (this._config.backdrop) {
+            this.hide();
+          }
+        });
+      });
+    }
+    _hideModal() {
+      this._element.style.display = 'none';
+      this._element.setAttribute('aria-hidden', true);
+      this._element.removeAttribute('aria-modal');
+      this._element.removeAttribute('role');
+      this._isTransitioning = false;
+      this._backdrop.hide(() => {
+        document.body.classList.remove(CLASS_NAME_OPEN);
+        this._resetAdjustments();
+        this._scrollBar.reset();
+        EventHandler.trigger(this._element, EVENT_HIDDEN$4);
+      });
+    }
+    _isAnimated() {
+      return this._element.classList.contains(CLASS_NAME_FADE$3);
+    }
+    _triggerBackdropTransition() {
+      const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1);
+      if (hideEvent.defaultPrevented) {
+        return;
+      }
+      const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
+      const initialOverflowY = this._element.style.overflowY;
+      // return if the following background transition hasn't yet completed
+      if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {
+        return;
+      }
+      if (!isModalOverflowing) {
+        this._element.style.overflowY = 'hidden';
+      }
+      this._element.classList.add(CLASS_NAME_STATIC);
+      this._queueCallback(() => {
+        this._element.classList.remove(CLASS_NAME_STATIC);
+        this._queueCallback(() => {
+          this._element.style.overflowY = initialOverflowY;
+        }, this._dialog);
+      }, this._dialog);
+      this._element.focus();
+    }
+
+    /**
+     * The following methods are used to handle overflowing modals
+     */
+
+    _adjustDialog() {
+      const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
+      const scrollbarWidth = this._scrollBar.getWidth();
+      const isBodyOverflowing = scrollbarWidth > 0;
+      if (isBodyOverflowing && !isModalOverflowing) {
+        const property = isRTL() ? 'paddingLeft' : 'paddingRight';
+        this._element.style[property] = `${scrollbarWidth}px`;
+      }
+      if (!isBodyOverflowing && isModalOverflowing) {
+        const property = isRTL() ? 'paddingRight' : 'paddingLeft';
+        this._element.style[property] = `${scrollbarWidth}px`;
+      }
+    }
+    _resetAdjustments() {
+      this._element.style.paddingLeft = '';
+      this._element.style.paddingRight = '';
+    }
+
+    // Static
+    static jQueryInterface(config, relatedTarget) {
+      return this.each(function () {
+        const data = Modal.getOrCreateInstance(this, config);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (typeof data[config] === 'undefined') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config](relatedTarget);
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {
+    const target = SelectorEngine.getElementFromSelector(this);
+    if (['A', 'AREA'].includes(this.tagName)) {
+      event.preventDefault();
+    }
+    EventHandler.one(target, EVENT_SHOW$4, showEvent => {
+      if (showEvent.defaultPrevented) {
+        // only register focus restorer if modal will actually get shown
+        return;
+      }
+      EventHandler.one(target, EVENT_HIDDEN$4, () => {
+        if (isVisible(this)) {
+          this.focus();
+        }
+      });
+    });
+
+    // avoid conflict when clicking modal toggler while another one is open
+    const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1);
+    if (alreadyOpen) {
+      Modal.getInstance(alreadyOpen).hide();
+    }
+    const data = Modal.getOrCreateInstance(target);
+    data.toggle(this);
+  });
+  enableDismissTrigger(Modal);
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Modal);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap offcanvas.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$6 = 'offcanvas';
+  const DATA_KEY$3 = 'bs.offcanvas';
+  const EVENT_KEY$3 = `.${DATA_KEY$3}`;
+  const DATA_API_KEY$1 = '.data-api';
+  const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;
+  const ESCAPE_KEY = 'Escape';
+  const CLASS_NAME_SHOW$3 = 'show';
+  const CLASS_NAME_SHOWING$1 = 'showing';
+  const CLASS_NAME_HIDING = 'hiding';
+  const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
+  const OPEN_SELECTOR = '.offcanvas.show';
+  const EVENT_SHOW$3 = `show${EVENT_KEY$3}`;
+  const EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`;
+  const EVENT_HIDE$3 = `hide${EVENT_KEY$3}`;
+  const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`;
+  const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`;
+  const EVENT_RESIZE = `resize${EVENT_KEY$3}`;
+  const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;
+  const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`;
+  const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]';
+  const Default$5 = {
+    backdrop: true,
+    keyboard: true,
+    scroll: false
+  };
+  const DefaultType$5 = {
+    backdrop: '(boolean|string)',
+    keyboard: 'boolean',
+    scroll: 'boolean'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Offcanvas extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+      this._isShown = false;
+      this._backdrop = this._initializeBackDrop();
+      this._focustrap = this._initializeFocusTrap();
+      this._addEventListeners();
+    }
+
+    // Getters
+    static get Default() {
+      return Default$5;
+    }
+    static get DefaultType() {
+      return DefaultType$5;
+    }
+    static get NAME() {
+      return NAME$6;
+    }
+
+    // Public
+    toggle(relatedTarget) {
+      return this._isShown ? this.hide() : this.show(relatedTarget);
+    }
+    show(relatedTarget) {
+      if (this._isShown) {
+        return;
+      }
+      const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, {
+        relatedTarget
+      });
+      if (showEvent.defaultPrevented) {
+        return;
+      }
+      this._isShown = true;
+      this._backdrop.show();
+      if (!this._config.scroll) {
+        new ScrollBarHelper().hide();
+      }
+      this._element.setAttribute('aria-modal', true);
+      this._element.setAttribute('role', 'dialog');
+      this._element.classList.add(CLASS_NAME_SHOWING$1);
+      const completeCallBack = () => {
+        if (!this._config.scroll || this._config.backdrop) {
+          this._focustrap.activate();
+        }
+        this._element.classList.add(CLASS_NAME_SHOW$3);
+        this._element.classList.remove(CLASS_NAME_SHOWING$1);
+        EventHandler.trigger(this._element, EVENT_SHOWN$3, {
+          relatedTarget
+        });
+      };
+      this._queueCallback(completeCallBack, this._element, true);
+    }
+    hide() {
+      if (!this._isShown) {
+        return;
+      }
+      const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3);
+      if (hideEvent.defaultPrevented) {
+        return;
+      }
+      this._focustrap.deactivate();
+      this._element.blur();
+      this._isShown = false;
+      this._element.classList.add(CLASS_NAME_HIDING);
+      this._backdrop.hide();
+      const completeCallback = () => {
+        this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING);
+        this._element.removeAttribute('aria-modal');
+        this._element.removeAttribute('role');
+        if (!this._config.scroll) {
+          new ScrollBarHelper().reset();
+        }
+        EventHandler.trigger(this._element, EVENT_HIDDEN$3);
+      };
+      this._queueCallback(completeCallback, this._element, true);
+    }
+    dispose() {
+      this._backdrop.dispose();
+      this._focustrap.deactivate();
+      super.dispose();
+    }
+
+    // Private
+    _initializeBackDrop() {
+      const clickCallback = () => {
+        if (this._config.backdrop === 'static') {
+          EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
+          return;
+        }
+        this.hide();
+      };
+
+      // 'static' option will be translated to true, and booleans will keep their value
+      const isVisible = Boolean(this._config.backdrop);
+      return new Backdrop({
+        className: CLASS_NAME_BACKDROP,
+        isVisible,
+        isAnimated: true,
+        rootElement: this._element.parentNode,
+        clickCallback: isVisible ? clickCallback : null
+      });
+    }
+    _initializeFocusTrap() {
+      return new FocusTrap({
+        trapElement: this._element
+      });
+    }
+    _addEventListeners() {
+      EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
+        if (event.key !== ESCAPE_KEY) {
+          return;
+        }
+        if (this._config.keyboard) {
+          this.hide();
+          return;
+        }
+        EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
+      });
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Offcanvas.getOrCreateInstance(this, config);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config](this);
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {
+    const target = SelectorEngine.getElementFromSelector(this);
+    if (['A', 'AREA'].includes(this.tagName)) {
+      event.preventDefault();
+    }
+    if (isDisabled(this)) {
+      return;
+    }
+    EventHandler.one(target, EVENT_HIDDEN$3, () => {
+      // focus on trigger when it is closed
+      if (isVisible(this)) {
+        this.focus();
+      }
+    });
+
+    // avoid conflict when clicking a toggler of an offcanvas, while another is open
+    const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);
+    if (alreadyOpen && alreadyOpen !== target) {
+      Offcanvas.getInstance(alreadyOpen).hide();
+    }
+    const data = Offcanvas.getOrCreateInstance(target);
+    data.toggle(this);
+  });
+  EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => {
+    for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {
+      Offcanvas.getOrCreateInstance(selector).show();
+    }
+  });
+  EventHandler.on(window, EVENT_RESIZE, () => {
+    for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {
+      if (getComputedStyle(element).position !== 'fixed') {
+        Offcanvas.getOrCreateInstance(element).hide();
+      }
+    }
+  });
+  enableDismissTrigger(Offcanvas);
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Offcanvas);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/sanitizer.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  // js-docs-start allow-list
+  const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
+  const DefaultAllowlist = {
+    // Global attributes allowed on any supplied element below.
+    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
+    a: ['target', 'href', 'title', 'rel'],
+    area: [],
+    b: [],
+    br: [],
+    col: [],
+    code: [],
+    div: [],
+    em: [],
+    hr: [],
+    h1: [],
+    h2: [],
+    h3: [],
+    h4: [],
+    h5: [],
+    h6: [],
+    i: [],
+    img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
+    li: [],
+    ol: [],
+    p: [],
+    pre: [],
+    s: [],
+    small: [],
+    span: [],
+    sub: [],
+    sup: [],
+    strong: [],
+    u: [],
+    ul: []
+  };
+  // js-docs-end allow-list
+
+  const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
+
+  /**
+   * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
+   * contexts.
+   *
+   * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
+   */
+  // eslint-disable-next-line unicorn/better-regex
+  const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
+  const allowedAttribute = (attribute, allowedAttributeList) => {
+    const attributeName = attribute.nodeName.toLowerCase();
+    if (allowedAttributeList.includes(attributeName)) {
+      if (uriAttributes.has(attributeName)) {
+        return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
+      }
+      return true;
+    }
+
+    // Check if a regular expression validates the attribute.
+    return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
+  };
+  function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
+    if (!unsafeHtml.length) {
+      return unsafeHtml;
+    }
+    if (sanitizeFunction && typeof sanitizeFunction === 'function') {
+      return sanitizeFunction(unsafeHtml);
+    }
+    const domParser = new window.DOMParser();
+    const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
+    const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
+    for (const element of elements) {
+      const elementName = element.nodeName.toLowerCase();
+      if (!Object.keys(allowList).includes(elementName)) {
+        element.remove();
+        continue;
+      }
+      const attributeList = [].concat(...element.attributes);
+      const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
+      for (const attribute of attributeList) {
+        if (!allowedAttribute(attribute, allowedAttributes)) {
+          element.removeAttribute(attribute.nodeName);
+        }
+      }
+    }
+    return createdDocument.body.innerHTML;
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap util/template-factory.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$5 = 'TemplateFactory';
+  const Default$4 = {
+    allowList: DefaultAllowlist,
+    content: {},
+    // { selector : text ,  selector2 : text2 , }
+    extraClass: '',
+    html: false,
+    sanitize: true,
+    sanitizeFn: null,
+    template: '<div></div>'
+  };
+  const DefaultType$4 = {
+    allowList: 'object',
+    content: 'object',
+    extraClass: '(string|function)',
+    html: 'boolean',
+    sanitize: 'boolean',
+    sanitizeFn: '(null|function)',
+    template: 'string'
+  };
+  const DefaultContentType = {
+    entry: '(string|element|function|null)',
+    selector: '(string|element)'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class TemplateFactory extends Config {
+    constructor(config) {
+      super();
+      this._config = this._getConfig(config);
+    }
+
+    // Getters
+    static get Default() {
+      return Default$4;
+    }
+    static get DefaultType() {
+      return DefaultType$4;
+    }
+    static get NAME() {
+      return NAME$5;
+    }
+
+    // Public
+    getContent() {
+      return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);
+    }
+    hasContent() {
+      return this.getContent().length > 0;
+    }
+    changeContent(content) {
+      this._checkContent(content);
+      this._config.content = {
+        ...this._config.content,
+        ...content
+      };
+      return this;
+    }
+    toHtml() {
+      const templateWrapper = document.createElement('div');
+      templateWrapper.innerHTML = this._maybeSanitize(this._config.template);
+      for (const [selector, text] of Object.entries(this._config.content)) {
+        this._setContent(templateWrapper, text, selector);
+      }
+      const template = templateWrapper.children[0];
+      const extraClass = this._resolvePossibleFunction(this._config.extraClass);
+      if (extraClass) {
+        template.classList.add(...extraClass.split(' '));
+      }
+      return template;
+    }
+
+    // Private
+    _typeCheckConfig(config) {
+      super._typeCheckConfig(config);
+      this._checkContent(config.content);
+    }
+    _checkContent(arg) {
+      for (const [selector, content] of Object.entries(arg)) {
+        super._typeCheckConfig({
+          selector,
+          entry: content
+        }, DefaultContentType);
+      }
+    }
+    _setContent(template, content, selector) {
+      const templateElement = SelectorEngine.findOne(selector, template);
+      if (!templateElement) {
+        return;
+      }
+      content = this._resolvePossibleFunction(content);
+      if (!content) {
+        templateElement.remove();
+        return;
+      }
+      if (isElement$1(content)) {
+        this._putElementInTemplate(getElement(content), templateElement);
+        return;
+      }
+      if (this._config.html) {
+        templateElement.innerHTML = this._maybeSanitize(content);
+        return;
+      }
+      templateElement.textContent = content;
+    }
+    _maybeSanitize(arg) {
+      return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;
+    }
+    _resolvePossibleFunction(arg) {
+      return execute(arg, [this]);
+    }
+    _putElementInTemplate(element, templateElement) {
+      if (this._config.html) {
+        templateElement.innerHTML = '';
+        templateElement.append(element);
+        return;
+      }
+      templateElement.textContent = element.textContent;
+    }
+  }
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap tooltip.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$4 = 'tooltip';
+  const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);
+  const CLASS_NAME_FADE$2 = 'fade';
+  const CLASS_NAME_MODAL = 'modal';
+  const CLASS_NAME_SHOW$2 = 'show';
+  const SELECTOR_TOOLTIP_INNER = '.tooltip-inner';
+  const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;
+  const EVENT_MODAL_HIDE = 'hide.bs.modal';
+  const TRIGGER_HOVER = 'hover';
+  const TRIGGER_FOCUS = 'focus';
+  const TRIGGER_CLICK = 'click';
+  const TRIGGER_MANUAL = 'manual';
+  const EVENT_HIDE$2 = 'hide';
+  const EVENT_HIDDEN$2 = 'hidden';
+  const EVENT_SHOW$2 = 'show';
+  const EVENT_SHOWN$2 = 'shown';
+  const EVENT_INSERTED = 'inserted';
+  const EVENT_CLICK$1 = 'click';
+  const EVENT_FOCUSIN$1 = 'focusin';
+  const EVENT_FOCUSOUT$1 = 'focusout';
+  const EVENT_MOUSEENTER = 'mouseenter';
+  const EVENT_MOUSELEAVE = 'mouseleave';
+  const AttachmentMap = {
+    AUTO: 'auto',
+    TOP: 'top',
+    RIGHT: isRTL() ? 'left' : 'right',
+    BOTTOM: 'bottom',
+    LEFT: isRTL() ? 'right' : 'left'
+  };
+  const Default$3 = {
+    allowList: DefaultAllowlist,
+    animation: true,
+    boundary: 'clippingParents',
+    container: false,
+    customClass: '',
+    delay: 0,
+    fallbackPlacements: ['top', 'right', 'bottom', 'left'],
+    html: false,
+    offset: [0, 6],
+    placement: 'top',
+    popperConfig: null,
+    sanitize: true,
+    sanitizeFn: null,
+    selector: false,
+    template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>',
+    title: '',
+    trigger: 'hover focus'
+  };
+  const DefaultType$3 = {
+    allowList: 'object',
+    animation: 'boolean',
+    boundary: '(string|element)',
+    container: '(string|element|boolean)',
+    customClass: '(string|function)',
+    delay: '(number|object)',
+    fallbackPlacements: 'array',
+    html: 'boolean',
+    offset: '(array|string|function)',
+    placement: '(string|function)',
+    popperConfig: '(null|object|function)',
+    sanitize: 'boolean',
+    sanitizeFn: '(null|function)',
+    selector: '(string|boolean)',
+    template: 'string',
+    title: '(string|element|function)',
+    trigger: 'string'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Tooltip extends BaseComponent {
+    constructor(element, config) {
+      if (typeof Popper === 'undefined') {
+        throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)');
+      }
+      super(element, config);
+
+      // Private
+      this._isEnabled = true;
+      this._timeout = 0;
+      this._isHovered = null;
+      this._activeTrigger = {};
+      this._popper = null;
+      this._templateFactory = null;
+      this._newContent = null;
+
+      // Protected
+      this.tip = null;
+      this._setListeners();
+      if (!this._config.selector) {
+        this._fixTitle();
+      }
+    }
+
+    // Getters
+    static get Default() {
+      return Default$3;
+    }
+    static get DefaultType() {
+      return DefaultType$3;
+    }
+    static get NAME() {
+      return NAME$4;
+    }
+
+    // Public
+    enable() {
+      this._isEnabled = true;
+    }
+    disable() {
+      this._isEnabled = false;
+    }
+    toggleEnabled() {
+      this._isEnabled = !this._isEnabled;
+    }
+    toggle() {
+      if (!this._isEnabled) {
+        return;
+      }
+      this._activeTrigger.click = !this._activeTrigger.click;
+      if (this._isShown()) {
+        this._leave();
+        return;
+      }
+      this._enter();
+    }
+    dispose() {
+      clearTimeout(this._timeout);
+      EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);
+      if (this._element.getAttribute('data-bs-original-title')) {
+        this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));
+      }
+      this._disposePopper();
+      super.dispose();
+    }
+    show() {
+      if (this._element.style.display === 'none') {
+        throw new Error('Please use show on visible elements');
+      }
+      if (!(this._isWithContent() && this._isEnabled)) {
+        return;
+      }
+      const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2));
+      const shadowRoot = findShadowRoot(this._element);
+      const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);
+      if (showEvent.defaultPrevented || !isInTheDom) {
+        return;
+      }
+
+      // TODO: v6 remove this or make it optional
+      this._disposePopper();
+      const tip = this._getTipElement();
+      this._element.setAttribute('aria-describedby', tip.getAttribute('id'));
+      const {
+        container
+      } = this._config;
+      if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
+        container.append(tip);
+        EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));
+      }
+      this._popper = this._createPopper(tip);
+      tip.classList.add(CLASS_NAME_SHOW$2);
+
+      // If this is a touch-enabled device we add extra
+      // empty mouseover listeners to the body's immediate children;
+      // only needed because of broken event delegation on iOS
+      // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
+      if ('ontouchstart' in document.documentElement) {
+        for (const element of [].concat(...document.body.children)) {
+          EventHandler.on(element, 'mouseover', noop);
+        }
+      }
+      const complete = () => {
+        EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2));
+        if (this._isHovered === false) {
+          this._leave();
+        }
+        this._isHovered = false;
+      };
+      this._queueCallback(complete, this.tip, this._isAnimated());
+    }
+    hide() {
+      if (!this._isShown()) {
+        return;
+      }
+      const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2));
+      if (hideEvent.defaultPrevented) {
+        return;
+      }
+      const tip = this._getTipElement();
+      tip.classList.remove(CLASS_NAME_SHOW$2);
+
+      // If this is a touch-enabled device we remove the extra
+      // empty mouseover listeners we added for iOS support
+      if ('ontouchstart' in document.documentElement) {
+        for (const element of [].concat(...document.body.children)) {
+          EventHandler.off(element, 'mouseover', noop);
+        }
+      }
+      this._activeTrigger[TRIGGER_CLICK] = false;
+      this._activeTrigger[TRIGGER_FOCUS] = false;
+      this._activeTrigger[TRIGGER_HOVER] = false;
+      this._isHovered = null; // it is a trick to support manual triggering
+
+      const complete = () => {
+        if (this._isWithActiveTrigger()) {
+          return;
+        }
+        if (!this._isHovered) {
+          this._disposePopper();
+        }
+        this._element.removeAttribute('aria-describedby');
+        EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2));
+      };
+      this._queueCallback(complete, this.tip, this._isAnimated());
+    }
+    update() {
+      if (this._popper) {
+        this._popper.update();
+      }
+    }
+
+    // Protected
+    _isWithContent() {
+      return Boolean(this._getTitle());
+    }
+    _getTipElement() {
+      if (!this.tip) {
+        this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());
+      }
+      return this.tip;
+    }
+    _createTipElement(content) {
+      const tip = this._getTemplateFactory(content).toHtml();
+
+      // TODO: remove this check in v6
+      if (!tip) {
+        return null;
+      }
+      tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2);
+      // TODO: v6 the following can be achieved with CSS only
+      tip.classList.add(`bs-${this.constructor.NAME}-auto`);
+      const tipId = getUID(this.constructor.NAME).toString();
+      tip.setAttribute('id', tipId);
+      if (this._isAnimated()) {
+        tip.classList.add(CLASS_NAME_FADE$2);
+      }
+      return tip;
+    }
+    setContent(content) {
+      this._newContent = content;
+      if (this._isShown()) {
+        this._disposePopper();
+        this.show();
+      }
+    }
+    _getTemplateFactory(content) {
+      if (this._templateFactory) {
+        this._templateFactory.changeContent(content);
+      } else {
+        this._templateFactory = new TemplateFactory({
+          ...this._config,
+          // the `content` var has to be after `this._config`
+          // to override config.content in case of popover
+          content,
+          extraClass: this._resolvePossibleFunction(this._config.customClass)
+        });
+      }
+      return this._templateFactory;
+    }
+    _getContentForTemplate() {
+      return {
+        [SELECTOR_TOOLTIP_INNER]: this._getTitle()
+      };
+    }
+    _getTitle() {
+      return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');
+    }
+
+    // Private
+    _initializeOnDelegatedTarget(event) {
+      return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());
+    }
+    _isAnimated() {
+      return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2);
+    }
+    _isShown() {
+      return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2);
+    }
+    _createPopper(tip) {
+      const placement = execute(this._config.placement, [this, tip, this._element]);
+      const attachment = AttachmentMap[placement.toUpperCase()];
+      return createPopper(this._element, tip, this._getPopperConfig(attachment));
+    }
+    _getOffset() {
+      const {
+        offset
+      } = this._config;
+      if (typeof offset === 'string') {
+        return offset.split(',').map(value => Number.parseInt(value, 10));
+      }
+      if (typeof offset === 'function') {
+        return popperData => offset(popperData, this._element);
+      }
+      return offset;
+    }
+    _resolvePossibleFunction(arg) {
+      return execute(arg, [this._element]);
+    }
+    _getPopperConfig(attachment) {
+      const defaultBsPopperConfig = {
+        placement: attachment,
+        modifiers: [{
+          name: 'flip',
+          options: {
+            fallbackPlacements: this._config.fallbackPlacements
+          }
+        }, {
+          name: 'offset',
+          options: {
+            offset: this._getOffset()
+          }
+        }, {
+          name: 'preventOverflow',
+          options: {
+            boundary: this._config.boundary
+          }
+        }, {
+          name: 'arrow',
+          options: {
+            element: `.${this.constructor.NAME}-arrow`
+          }
+        }, {
+          name: 'preSetPlacement',
+          enabled: true,
+          phase: 'beforeMain',
+          fn: data => {
+            // Pre-set Popper's placement attribute in order to read the arrow sizes properly.
+            // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement
+            this._getTipElement().setAttribute('data-popper-placement', data.state.placement);
+          }
+        }]
+      };
+      return {
+        ...defaultBsPopperConfig,
+        ...execute(this._config.popperConfig, [defaultBsPopperConfig])
+      };
+    }
+    _setListeners() {
+      const triggers = this._config.trigger.split(' ');
+      for (const trigger of triggers) {
+        if (trigger === 'click') {
+          EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {
+            const context = this._initializeOnDelegatedTarget(event);
+            context.toggle();
+          });
+        } else if (trigger !== TRIGGER_MANUAL) {
+          const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1);
+          const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1);
+          EventHandler.on(this._element, eventIn, this._config.selector, event => {
+            const context = this._initializeOnDelegatedTarget(event);
+            context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;
+            context._enter();
+          });
+          EventHandler.on(this._element, eventOut, this._config.selector, event => {
+            const context = this._initializeOnDelegatedTarget(event);
+            context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);
+            context._leave();
+          });
+        }
+      }
+      this._hideModalHandler = () => {
+        if (this._element) {
+          this.hide();
+        }
+      };
+      EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);
+    }
+    _fixTitle() {
+      const title = this._element.getAttribute('title');
+      if (!title) {
+        return;
+      }
+      if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {
+        this._element.setAttribute('aria-label', title);
+      }
+      this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility
+      this._element.removeAttribute('title');
+    }
+    _enter() {
+      if (this._isShown() || this._isHovered) {
+        this._isHovered = true;
+        return;
+      }
+      this._isHovered = true;
+      this._setTimeout(() => {
+        if (this._isHovered) {
+          this.show();
+        }
+      }, this._config.delay.show);
+    }
+    _leave() {
+      if (this._isWithActiveTrigger()) {
+        return;
+      }
+      this._isHovered = false;
+      this._setTimeout(() => {
+        if (!this._isHovered) {
+          this.hide();
+        }
+      }, this._config.delay.hide);
+    }
+    _setTimeout(handler, timeout) {
+      clearTimeout(this._timeout);
+      this._timeout = setTimeout(handler, timeout);
+    }
+    _isWithActiveTrigger() {
+      return Object.values(this._activeTrigger).includes(true);
+    }
+    _getConfig(config) {
+      const dataAttributes = Manipulator.getDataAttributes(this._element);
+      for (const dataAttribute of Object.keys(dataAttributes)) {
+        if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {
+          delete dataAttributes[dataAttribute];
+        }
+      }
+      config = {
+        ...dataAttributes,
+        ...(typeof config === 'object' && config ? config : {})
+      };
+      config = this._mergeConfigObj(config);
+      config = this._configAfterMerge(config);
+      this._typeCheckConfig(config);
+      return config;
+    }
+    _configAfterMerge(config) {
+      config.container = config.container === false ? document.body : getElement(config.container);
+      if (typeof config.delay === 'number') {
+        config.delay = {
+          show: config.delay,
+          hide: config.delay
+        };
+      }
+      if (typeof config.title === 'number') {
+        config.title = config.title.toString();
+      }
+      if (typeof config.content === 'number') {
+        config.content = config.content.toString();
+      }
+      return config;
+    }
+    _getDelegateConfig() {
+      const config = {};
+      for (const [key, value] of Object.entries(this._config)) {
+        if (this.constructor.Default[key] !== value) {
+          config[key] = value;
+        }
+      }
+      config.selector = false;
+      config.trigger = 'manual';
+
+      // In the future can be replaced with:
+      // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])
+      // `Object.fromEntries(keysWithDifferentValues)`
+      return config;
+    }
+    _disposePopper() {
+      if (this._popper) {
+        this._popper.destroy();
+        this._popper = null;
+      }
+      if (this.tip) {
+        this.tip.remove();
+        this.tip = null;
+      }
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Tooltip.getOrCreateInstance(this, config);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (typeof data[config] === 'undefined') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config]();
+      });
+    }
+  }
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Tooltip);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap popover.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$3 = 'popover';
+  const SELECTOR_TITLE = '.popover-header';
+  const SELECTOR_CONTENT = '.popover-body';
+  const Default$2 = {
+    ...Tooltip.Default,
+    content: '',
+    offset: [0, 8],
+    placement: 'right',
+    template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>',
+    trigger: 'click'
+  };
+  const DefaultType$2 = {
+    ...Tooltip.DefaultType,
+    content: '(null|string|element|function)'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Popover extends Tooltip {
+    // Getters
+    static get Default() {
+      return Default$2;
+    }
+    static get DefaultType() {
+      return DefaultType$2;
+    }
+    static get NAME() {
+      return NAME$3;
+    }
+
+    // Overrides
+    _isWithContent() {
+      return this._getTitle() || this._getContent();
+    }
+
+    // Private
+    _getContentForTemplate() {
+      return {
+        [SELECTOR_TITLE]: this._getTitle(),
+        [SELECTOR_CONTENT]: this._getContent()
+      };
+    }
+    _getContent() {
+      return this._resolvePossibleFunction(this._config.content);
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Popover.getOrCreateInstance(this, config);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (typeof data[config] === 'undefined') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config]();
+      });
+    }
+  }
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Popover);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap scrollspy.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$2 = 'scrollspy';
+  const DATA_KEY$2 = 'bs.scrollspy';
+  const EVENT_KEY$2 = `.${DATA_KEY$2}`;
+  const DATA_API_KEY = '.data-api';
+  const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;
+  const EVENT_CLICK = `click${EVENT_KEY$2}`;
+  const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;
+  const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
+  const CLASS_NAME_ACTIVE$1 = 'active';
+  const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]';
+  const SELECTOR_TARGET_LINKS = '[href]';
+  const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
+  const SELECTOR_NAV_LINKS = '.nav-link';
+  const SELECTOR_NAV_ITEMS = '.nav-item';
+  const SELECTOR_LIST_ITEMS = '.list-group-item';
+  const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;
+  const SELECTOR_DROPDOWN = '.dropdown';
+  const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';
+  const Default$1 = {
+    offset: null,
+    // TODO: v6 @deprecated, keep it for backwards compatibility reasons
+    rootMargin: '0px 0px -25%',
+    smoothScroll: false,
+    target: null,
+    threshold: [0.1, 0.5, 1]
+  };
+  const DefaultType$1 = {
+    offset: '(number|null)',
+    // TODO v6 @deprecated, keep it for backwards compatibility reasons
+    rootMargin: 'string',
+    smoothScroll: 'boolean',
+    target: 'element',
+    threshold: 'array'
+  };
+
+  /**
+   * Class definition
+   */
+
+  class ScrollSpy extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+
+      // this._element is the observablesContainer and config.target the menu links wrapper
+      this._targetLinks = new Map();
+      this._observableSections = new Map();
+      this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;
+      this._activeTarget = null;
+      this._observer = null;
+      this._previousScrollData = {
+        visibleEntryTop: 0,
+        parentScrollTop: 0
+      };
+      this.refresh(); // initialize
+    }
+
+    // Getters
+    static get Default() {
+      return Default$1;
+    }
+    static get DefaultType() {
+      return DefaultType$1;
+    }
+    static get NAME() {
+      return NAME$2;
+    }
+
+    // Public
+    refresh() {
+      this._initializeTargetsAndObservables();
+      this._maybeEnableSmoothScroll();
+      if (this._observer) {
+        this._observer.disconnect();
+      } else {
+        this._observer = this._getNewObserver();
+      }
+      for (const section of this._observableSections.values()) {
+        this._observer.observe(section);
+      }
+    }
+    dispose() {
+      this._observer.disconnect();
+      super.dispose();
+    }
+
+    // Private
+    _configAfterMerge(config) {
+      // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
+      config.target = getElement(config.target) || document.body;
+
+      // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
+      config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;
+      if (typeof config.threshold === 'string') {
+        config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));
+      }
+      return config;
+    }
+    _maybeEnableSmoothScroll() {
+      if (!this._config.smoothScroll) {
+        return;
+      }
+
+      // unregister any previous listeners
+      EventHandler.off(this._config.target, EVENT_CLICK);
+      EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {
+        const observableSection = this._observableSections.get(event.target.hash);
+        if (observableSection) {
+          event.preventDefault();
+          const root = this._rootElement || window;
+          const height = observableSection.offsetTop - this._element.offsetTop;
+          if (root.scrollTo) {
+            root.scrollTo({
+              top: height,
+              behavior: 'smooth'
+            });
+            return;
+          }
+
+          // Chrome 60 doesn't support `scrollTo`
+          root.scrollTop = height;
+        }
+      });
+    }
+    _getNewObserver() {
+      const options = {
+        root: this._rootElement,
+        threshold: this._config.threshold,
+        rootMargin: this._config.rootMargin
+      };
+      return new IntersectionObserver(entries => this._observerCallback(entries), options);
+    }
+
+    // The logic of selection
+    _observerCallback(entries) {
+      const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);
+      const activate = entry => {
+        this._previousScrollData.visibleEntryTop = entry.target.offsetTop;
+        this._process(targetElement(entry));
+      };
+      const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;
+      const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;
+      this._previousScrollData.parentScrollTop = parentScrollTop;
+      for (const entry of entries) {
+        if (!entry.isIntersecting) {
+          this._activeTarget = null;
+          this._clearActiveClass(targetElement(entry));
+          continue;
+        }
+        const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;
+        // if we are scrolling down, pick the bigger offsetTop
+        if (userScrollsDown && entryIsLowerThanPrevious) {
+          activate(entry);
+          // if parent isn't scrolled, let's keep the first visible item, breaking the iteration
+          if (!parentScrollTop) {
+            return;
+          }
+          continue;
+        }
+
+        // if we are scrolling up, pick the smallest offsetTop
+        if (!userScrollsDown && !entryIsLowerThanPrevious) {
+          activate(entry);
+        }
+      }
+    }
+    _initializeTargetsAndObservables() {
+      this._targetLinks = new Map();
+      this._observableSections = new Map();
+      const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);
+      for (const anchor of targetLinks) {
+        // ensure that the anchor has an id and is not disabled
+        if (!anchor.hash || isDisabled(anchor)) {
+          continue;
+        }
+        const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);
+
+        // ensure that the observableSection exists & is visible
+        if (isVisible(observableSection)) {
+          this._targetLinks.set(decodeURI(anchor.hash), anchor);
+          this._observableSections.set(anchor.hash, observableSection);
+        }
+      }
+    }
+    _process(target) {
+      if (this._activeTarget === target) {
+        return;
+      }
+      this._clearActiveClass(this._config.target);
+      this._activeTarget = target;
+      target.classList.add(CLASS_NAME_ACTIVE$1);
+      this._activateParents(target);
+      EventHandler.trigger(this._element, EVENT_ACTIVATE, {
+        relatedTarget: target
+      });
+    }
+    _activateParents(target) {
+      // Activate dropdown parents
+      if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
+        SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1);
+        return;
+      }
+      for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {
+        // Set triggered links parents as active
+        // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
+        for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {
+          item.classList.add(CLASS_NAME_ACTIVE$1);
+        }
+      }
+    }
+    _clearActiveClass(parent) {
+      parent.classList.remove(CLASS_NAME_ACTIVE$1);
+      const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE$1}`, parent);
+      for (const node of activeNodes) {
+        node.classList.remove(CLASS_NAME_ACTIVE$1);
+      }
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = ScrollSpy.getOrCreateInstance(this, config);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config]();
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => {
+    for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {
+      ScrollSpy.getOrCreateInstance(spy);
+    }
+  });
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(ScrollSpy);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap tab.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME$1 = 'tab';
+  const DATA_KEY$1 = 'bs.tab';
+  const EVENT_KEY$1 = `.${DATA_KEY$1}`;
+  const EVENT_HIDE$1 = `hide${EVENT_KEY$1}`;
+  const EVENT_HIDDEN$1 = `hidden${EVENT_KEY$1}`;
+  const EVENT_SHOW$1 = `show${EVENT_KEY$1}`;
+  const EVENT_SHOWN$1 = `shown${EVENT_KEY$1}`;
+  const EVENT_CLICK_DATA_API = `click${EVENT_KEY$1}`;
+  const EVENT_KEYDOWN = `keydown${EVENT_KEY$1}`;
+  const EVENT_LOAD_DATA_API = `load${EVENT_KEY$1}`;
+  const ARROW_LEFT_KEY = 'ArrowLeft';
+  const ARROW_RIGHT_KEY = 'ArrowRight';
+  const ARROW_UP_KEY = 'ArrowUp';
+  const ARROW_DOWN_KEY = 'ArrowDown';
+  const HOME_KEY = 'Home';
+  const END_KEY = 'End';
+  const CLASS_NAME_ACTIVE = 'active';
+  const CLASS_NAME_FADE$1 = 'fade';
+  const CLASS_NAME_SHOW$1 = 'show';
+  const CLASS_DROPDOWN = 'dropdown';
+  const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
+  const SELECTOR_DROPDOWN_MENU = '.dropdown-menu';
+  const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)';
+  const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
+  const SELECTOR_OUTER = '.nav-item, .list-group-item';
+  const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
+  const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // TODO: could only be `tab` in v6
+  const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
+  const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`;
+
+  /**
+   * Class definition
+   */
+
+  class Tab extends BaseComponent {
+    constructor(element) {
+      super(element);
+      this._parent = this._element.closest(SELECTOR_TAB_PANEL);
+      if (!this._parent) {
+        return;
+        // TODO: should throw exception in v6
+        // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
+      }
+
+      // Set up initial aria attributes
+      this._setInitialAttributes(this._parent, this._getChildren());
+      EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
+    }
+
+    // Getters
+    static get NAME() {
+      return NAME$1;
+    }
+
+    // Public
+    show() {
+      // Shows this elem and deactivate the active sibling if exists
+      const innerElem = this._element;
+      if (this._elemIsActive(innerElem)) {
+        return;
+      }
+
+      // Search for active tab on same parent to deactivate it
+      const active = this._getActiveElem();
+      const hideEvent = active ? EventHandler.trigger(active, EVENT_HIDE$1, {
+        relatedTarget: innerElem
+      }) : null;
+      const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW$1, {
+        relatedTarget: active
+      });
+      if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) {
+        return;
+      }
+      this._deactivate(active, innerElem);
+      this._activate(innerElem, active);
+    }
+
+    // Private
+    _activate(element, relatedElem) {
+      if (!element) {
+        return;
+      }
+      element.classList.add(CLASS_NAME_ACTIVE);
+      this._activate(SelectorEngine.getElementFromSelector(element)); // Search and activate/show the proper section
+
+      const complete = () => {
+        if (element.getAttribute('role') !== 'tab') {
+          element.classList.add(CLASS_NAME_SHOW$1);
+          return;
+        }
+        element.removeAttribute('tabindex');
+        element.setAttribute('aria-selected', true);
+        this._toggleDropDown(element, true);
+        EventHandler.trigger(element, EVENT_SHOWN$1, {
+          relatedTarget: relatedElem
+        });
+      };
+      this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1));
+    }
+    _deactivate(element, relatedElem) {
+      if (!element) {
+        return;
+      }
+      element.classList.remove(CLASS_NAME_ACTIVE);
+      element.blur();
+      this._deactivate(SelectorEngine.getElementFromSelector(element)); // Search and deactivate the shown section too
+
+      const complete = () => {
+        if (element.getAttribute('role') !== 'tab') {
+          element.classList.remove(CLASS_NAME_SHOW$1);
+          return;
+        }
+        element.setAttribute('aria-selected', false);
+        element.setAttribute('tabindex', '-1');
+        this._toggleDropDown(element, false);
+        EventHandler.trigger(element, EVENT_HIDDEN$1, {
+          relatedTarget: relatedElem
+        });
+      };
+      this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1));
+    }
+    _keydown(event) {
+      if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key)) {
+        return;
+      }
+      event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
+      event.preventDefault();
+      const children = this._getChildren().filter(element => !isDisabled(element));
+      let nextActiveElement;
+      if ([HOME_KEY, END_KEY].includes(event.key)) {
+        nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1];
+      } else {
+        const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key);
+        nextActiveElement = getNextActiveElement(children, event.target, isNext, true);
+      }
+      if (nextActiveElement) {
+        nextActiveElement.focus({
+          preventScroll: true
+        });
+        Tab.getOrCreateInstance(nextActiveElement).show();
+      }
+    }
+    _getChildren() {
+      // collection of inner elements
+      return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent);
+    }
+    _getActiveElem() {
+      return this._getChildren().find(child => this._elemIsActive(child)) || null;
+    }
+    _setInitialAttributes(parent, children) {
+      this._setAttributeIfNotExists(parent, 'role', 'tablist');
+      for (const child of children) {
+        this._setInitialAttributesOnChild(child);
+      }
+    }
+    _setInitialAttributesOnChild(child) {
+      child = this._getInnerElement(child);
+      const isActive = this._elemIsActive(child);
+      const outerElem = this._getOuterElement(child);
+      child.setAttribute('aria-selected', isActive);
+      if (outerElem !== child) {
+        this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
+      }
+      if (!isActive) {
+        child.setAttribute('tabindex', '-1');
+      }
+      this._setAttributeIfNotExists(child, 'role', 'tab');
+
+      // set attributes to the related panel too
+      this._setInitialAttributesOnTargetPanel(child);
+    }
+    _setInitialAttributesOnTargetPanel(child) {
+      const target = SelectorEngine.getElementFromSelector(child);
+      if (!target) {
+        return;
+      }
+      this._setAttributeIfNotExists(target, 'role', 'tabpanel');
+      if (child.id) {
+        this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`);
+      }
+    }
+    _toggleDropDown(element, open) {
+      const outerElem = this._getOuterElement(element);
+      if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
+        return;
+      }
+      const toggle = (selector, className) => {
+        const element = SelectorEngine.findOne(selector, outerElem);
+        if (element) {
+          element.classList.toggle(className, open);
+        }
+      };
+      toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE);
+      toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW$1);
+      outerElem.setAttribute('aria-expanded', open);
+    }
+    _setAttributeIfNotExists(element, attribute, value) {
+      if (!element.hasAttribute(attribute)) {
+        element.setAttribute(attribute, value);
+      }
+    }
+    _elemIsActive(elem) {
+      return elem.classList.contains(CLASS_NAME_ACTIVE);
+    }
+
+    // Try to get the inner element (usually the .nav-link)
+    _getInnerElement(elem) {
+      return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem);
+    }
+
+    // Try to get the outer element (usually the .nav-item)
+    _getOuterElement(elem) {
+      return elem.closest(SELECTOR_OUTER) || elem;
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Tab.getOrCreateInstance(this);
+        if (typeof config !== 'string') {
+          return;
+        }
+        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+          throw new TypeError(`No method named "${config}"`);
+        }
+        data[config]();
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+    if (['A', 'AREA'].includes(this.tagName)) {
+      event.preventDefault();
+    }
+    if (isDisabled(this)) {
+      return;
+    }
+    Tab.getOrCreateInstance(this).show();
+  });
+
+  /**
+   * Initialize on focus
+   */
+  EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+    for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
+      Tab.getOrCreateInstance(element);
+    }
+  });
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Tab);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap toast.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+
+  /**
+   * Constants
+   */
+
+  const NAME = 'toast';
+  const DATA_KEY = 'bs.toast';
+  const EVENT_KEY = `.${DATA_KEY}`;
+  const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`;
+  const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`;
+  const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
+  const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`;
+  const EVENT_HIDE = `hide${EVENT_KEY}`;
+  const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
+  const EVENT_SHOW = `show${EVENT_KEY}`;
+  const EVENT_SHOWN = `shown${EVENT_KEY}`;
+  const CLASS_NAME_FADE = 'fade';
+  const CLASS_NAME_HIDE = 'hide'; // @deprecated - kept here only for backwards compatibility
+  const CLASS_NAME_SHOW = 'show';
+  const CLASS_NAME_SHOWING = 'showing';
+  const DefaultType = {
+    animation: 'boolean',
+    autohide: 'boolean',
+    delay: 'number'
+  };
+  const Default = {
+    animation: true,
+    autohide: true,
+    delay: 5000
+  };
+
+  /**
+   * Class definition
+   */
+
+  class Toast extends BaseComponent {
+    constructor(element, config) {
+      super(element, config);
+      this._timeout = null;
+      this._hasMouseInteraction = false;
+      this._hasKeyboardInteraction = false;
+      this._setListeners();
+    }
+
+    // Getters
+    static get Default() {
+      return Default;
+    }
+    static get DefaultType() {
+      return DefaultType;
+    }
+    static get NAME() {
+      return NAME;
+    }
+
+    // Public
+    show() {
+      const showEvent = EventHandler.trigger(this._element, EVENT_SHOW);
+      if (showEvent.defaultPrevented) {
+        return;
+      }
+      this._clearTimeout();
+      if (this._config.animation) {
+        this._element.classList.add(CLASS_NAME_FADE);
+      }
+      const complete = () => {
+        this._element.classList.remove(CLASS_NAME_SHOWING);
+        EventHandler.trigger(this._element, EVENT_SHOWN);
+        this._maybeScheduleHide();
+      };
+      this._element.classList.remove(CLASS_NAME_HIDE); // @deprecated
+      reflow(this._element);
+      this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING);
+      this._queueCallback(complete, this._element, this._config.animation);
+    }
+    hide() {
+      if (!this.isShown()) {
+        return;
+      }
+      const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE);
+      if (hideEvent.defaultPrevented) {
+        return;
+      }
+      const complete = () => {
+        this._element.classList.add(CLASS_NAME_HIDE); // @deprecated
+        this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW);
+        EventHandler.trigger(this._element, EVENT_HIDDEN);
+      };
+      this._element.classList.add(CLASS_NAME_SHOWING);
+      this._queueCallback(complete, this._element, this._config.animation);
+    }
+    dispose() {
+      this._clearTimeout();
+      if (this.isShown()) {
+        this._element.classList.remove(CLASS_NAME_SHOW);
+      }
+      super.dispose();
+    }
+    isShown() {
+      return this._element.classList.contains(CLASS_NAME_SHOW);
+    }
+
+    // Private
+
+    _maybeScheduleHide() {
+      if (!this._config.autohide) {
+        return;
+      }
+      if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
+        return;
+      }
+      this._timeout = setTimeout(() => {
+        this.hide();
+      }, this._config.delay);
+    }
+    _onInteraction(event, isInteracting) {
+      switch (event.type) {
+        case 'mouseover':
+        case 'mouseout':
+          {
+            this._hasMouseInteraction = isInteracting;
+            break;
+          }
+        case 'focusin':
+        case 'focusout':
+          {
+            this._hasKeyboardInteraction = isInteracting;
+            break;
+          }
+      }
+      if (isInteracting) {
+        this._clearTimeout();
+        return;
+      }
+      const nextElement = event.relatedTarget;
+      if (this._element === nextElement || this._element.contains(nextElement)) {
+        return;
+      }
+      this._maybeScheduleHide();
+    }
+    _setListeners() {
+      EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true));
+      EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false));
+      EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true));
+      EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false));
+    }
+    _clearTimeout() {
+      clearTimeout(this._timeout);
+      this._timeout = null;
+    }
+
+    // Static
+    static jQueryInterface(config) {
+      return this.each(function () {
+        const data = Toast.getOrCreateInstance(this, config);
+        if (typeof config === 'string') {
+          if (typeof data[config] === 'undefined') {
+            throw new TypeError(`No method named "${config}"`);
+          }
+          data[config](this);
+        }
+      });
+    }
+  }
+
+  /**
+   * Data API implementation
+   */
+
+  enableDismissTrigger(Toast);
+
+  /**
+   * jQuery
+   */
+
+  defineJQueryPlugin(Toast);
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap index.umd.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  const index_umd = {
+    Alert,
+    Button,
+    Carousel,
+    Collapse,
+    Dropdown,
+    Modal,
+    Offcanvas,
+    Popover,
+    ScrollSpy,
+    Tab,
+    Toast,
+    Tooltip
+  };
+
+  return index_umd;
+
+}));

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 290 - 158
src/static/scripts/bootstrap.css


+ 27 - 20
src/static/scripts/datatables.css

@@ -4,10 +4,10 @@
  *
  * To rebuild or modify this file with the latest versions of the included
  * software please visit:
- *   https://datatables.net/download/#bs5/dt-1.13.4
+ *   https://datatables.net/download/#bs5/dt-1.13.6
  *
  * Included libraries:
- *   DataTables 1.13.4
+ *   DataTables 1.13.6
  */
 
 @charset "UTF-8";
@@ -15,6 +15,13 @@
   --dt-row-selected: 13, 110, 253;
   --dt-row-selected-text: 255, 255, 255;
   --dt-row-selected-link: 9, 10, 11;
+  --dt-row-stripe: 0, 0, 0;
+  --dt-row-hover: 0, 0, 0;
+  --dt-column-ordering: 0, 0, 0;
+  --dt-html-background: white;
+}
+:root.dark {
+  --dt-html-background: rgb(33, 37, 41);
 }
 
 table.dataTable td.dt-control {
@@ -22,25 +29,19 @@ table.dataTable td.dt-control {
   cursor: pointer;
 }
 table.dataTable td.dt-control:before {
-  height: 1em;
-  width: 1em;
-  margin-top: -9px;
   display: inline-block;
-  color: white;
-  border: 0.15em solid white;
-  border-radius: 1em;
-  box-shadow: 0 0 0.2em #444;
-  box-sizing: content-box;
-  text-align: center;
-  text-indent: 0 !important;
-  font-family: "Courier New", Courier, monospace;
-  line-height: 1em;
-  content: "+";
-  background-color: #31b131;
+  color: rgba(0, 0, 0, 0.5);
+  content: "►";
 }
 table.dataTable tr.dt-hasChild td.dt-control:before {
-  content: "-";
-  background-color: #d33333;
+  content: "▼";
+}
+
+html.dark table.dataTable td.dt-control:before {
+  color: rgba(255, 255, 255, 0.5);
+}
+html.dark table.dataTable tr.dt-hasChild td.dt-control:before {
+  color: rgba(255, 255, 255, 0.5);
 }
 
 table.dataTable thead > tr > th.sorting, table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting_asc_disabled, table.dataTable thead > tr > th.sorting_desc_disabled,
@@ -303,14 +304,14 @@ table.dataTable > tbody > tr.selected a {
   color: rgb(var(--dt-row-selected-link));
 }
 table.dataTable.table-striped > tbody > tr.odd > * {
-  box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.05);
 }
 table.dataTable.table-striped > tbody > tr.odd.selected > * {
   box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.95);
   box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.95);
 }
 table.dataTable.table-hover > tbody > tr:hover > * {
-  box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.075);
 }
 table.dataTable.table-hover > tbody > tr.selected:hover > * {
   box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.975);
@@ -441,4 +442,10 @@ div.table-responsive > div.dataTables_wrapper > div.row > div[class^=col-]:last-
   padding-right: 0;
 }
 
+:root[data-bs-theme=dark] {
+  --dt-row-hover: 255, 255, 255;
+  --dt-row-stripe: 255, 255, 255;
+  --dt-column-ordering: 255, 255, 255;
+}
+
 

+ 59 - 34
src/static/scripts/datatables.js

@@ -4,20 +4,20 @@
  *
  * To rebuild or modify this file with the latest versions of the included
  * software please visit:
- *   https://datatables.net/download/#bs5/dt-1.13.4
+ *   https://datatables.net/download/#bs5/dt-1.13.6
  *
  * Included libraries:
- *   DataTables 1.13.4
+ *   DataTables 1.13.6
  */
 
-/*! DataTables 1.13.4
+/*! DataTables 1.13.6
  * ©2008-2023 SpryMedia Ltd - datatables.net/license
  */
 
 /**
  * @summary     DataTables
  * @description Paginate, search and order HTML tables
- * @version     1.13.4
+ * @version     1.13.6
  * @author      SpryMedia Ltd
  * @contact     www.datatables.net
  * @copyright   SpryMedia Ltd.
@@ -50,7 +50,7 @@
 		// returns a factory function that expects the window object
 		var jq = require('jquery');
 
-		if (typeof window !== 'undefined') {
+		if (typeof window === 'undefined') {
 			module.exports = function (root, $) {
 				if ( ! root ) {
 					// CommonJS environments without a window global must pass a
@@ -1396,7 +1396,7 @@
 	
 	
 	var _isNumber = function ( d, decimalPoint, formatted ) {
-		let type = typeof d;
+		var type = typeof d;
 		var strType = type === 'string';
 	
 		if ( type === 'number' || type === 'bigint') {
@@ -1530,7 +1530,9 @@
 	
 	
 	var _stripHtml = function ( d ) {
-		return d.replace( _re_html, '' );
+		return d
+			.replace( _re_html, '' ) // Complete tags
+			.replace(/<script/i, ''); // Safety for incomplete script tag
 	};
 	
 	
@@ -1904,7 +1906,10 @@
 								continue;
 							}
 		
-							if ( data === null || data[ a[i] ] === undefined ) {
+							if (data === null || data[ a[i] ] === null) {
+								return null;
+							}
+							else if ( data === undefined || data[ a[i] ] === undefined ) {
 								return undefined;
 							}
 	
@@ -2351,6 +2356,12 @@
 				oCol.aDataSort = [ oOptions.iDataSort ];
 			}
 			_fnMap( oCol, oOptions, "aDataSort" );
+	
+			// Fall back to the aria-label attribute on the table header if no ariaTitle is
+			// provided.
+			if (! oCol.ariaTitle) {
+				oCol.ariaTitle = th.attr("aria-label");
+			}
 		}
 	
 		/* Cache the data get and set functions for speed */
@@ -4075,11 +4086,16 @@
 		settings.iDraw++;
 		_fnProcessingDisplay( settings, true );
 	
+		// Keep track of drawHold state to handle scrolling after the Ajax call
+		var drawHold = settings._drawHold;
+	
 		_fnBuildAjax(
 			settings,
 			_fnAjaxParameters( settings ),
 			function(json) {
+				settings._drawHold = drawHold;
 				_fnAjaxUpdateDraw( settings, json );
+				settings._drawHold = false;
 			}
 		);
 	}
@@ -4343,7 +4359,7 @@
 					_fnThrottle( searchFn, searchDelay ) :
 					searchFn
 			)
-			.on( 'mouseup', function(e) {
+			.on( 'mouseup.DT', function(e) {
 				// Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
 				// on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
 				// checks the value to see if it has changed. In other browsers it won't have.
@@ -4409,7 +4425,7 @@
 		if ( _fnDataSource( oSettings ) != 'ssp' )
 		{
 			/* Global filter */
-			_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return );
+			_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
 			fnSaveFilter( oInput );
 	
 			/* Now do the individual column filter */
@@ -4578,11 +4594,15 @@
 			 * 
 			 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
 			 */
-			var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
+			var a = $.map( search.match( /["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''], function ( word ) {
 				if ( word.charAt(0) === '"' ) {
 					var m = word.match( /^"(.*)"$/ );
 					word = m ? m[1] : word;
 				}
+				else if ( word.charAt(0) === '\u201C' ) {
+					var m = word.match( /^\u201C(.*)\u201D$/ );
+					word = m ? m[1] : word;
+				}
 	
 				return word.replace('"', '');
 			} );
@@ -9386,7 +9406,8 @@
 	 * Set the jQuery or window object to be used by DataTables
 	 *
 	 * @param {*} module Library / container object
-	 * @param {string} type Library or container type `lib` or `win`.
+	 * @param {string} [type] Library or container type `lib`, `win` or `datetime`.
+	 *   If not provided, automatic detection is attempted.
 	 */
 	DataTable.use = function (module, type) {
 		if (type === 'lib' || module.fn) {
@@ -9396,6 +9417,9 @@
 			window = module;
 			document = module.document;
 		}
+		else if (type === 'datetime' || module.type === 'DateTime') {
+			DataTable.DateTime = module;
+		}
 	}
 	
 	/**
@@ -9755,7 +9779,9 @@
 				resolved._;
 		}
 	
-		return resolved.replace( '%d', plural ); // nb: plural might be undefined,
+		return typeof resolved === 'string'
+			? resolved.replace( '%d', plural ) // nb: plural might be undefined,
+			: resolved;
 	} );	
 	/**
 	 * Version string for plug-ins to check compatibility. Allowed format is
@@ -9765,7 +9791,7 @@
 	 *  @type string
 	 *  @default Version number
 	 */
-	DataTable.version = "1.13.4";
+	DataTable.version = "1.13.6";
 	
 	/**
 	 * Private data store, containing all of the settings objects that are
@@ -14189,7 +14215,7 @@
 		 *
 		 *  @type string
 		 */
-		build:"bs5/dt-1.13.4",
+		build:"bs5/dt-1.13.6",
 	
 	
 		/**
@@ -14830,7 +14856,7 @@
 				var btnDisplay, btnClass;
 	
 				var attach = function( container, buttons ) {
-					var i, ien, node, button, tabIndex;
+					var i, ien, node, button;
 					var disabledClass = classes.sPageButtonDisabled;
 					var clickHandler = function ( e ) {
 						_fnPageChange( settings, e.data.action, true );
@@ -14845,9 +14871,10 @@
 							attach( inner, button );
 						}
 						else {
+							var disabled = false;
+	
 							btnDisplay = null;
 							btnClass = button;
-							tabIndex = settings.iTabIndex;
 	
 							switch ( button ) {
 								case 'ellipsis':
@@ -14858,8 +14885,7 @@
 									btnDisplay = lang.sFirst;
 	
 									if ( page === 0 ) {
-										tabIndex = -1;
-										btnClass += ' ' + disabledClass;
+										disabled = true;
 									}
 									break;
 	
@@ -14867,8 +14893,7 @@
 									btnDisplay = lang.sPrevious;
 	
 									if ( page === 0 ) {
-										tabIndex = -1;
-										btnClass += ' ' + disabledClass;
+										disabled = true;
 									}
 									break;
 	
@@ -14876,8 +14901,7 @@
 									btnDisplay = lang.sNext;
 	
 									if ( pages === 0 || page === pages-1 ) {
-										tabIndex = -1;
-										btnClass += ' ' + disabledClass;
+										disabled = true;
 									}
 									break;
 	
@@ -14885,8 +14909,7 @@
 									btnDisplay = lang.sLast;
 	
 									if ( pages === 0 || page === pages-1 ) {
-										tabIndex = -1;
-										btnClass += ' ' + disabledClass;
+										disabled = true;
 									}
 									break;
 	
@@ -14899,18 +14922,20 @@
 	
 							if ( btnDisplay !== null ) {
 								var tag = settings.oInit.pagingTag || 'a';
-								var disabled = btnClass.indexOf(disabledClass) !== -1;
-			
+	
+								if (disabled) {
+									btnClass += ' ' + disabledClass;
+								}
 	
 								node = $('<'+tag+'>', {
 										'class': classes.sPageButton+' '+btnClass,
 										'aria-controls': settings.sTableId,
 										'aria-disabled': disabled ? 'true' : null,
 										'aria-label': aria[ button ],
-										'aria-role': 'link',
+										'role': 'link',
 										'aria-current': btnClass === classes.sPageButtonActive ? 'page' : null,
 										'data-dt-idx': button,
-										'tabindex': tabIndex,
+										'tabindex': disabled ? -1 : settings.iTabIndex,
 										'id': idx === 0 && typeof button === 'string' ?
 											settings.sTableId +'_'+ button :
 											null
@@ -15041,7 +15066,7 @@
 			return -Infinity;
 		}
 		
-		let type = typeof d;
+		var type = typeof d;
 	
 		if (type === 'number' || type === 'bigint') {
 			return d;
@@ -15415,7 +15440,7 @@
 	var __thousands = ',';
 	var __decimal = '.';
 	
-	if (Intl) {
+	if (window.Intl !== undefined) {
 		try {
 			var num = new Intl.NumberFormat().formatToParts(100000.1);
 		
@@ -15718,7 +15743,7 @@
 			}
 		};
 
-		if (typeof window !== 'undefined') {
+		if (typeof window === 'undefined') {
 			module.exports = function (root, $) {
 				if ( ! root ) {
 					// CommonJS environments without a window global must pass a
@@ -15856,10 +15881,10 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
 								'aria-controls': settings.sTableId,
 								'aria-disabled': disabled ? 'true' : null,
 								'aria-label': aria[ button ],
-								'aria-role': 'link',
+								'role': 'link',
 								'aria-current': btnClass === 'active' ? 'page' : null,
 								'data-dt-idx': button,
-								'tabindex': settings.iTabIndex,
+								'tabindex': disabled ? -1 : settings.iTabIndex,
 								'class': 'page-link'
 							} )
 							.html( btnDisplay )

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 303 - 434
src/static/scripts/jquery-3.7.0.slim.js


+ 51 - 7
src/static/templates/admin/base.hbs

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="en" data-bs-theme="auto">
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -10,17 +10,17 @@
     <link rel="stylesheet" href="{{urlpath}}/vw_static/admin.css" />
     <script src="{{urlpath}}/vw_static/admin.js"></script>
 </head>
-<body class="bg-light">
+<body>
     <nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top">
         <div class="container-xl">
             <a class="navbar-brand" href="{{urlpath}}/admin"><img class="vaultwarden-icon" src="{{urlpath}}/vw_static/vaultwarden-icon.png" alt="V">aultwarden Admin</a>
             <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
-                    aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
+                aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
                 <span class="navbar-toggler-icon"></span>
             </button>
             <div class="collapse navbar-collapse" id="navbarCollapse">
                 <ul class="navbar-nav me-auto">
-                {{#if logged_in}}
+                    {{#if logged_in}}
                     <li class="nav-item">
                         <a class="nav-link" href="{{urlpath}}/admin">Settings</a>
                     </li>
@@ -33,15 +33,59 @@
                     <li class="nav-item">
                         <a class="nav-link" href="{{urlpath}}/admin/diagnostics">Diagnostics</a>
                     </li>
-                {{/if}}
+                    {{/if}}
                     <li class="nav-item">
                         <a class="nav-link" href="{{urlpath}}/" target="_blank" rel="noreferrer">Vault</a>
                     </li>
                 </ul>
 
+                <ul class="navbar-nav">
+                    <li class="nav-item dropdown">
+                        <button
+                            class="btn btn-link nav-link py-0 px-0 px-md-2 dropdown-toggle d-flex align-items-center"
+                            id="bd-theme" type="button" aria-expanded="false" data-bs-toggle="dropdown"
+                            data-bs-display="static" aria-label="Toggle theme (auto)">
+                            <span class="my-1 fs-4 theme-icon-active">
+                                <use>&#9775;</use>
+                            </span>
+                            <span class="d-md-none ms-2" id="bd-theme-text">Toggle theme</span>
+                        </button>
+                        <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme-text">
+                            <li>
+                                <button type="button" class="dropdown-item d-flex align-items-center"
+                                    data-bs-theme-value="light" aria-pressed="false">
+                                    <span class="me-2 fs-4 theme-icon">
+                                        <use>&#9728;</use>
+                                    </span>
+                                    Light
+                                </button>
+                            </li>
+                            <li>
+                                <button type="button" class="dropdown-item d-flex align-items-center"
+                                    data-bs-theme-value="dark" aria-pressed="false">
+                                    <span class="me-2 fs-4 theme-icon">
+                                        <use>&starf;</use>
+                                    </span>
+                                    Dark
+                                </button>
+                            </li>
+                            <li>
+                                <button type="button" class="dropdown-item d-flex align-items-center active"
+                                    data-bs-theme-value="auto" aria-pressed="true">
+                                    <span class="me-2 fs-4 theme-icon">
+                                        <use>&#9775;</use>
+                                    </span>
+                                    Auto
+                                </button>
+                            </li>
+                        </ul>
+                    </li>
+                </ul>
+
                 {{#if logged_in}}
-                    <a class="btn btn-sm btn-secondary" href="{{urlpath}}/admin/logout">Log Out</a>
+                <a class="btn btn-sm btn-secondary" href="{{urlpath}}/admin/logout">Log Out</a>
                 {{/if}}
+
             </div>
         </div>
     </nav>
@@ -49,6 +93,6 @@
     {{> (lookup this "page_content") }}
 
     <!-- This script needs to be at the bottom, else it will fail! -->
-    <script src="{{urlpath}}/vw_static/bootstrap-native.js"></script>
+    <script src="{{urlpath}}/vw_static/bootstrap.bundle.js"></script>
 </body>
 </html>

+ 3 - 3
src/static/templates/admin/diagnostics.hbs

@@ -1,5 +1,5 @@
 <main class="container-xl">
-    <div id="diagnostics-block" class="my-3 p-3 bg-white rounded shadow">
+    <div id="diagnostics-block" class="my-3 p-3 rounded shadow">
         <h6 class="border-bottom pb-2 mb-2">Diagnostics</h6>
 
         <h3>Versions</h3>
@@ -8,8 +8,8 @@
                 <dl class="row">
                     <dt class="col-sm-5">Server Installed
                         <span class="badge bg-success d-none" id="server-success" title="Latest version is installed.">Ok</span>
-                        <span class="badge bg-warning d-none" id="server-warning" title="There seems to be an update available.">Update</span>
-                        <span class="badge bg-info d-none" id="server-branch" title="This is a branched version.">Branched</span>
+                        <span class="badge bg-warning text-dark d-none" id="server-warning" title="There seems to be an update available.">Update</span>
+                        <span class="badge bg-info text-dark d-none" id="server-branch" title="This is a branched version.">Branched</span>
                     </dt>
                     <dd class="col-sm-7">
                         <span id="server-installed">{{page_data.current_release}}</span>

+ 5 - 5
src/static/templates/admin/login.hbs

@@ -1,15 +1,15 @@
 <main class="container-xl">
     {{#if error}}
-    <div class="align-items-center p-3 mb-3 text-white-50 bg-warning rounded shadow">
+    <div class="align-items-center p-3 mb-3 text-opacity-50 text-dark bg-warning rounded shadow">
         <div>
-            <h6 class="mb-0 text-white">{{error}}</h6>
+            <h6 class="mb-0 text-dark">{{error}}</h6>
         </div>
     </div>
     {{/if}}
 
-    <div class="align-items-center p-3 mb-3 text-white-50 bg-danger rounded shadow">
+    <div class="align-items-center p-3 mb-3 text-opacity-75 text-light bg-danger rounded shadow">
         <div>
-            <h6 class="mb-0 text-white">Authentication key needed to continue</h6>
+            <h6 class="mb-0 text-light">Authentication key needed to continue</h6>
             <small>Please provide it below:</small>
 
             <form class="form-inline" method="post" action="{{urlpath}}/admin">
@@ -17,7 +17,7 @@
                 {{#if redirect}}
                 <input type="hidden" id="redirect" name="redirect" value="/{{redirect}}">
                 {{/if}}
-                <button type="submit" class="btn btn-primary">Enter</button>
+                <button type="submit" class="btn btn-primary mt-2">Enter</button>
             </form>
         </div>
     </div>

+ 2 - 2
src/static/templates/admin/organizations.hbs

@@ -1,5 +1,5 @@
 <main class="container-xl">
-    <div id="organizations-block" class="my-3 p-3 bg-white rounded shadow">
+    <div id="organizations-block" class="my-3 p-3 rounded shadow">
         <h6 class="border-bottom pb-2 mb-3">Organizations</h6>
         <div class="table-responsive-xl small">
             <table id="orgs-table" class="table table-sm table-striped table-hover">
@@ -59,7 +59,7 @@
 </main>
 
 <link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
-<script src="{{urlpath}}/vw_static/jquery-3.6.4.slim.js"></script>
+<script src="{{urlpath}}/vw_static/jquery-3.7.0.slim.js"></script>
 <script src="{{urlpath}}/vw_static/datatables.js"></script>
 <script src="{{urlpath}}/vw_static/admin_organizations.js"></script>
 <script src="{{urlpath}}/vw_static/jdenticon.js"></script>

+ 3 - 3
src/static/templates/admin/settings.hbs

@@ -17,7 +17,7 @@
             <form class="form needs-validation" id="config-form" novalidate>
                 {{#each page_data.config}}
                 {{#if groupdoc}}
-                <div class="card bg-light mb-3">
+                <div class="card mb-3">
                     <button id="b_{{group}}" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_{{group}}" data-bs-toggle="collapse" data-bs-target="#g_{{group}}">{{groupdoc}}</button>
                     <div id="g_{{group}}" class="card-body collapse">
                         {{#each elements}}
@@ -64,7 +64,7 @@
                 {{/if}}
                 {{/each}}
 
-                <div class="card bg-light mb-3">
+                <div class="card mb-3">
                     <button id="b_readonly" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_readonly"
                             data-bs-toggle="collapse" data-bs-target="#g_readonly">Read-Only Config</button>
                     <div id="g_readonly" class="card-body collapse">
@@ -119,7 +119,7 @@
                 </div>
 
                 {{#if page_data.can_backup}}
-                <div class="card bg-light mb-3">
+                <div class="card mb-3">
                     <button id="b_database" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_database"
                             data-bs-toggle="collapse" data-bs-target="#g_database">Backup Database</button>
                     <div id="g_database" class="card-body collapse">

+ 3 - 3
src/static/templates/admin/users.hbs

@@ -1,5 +1,5 @@
 <main class="container-xl">
-    <div id="users-block" class="my-3 p-3 bg-white rounded shadow">
+    <div id="users-block" class="my-3 p-3 rounded shadow">
         <h6 class="border-bottom pb-2 mb-3">Registered Users</h6>
         <div class="table-responsive-xl small">
             <table id="users-table" class="table table-sm table-striped table-hover">
@@ -30,7 +30,7 @@
                                         <span class="badge bg-success me-2" title="2FA is enabled">2FA</span>
                                     {{/if}}
                                     {{#case _Status 1}}
-                                        <span class="badge bg-warning me-2" title="User is invited">Invited</span>
+                                        <span class="badge bg-warning text-dark me-2" title="User is invited">Invited</span>
                                     {{/case}}
                                     {{#if EmailVerified}}
                                         <span class="badge bg-success me-2" title="Email has been verified">Verified</span>
@@ -140,7 +140,7 @@
 </main>
 
 <link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
-<script src="{{urlpath}}/vw_static/jquery-3.6.4.slim.js"></script>
+<script src="{{urlpath}}/vw_static/jquery-3.7.0.slim.js"></script>
 <script src="{{urlpath}}/vw_static/datatables.js"></script>
 <script src="{{urlpath}}/vw_static/admin_users.js"></script>
 <script src="{{urlpath}}/vw_static/jdenticon.js"></script>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio